Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/thirdweb/src/exports/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,9 @@ export {
// auth
export { type SiweAuthOptions } from "../react/core/hooks/auth/useSiweAuth.js";

export { PayEmbed, type PayEmbedProps } from "../react/web/ui/PayEmbed.js";
export {
PayEmbed,
type PayEmbedProps,
type PayEmbedConnectOptions,
} from "../react/web/ui/PayEmbed.js";
export type { PayUIOptions } from "../react/web/ui/ConnectWallet/ConnectButtonProps.js";
3 changes: 2 additions & 1 deletion packages/thirdweb/src/pay/getBuyHistory.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ThirdwebClient } from "../client/client.js";
import type { BuyWithCryptoStatus, BuyWithFiatStatus } from "../exports/pay.js";
import { getClientFetch } from "../utils/fetch.js";
import type { BuyWithCryptoStatus } from "./buyWithCrypto/getStatus.js";
import type { BuyWithFiatStatus } from "./buyWithFiat/getStatus.js";
import { getPayBuyHistoryEndpoint } from "./utils/definitions.js";

/**
Expand Down
10 changes: 2 additions & 8 deletions packages/thirdweb/src/react/core/hooks/pay/useBuyHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export type BuyHistoryQueryOptions = Omit<
* import { useBuyHistory } from "thirdweb/react";
*
* function Component() {
* const buyWithCryptoHistory = useBuyHistory(params);
* const buyHistoryQuery = useBuyHistory(params);
* return <div> ... </div>
* }
* ```
Expand All @@ -47,13 +47,7 @@ export function useBuyHistory(
if (!params) {
throw new Error("params are required");
}
if (!params?.client) {
throw new Error("Client is required");
}
return getBuyHistory({
...params,
client: params.client,
});
return getBuyHistory(params);
},
enabled: !!params,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type BuyWithCryptoHistoryQueryOptions = Omit<
>;

/**
* Hook to get the "Buy with crypto" transaction history for a given wallet.
* Hook to get the "Buy with crypto" transaction history for a given wallet address.
*
* 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type BuyWithFiatHistoryQueryOptions = Omit<
>;

/**
* Hook to get the "Buy with Fiat" transaction history for a given wallet.
* Hook to get the "Buy with Fiat" transaction history for a given wallet address.
*
* 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export type BuyWithFiatQuoteQueryOptions = Omit<
* 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.
* Once you have the `quote`, you can open a new window with `quote.onRampLink` 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)
Expand All @@ -38,12 +38,13 @@ export type BuyWithFiatQuoteQueryOptions = Omit<
* import { base } from "thirdweb/chains";
* import { useBuyWithFiatQuote } from "thirdweb/react";
*
* // get a quote for buying 0.01 base native token with USD fiat currency
* 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
* toAmount: "0.01", // amount of token to buy
* toTokenAddress: NATIVE_TOKEN_ADDRESS, // native token
* toAddress: "0x...", // user's wallet address
* });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ export type PostOnRampQuoteQueryOptions = Omit<
>;

/**
* When buying a token with fiat currency, It may be a 2 step process where the user is sent an intermediate token from the on-ramp provider ( known as "On-ramp" token )
* and then it needs to be swapped to destination token.
* 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.
*
* When you get a "Buy with Fiat" status of type "CRYPTO_SWAP_REQUIRED" from the [`useBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/useBuyWithFiatStatus) hook,
* 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.
*
* `usePostOnRampQuote` hook 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 [`useBuyWithFiatStatus`](https://portal.thirdweb.com/references/typescript/v5/useBuyWithFiatStatus) hook,
* you can use `usePostOnRampQuote` hook to get the quote of type [`BuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/BuyWithCryptoQuote) for swapping the on-ramp token to destination token to complete the step-2 of the process.
*
* Once you have the quote, you can start the Swap process by following the same steps as mentioned in the [`useBuyWithCryptoQuote`](https://portal.thirdweb.com/references/typescript/v5/useBuyWithCryptoQuote) documentation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ export type PayUIOptions = {
*
* By default, the "Crypto" option is enabled. You can disable it by setting `buyWithCrypto` to `false`
*
* You can also prefill the source token and chain for the swap to customize the default values.
* You can also disable the edits for the prefilled values by setting `allowEdits` - By default all are editable
* You can prefill the source token and chain using `prefillSource`
* You can also disable the edits for the prefilled values by setting `prefillSource.allowEdits` - By default all are editable
*
* For example, if you want to allow selecting chain and but disable selecting token, you can set `allowEdits` to `{ token: false, chain: true }`
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ export const ConnectedWalletDetails: React.FC<{
);
}

// swap tokens
// thirdweb pay
else if (screen === "buy") {
content = (
<LazyBuyScreen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -497,17 +497,20 @@ function BuyScreenContent(props: BuyScreenContentProps) {
)}

<Container px="lg" flex="column" gap="sm">
<Button
variant="outline"
fullWidth
style={{
padding: spacing.xs,
fontSize: fontSize.sm,
}}
onClick={props.onViewPendingTx}
>
View all transactions
</Button>
{account && (
<Button
variant="outline"
fullWidth
style={{
padding: spacing.xs,
fontSize: fontSize.sm,
}}
onClick={props.onViewPendingTx}
>
View all transactions
</Button>
)}

{!isExpanded && (
<>
{!account && props.connectButton ? (
Expand Down Expand Up @@ -572,13 +575,13 @@ function SwapScreenContent(
? {
// wallet
fromAddress: account.address,
// from token
// from
fromChainId: fromChain.id,
fromTokenAddress: isNativeToken(fromToken)
? NATIVE_TOKEN_ADDRESS
: fromToken.address,
toChainId: toChain.id,
// to
toChainId: toChain.id,
toTokenAddress: isNativeToken(toToken)
? NATIVE_TOKEN_ADDRESS
: toToken.address,
Expand Down Expand Up @@ -854,8 +857,8 @@ function FiatScreenContent(
type AmountTooLowError = {
code: "MINIMUM_PURCHASE_AMOUNT";
data: {
minimumAmountUSDCents: 250;
requestedAmountUSDCents: 7;
minimumAmountUSDCents: number;
requestedAmountUSDCents: number;
};
};

Expand All @@ -877,7 +880,7 @@ function FiatScreenContent(

return (
<Container px="lg" flex="column" gap="md">
{/* Show Currency Selector + Calculated Amount */}
{/* Show Calculated Fiat Amount */}
<div>
<PayWithCreditCard
isLoading={fiatQuoteQuery.isLoading}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ import { OnrampStatusScreen } from "./FiatStatusScreen.js";
import { FiatSteps, fiatQuoteToPartialQuote } from "./FiatSteps.js";
import { PostOnRampSwapFlow } from "./PostOnRampSwapFlow.js";

