diff --git a/.changeset/great-rockets-scream.md b/.changeset/great-rockets-scream.md
new file mode 100644
index 00000000000..8b9f3f7dcf2
--- /dev/null
+++ b/.changeset/great-rockets-scream.md
@@ -0,0 +1,5 @@
+---
+"@thirdweb-dev/react": patch
+---
+
+thirdweb Pay UI minor improvements
diff --git a/.changeset/little-coins-thank.md b/.changeset/little-coins-thank.md
new file mode 100644
index 00000000000..10e38f216d6
--- /dev/null
+++ b/.changeset/little-coins-thank.md
@@ -0,0 +1,50 @@
+---
+"thirdweb": minor
+---
+
+### "Credit Card" payment method added in thirdweb Pay for Fiat on-ramp
+
+### `PayEmbed` component added to embed thirdweb Pay UI
+
+```tsx
+
+```
+
+### thirdweb Pay UI customization available in `PayEmbed` and `ConnectButton`
+
+`payOptions` prop in `PayEmbed` and `ConnectButton > detailsModal` allows you custimize :
+
+- Enable/Disable payment methods
+- Set default amount for Buy token
+- Set Buy token/chain to be selected by default
+- Set Source token/chain to be selected by default for Crypto payment method
+- Disable editing for Buy token/chain/amount and Source token/chain
+
+```tsx
+
+
+
+```
+
+### Fiat on-ramp functions and hooks added
+
+- `getBuyWithFiatQuote`, `useBuyWithFiatQuote` to get a quote for buying crypto with fiat currency
+- `getBuyWithFiatStatus`, `useBuyWithFiatStatus` to get status of "Buy with fiat" transaction
+- `getBuyWithFiatHistory`, `useBuyWithFiatHistory` to get "Buy with fiat" transaction history
+- `getPostOnRampQuote`, `usePostOnRampQuote` to get quote for swapping on-ramp token to destination token after doing on-ramp
+- Add `getBuyHistory` and `useBuyHistory` to get both "Buy with Fiat" and "Buy with Crypto" transaction history in a single list
diff --git a/.vscode/settings.json b/.vscode/settings.json
index a8bae8a1cab..4c3d31af01a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -5,11 +5,15 @@
"quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
},
- "typescript.preferences.importModuleSpecifier": "relative",
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
- }
+ },
+ "[typescript]": {
+ "editor.defaultFormatter": "biomejs.biome"
+ },
+ "typescript.preferences.autoImportFileExcludePatterns": ["/exports"],
+ "typescript.preferences.importModuleSpecifier": "relative"
}
diff --git a/legacy_packages/react/src/wallet/ConnectWallet/screens/Buy/swap/pendingSwapTx.ts b/legacy_packages/react/src/wallet/ConnectWallet/screens/Buy/swap/pendingSwapTx.ts
index 52532b87adc..3000fc136b3 100644
--- a/legacy_packages/react/src/wallet/ConnectWallet/screens/Buy/swap/pendingSwapTx.ts
+++ b/legacy_packages/react/src/wallet/ConnectWallet/screens/Buy/swap/pendingSwapTx.ts
@@ -1,11 +1,12 @@
-import { getBuyWithCryptoStatus } from "@thirdweb-dev/sdk";
-import type { BuyWithCryptoStatus } from "@thirdweb-dev/sdk";
+import { getBuyWithCryptoStatus, type BuyWithCryptoStatus } from "@thirdweb-dev/sdk";
import { wait } from "../../../../../utils/wait";
+type ValidBuyWithCryptoStatus = Exclude
+
type SwapTxInfo = {
transactionHash: string;
- status: BuyWithCryptoStatus["status"];
- subStatus?: BuyWithCryptoStatus["subStatus"];
+ status: ValidBuyWithCryptoStatus["status"];
+ subStatus?: ValidBuyWithCryptoStatus["subStatus"];
source: {
symbol: string;
value: string;
diff --git a/legacy_packages/react/src/wallet/ConnectWallet/screens/SwapTransactionsScreen.tsx b/legacy_packages/react/src/wallet/ConnectWallet/screens/SwapTransactionsScreen.tsx
index 626361eeee2..bfdeddc07cc 100644
--- a/legacy_packages/react/src/wallet/ConnectWallet/screens/SwapTransactionsScreen.tsx
+++ b/legacy_packages/react/src/wallet/ConnectWallet/screens/SwapTransactionsScreen.tsx
@@ -24,13 +24,16 @@ import { BuyIcon } from "../icons/BuyIcon";
import { Text } from "../../../components/text";
import { CryptoIcon } from "../icons/CryptoIcon";
+type ValidBuyWithCryptoStatus = Exclude
+
+
type TxStatusInfo = {
boughChainId: number;
transactionHash: string;
boughtTokenAmount: string;
boughtTokenSymbol: string;
- status: BuyWithCryptoStatus["status"];
- subStatus?: BuyWithCryptoStatus["subStatus"];
+ status: ValidBuyWithCryptoStatus["status"];
+ subStatus?: ValidBuyWithCryptoStatus["subStatus"];
};
const PAGE_SIZE = 10;
@@ -51,7 +54,11 @@ export function SwapTransactionsScreen(props: { onBack: () => void }) {
const txHashSet = new Set();
_historyQuery.data?.page.forEach((tx) => {
- txHashSet.add(tx.source.transactionHash);
+ if (tx.status !== "NOT_FOUND" && tx.status !== 'NONE') {
+ if (tx.source?.transactionHash) {
+ txHashSet.add(tx.source?.transactionHash);
+ }
+ }
});
// add in-memory pending transactions
@@ -76,15 +83,20 @@ export function SwapTransactionsScreen(props: { onBack: () => void }) {
// Add data from endpoint
_historyQuery.data?.page.forEach((tx) => {
- txInfosToShow.push({
- boughChainId: tx.destination?.token.chainId || tx.quote.toToken.chainId,
- transactionHash: tx.source.transactionHash,
- boughtTokenAmount: tx.destination?.amount || tx.quote.toAmount,
- boughtTokenSymbol:
- tx.destination?.token.symbol || tx.quote.toToken.symbol || "",
- status: tx.status,
- subStatus: tx.subStatus,
- });
+ if (tx.status !== "NOT_FOUND" && tx.status !== 'NONE') {
+ if (tx.source?.transactionHash) {
+ txInfosToShow.push({
+ boughChainId:
+ tx.destination?.token.chainId || tx.quote.toToken.chainId,
+ transactionHash: tx.source?.transactionHash,
+ boughtTokenAmount: tx.destination?.amount || tx.quote.toAmount,
+ boughtTokenSymbol:
+ tx.destination?.token.symbol || tx.quote.toToken.symbol || "",
+ status: tx.status,
+ subStatus: tx.subStatus,
+ });
+ }
+ }
});
const activeChainId = useChainId();
@@ -367,8 +379,8 @@ const TxHashLink = /* @__PURE__ */ StyledAnchor(() => {
});
function getStatusMeta(
- status: BuyWithCryptoStatus["status"],
- subStatus?: BuyWithCryptoStatus["subStatus"],
+ status: ValidBuyWithCryptoStatus["status"],
+ subStatus?: ValidBuyWithCryptoStatus["subStatus"],
) {
if (subStatus === "WAITING_BRIDGE") {
return {
diff --git a/packages/thirdweb/src/exports/pay.ts b/packages/thirdweb/src/exports/pay.ts
index 6b485a1eed0..c8b463af4b9 100644
--- a/packages/thirdweb/src/exports/pay.ts
+++ b/packages/thirdweb/src/exports/pay.ts
@@ -4,17 +4,56 @@ export {
type QuoteApprovalParams,
type QuoteTokenInfo,
type GetBuyWithCryptoQuoteParams,
-} from "../pay/buyWithCrypto/actions/getQuote.js";
+} from "../pay/buyWithCrypto/getQuote.js";
export {
getBuyWithCryptoStatus,
type BuyWithCryptoStatus,
type BuyWithCryptoTransaction,
- type BuyWithCryptoTransactionDetails,
-} from "../pay/buyWithCrypto/actions/getStatus.js";
+} from "../pay/buyWithCrypto/getStatus.js";
export {
getBuyWithCryptoHistory,
type BuyWithCryptoHistoryData,
type BuyWithCryptoHistoryParams,
-} from "../pay/buyWithCrypto/actions/getHistory.js";
+} from "../pay/buyWithCrypto/getHistory.js";
+
+// fiat ------------------------------------------------
+
+export {
+ getBuyWithFiatQuote,
+ type BuyWithFiatQuote,
+ type GetBuyWithFiatQuoteParams,
+} from "../pay/buyWithFiat/getQuote.js";
+
+export {
+ getBuyWithFiatStatus,
+ type BuyWithFiatStatus,
+ type GetBuyWithFiatStatusParams,
+} from "../pay/buyWithFiat/getStatus.js";
+
+export {
+ getBuyWithFiatHistory,
+ type BuyWithFiatHistoryData,
+ type BuyWithFiatHistoryParams,
+} from "../pay/buyWithFiat/getHistory.js";
+
+export {
+ getPostOnRampQuote,
+ type GetPostOnRampQuoteParams,
+} from "../pay/buyWithFiat/getPostOnRampQuote.js";
+
+export {
+ getBuyHistory,
+ type BuyHistoryData,
+ type BuyHistoryParams,
+} from "../pay/getBuyHistory.js";
+
+export { isSwapRequiredPostOnramp } from "../pay/buyWithFiat/isSwapRequiredPostOnramp.js";
+
+// types ------------------------------------------------
+
+export type {
+ PayTokenInfo,
+ PayOnChainTransactionDetails,
+} from "../pay/utils/commonTypes.js";
diff --git a/packages/thirdweb/src/exports/react-native.ts b/packages/thirdweb/src/exports/react-native.ts
index d530c9ceba3..c9208e6d23e 100644
--- a/packages/thirdweb/src/exports/react-native.ts
+++ b/packages/thirdweb/src/exports/react-native.ts
@@ -32,19 +32,33 @@ export {
export { createContractQuery } from "../react/core/utils/createQuery.js";
export { useInvalidateContractQuery } from "../react/core/hooks/others/useInvalidateQueries.js";
-// Buy with crypto
+// pay
export {
useBuyWithCryptoQuote,
- type BuyWithCryptoQuoteQueryParams,
+ type BuyWithCryptoQuoteQueryOptions,
} from "../react/core/hooks/pay/useBuyWithCryptoQuote.js";
-export {
- useBuyWithCryptoStatus,
- type BuyWithCryptoStatusQueryParams,
-} from "../react/core/hooks/pay/useBuyWithCryptoStatus.js";
+export { useBuyWithCryptoStatus } from "../react/core/hooks/pay/useBuyWithCryptoStatus.js";
export {
useBuyWithCryptoHistory,
- type BuyWithCryptoHistoryQueryParams,
+ type BuyWithCryptoHistoryQueryOptions,
} from "../react/core/hooks/pay/useBuyWithCryptoHistory.js";
+export {
+ useBuyWithFiatQuote,
+ type BuyWithFiatQuoteQueryOptions,
+} from "../react/core/hooks/pay/useBuyWithFiatQuote.js";
+export { useBuyWithFiatStatus } from "../react/core/hooks/pay/useBuyWithFiatStatus.js";
+export {
+ useBuyWithFiatHistory,
+ type BuyWithFiatHistoryQueryOptions,
+} from "../react/core/hooks/pay/useBuyWithFiatHistory.js";
+export {
+ useBuyHistory,
+ type BuyHistoryQueryOptions,
+} from "../react/core/hooks/pay/useBuyHistory.js";
+export {
+ usePostOnRampQuote,
+ type PostOnRampQuoteQueryOptions,
+} from "../react/core/hooks/pay/usePostOnrampQuote.js";
import { useSendTransactionCore } from "../react/core/hooks/contract/useSendTransaction.js";
diff --git a/packages/thirdweb/src/exports/react.ts b/packages/thirdweb/src/exports/react.ts
index c83b80b056c..5606a641f27 100644
--- a/packages/thirdweb/src/exports/react.ts
+++ b/packages/thirdweb/src/exports/react.ts
@@ -80,20 +80,33 @@ export {
export { createContractQuery } from "../react/core/utils/createQuery.js";
export { useInvalidateContractQuery } from "../react/core/hooks/others/useInvalidateQueries.js";
-// Buy with crypto
+// pay
export {
useBuyWithCryptoQuote,
- type BuyWithCryptoQuoteQueryParams,
+ type BuyWithCryptoQuoteQueryOptions,
} from "../react/core/hooks/pay/useBuyWithCryptoQuote.js";
-
-export {
- useBuyWithCryptoStatus,
- type BuyWithCryptoStatusQueryParams,
-} from "../react/core/hooks/pay/useBuyWithCryptoStatus.js";
+export { useBuyWithCryptoStatus } from "../react/core/hooks/pay/useBuyWithCryptoStatus.js";
export {
useBuyWithCryptoHistory,
- type BuyWithCryptoHistoryQueryParams,
+ type BuyWithCryptoHistoryQueryOptions,
} from "../react/core/hooks/pay/useBuyWithCryptoHistory.js";
+export {
+ useBuyWithFiatQuote,
+ type BuyWithFiatQuoteQueryOptions,
+} from "../react/core/hooks/pay/useBuyWithFiatQuote.js";
+export { useBuyWithFiatStatus } from "../react/core/hooks/pay/useBuyWithFiatStatus.js";
+export {
+ useBuyWithFiatHistory,
+ type BuyWithFiatHistoryQueryOptions,
+} from "../react/core/hooks/pay/useBuyWithFiatHistory.js";
+export {
+ useBuyHistory,
+ type BuyHistoryQueryOptions,
+} from "../react/core/hooks/pay/useBuyHistory.js";
+export {
+ usePostOnRampQuote,
+ type PostOnRampQuoteQueryOptions,
+} from "../react/core/hooks/pay/usePostOnrampQuote.js";
export {
AutoConnect,
@@ -102,3 +115,6 @@ export {
// auth
export { type SiweAuthOptions } from "../react/core/hooks/auth/useSiweAuth.js";
+
+export { PayEmbed, type PayEmbedProps } from "../react/web/ui/PayEmbed.js";
+export type { PayUIOptions } from "../react/web/ui/ConnectWallet/ConnectButtonProps.js";
diff --git a/packages/thirdweb/src/exports/thirdweb.ts b/packages/thirdweb/src/exports/thirdweb.ts
index c95fa95c319..bd7c6ffd3bd 100644
--- a/packages/thirdweb/src/exports/thirdweb.ts
+++ b/packages/thirdweb/src/exports/thirdweb.ts
@@ -156,20 +156,24 @@ export {
type QuoteApprovalParams,
type QuoteTokenInfo,
type GetBuyWithCryptoQuoteParams,
-} from "../pay/buyWithCrypto/actions/getQuote.js";
+} from "../pay/buyWithCrypto/getQuote.js";
export {
getBuyWithCryptoStatus,
type BuyWithCryptoStatus,
type BuyWithCryptoTransaction,
- type BuyWithCryptoTransactionDetails,
-} from "../pay/buyWithCrypto/actions/getStatus.js";
+} from "../pay/buyWithCrypto/getStatus.js";
export {
getBuyWithCryptoHistory,
type BuyWithCryptoHistoryData,
type BuyWithCryptoHistoryParams,
-} from "../pay/buyWithCrypto/actions/getHistory.js";
+} from "../pay/buyWithCrypto/getHistory.js";
+
+export type {
+ PayOnChainTransactionDetails,
+ PayTokenInfo,
+} from "../pay/utils/commonTypes.js";
// ------------------------------------------------
// encoding
diff --git a/packages/thirdweb/src/pay/buyWithCrypto/actions/getHistory.ts b/packages/thirdweb/src/pay/buyWithCrypto/getHistory.ts
similarity index 96%
rename from packages/thirdweb/src/pay/buyWithCrypto/actions/getHistory.ts
rename to packages/thirdweb/src/pay/buyWithCrypto/getHistory.ts
index bd242378a6f..a49a7fb7732 100644
--- a/packages/thirdweb/src/pay/buyWithCrypto/actions/getHistory.ts
+++ b/packages/thirdweb/src/pay/buyWithCrypto/getHistory.ts
@@ -1,5 +1,5 @@
-import type { ThirdwebClient } from "../../../client/client.js";
-import { getClientFetch } from "../../../utils/fetch.js";
+import type { ThirdwebClient } from "../../client/client.js";
+import { getClientFetch } from "../../utils/fetch.js";
import { getPayBuyWithCryptoHistoryEndpoint } from "../utils/definitions.js";
import type { BuyWithCryptoStatus } from "./getStatus.js";
diff --git a/packages/thirdweb/src/pay/buyWithCrypto/actions/getQuote.ts b/packages/thirdweb/src/pay/buyWithCrypto/getQuote.ts
similarity index 90%
rename from packages/thirdweb/src/pay/buyWithCrypto/actions/getQuote.ts
rename to packages/thirdweb/src/pay/buyWithCrypto/getQuote.ts
index 3bd36a86488..af447124ce5 100644
--- a/packages/thirdweb/src/pay/buyWithCrypto/actions/getQuote.ts
+++ b/packages/thirdweb/src/pay/buyWithCrypto/getQuote.ts
@@ -1,14 +1,14 @@
import type { Hash } from "viem";
-import { defineChain } from "../../../chains/utils.js";
-import type { ThirdwebClient } from "../../../client/client.js";
-import { getContract } from "../../../contract/contract.js";
+import { defineChain } from "../../chains/utils.js";
+import type { ThirdwebClient } from "../../client/client.js";
+import { getContract } from "../../contract/contract.js";
import {
type ApproveParams,
approve,
-} from "../../../extensions/erc20/write/approve.js";
-import type { PrepareTransactionOptions } from "../../../transaction/prepare-transaction.js";
-import type { BaseTransactionOptions } from "../../../transaction/types.js";
-import { getClientFetch } from "../../../utils/fetch.js";
+} from "../../extensions/erc20/write/approve.js";
+import type { PrepareTransactionOptions } from "../../transaction/prepare-transaction.js";
+import type { BaseTransactionOptions } from "../../transaction/types.js";
+import { getClientFetch } from "../../utils/fetch.js";
import { getPayBuyWithCryptoQuoteEndpoint } from "../utils/definitions.js";
// TODO: add JSDoc description for all properties
@@ -27,6 +27,15 @@ export type GetBuyWithCryptoQuoteParams = {
*/
client: ThirdwebClient;
+ /**
+ * This is only relevant if the buy-with-crypto transaction is part of buy-with-fiat flow.
+ *
+ * When a swap is required after an onramp transaction, the intentId is used to link the buy-with-crypto transaction to the onramp transaction.
+ * Refer to [`getPostOnRampQuote`](https://portal.thirdweb.com/references/typescript/v5/getPostOnRampQuote) for more information.`
+ *
+ */
+ intentId?: string;
+
/**
* The address of the wallet from which the tokens will be sent.
*/
@@ -240,6 +249,10 @@ export async function getBuyWithCryptoQuote(
queryParams.append("maxSlippageBPS", params.maxSlippageBPS.toString());
}
+ if (params.intentId) {
+ queryParams.append("intentId", params.intentId);
+ }
+
const queryString = queryParams.toString();
const url = `${getPayBuyWithCryptoQuoteEndpoint()}?${queryString}`;
diff --git a/packages/thirdweb/src/pay/buyWithCrypto/actions/getStatus.ts b/packages/thirdweb/src/pay/buyWithCrypto/getStatus.ts
similarity index 66%
rename from packages/thirdweb/src/pay/buyWithCrypto/actions/getStatus.ts
rename to packages/thirdweb/src/pay/buyWithCrypto/getStatus.ts
index 6ad90a9bc4e..9761d0ff980 100644
--- a/packages/thirdweb/src/pay/buyWithCrypto/actions/getStatus.ts
+++ b/packages/thirdweb/src/pay/buyWithCrypto/getStatus.ts
@@ -1,23 +1,16 @@
-import type { ThirdwebClient } from "../../../client/client.js";
-import { getClientFetch } from "../../../utils/fetch.js";
+import type { ThirdwebClient } from "../../client/client.js";
+import { getClientFetch } from "../../utils/fetch.js";
+import type {
+ PayOnChainTransactionDetails,
+ PayTokenInfo,
+} from "../utils/commonTypes.js";
import { getPayBuyWithCryptoStatusUrl } from "../utils/definitions.js";
-import type { QuoteTokenInfo } from "./getQuote.js";
// TODO: add JSDoc description for all properties
-export type BuyWithCryptoTransactionDetails = {
- transactionHash: string;
- token: QuoteTokenInfo;
- amountWei: string;
- amount: string;
- amountUSDCents: number;
- completedAt?: string; // ISO DATE
- explorerLink?: string;
-};
-
export type BuyWithCryptoQuoteSummary = {
- fromToken: QuoteTokenInfo;
- toToken: QuoteTokenInfo;
+ fromToken: PayTokenInfo;
+ toToken: PayTokenInfo;
fromAmountWei: string;
fromAmount: string;
@@ -46,12 +39,7 @@ export type BuyWithCryptoTransaction = {
transactionHash: string;
};
-export type BuyWithCryptoStatuses =
- | "NOT_FOUND"
- | "NONE"
- | "PENDING"
- | "FAILED"
- | "COMPLETED";
+export type BuyWithCryptoStatuses = "NONE" | "PENDING" | "FAILED" | "COMPLETED";
export type BuyWithCryptoSubStatuses =
| "NONE"
@@ -67,18 +55,27 @@ export type SwapType = "SAME_CHAIN" | "CROSS_CHAIN";
* The object returned by the [`getBuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoStatus) function to represent the status of a quoted transaction
* @buyCrypto
*/
-export type BuyWithCryptoStatus = {
- quote: BuyWithCryptoQuoteSummary;
- swapType: SwapType;
- source: BuyWithCryptoTransactionDetails;
- destination?: BuyWithCryptoTransactionDetails;
- status: BuyWithCryptoStatuses;
- subStatus: BuyWithCryptoSubStatuses;
- fromAddress: string;
- toAddress: string;
- failureMessage?: string;
- bridge?: string;
-};
+export type BuyWithCryptoStatus =
+ | {
+ status: "NOT_FOUND";
+ }
+ | {
+ quote: BuyWithCryptoQuoteSummary;
+ swapType: SwapType;
+ source?: PayOnChainTransactionDetails;
+ destination?: PayOnChainTransactionDetails;
+ status: BuyWithCryptoStatuses;
+ subStatus: BuyWithCryptoSubStatuses;
+ fromAddress: string;
+ toAddress: string;
+ failureMessage?: string;
+ bridge?: string;
+ };
+
+export type ValidBuyWithCryptoStatus = Exclude<
+ BuyWithCryptoStatus,
+ { status: "NOT_FOUND" }
+>;
/**
* Gets the status of a buy with crypto transaction
@@ -86,7 +83,7 @@ export type BuyWithCryptoStatus = {
* @example
*
* ```ts
- * import { sendTransaction, prepareTransaction } from "thirdweb";
+ * import { sendTransaction } from "thirdweb";
* import { getBuyWithCryptoStatus, getBuyWithCryptoQuote } from "thirdweb/pay";
*
* // get a quote between two tokens
@@ -94,23 +91,26 @@ export type BuyWithCryptoStatus = {
*
* // if approval is required, send the approval transaction
* if (quote.approval) {
- * const preparedApproval = prepareTransaction(quote.approval);
- * await sendTransaction({
- * transaction,
- * wallet,
+ * const txResult = await sendTransaction({
+ * transaction: quote.approval,
+ * account: account, // account from connected wallet
* });
+ *
+ * await waitForReceipt(txResult);
* }
*
* // send the quoted transaction
- * const preparedTransaction = prepareTransaction(quote.transactionRequest);
- * const transactionResult = await sendTransaction({
- * transaction,
- * wallet,
+ * const swapTxResult = await sendTransaction({
+ * transaction: quote.transactionRequest,
+ * account: account, // account from connected wallet
* });
+ *
+ * await waitForReceipt(swapTxResult);
+ *
* // keep polling the status of the quoted transaction until it returns a success or failure status
* const status = await getBuyWithCryptoStatus({
* client,
- * transactionHash: transactionResult.transactionHash,
+ * transactionHash: swapTxResult.transactionHash,
* }});
* ```
* @returns Object of type [`BuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoStatus)
@@ -130,7 +130,7 @@ export async function getBuyWithCryptoStatus(
const response = await getClientFetch(buyWithCryptoTransaction.client)(url);
- // Assuming the response directly matches the SwapResponse interface
+ // Assuming the response directly matches the BuyWithCryptoStatus interface
if (!response.ok) {
response.body?.cancel();
throw new Error(`HTTP error! status: ${response.status}`);
diff --git a/packages/thirdweb/src/pay/buyWithCrypto/utils/definitions.ts b/packages/thirdweb/src/pay/buyWithCrypto/utils/definitions.ts
deleted file mode 100644
index b93cd1f49d4..00000000000
--- a/packages/thirdweb/src/pay/buyWithCrypto/utils/definitions.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-import { getThirdwebDomains } from "../../../utils/domains.js";
-
-/**
- * Constructs the endpoint to get the status of a quote.
- * @param client - The Thirdweb client containing the baseUrl config
- * @internal
- */
-export const getPayBuyWithCryptoStatusUrl = () =>
- `https://${getThirdwebDomains().pay}/buy-with-crypto/status/v1`;
-/**
- * Constructs the endpoint to get a pay quote.
- * @param client - The Thirdweb client containing the baseUrl config
- * @internal
- */
-export const getPayBuyWithCryptoQuoteEndpoint = () =>
- `https://${getThirdwebDomains().pay}/buy-with-crypto/quote/v1`;
-
-/**
- * Constructs the endpoint to get a wallet address swap history.
- * @param client - The Thirdweb client containing the baseUrl config
- * @internal
- */
-export const getPayBuyWithCryptoHistoryEndpoint = () =>
- `https://${getThirdwebDomains().pay}/buy-with-crypto/history/v1`;
-
-/**
- * Constructs the endpoint to get the pay endpoint
- * @internal
- */
-export const getPayChainsEndpoint = () =>
- `https://${getThirdwebDomains().pay}/chains`;
diff --git a/packages/thirdweb/src/pay/buyWithFiat/getHistory.ts b/packages/thirdweb/src/pay/buyWithFiat/getHistory.ts
new file mode 100644
index 00000000000..a1aa37047e5
--- /dev/null
+++ b/packages/thirdweb/src/pay/buyWithFiat/getHistory.ts
@@ -0,0 +1,90 @@
+import type { ThirdwebClient } from "../../client/client.js";
+import { getClientFetch } from "../../utils/fetch.js";
+import { getPayBuyWithFiatHistoryEndpoint } from "../utils/definitions.js";
+import type { BuyWithFiatStatus } from "./getStatus.js";
+
+/**
+ * The parameters for [`getBuyWithFiatHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatHistory) function
+ * @buyCrypto
+ */
+export type BuyWithFiatHistoryParams = {
+ /**
+ * A client is the entry point to the thirdweb SDK. It is required for all other actions.
+ *
+ * You can create a client using the `createThirdwebClient` function.
+ * Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
+ */
+ client: ThirdwebClient;
+ /**
+ * The address of the wallet to get the wallet history for
+ */
+ walletAddress: string;
+ /**
+ * The number of results to return in a single page. The default value is `10`.
+ */
+ count: number;
+ /**
+ * index of the first result to return. The default value is `0`.
+ *
+ * If you want to start the list from nth item, you can set the start value to (n-1).
+ */
+ start: number;
+};
+
+/**
+ * The results for [`getBuyWithFiatHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatHistory) function
+ * @buyFiat
+ */
+export type BuyWithFiatHistoryData = {
+ page: BuyWithFiatStatus[];
+ hasNextPage: boolean;
+};
+
+/**
+ * Get the "Buy with fiat" transaction history for a given wallet address
+ * @param params Object of type [`BuyWithFiatHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatHistoryParams)
+ * @example
+ *
+ * ```ts
+ * import { createThirdwebClient } from "thirdweb";
+ * import { getBuyWithFiatHistory } from "thirdweb/pay";
+ *
+ * const client = createThirdwebClient({ clientId: "..." });
+ *
+ * // get the 10 latest "Buy with fiat" transactions dony by the wallet
+ * const history = await getBuyWithFiatHistory({
+ * client: client,
+ * walletAddress: '0x...',
+ * start: 0,
+ * count: 10,
+ * })
+ * ```
+ * @returns Object of type [`BuyWithFiatHistoryData`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatHistoryData)
+ * @buyFiat
+ */
+export async function getBuyWithFiatHistory(
+ params: BuyWithFiatHistoryParams,
+): Promise {
+ try {
+ const queryParams = new URLSearchParams();
+ queryParams.append("walletAddress", params.walletAddress);
+ queryParams.append("start", params.start.toString());
+ queryParams.append("count", params.count.toString());
+
+ const queryString = queryParams.toString();
+ const url = `${getPayBuyWithFiatHistoryEndpoint()}?${queryString}`;
+
+ const response = await getClientFetch(params.client)(url);
+
+ // Assuming the response directly matches the BuyWithFiatStatus response interface
+ if (!response.ok) {
+ response.body?.cancel();
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data: BuyWithFiatHistoryData = (await response.json()).result;
+ return data;
+ } catch (error) {
+ throw new Error(`Fetch failed: ${error}`);
+ }
+}
diff --git a/packages/thirdweb/src/pay/buyWithFiat/getPostOnRampQuote.ts b/packages/thirdweb/src/pay/buyWithFiat/getPostOnRampQuote.ts
new file mode 100644
index 00000000000..346d0628747
--- /dev/null
+++ b/packages/thirdweb/src/pay/buyWithFiat/getPostOnRampQuote.ts
@@ -0,0 +1,77 @@
+import type { ThirdwebClient } from "../../client/client.js";
+import {
+ type BuyWithCryptoQuote,
+ getBuyWithCryptoQuote,
+} from "../buyWithCrypto/getQuote.js";
+import type { BuyWithFiatStatus } from "./getStatus.js";
+
+/**
+ * The parameters for [`getPostOnRampQuote`](https://portal.thirdweb.com/references/typescript/v5/getPostOnRampQuote) function
+ */
+export type GetPostOnRampQuoteParams = {
+ /**
+ * A client is the entry point to the thirdweb SDK. It is required for all other actions.
+ *
+ * You can create a client using the `createThirdwebClient` function.
+ * Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
+ */
+ client: ThirdwebClient;
+ /**
+ * The "Buy with fiat" transaction status object returned by [`getBuyWithFiatStatus`](https://portal.thirdweb.com/typescript/v5/getBuyWithFiatStatus) function
+ */
+ buyWithFiatStatus: BuyWithFiatStatus;
+};
+
+/**
+ * When buying a token with fiat currency - It only involes doing on-ramp if the on-ramp provider supports buying the given destination token directly.
+ *
+ * If the on-ramp provider does not support buying the destination token directly, user can be sent an intermediate token with fiat currency from the on-ramp provider which
+ * can be swapped to destination token onchain.
+ *
+ * `getPostOnRampQuote` function is used to get the quote for swapping the on-ramp token to destination token.
+ *
+ * When you get a "Buy with Fiat" status of type "CRYPTO_SWAP_REQUIRED" from the [`getBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatStatus) function,
+ * you can use `getPostOnRampQuote` function to get the quote of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) for swapping the on-ramp token to destination token
+ *
+ * Once you have the quote, you can start the Swap process by following the same steps as mentioned in the [`getBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoQuote) documentation.
+ *
+ * @param params - object of type [`GetPostOnRampQuoteParams`](https://portal.thirdweb.com/references/typescript/v5/GetPostOnRampQuoteParams)
+ * @returns Object of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) which contains the information about the quote such as processing fees, estimated time, converted token amounts, etc.
+ * @example
+ * ```ts
+ * import { getPostOnRampQuote, getBuyWithFiatStatus } from "thirdweb/pay";
+ *
+ * // previous steps
+ * const fiatQuote = await getBuyWithFiatQuote(fiatQuoteParams);
+ * window.open(fiatQuote.onRampLink, "_blank");
+ * const buyWithFiatStatus = await getBuyWithFiatStatus({ client, intentId }); // keep calling this until status is "settled" state
+ *
+ * // when a swap is required after onramp
+ * if (buyWithFiatStatus.status === "CRYPTO_SWAP_REQUIRED") {
+ * const buyWithCryptoQuote = await getPostOnRampQuote({
+ * client,
+ * buyWithFiatStatus
+ * });
+ * }
+ * ```
+ * @buyFiat
+ */
+export async function getPostOnRampQuote({
+ client,
+ buyWithFiatStatus,
+}: GetPostOnRampQuoteParams): Promise {
+ if (buyWithFiatStatus.status === "NOT_FOUND") {
+ throw new Error("Invalid buyWithFiatStatus");
+ }
+
+ return getBuyWithCryptoQuote({
+ client,
+ intentId: buyWithFiatStatus.intentId,
+ fromAddress: buyWithFiatStatus.toAddress,
+ fromChainId: buyWithFiatStatus.quote.onRampToken.chainId,
+ fromTokenAddress: buyWithFiatStatus.quote.onRampToken.tokenAddress,
+ toChainId: buyWithFiatStatus.quote.toToken.chainId,
+ toTokenAddress: buyWithFiatStatus.quote.toToken.tokenAddress,
+ toAmount: buyWithFiatStatus.quote.estimatedToTokenAmount,
+ });
+}
diff --git a/packages/thirdweb/src/pay/buyWithFiat/getQuote.ts b/packages/thirdweb/src/pay/buyWithFiat/getQuote.ts
new file mode 100644
index 00000000000..2a975985139
--- /dev/null
+++ b/packages/thirdweb/src/pay/buyWithFiat/getQuote.ts
@@ -0,0 +1,283 @@
+import type { ThirdwebClient } from "../../client/client.js";
+import { getClientFetch } from "../../utils/fetch.js";
+import { getPayBuyWithFiatQuoteEndpoint } from "../utils/definitions.js";
+
+/**
+ * Parameters for [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function
+ */
+export type GetBuyWithFiatQuoteParams = {
+ /**
+ * A client is the entry point to the thirdweb SDK. It is required for all other actions.
+ *
+ * You can create a client using the `createThirdwebClient` function.
+ * Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
+ */
+ client: ThirdwebClient;
+
+ /**
+ * The address of the wallet to which the tokens will be sent.
+ */
+ toAddress: string;
+
+ /**
+ * Chain id of the token to buy.
+ */
+ toChainId: number;
+
+ /**
+ * Token address of the token to buy.
+ */
+ toTokenAddress: string;
+
+ /**
+ * Symbol of the fiat currency to buy the token with.
+ *
+ * Currently, only `USD` is supported.
+ */
+ fromCurrencySymbol: "USD";
+
+ /**
+ * The maximum slippage in basis points (bps) allowed for the transaction.
+ * For example, if you want to allow a maximum slippage of 0.5%, you should specify `50` bps.
+ */
+ maxSlippageBPS?: number;
+
+ /**
+ * The amount of fiat currency to spend to buy the token.
+ * This is useful if you want to buy whatever amount of token you can get for a certain amount of fiat currency.
+ *
+ * If you want a certain amount of token, you can provide `toAmount` instead of `fromAmount`.
+ */
+ fromAmount?: string;
+
+ /**
+ * The amount of token to buy
+ * This is useful if you want to get a certain amount of token.
+ *
+ * If you want to buy however much token you can get for a certain amount of fiat currency, you can provide `fromAmount` instead of `toAmount`.
+ */
+ toAmount?: string;
+
+ /**
+ * Whether to use on-ramp provider in test mode for testing purpose or not.
+ *
+ * Defaults to `false`
+ */
+ isTestMode?: boolean;
+};
+
+/**
+ * The response object returned by the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function.
+ *
+ * This includes various information for buying a token using a fiat currency:
+ * - on-ramp provider UI link
+ * - The estimated time for the transaction to complete.
+ * - The on-ramp and destination token information.
+ * - Processing fees
+ */
+export type BuyWithFiatQuote = {
+ /**
+ * Estimated time for the transaction to complete in seconds.
+ */
+ estimatedDurationSeconds: number;
+ /**
+ * Minimum amount of token that is expected to be received in units.
+ */
+ estimatedToAmountMin: string;
+ /**
+ * Minimum amount of token that is expected to be received in wei.
+ */
+ estimatedToAmountMinWei: string;
+ /**
+ * Amount of token that is expected to be received in units.
+ *
+ * (estimatedToAmountMinWei - maxSlippageWei)
+ */
+ toAmountMinWei: string;
+ /**
+ * Amount of token that is expected to be received in wei.
+ *
+ * (estimatedToAmountMin - maxSlippageWei)
+ */
+ toAmountMin: string;
+ /**
+ * fiat currency used to buy the token - excluding the fees.
+ */
+ fromCurrency: {
+ amount: string;
+ amountUnits: string;
+ decimals: number;
+ currencySymbol: string;
+ };
+ /**
+ * Fiat currency used to buy the token - including the fees.
+ */
+ fromCurrencyWithFees: {
+ amount: string;
+ amountUnits: string;
+ decimals: number;
+ currencySymbol: string;
+ };
+ /**
+ * Token information for the desired token. (token the user wants to buy)
+ */
+ toToken: {
+ symbol?: string | undefined;
+ priceUSDCents?: number | undefined;
+ name?: string | undefined;
+ chainId: number;
+ tokenAddress: string;
+ decimals: number;
+ };
+ /**
+ * Address of the wallet to which the tokens will be sent.
+ */
+ toAddress: string;
+ /**
+ * The maximum slippage in basis points (bps) allowed for the transaction.
+ */
+ maxSlippageBPS: number;
+ /**
+ * Id of transaction
+ */
+ intentId: string;
+ /**
+ * Array of processing fees for the transaction.
+ *
+ * This includes the processing fees for on-ramp and swap (if required).
+ */
+ processingFees: {
+ amount: string;
+ amountUnits: string;
+ decimals: number;
+ currencySymbol: string;
+ feeType: "ON_RAMP" | "NETWORK";
+ }[];
+ /**
+ * Token that will be sent to the user's wallet address by the on-ramp provider.
+ *
+ * If the token is same as `toToken` - the user can directly buy the token from the on-ramp provider.
+ * If not, the user will receive this token and a swap is required to convert it `toToken`.
+ */
+ onRampToken: {
+ amount: string;
+ amountWei: string;
+ amountUSDCents: number;
+ token: {
+ chainId: number;
+ decimals: number;
+ name: string;
+ priceUSDCents: number;
+ symbol: string;
+ tokenAddress: string;
+ };
+ };
+
+ /**
+ * Link to the on-ramp provider UI that will prompt the user to buy the token with fiat currency.
+ *
+ * This link should be opened in a new tab.
+ * @example
+ * ```ts
+ * window.open(quote.onRampLink, "_blank");
+ * ```
+ *
+ */
+ onRampLink: string;
+};
+
+/**
+ * Get a quote of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote) to buy given token with fiat currency.
+ * This quote contains the information about the swap such as token amounts, processing fees, estimated time etc.
+ *
+ * ### Rendering the On-Ramp provider UI
+ * Once you have the `quote`, you can open the `quote.onRampLink` in a new tab - This will prompt the user to buy the token with fiat currency
+ *
+ * ### Determining the steps required
+ * If `quote.onRampToken.token` is same as `quote.toToken` ( same chain + same token address ) - This means that the token can be directly bought from the on-ramp provider.
+ * But if they are different, On-ramp provider will send the `quote.onRampToken` to the user's wallet address and a swap is required to swap it to the desired token onchain.
+ *
+ * You can use the [`isSwapRequiredPostOnramp`](https://portal.thirdweb.com/references/typescript/v5/isSwapRequiredPostOnramp) utility function to check if a swap is required after the on-ramp is done.
+ *
+ * ### Polling for the status
+ * Once you open the `quote.onRampLink` in a new tab, you can start polling for the status using [`getBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatStatus) to get the status of the transaction.
+ *
+ * `getBuyWithFiatStatus` returns a status object of type [`BuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatStatus).
+ *
+ * - If no swap is required - the status will become `"ON_RAMP_TRANSFER_COMPLETED"` once the on-ramp provider has sent the desired token to the user's wallet address. Once you receive this status, the process is complete.
+ * - If a swap is required - the status will become `"CRYPTO_SWAP_REQUIRED"` once the on-ramp provider has sent the tokens to the user's wallet address. Once you receive this status, you need to start the swap process.
+ *
+ * ### Swap Process
+ * On receiving the `"CRYPTO_SWAP_REQUIRED"` status, you can use the [`getPostOnRampQuote`](https://portal.thirdweb.com/references/typescript/v5/getPostOnRampQuote) function to get the quote for the swap of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote).
+ *
+ * Once you have this quote - You can follow the same steps as mentioned in the [`getBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoQuote) documentation to perform the swap.
+ *
+ * @param params - object of type [`GetBuyWithFiatQuoteParams`](https://portal.thirdweb.com/references/typescript/v5/GetBuyWithFiatQuoteParams)
+ * @returns Object of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote) which contains the information about the quote such as processing fees, estimated time, converted token amounts, etc.
+ * @example
+ * Get a quote for buying 10 USDC on polygon chain (chainId: 137) with USD fiat currency:
+ *
+ * ```ts
+ * import { getBuyWithFiatQuote } from "thirdweb/pay";
+ *
+ * const quote = await getBuyWithFiatQuote({
+ * client: client, // thirdweb client
+ * fromCurrencySymbol: "USD", // fiat currency symbol
+ * toChainId: 137, // polygon chain id
+ * toAmount: "10", // amount of USDC to buy
+ * toTokenAddress: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359" // USDC token address in polygon chain
+ * toAddress: "0x...", // user's wallet address
+ * isTestMode: false, // whether to use onramp in test mode for testing purpose (defaults to false)
+ * });
+ *
+ * window.open(quote.onRampLink, "_blank");
+ * ```
+ * @buyFiat
+ */
+export async function getBuyWithFiatQuote(
+ params: GetBuyWithFiatQuoteParams,
+): Promise {
+ try {
+ const queryParams = new URLSearchParams({
+ toAddress: params.toAddress,
+ fromCurrencySymbol: params.fromCurrencySymbol,
+ toChainId: params.toChainId.toString(),
+ toTokenAddress: params.toTokenAddress.toLowerCase(),
+ });
+
+ if (params.fromAmount) {
+ queryParams.append("fromAmount", params.fromAmount);
+ }
+
+ if (params.toAmount) {
+ queryParams.append("toAmount", params.toAmount);
+ }
+
+ if (params.maxSlippageBPS) {
+ queryParams.append("maxSlippageBPS", params.maxSlippageBPS.toString());
+ }
+
+ if (params.isTestMode) {
+ queryParams.append("isTestMode", params.isTestMode.toString());
+ }
+
+ const queryString = queryParams.toString();
+ const url = `${getPayBuyWithFiatQuoteEndpoint()}?${queryString}`;
+
+ const response = await getClientFetch(params.client)(url);
+
+ // Assuming the response directly matches the SwapResponse interface
+ if (!response.ok) {
+ const errorObj = await response.json();
+ if (errorObj && "error" in errorObj) {
+ throw errorObj;
+ }
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ return (await response.json()).result;
+ } catch (error) {
+ console.error("Fetch error:", error);
+ throw error;
+ }
+}
diff --git a/packages/thirdweb/src/pay/buyWithFiat/getStatus.ts b/packages/thirdweb/src/pay/buyWithFiat/getStatus.ts
new file mode 100644
index 00000000000..b26d9150c0b
--- /dev/null
+++ b/packages/thirdweb/src/pay/buyWithFiat/getStatus.ts
@@ -0,0 +1,186 @@
+import type { ThirdwebClient } from "../../client/client.js";
+import { getClientFetch } from "../../utils/fetch.js";
+import type {
+ PayOnChainTransactionDetails,
+ PayTokenInfo,
+} from "../utils/commonTypes.js";
+import { getPayBuyWithFiatStatusEndpoint } from "../utils/definitions.js";
+
+/**
+ * Parameters for the [`getBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatStatus) function
+ */
+export type GetBuyWithFiatStatusParams = {
+ /**
+ * A client is the entry point to the thirdweb SDK. It is required for all other actions.
+ *
+ * You can create a client using the `createThirdwebClient` function.
+ * Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
+ */
+ client: ThirdwebClient;
+ /**
+ * Intent ID of the "Buy with fiat" transaction. You can get the intent ID from the quote object returned by the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function
+ */
+ intentId: string;
+};
+
+export type ValidBuyWithFiatStatus = Exclude<
+ BuyWithFiatStatus,
+ { status: "NOT_FOUND" }
+>;
+
+/**
+ * The returned object from [`getBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatStatus) function
+ *
+ * If the in invalid intentId is provided, the object will have a status of "NOT_FOUND" and no other fields.
+ */
+export type BuyWithFiatStatus =
+ | {
+ status: "NOT_FOUND";
+ }
+ | {
+ /**
+ * Intent ID of the "Buy with fiat" transaction. You can get the intent ID from the quote object returned by the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function
+ */
+ intentId: string;
+ /**
+ * The status of the transaction
+ * - `NONE` - No status
+ * - `PENDING_PAYMENT` - Payment is not done yet in the on-ramp provider
+ * - `PAYMENT_FAILED` - Payment failed in the on-ramp provider
+ * - `PENDING_ON_RAMP_TRANSFER` - Payment is done but the on-ramp provider is yet to transfer the tokens to the user's wallet
+ * - `ON_RAMP_TRANSFER_IN_PROGRESS` - On-ramp provider is transferring the tokens to the user's wallet
+ * - `ON_RAMP_TRANSFER_COMPLETED` - On-ramp provider has transferred the tokens to the user's wallet
+ * - `ON_RAMP_TRANSFER_FAILED` - On-ramp provider failed to transfer the tokens to the user's wallet
+ * - `CRYPTO_SWAP_REQUIRED` - On-ramp provider has sent the tokens to the user's wallet but a swap is required to convert it to the desired token
+ * - `CRYPTO_SWAP_IN_PROGRESS` - Swap is in progress
+ * - `CRYPTO_SWAP_COMPLETED` - Swap is completed and the user has received the desired token
+ * - `CRYPTO_SWAP_FALLBACK` - Swap failed and the user has received a fallback token which is not the desired token
+ */
+ status:
+ | "NONE"
+ | "PENDING_PAYMENT"
+ | "PAYMENT_FAILED"
+ | "PENDING_ON_RAMP_TRANSFER"
+ | "ON_RAMP_TRANSFER_IN_PROGRESS"
+ | "ON_RAMP_TRANSFER_COMPLETED"
+ | "ON_RAMP_TRANSFER_FAILED"
+ | "CRYPTO_SWAP_REQUIRED"
+ | "CRYPTO_SWAP_COMPLETED"
+ | "CRYPTO_SWAP_FALLBACK"
+ | "CRYPTO_SWAP_IN_PROGRESS"
+ | "CRYPTO_SWAP_FAILED";
+ /**
+ * The wallet address to which the tokens are sent to
+ */
+ toAddress: string;
+ /**
+ * The quote object for the transaction
+ */
+ quote: {
+ estimatedOnRampAmount: string;
+ estimatedOnRampAmountWei: string;
+
+ estimatedToTokenAmount: string;
+ estimatedToTokenAmountWei: string;
+
+ fromCurrency: {
+ amount: string;
+ amountUnits: string;
+ decimals: number;
+ currencySymbol: string;
+ };
+ fromCurrencyWithFees: {
+ amount: string;
+ amountUnits: string;
+ decimals: number;
+ currencySymbol: string;
+ };
+ onRampToken: PayTokenInfo;
+ toToken: PayTokenInfo;
+ estimatedDurationSeconds?: number;
+ createdAt: string;
+ };
+ /**
+ * The on-ramp transaction details
+ *
+ * This field is only present when on-ramp transaction is completed or failed
+ */
+ source?: PayOnChainTransactionDetails;
+ /**
+ * The destination transaction details
+ *
+ * This field is only present when swap transaction is completed or failed
+ */
+ destination?: PayOnChainTransactionDetails;
+ /**
+ * Message indicating the reason for failure
+ */
+ failureMessage?: string;
+ };
+
+/**
+ * Once you get a `quote` from [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote)
+ * and open the `quote.onRampLink` in a new tab, you can start polling for the transaction status using `getBuyWithFiatStatus`
+ *
+ * You should keep calling this function at regular intervals while the status is in one of the pending states such as - "PENDING_PAYMENT", "PENDING_ON_RAMP_TRANSFER", "ON_RAMP_TRANSFER_IN_PROGRESS", "CRYPTO_SWAP_IN_PROGRESS" etc..
+ *
+ * If `quote.onRampToken` is same as `quote.toToken` (same chain + same token address) - This means that the token can be directly bought from the on-ramp provider.
+ * But if they are different - On-ramp provider will send the `quote.onRampToken` to the user's wallet address and a swap is required to convert it to the desired token.
+ * You can use the [`isSwapRequiredPostOnramp`](https://portal.thirdweb.com/references/typescript/v5/isSwapRequiredPostOnramp) utility function to check if a swap is required after the on-ramp is done.
+ *
+ * #### When no swap is required
+ * If there is no swap required - the status will become `"ON_RAMP_TRANSFER_COMPLETED"` once the on-ramp provider has sent the tokens to the user's wallet address.
+ * Once you receive this status, the process is complete.
+ *
+ * ### When a swap is required
+ * If a swap is required - the status will become `"CRYPTO_SWAP_REQUIRED"` once the on-ramp provider has sent the tokens to the user's wallet address.
+ * Once you receive this status, you need to start the swap process.
+ *
+ * On receiving the `"CRYPTO_SWAP_REQUIRED"` status, you can use the [`getPostOnRampQuote`](https://portal.thirdweb.com/references/typescript/v5/getPostOnRampQuote) function to get the quote for the swap of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote).
+ *
+ * Once you have this quote - You can follow the same steps as mentioned in the [`getBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoQuote) documentation to perform the swap.
+ *
+ * @param params - Object of type [`GetBuyWithFiatStatusParams`](https://portal.thirdweb.com/references/typescript/v5/GetBuyWithFiatStatusParams)
+ * @example
+ * ```ts
+ * // step 1 - get a quote
+ * const fiatQuote = await getBuyWithFiatQuote(fiatQuoteParams)
+ *
+ * // step 2 - open the on-ramp provider UI
+ * window.open(quote.onRampLink, "_blank");
+ *
+ * // step 3 - keep calling getBuyWithFiatStatus while the status is in one of the pending states
+ * const fiatStatus = await getBuyWithFiatStatus({
+ * client,
+ * intentId: fiatQuote.intentId,
+ * })
+ *
+ * // when the fiatStatus.status is "ON_RAMP_TRANSFER_COMPLETED" - the process is complete
+ * // when the fiatStatus.status is "CRYPTO_SWAP_REQUIRED" - start the swap process
+ * ```
+ * @buyFiat
+ */
+export async function getBuyWithFiatStatus(
+ params: GetBuyWithFiatStatusParams,
+): Promise {
+ try {
+ const queryParams = new URLSearchParams({
+ intentId: params.intentId,
+ });
+
+ const queryString = queryParams.toString();
+ const url = `${getPayBuyWithFiatStatusEndpoint()}?${queryString}`;
+
+ const response = await getClientFetch(params.client)(url);
+
+ if (!response.ok) {
+ response.body?.cancel();
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ return (await response.json()).result;
+ } catch (error) {
+ console.error("Fetch error:", error);
+ throw new Error(`Fetch failed: ${error}`);
+ }
+}
diff --git a/packages/thirdweb/src/pay/buyWithFiat/isSwapRequiredPostOnramp.ts b/packages/thirdweb/src/pay/buyWithFiat/isSwapRequiredPostOnramp.ts
new file mode 100644
index 00000000000..d995c7d6304
--- /dev/null
+++ b/packages/thirdweb/src/pay/buyWithFiat/isSwapRequiredPostOnramp.ts
@@ -0,0 +1,28 @@
+import { getAddress } from "../../utils/address.js";
+import type { BuyWithFiatQuote } from "./getQuote.js";
+
+/**
+ * Check if a Swap is required after on-ramp when buying a token with fiat currency.
+ *
+ * If `quote.toToken` and `quote.onRampToken` are the same (same token and chain),
+ * it means on-ramp provider can directly send the desired token to the user's wallet and no swap is required.
+ *
+ * If `quote.toToken` and `quote.onRampToken` are different (different token or chain), A swap is required to swap the on-ramp token to the desired token.
+ *
+ * @param buyWithFiatQuote - The quote of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote) returned
+ * by the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function.
+ * @buyFiat
+ */
+export function isSwapRequiredPostOnramp(
+ buyWithFiatQuote: Pick,
+) {
+ const sameChain =
+ buyWithFiatQuote.toToken.chainId ===
+ buyWithFiatQuote.onRampToken.token.chainId;
+
+ const sameToken =
+ getAddress(buyWithFiatQuote.toToken.tokenAddress) ===
+ getAddress(buyWithFiatQuote.onRampToken.token.tokenAddress);
+
+ return !(sameChain && sameToken);
+}
diff --git a/packages/thirdweb/src/pay/getBuyHistory.ts b/packages/thirdweb/src/pay/getBuyHistory.ts
new file mode 100644
index 00000000000..9b5b5d2cbb8
--- /dev/null
+++ b/packages/thirdweb/src/pay/getBuyHistory.ts
@@ -0,0 +1,100 @@
+import type { ThirdwebClient } from "../client/client.js";
+import type { BuyWithCryptoStatus, BuyWithFiatStatus } from "../exports/pay.js";
+import { getClientFetch } from "../utils/fetch.js";
+import { getPayBuyHistoryEndpoint } from "./utils/definitions.js";
+
+/**
+ * The parameters for [`getBuyHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyHistory) function
+ */
+export type BuyHistoryParams = {
+ /**
+ * A client is the entry point to the thirdweb SDK. It is required for all other actions.
+ *
+ * You can create a client using the `createThirdwebClient` function.
+ * Refer to the [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
+ */
+ client: ThirdwebClient;
+ /**
+ * The wallet address to get the buy history for.
+ */
+ walletAddress: string;
+ /**
+ * The number of results to return.
+ *
+ * The default value is `10`.
+ */
+ count: number;
+ /**
+ * Index of the first result to return. The default value is `0`.
+ */
+ start: number;
+};
+
+/**
+ * The result for [`getBuyHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoHistory) function
+ *
+ * It includes both "Buy with Crypto" and "Buy with Fiat" transactions
+ */
+export type BuyHistoryData = {
+ /**
+ * The list of buy transactions.
+ */
+ page: Array<
+ | {
+ buyWithFiatStatus: BuyWithFiatStatus;
+ }
+ | {
+ buyWithCryptoStatus: BuyWithCryptoStatus;
+ }
+ >;
+ /**
+ * Whether there are more pages of results.
+ */
+ hasNextPage: boolean;
+};
+
+/**
+ * Get Buy transaction history for a given wallet address.
+ *
+ * This includes both "Buy with Cryto" and "Buy with Fiat" transactions
+ *
+ * @param params Object of type [`BuyHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyHistoryParams)
+ * @example
+ * ```ts
+ * import { createThirdwebClient } from "thirdweb";
+ * import { getBuyHistory } from "thirdweb/pay";
+ *
+ * const client = createThirdwebClient({ clientId: "..." });
+ *
+ * const history = await getBuyHistory({
+ * client,
+ * walletAddress: "0x...",
+ * })
+ * ```
+ */
+export async function getBuyHistory(
+ params: BuyHistoryParams,
+): Promise {
+ try {
+ const queryParams = new URLSearchParams();
+ queryParams.append("walletAddress", params.walletAddress);
+ queryParams.append("start", params.start.toString());
+ queryParams.append("count", params.count.toString());
+
+ const queryString = queryParams.toString();
+ const url = `${getPayBuyHistoryEndpoint()}?${queryString}`;
+
+ const response = await getClientFetch(params.client)(url);
+
+ // Assuming the response directly matches the SwapResponse interface
+ if (!response.ok) {
+ response.body?.cancel();
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data: BuyHistoryData = (await response.json()).result;
+ return data;
+ } catch (error) {
+ throw new Error(`Fetch failed: ${error}`);
+ }
+}
diff --git a/packages/thirdweb/src/pay/utils/commonTypes.ts b/packages/thirdweb/src/pay/utils/commonTypes.ts
new file mode 100644
index 00000000000..44196d57e3e
--- /dev/null
+++ b/packages/thirdweb/src/pay/utils/commonTypes.ts
@@ -0,0 +1,18 @@
+export type PayTokenInfo = {
+ chainId: number;
+ tokenAddress: string;
+ decimals: number;
+ priceUSDCents: number;
+ name?: string;
+ symbol?: string;
+};
+
+export type PayOnChainTransactionDetails = {
+ transactionHash: string;
+ token: PayTokenInfo;
+ amountWei: string;
+ amount: string;
+ amountUSDCents: number;
+ completedAt?: string; // ISO DATE
+ explorerLink?: string;
+};
diff --git a/packages/thirdweb/src/pay/utils/definitions.ts b/packages/thirdweb/src/pay/utils/definitions.ts
new file mode 100644
index 00000000000..8480540eec7
--- /dev/null
+++ b/packages/thirdweb/src/pay/utils/definitions.ts
@@ -0,0 +1,64 @@
+import { getThirdwebDomains } from "../../utils/domains.js";
+
+/**
+ * Endpoint to get the status of a "Buy with Crypto" quote.
+ * @internal
+ */
+export const getPayBuyWithCryptoStatusUrl = () =>
+ `https://${getThirdwebDomains().pay}/buy-with-crypto/status/v1`;
+/**
+ * Endpoint to get "Buy with Crypto" quote.
+ * @internal
+ */
+export const getPayBuyWithCryptoQuoteEndpoint = () =>
+ `https://${getThirdwebDomains().pay}/buy-with-crypto/quote/v1`;
+
+/**
+ * Endpoint to get a "Buy with Fiat" quote.
+ * @internal
+ */
+export const getPayBuyWithFiatQuoteEndpoint = () =>
+ `https://${getThirdwebDomains().pay}/buy-with-fiat/quote/v1`;
+
+/**
+ * Endpoint to get the status of a "Buy with Fiat" transaction status.
+ * @internal
+ */
+export const getPayBuyWithFiatStatusEndpoint = () =>
+ `https://${getThirdwebDomains().pay}/buy-with-fiat/status/v1`;
+
+/**
+ * Endpoint to get history of "Buy with Fiat" transactions for given wallet address.
+ * @internal
+ */
+export const getPayBuyWithFiatHistoryEndpoint = () =>
+ `https://${getThirdwebDomains().pay}/buy-with-fiat/history/v1`;
+
+/**
+ * Endpoint to get a "Buy with Crypto" transaction history for a given wallet address.
+ * @internal
+ */
+export const getPayBuyWithCryptoHistoryEndpoint = () =>
+ `https://${getThirdwebDomains().pay}/buy-with-crypto/history/v1`;
+
+/**
+ * Endpoint to get a list of supported destination chains and tokens for thirdweb pay.
+ * @internal
+ */
+export const getPaySupportedDestinations = () =>
+ `https://${getThirdwebDomains().pay}/destination-tokens/v1`;
+
+/**
+ * Endpoint to get a list of supported source chains + tokens for thirdweb pay.
+ * @internal
+ */
+export const getPaySupportedSources = () =>
+ `https://${getThirdwebDomains().pay}/buy-with-crypto/source-tokens/v1`;
+
+/**
+ * Endpoint to get buy history for a given wallet address.
+ * This includes both "Buy with Crypto" and "Buy with Fiat" transactions.
+ * @internal
+ */
+export const getPayBuyHistoryEndpoint = () =>
+ `https://${getThirdwebDomains().pay}/wallet/history/v1`;
diff --git a/packages/thirdweb/src/react/core/hooks/contract/useSendTransaction.ts b/packages/thirdweb/src/react/core/hooks/contract/useSendTransaction.ts
index c385d4b3741..c14ceab2175 100644
--- a/packages/thirdweb/src/react/core/hooks/contract/useSendTransaction.ts
+++ b/packages/thirdweb/src/react/core/hooks/contract/useSendTransaction.ts
@@ -9,7 +9,7 @@ import {
type GetWalletBalanceResult,
getWalletBalance,
} from "../../../../wallets/utils/getWalletBalance.js";
-import { fetchSwapSupportedChains } from "../../../web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.js";
+import { fetchBuySupportedDestinations } from "../../../web/ui/ConnectWallet/screens/Buy/swap/useSwapSupportedChains.js";
import { useActiveAccount } from "../wallets/wallet-hooks.js";
type ShowModalData = {
@@ -70,12 +70,10 @@ export function useSendTransactionCore(
(async () => {
try {
- const swapSupportedChains = await fetchSwapSupportedChains(
- tx.client,
- );
+ const destinations = await fetchBuySupportedDestinations(tx.client);
- const isBuySupported = swapSupportedChains.find(
- (c) => c.id === tx.chain.id,
+ const isBuySupported = destinations.find(
+ (c) => c.chain.id === tx.chain.id,
);
// buy not supported, can't show modal - send tx directly
@@ -125,9 +123,8 @@ export function useSendTransactionCore(
}
export async function getTotalTxCostForBuy(tx: PreparedTransaction) {
- // Must pass 0 otherwise it will throw on some chains
const gasCost = await estimateGasCost({
- transaction: { ...tx, value: 0n },
+ transaction: tx,
});
const bufferCost = gasCost.wei / 10n;
diff --git a/packages/thirdweb/src/react/core/hooks/others/useTokenInfo.ts b/packages/thirdweb/src/react/core/hooks/others/useTokenInfo.ts
new file mode 100644
index 00000000000..1fea20e42b9
--- /dev/null
+++ b/packages/thirdweb/src/react/core/hooks/others/useTokenInfo.ts
@@ -0,0 +1,57 @@
+import { useQuery } from "@tanstack/react-query";
+import type { Chain } from "../../../../chains/types.js";
+import type { ThirdwebClient } from "../../../../client/client.js";
+import { getContract } from "../../../../contract/contract.js";
+
+type GetTokenInfoOptions = {
+ client: ThirdwebClient;
+ chain: Chain;
+ tokenAddress?: string;
+};
+
+type GetTokenInfoResult = {
+ name: string;
+ symbol: string;
+ decimals: number;
+};
+
+/**
+ * @internal
+ */
+export function useTokenInfo(options: GetTokenInfoOptions) {
+ const { chain, tokenAddress, client } = options;
+ return useQuery({
+ queryKey: ["tokenInfo", chain?.id || -1, { tokenAddress }] as const,
+ queryFn: async () => {
+ // erc20 case
+ if (tokenAddress) {
+ const { getCurrencyMetadata } = await import(
+ "../../../../extensions/erc20/read/getCurrencyMetadata.js"
+ );
+ const result: GetTokenInfoResult = await getCurrencyMetadata({
+ contract: getContract({ client, chain, address: tokenAddress }),
+ });
+
+ return result;
+ }
+
+ const { getChainDecimals, getChainNativeCurrencyName, getChainSymbol } =
+ await import("../../../../chains/utils.js");
+
+ const [nativeSymbol, nativeDecimals, nativeName] = await Promise.all([
+ getChainSymbol(chain),
+ getChainDecimals(chain),
+ getChainNativeCurrencyName(chain),
+ ]);
+
+ const result: GetTokenInfoResult = {
+ decimals: nativeDecimals,
+ symbol: nativeSymbol,
+ name: nativeName,
+ };
+
+ return result;
+ },
+ enabled: !!chain && !!client,
+ });
+}
diff --git a/packages/thirdweb/src/react/core/hooks/pay/useBuyHistory.ts b/packages/thirdweb/src/react/core/hooks/pay/useBuyHistory.ts
new file mode 100644
index 00000000000..097b41afef8
--- /dev/null
+++ b/packages/thirdweb/src/react/core/hooks/pay/useBuyHistory.ts
@@ -0,0 +1,60 @@
+import {
+ type UseQueryOptions,
+ type UseQueryResult,
+ useQuery,
+} from "@tanstack/react-query";
+import {
+ type BuyHistoryData,
+ type BuyHistoryParams,
+ getBuyHistory,
+} from "../../../../pay/getBuyHistory.js";
+
+/**
+ * @internal
+ */
+export type BuyHistoryQueryOptions = Omit<
+ UseQueryOptions,
+ "queryFn" | "queryKey" | "enabled"
+>;
+
+/**
+ * Hook to get the history of Buy transactions for a given wallet - This includes both "buy with crypto" and "buy with fiat" transactions.
+ *
+ * This hook is a React Query wrapper of the [`getBuyHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyHistory) function.
+ * You can also use that function directly
+ *
+ * @param params - object of type [`BuyHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyHistoryParams)
+ * @param queryParams - options to configure the react query
+ * @returns A React Query object which contains the data of type [`BuyHistoryData`](https://portal.thirdweb.com/references/typescript/v5/BuyHistoryData)
+ * @example
+ * ```tsx
+ * import { useBuyHistory } from "thirdweb/react";
+ *
+ * function Component() {
+ * const buyWithCryptoHistory = useBuyHistory(params);
+ * return
...
+ * }
+ * ```
+ */
+export function useBuyHistory(
+ params?: BuyHistoryParams,
+ queryParams?: BuyHistoryQueryOptions,
+): UseQueryResult {
+ return useQuery({
+ ...queryParams,
+ queryKey: ["getBuyHistory", params],
+ queryFn: () => {
+ if (!params) {
+ throw new Error("params are required");
+ }
+ if (!params?.client) {
+ throw new Error("Client is required");
+ }
+ return getBuyHistory({
+ ...params,
+ client: params.client,
+ });
+ },
+ enabled: !!params,
+ });
+}
diff --git a/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoHistory.ts b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoHistory.ts
index cceea07ac52..dc5acda172a 100644
--- a/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoHistory.ts
+++ b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoHistory.ts
@@ -7,20 +7,22 @@ import {
type BuyWithCryptoHistoryData,
type BuyWithCryptoHistoryParams,
getBuyWithCryptoHistory,
-} from "../../../../pay/buyWithCrypto/actions/getHistory.js";
+} from "../../../../pay/buyWithCrypto/getHistory.js";
-export type BuyWithCryptoHistoryQueryParams = BuyWithCryptoHistoryParams;
-export type BuyWithCryptoQuoteQueryOptions = Omit<
+/**
+ * @internal
+ */
+export type BuyWithCryptoHistoryQueryOptions = Omit<
UseQueryOptions,
"queryFn" | "queryKey" | "enabled"
>;
/**
- * Hook to get the history of purchases a given wallet has performed.
+ * Hook to get the "Buy with crypto" transaction history for a given wallet.
*
* This hook is a React Query wrapper of the [`getBuyWithCryptoHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoHistory) function.
* You can also use that function directly
- * @param buyWithCryptoHistoryParams - object of type [`BuyWithCryptoHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoHistoryParams)
+ * @param params - object of type [`BuyWithCryptoHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoHistoryParams)
* @param queryParams - options to configure the react query
* @returns A React Query object which contains the data of type [`BuyWithCryptoHistoryData`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoHistoryData)
* @example
@@ -29,31 +31,24 @@ export type BuyWithCryptoQuoteQueryOptions = Omit<
*
* function Component() {
* const buyWithCryptoHistory = useBuyWithCryptoHistory(params);
- * return
* }
* ```
* @buyCrypto
*/
export function useBuyWithCryptoHistory(
- buyWithCryptoHistoryParams?: BuyWithCryptoHistoryQueryParams,
- queryParams?: BuyWithCryptoQuoteQueryOptions,
+ params?: BuyWithCryptoHistoryParams,
+ queryParams?: BuyWithCryptoHistoryQueryOptions,
): UseQueryResult {
return useQuery({
...queryParams,
-
- queryKey: ["buyWithCryptoHistory", buyWithCryptoHistoryParams],
+ queryKey: ["getBuyWithCryptoHistory", params],
queryFn: () => {
- if (!buyWithCryptoHistoryParams) {
+ if (!params) {
throw new Error("Swap params are required");
}
- if (!buyWithCryptoHistoryParams?.client) {
- throw new Error("Client is required");
- }
- return getBuyWithCryptoHistory({
- ...buyWithCryptoHistoryParams,
- client: buyWithCryptoHistoryParams.client,
- });
+ return getBuyWithCryptoHistory(params);
},
- enabled: !!buyWithCryptoHistoryParams,
+ enabled: !!params,
});
}
diff --git a/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoQuote.ts b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoQuote.ts
index 451e5417400..21bb3203c42 100644
--- a/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoQuote.ts
+++ b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoQuote.ts
@@ -7,15 +7,20 @@ import {
type BuyWithCryptoQuote,
type GetBuyWithCryptoQuoteParams,
getBuyWithCryptoQuote,
-} from "../../../../pay/buyWithCrypto/actions/getQuote.js";
+} from "../../../../pay/buyWithCrypto/getQuote.js";
+/**
+ * @internal
+ */
export type BuyWithCryptoQuoteQueryOptions = Omit<
UseQueryOptions,
"queryFn" | "queryKey" | "enabled"
>;
-export type BuyWithCryptoQuoteQueryParams = GetBuyWithCryptoQuoteParams;
+
/**
- * Hook to get a quote of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) for buying tokens with crypto.
+ * Hook to get a price quote for performing a "Buy with crypto" transaction that allows users to buy a token with another token - aka a swap.
+ *
+ * The price quote is an object of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote).
* This quote contains the information about the purchase such as token amounts, processing fees, estimated time etc.
*
* This hook is a React Query wrapper of the [`getBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoQuote) function.
@@ -23,16 +28,16 @@ export type BuyWithCryptoQuoteQueryParams = GetBuyWithCryptoQuoteParams;
*
* Once you have the quote, you can use the [`useSendTransaction`](https://portal.thirdweb.com/references/typescript/v5/useSendTransaction) function to send the purchase
* and [`useBuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/useBuyWithCryptoStatus) function to get the status of the swap transaction.
- * @param buyWithCryptoParams - object of type [`BuyWithCryptoQuoteQueryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuoteQueryParams)
+ * @param params - object of type [`BuyWithCryptoQuoteQueryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuoteQueryParams)
* @param queryParams - options to configure the react query
* @returns A React Query object which contains the data of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote)
* @example
* ```tsx
- * import { useSendTransaction, useBuyWithCryptoQuote, useBuyWithCryptoStatus, type BuyWithCryptoStatusQueryParams } from "thirdweb/react";
+ * import { useBuyWithCryptoQuote, useBuyWithCryptoStatus, type BuyWithCryptoStatusQueryParams, useActiveAccount } from "thirdweb/react";
+ * import { sendTransaction } from 'thirdweb';
*
* function Component() {
* const buyWithCryptoQuoteQuery = useBuyWithCryptoQuote(swapParams);
- * const sendTransactionMutation = useSendTransaction();
* const [buyTxHash, setBuyTxHash] = useState();
* const buyWithCryptoStatusQuery = useBuyWithCryptoStatus(buyTxHash ? {
* client,
@@ -40,16 +45,23 @@ export type BuyWithCryptoQuoteQueryParams = GetBuyWithCryptoQuoteParams;
* }: undefined);
*
* async function handleBuyWithCrypto() {
+ * const account = useActiveAccount();
*
* // if approval is required
* if (buyWithCryptoQuoteQuery.data.approval) {
- * const approveTx = await sendTransactionMutation.mutateAsync(swapQuote.data.approval);
+ * const approveTx = await sendTransaction({
+ * transaction: swapQuote.data.approval,
+ * account: account,
+ * });
* await waitForApproval(approveTx);
* }
*
* // send the transaction to buy crypto
* // this promise is resolved when user confirms the transaction in the wallet and the transaction is sent to the blockchain
- * const buyTx = await sendTransactionMutation.mutateAsync(swapQuote.data.transactionRequest);
+ * const buyTx = await sendTransaction({
+ * transaction: swapQuote.data.transactionRequest,
+ * account: account,
+ * });
* await waitForApproval(buyTx);
*
* // set buyTx.transactionHash to poll the status of the swap transaction
@@ -62,26 +74,30 @@ export type BuyWithCryptoQuoteQueryParams = GetBuyWithCryptoQuoteParams;
* @buyCrypto
*/
export function useBuyWithCryptoQuote(
- buyWithCryptoParams?: BuyWithCryptoQuoteQueryParams,
+ params?: GetBuyWithCryptoQuoteParams,
queryParams?: BuyWithCryptoQuoteQueryOptions,
): UseQueryResult {
return useQuery({
...queryParams,
-
- queryKey: ["buyWithCryptoQuote", buyWithCryptoParams],
+ queryKey: ["buyWithCryptoQuote", params],
queryFn: () => {
- if (!buyWithCryptoParams) {
+ if (!params) {
throw new Error("Swap params are required");
}
- if (!buyWithCryptoParams?.client) {
- throw new Error("Client is required in swap params");
+
+ return getBuyWithCryptoQuote(params);
+ },
+ enabled: !!params,
+ retry(failureCount, error) {
+ if (failureCount > 3) {
+ return false;
}
- return getBuyWithCryptoQuote({
- // typescript limitation with discriminated unions are collapsed
- ...(buyWithCryptoParams as GetBuyWithCryptoQuoteParams),
- client: buyWithCryptoParams.client,
- });
+
+ if (error.message.includes("Minimum purchase")) {
+ return false;
+ }
+
+ return true;
},
- enabled: !!buyWithCryptoParams,
});
}
diff --git a/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoStatus.ts b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoStatus.ts
index 2042cc21765..452b4c847f7 100644
--- a/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoStatus.ts
+++ b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithCryptoStatus.ts
@@ -1,47 +1,48 @@
import { useQuery } from "@tanstack/react-query";
-import { useState } from "react";
import {
type BuyWithCryptoStatus,
type BuyWithCryptoTransaction,
getBuyWithCryptoStatus,
-} from "../../../../pay/buyWithCrypto/actions/getStatus.js";
-
-// TODO: use the estimate to vary the polling interval
-const DEFAULT_POLL_INTERVAL = 5000;
-
-export type BuyWithCryptoStatusQueryParams = BuyWithCryptoTransaction;
+} from "../../../../pay/buyWithCrypto/getStatus.js";
/**
- * A hook to get a status of swap transaction.
+ * A hook to get a status of a "Buy with crypto" transaction to determine if the transaction is completed, failed or pending.
*
* This hook is a React Query wrapper of the [`getBuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithCryptoStatus) function.
* You can also use that function directly.
- * @param buyWithCryptoStatusParams - object of type [`BuyWithCryptoTransaction`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoTransaction)
+ * @param params - object of type [`BuyWithCryptoTransaction`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoTransaction)
* @returns A react query object which contains the data of type [`BuyWithCryptoStatus`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoStatus)
* @example
* ```tsx
- * import { useSendTransaction, useBuyWithCryptoQuote, useBuyWithCryptoStatus, type BuyWithCryptoStatusQueryParams } from "thirdweb/react";
+ * import { useSendTransaction, useBuyWithCryptoQuote, useBuyWithCryptoStatus, type BuyWithCryptoStatusQueryParams, useActiveAccount } from "thirdweb/react";
+ * import { sendTransaction } from 'thirdweb';
*
* function Component() {
* const buyWithCryptoQuoteQuery = useBuyWithCryptoQuote(swapParams);
- * const sendTransactionMutation = useSendTransaction();
* const [buyTxHash, setBuyTxHash] = useState();
* const buyWithCryptoStatusQuery = useBuyWithCryptoStatus(buyTxHash ? {
* client,
* transactionHash: buyTxHash,
* }: undefined);
+ * const account = useActiveAccount();
*
* async function handleBuyWithCrypto() {
*
* // if approval is required
* if (buyWithCryptoQuoteQuery.data.approval) {
- * const approveTx = await sendTransactionMutation.mutateAsync(swapQuote.data.approval);
+ * const approveTx = await sendTransaction({
+ * account: account,
+ * transaction: swapQuote.data.approval,
+ * });
* await waitForApproval(approveTx);
* }
*
* // send the transaction to buy crypto
* // this promise is resolved when user confirms the transaction in the wallet and the transaction is sent to the blockchain
- * const buyTx = await sendTransactionMutation.mutateAsync(swapQuote.data.transactionRequest);
+ * const buyTx = await sendTransactionMutation.mutateAsync({
+ * transaction: swapQuote.data.transactionRequest,
+ * account: account,
+ * });
* await waitForApproval(buyTx);
*
* // set buyTx.transactionHash to poll the status of the swap transaction
@@ -53,40 +54,17 @@ export type BuyWithCryptoStatusQueryParams = BuyWithCryptoTransaction;
* ```
* @buyCrypto
*/
-export function useBuyWithCryptoStatus(
- buyWithCryptoStatusParams?: BuyWithCryptoStatusQueryParams,
-) {
- const [refetchInterval, setRefetchInterval] = useState(
- DEFAULT_POLL_INTERVAL,
- );
-
+export function useBuyWithCryptoStatus(params?: BuyWithCryptoTransaction) {
return useQuery({
- queryKey: [
- "swapStatus",
- buyWithCryptoStatusParams?.transactionHash,
- ] as const,
+ queryKey: ["getBuyWithCryptoStatus", params?.transactionHash] as const,
queryFn: async () => {
- if (!buyWithCryptoStatusParams) {
- throw new Error("Missing swap status params");
- }
- if (!buyWithCryptoStatusParams?.client) {
- throw new Error("Missing client in swap status params");
- }
-
- const swapStatus_ = await getBuyWithCryptoStatus({
- ...buyWithCryptoStatusParams,
- client: buyWithCryptoStatusParams.client,
- });
- if (
- swapStatus_.status === "COMPLETED" ||
- swapStatus_.status === "FAILED"
- ) {
- setRefetchInterval(0);
+ if (!params) {
+ throw new Error("No params");
}
- return swapStatus_;
+ return getBuyWithCryptoStatus(params);
},
- enabled: !!buyWithCryptoStatusParams,
- refetchInterval: refetchInterval,
+ enabled: !!params,
+ refetchInterval: 5000,
refetchIntervalInBackground: true,
retry: true,
});
diff --git a/packages/thirdweb/src/react/core/hooks/pay/useBuyWithFiatHistory.ts b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithFiatHistory.ts
new file mode 100644
index 00000000000..cad0c064da2
--- /dev/null
+++ b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithFiatHistory.ts
@@ -0,0 +1,54 @@
+import {
+ type UseQueryOptions,
+ type UseQueryResult,
+ useQuery,
+} from "@tanstack/react-query";
+import {
+ type BuyWithFiatHistoryData,
+ type BuyWithFiatHistoryParams,
+ getBuyWithFiatHistory,
+} from "../../../../pay/buyWithFiat/getHistory.js";
+
+/**
+ * @internal
+ */
+export type BuyWithFiatHistoryQueryOptions = Omit<
+ UseQueryOptions,
+ "queryFn" | "queryKey" | "enabled"
+>;
+
+/**
+ * Hook to get the "Buy with Fiat" transaction history for a given wallet.
+ *
+ * This hook is a React Query wrapper of the [`getBuyWithFiatHistory`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatHistory) function.
+ * You can also use that function directly
+ * @param params - object of type [`BuyWithFiatHistoryParams`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatHistoryParams)
+ * @param queryParams - options to configure the react query
+ * @returns A React Query object which contains the data of type [`BuyWithFiatHistoryData`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatHistoryData)
+ * @example
+ * ```tsx
+ * import { useBuyWithFiatHistory } from "thirdweb/react";
+ *
+ * function Component() {
+ * const historyQuery = useBuyWithFiatHistory(params);
+ * return
...
+ * }
+ * ```
+ * @buyFiat
+ */
+export function useBuyWithFiatHistory(
+ params?: BuyWithFiatHistoryParams,
+ queryParams?: BuyWithFiatHistoryQueryOptions,
+): UseQueryResult {
+ return useQuery({
+ ...queryParams,
+ queryKey: ["buyWithFiatHistory", params],
+ queryFn: () => {
+ if (!params) {
+ throw new Error("params are required");
+ }
+ return getBuyWithFiatHistory(params);
+ },
+ enabled: !!params,
+ });
+}
diff --git a/packages/thirdweb/src/react/core/hooks/pay/useBuyWithFiatQuote.ts b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithFiatQuote.ts
new file mode 100644
index 00000000000..dee064b962d
--- /dev/null
+++ b/packages/thirdweb/src/react/core/hooks/pay/useBuyWithFiatQuote.ts
@@ -0,0 +1,94 @@
+import {
+ type UseQueryOptions,
+ type UseQueryResult,
+ useQuery,
+} from "@tanstack/react-query";
+import {
+ type BuyWithFiatQuote,
+ type GetBuyWithFiatQuoteParams,
+ getBuyWithFiatQuote,
+} from "../../../../pay/buyWithFiat/getQuote.js";
+
+/**
+ * @internal
+ */
+export type BuyWithFiatQuoteQueryOptions = Omit<
+ UseQueryOptions,
+ "queryFn" | "queryKey" | "enabled"
+>;
+
+/**
+ * Hook to get a price quote for performing a "Buy with Fiat" transaction that allows users to buy a token with fiat currency.
+ *
+ * The price quote is an object of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote).
+ * This quote contains the information about the purchase such as token amounts, processing fees, estimated time etc.
+ *
+ * This hook is a React Query wrapper of the [`getBuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/getBuyWithFiatQuote) function.
+ * You can also use that function directly
+ *
+ * Once you have the quote, you can open a new window with `onRampLink` as window location to allow the user to buy the token with fiat currency.
+ * and [`useBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/useBuyWithFiatStatus) function to start polling for the status of this transaction.
+ *
+ * @param params - object of type [`GetBuyWithFiatQuoteParams`](https://portal.thirdweb.com/references/typescript/v5/GetBuyWithFiatQuoteParams)
+ * @param queryParams - options to configure the react query
+ * @returns A React Query object which contains the data of type [`BuyWithFiatQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithFiatQuote)
+ * @example
+ * ```ts
+ * import { NATIVE_TOKEN_ADDRESS } from "thirdweb";
+ * import { base } from "thirdweb/chains";
+ * import { useBuyWithFiatQuote } from "thirdweb/react";
+ *
+ * function Example() {
+ * const quote = useBuyWithFiatQuote({
+ * client: client, // thirdweb client
+ * fromCurrencySymbol: "USD", // fiat currency symbol
+ * toChainId: base.id, // base chain id
+ * toAmount: "10", // amount of token to buy
+ * toTokenAddress: NATIVE_TOKEN_ADDRESS, // native token
+ * toAddress: "0x...", // user's wallet address
+ * });
+ *
+ * return (
+ *