// Flows
// 2 possible flows

// If a Swap is required after doing onramp
// 1. show the 2 steps ui first
// 2. opwn provider window, show onramp status screen
// 3. show the 2 steps ui with step 2 highlighted
// 1. show the 2 steps ui with step 1 highlighted, on continue button click:
// 2. open provider window, show onramp status screen, on onramp success:
// 3. show the 2 steps ui with step 2 highlighted, on continue button click:
// 4. show swap flow

// If a Swap is not required after doing onramp
// 1. open provider window, show onramp status screen
// - window will already be opened before this component is mounted and `openedWindow` prop will be set, show onramp status screen

type Screen =
| {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ import { OnRampTxDetailsTable } from "./FiatTxDetailsTable.js";

type UIStatus = "loading" | "failed" | "completed" | "partialSuccess";

/**
* Poll for "Buy with Fiat" status - when the on-ramp is in progress
* - Show success screen if swap is not required and on-ramp is completed
* - Show Failed screen if on-ramp failed
* - call `onShowSwapFlow` if on-ramp is completed and swap is required
*/
export function OnrampStatusScreen(props: {
client: ThirdwebClient;
onBack: () => void;
Expand Down Expand Up @@ -56,8 +62,6 @@ export function OnrampStatusScreen(props: {
uiStatus = "completed";
}

// determine step

// close the onramp popup if onramp is completed
useEffect(() => {
if (!openedWindow || !statusQuery.data) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Button, ButtonLink } from "../../../../components/buttons.js";
import { Text } from "../../../../components/text.js";
import { TokenSymbol } from "../../../../components/token/TokenSymbol.js";
import {
type Theme,
fontSize,
iconSize,
radius,
Expand Down Expand Up @@ -67,7 +68,6 @@ export function fiatQuoteToPartialQuote(
name: quote.onRampToken.token.name,
symbol: quote.onRampToken.token.symbol,
},

toToken: {
chainId: quote.toToken.chainId,
tokenAddress: quote.toToken.tokenAddress,
Expand Down Expand Up @@ -532,16 +532,24 @@ function StepContainer(props: {
state?: FiatStatusMeta["progressStatus"];
children: React.ReactNode;
}) {
const color =
props.state === "actionRequired" || props.state === "pending"
? "accentText"
: props.state === "completed"
? "success"
: props.state === "failed"
? "danger"
: props.state === "partialSuccess"
? "danger"
: "borderColor";
let color: keyof Theme["colors"] = "borderColor";
let text: string | undefined;

if (props.state === "pending") {
text = "Pending";
color = "accentText";
} else if (props.state === "actionRequired") {
color = "accentText";
} else if (props.state === "completed") {
text = "Completed";
color = "success";
} else if (props.state === "failed") {
color = "danger";
text = "Failed";
} else if (props.state === "partialSuccess") {
color = "danger";
text = "Incomplete";
}

return (
<Container
Expand All @@ -568,19 +576,9 @@ function StepContainer(props: {
alignItems: "center",
}}
>
{props.state && (
{props.state && text && (
<Text size="sm" color={color}>
{props.state === "completed"
? "Completed"
: props.state === "failed"
? "Failed"
: props.state === "pending"
? "Pending"
: props.state === "actionRequired"
? ""
: props.state === "partialSuccess"
? "Incomplete"
: undefined}
{text}
</Text>
)}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ import { USDIcon } from "../../../icons/currencies/USDIcon.js";
import { TokenInfoRow } from "../tx-history/TokenInfoRow.js";
import type { FiatStatusMeta } from "../tx-history/statusMeta.js";

/**
* Show a table with the details of a "OnRamp" transaction step in the "Buy with Fiat" flow.
* - Show OnRamp token as "Receive"
* - Show fiat amount as "Pay"
*/
export function OnRampTxDetailsTable(props: {
// status: ValidBuyWithFiatStatus;
client: ThirdwebClient;
token: {
chainId: number;
Expand Down Expand Up @@ -44,6 +48,7 @@ export function OnRampTxDetailsTable(props: {

return (
<div>
{/* Receive */}
<TokenInfoRow
chainId={props.token.chainId}
client={props.client}
Expand Down Expand Up @@ -82,11 +87,10 @@ export function OnRampTxDetailsTable(props: {
</Container>
</Container>

{/* Status */}
{props.statusMeta && (
<>
{lineSpacer}

{/* Status */}
<Container
flex="row"
center="y"
Expand All @@ -106,6 +110,7 @@ export function OnRampTxDetailsTable(props: {

{lineSpacer}

{/* Transaction Hash link */}
{onrampTxHash && onRampChainQuery.data?.explorers?.[0]?.url && (
<>
<Spacer y="md" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function PostOnRampSwap(props: {
const account = useActiveAccount();

const [lockedOnRampQuote, setLockedOnRampQuote] = useState<
BuyWithCryptoQuote | undefined | null
BuyWithCryptoQuote | undefined
>(undefined);

const postOnRampQuoteQuery = useQuery({
Expand Down Expand Up @@ -116,28 +116,6 @@ export function PostOnRampSwap(props: {
);
}

if (lockedOnRampQuote === null) {
return (
<Container>
<Container p="lg">
<ModalHeader title="Buy" onBack={props.onBack} />
</Container>

<Spacer y="xxl" />

<Container flex="row" center="x">
<AccentFailIcon size={iconSize["3xl"]} />
</Container>
<Spacer y="xl" />
<Text color="primaryText" size="lg" center>
No transaction found
</Text>

<Spacer y="3xl" />
</Container>
);
}

return (
<SwapFlow
account={account}
Expand Down
Loading