UNPKG

@0xfutbol/id

Version:

React component library with shared providers for 0xFutbol ID

847 lines 154 kB
'use strict';var jsxRuntime=require('react/jsx-runtime'),reactQuery=require('@tanstack/react-query'),React=require('react'),index=require('./index-gEYw6hWC.js'),decimals=require('./decimals-C_tN8eFN.js'),getCurrencyMetadata=require('./getCurrencyMetadata-D7CN05L7.js');require('@0xfutbol/id-sign'),require('react-use'),require('@0xfutbol/constants'),require('thirdweb'),require('@matchain/matchid-sdk-react'),require('@matchain/matchid-sdk-react/index.css'),require('react-dom'),require('./decimals-DNF80AHH.js');/** * Sends a transaction using the provided wallet. * @param options - The options for sending the transaction. * @returns A promise that resolves to the confirmed transaction receipt. * @throws An error if the wallet is not connected. * @transaction * @example * * ### Basic usage * ```ts * import { sendAndConfirmTransaction } from "thirdweb"; * * const transactionReceipt = await sendAndConfirmTransaction({ * account, * transaction * }); * ``` * * ### Gasless usage with [thirdweb Engine](https://portal.thirdweb.com/engine) * ```ts * const transactionReceipt = await sendAndConfirmTransaction({ * account, * transaction, * gasless: { * provider: "engine", * relayerUrl: "https://thirdweb.engine-***.thirdweb.com/relayer/***", * relayerForwarderAddress: "0x...", * } * }); * ``` * * ### Gasless usage with OpenZeppelin * ```ts * const transactionReceipt = await sendAndConfirmTransaction({ * account, * transaction, * gasless: { * provider: "openzeppelin", * relayerUrl: "https://...", * relayerForwarderAddress: "0x...", * } * }); * ``` */ async function sendAndConfirmTransaction(options) { const submittedTx = await index.aD(options); return index.aL(submittedTx); }/** * 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. * You can also use that function directly * * 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 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 { useBuyWithCryptoQuote, useBuyWithCryptoStatus, type BuyWithCryptoStatusQueryParams, useActiveAccount } from "thirdweb/react"; * import { sendTransaction } from 'thirdweb'; * * function Component() { * const buyWithCryptoQuoteQuery = useBuyWithCryptoQuote(swapParams); * const [buyTxHash, setBuyTxHash] = useState<BuyWithCryptoStatusQueryParams | undefined>(); * const buyWithCryptoStatusQuery = useBuyWithCryptoStatus(buyTxHash ? { * client, * transactionHash: buyTxHash, * }: undefined); * * async function handleBuyWithCrypto() { * const account = useActiveAccount(); * * // if approval is required * if (buyWithCryptoQuoteQuery.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 sendTransaction({ * transaction: swapQuote.data.transactionRequest, * account: account, * }); * await waitForApproval(buyTx); * * // set buyTx.transactionHash to poll the status of the swap transaction * setBuyWithCryptoTx(buyTx.transactionHash); * } * * return <button onClick={handleBuyWithCrypto}>Swap</button> * } * ``` * @buyCrypto */ function useBuyWithCryptoQuote(params, queryParams) { return reactQuery.useQuery({ ...queryParams, queryKey: ["buyWithCryptoQuote", params], refetchInterval: 20_000, queryFn: () => { if (!params) { throw new Error("Swap params are required"); } return index.aM(params); }, enabled: !!params, retry: false, }); }/** * 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"); * ``` * @buyCrypto */ async function getBuyWithFiatQuote(params) { try { const clientFetch = index.g(params.client); const response = await clientFetch(index.aN(), { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json", }, body: index.s({ toAddress: params.toAddress, fromCurrencySymbol: params.fromCurrencySymbol, toChainId: params.toChainId.toString(), toTokenAddress: params.toTokenAddress, fromAmount: params.fromAmount, toAmount: params.toAmount, maxSlippageBPS: params.maxSlippageBPS, isTestMode: params.isTestMode, purchaseData: params.purchaseData, fromAddress: params.fromAddress, toGasAmountWei: params.toGasAmountWei, preferredProvider: params.preferredProvider, multiHopSupported: true, }), }); // 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("Error getting buy with fiat quote", error); throw error; } }/** * 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 `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) * @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"; * * // 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: "0.01", // amount of token to buy * toTokenAddress: NATIVE_TOKEN_ADDRESS, // native token * toAddress: "0x...", // user's wallet address * }); * * return ( * <div> * {quote.data && ( * <a href={quote.data.onRampLink} target="_blank"> * open onramp provider * </a> * )} * </div> * ); * } * ``` * @buyCrypto */ function useBuyWithFiatQuote(params, queryOptions) { return reactQuery.useQuery({ ...queryOptions, queryKey: ["useBuyWithFiatQuote", params], queryFn: async () => { if (!params) { throw new Error("No params provided"); } return getBuyWithFiatQuote(params); }, enabled: !!params, retry: false, }); }function DirectPaymentModeScreen(props) { const { payUiOptions, supportedDestinations, client, onContinue, payerAccount, } = props; const theme = index.aO(); const activeWallet = index.aP(); const metadata = payUiOptions.metadata; const paymentInfo = payUiOptions.paymentInfo; const { data: chainData } = index.aQ(paymentInfo.chain); const { data: sellerEns } = index.aR({ client, address: paymentInfo.sellerAddress, }); const totalCostQuery = reactQuery.useQuery({ queryKey: ["amount", paymentInfo], queryFn: async () => { let tokenDecimals = 18; if (paymentInfo.token && !index.aS(paymentInfo.token)) { tokenDecimals = await decimals.decimals({ contract: index.at({ address: paymentInfo.token.address, chain: paymentInfo.chain, client, }), }); } let cost; if ("amountWei" in paymentInfo) { cost = index.Q(paymentInfo.amountWei, tokenDecimals); } else { cost = paymentInfo.amount; } return cost; }, }); const totalCost = totalCostQuery.data; if (!chainData || totalCost === undefined) { return jsxRuntime.jsx(index.aT, {}); } const token = paymentInfo.token ? { ...paymentInfo.token, icon: paymentInfo.token?.icon || supportedDestinations .find((c) => c.chain.id === paymentInfo.chain.id) ?.tokens.find((t) => t.address.toLowerCase() === paymentInfo.token?.address.toLowerCase())?.icon, } : { address: index.b2, name: chainData.nativeCurrency.name, symbol: chainData.nativeCurrency.symbol, icon: chainData.icon?.url, }; return (jsxRuntime.jsxs(index.aU, { p: "lg", children: [jsxRuntime.jsx(index.aV, { title: metadata?.name || "Payment Details" }), jsxRuntime.jsx(index.aW, { y: "lg" }), jsxRuntime.jsxs(index.aU, { children: [metadata?.image ? (jsxRuntime.jsx(index.aX, { client: client, src: metadata?.image, style: { width: "100%", borderRadius: index.aY.md, backgroundColor: theme.colors.tertiaryBg, } })) : activeWallet ? (jsxRuntime.jsxs(index.aU, { flex: "row", center: "both", style: { padding: index.aY.md, marginBottom: index.aY.md, borderRadius: index.aY.md, backgroundColor: theme.colors.tertiaryBg, }, children: [jsxRuntime.jsx(index.aZ, { size: index.a_.xl, id: activeWallet.id, client: client }), jsxRuntime.jsx("div", { style: { flexGrow: 1, borderBottom: "6px dotted", borderColor: theme.colors.secondaryIconColor, marginLeft: index.aY.md, marginRight: index.aY.md, } }), jsxRuntime.jsx(index.a$, { client: client, size: index.a_.xl, chainIconUrl: chainData.icon?.url })] })) : null, jsxRuntime.jsx(index.aW, { y: "md" }), jsxRuntime.jsxs(index.aU, { flex: "row", children: [jsxRuntime.jsx(index.aU, { flex: "column", expand: true, children: jsxRuntime.jsx(index.b0, { size: "md", color: "primaryText", weight: 700, children: "Price" }) }), jsxRuntime.jsx(index.aU, { expand: true, children: jsxRuntime.jsxs(index.aU, { flex: "row", gap: "xs", center: "y", style: { justifyContent: "right" }, children: [jsxRuntime.jsx(index.b1, { chain: paymentInfo.chain, client: props.client, size: "sm", token: token }), jsxRuntime.jsxs(index.b0, { color: "primaryText", size: "md", weight: 700, children: [String(index.b3(Number(totalCost), 6)), " ", token.symbol] })] }) })] }), jsxRuntime.jsx(index.aW, { y: "md" }), jsxRuntime.jsx(index.b4, {}), jsxRuntime.jsx(index.aW, { y: "md" }), jsxRuntime.jsxs(index.aU, { flex: "row", children: [jsxRuntime.jsx(index.aU, { flex: "column", expand: true, children: jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", children: "Network" }) }), jsxRuntime.jsx(index.aU, { expand: true, children: jsxRuntime.jsxs(index.aU, { flex: "row", gap: "xs", center: "y", style: { justifyContent: "right" }, children: [jsxRuntime.jsx(index.a$, { chainIconUrl: chainData.icon?.url, size: "xs", client: props.client }), jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", style: { textAlign: "right" }, children: chainData.name })] }) })] }), jsxRuntime.jsx(index.aW, { y: "sm" }), jsxRuntime.jsxs(index.aU, { flex: "row", children: [jsxRuntime.jsx(index.aU, { flex: "column", expand: true, children: jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", children: "Seller" }) }), jsxRuntime.jsx(index.aU, { expand: true, children: jsxRuntime.jsx(index.aU, { flex: "row", gap: "xs", center: "y", style: { justifyContent: "right" }, children: jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", style: { textAlign: "right" }, children: sellerEns || index.b5(paymentInfo.sellerAddress) }) }) })] })] }), jsxRuntime.jsx(index.aW, { y: "xl" }), payerAccount ? (jsxRuntime.jsx(index.b6, { variant: "accent", fullWidth: true, onClick: () => { index.b7({ event: "choose_payment_method_direct_payment_mode", client, walletAddress: payerAccount.address, walletType: activeWallet?.id, }); onContinue(totalCost, paymentInfo.chain, token); }, children: "Choose Payment Method" })) : (jsxRuntime.jsx("div", { children: jsxRuntime.jsx(index.b8, { ...props.connectOptions, client: client, theme: theme, connectButton: { style: { width: "100%", }, } }) }))] })); }function useTransactionCostAndData(args) { const { transaction, account, supportedDestinations } = args; // Compute query key of the transaction first const [txQueryKey, setTxQueryKey] = React.useState(); React.useEffect(() => { Promise.all([ index.ap(transaction.value), index.ap(transaction.erc20Value), index.ap(transaction.to), index.ao(transaction), ]).then(([value, erc20Value, to, data]) => { setTxQueryKey({ value: value?.toString(), erc20Value: erc20Value?.amountWei?.toString(), erc20Currency: erc20Value?.tokenAddress, to, data, }); }); }, [transaction]); return reactQuery.useQuery({ queryKey: [ "transaction-cost", transaction.chain.id, account?.address, txQueryKey, ], queryFn: async () => { if (!account) { throw new Error("No payer account found"); } const erc20Value = await index.ap(transaction.erc20Value); if (erc20Value) { const [tokenBalance, tokenMeta, gasCostWei] = await Promise.all([ index.b9({ address: account.address, chain: transaction.chain, client: transaction.client, tokenAddress: erc20Value.tokenAddress, }), getCurrencyMetadata.getCurrencyMetadata({ contract: index.at({ address: erc20Value.tokenAddress, chain: transaction.chain, client: transaction.client, }), }), index.ba(transaction, account?.address), ]); const transactionValueWei = erc20Value.amountWei; const walletBalance = tokenBalance; const currency = { address: erc20Value.tokenAddress, name: tokenMeta.name, symbol: tokenMeta.symbol, icon: supportedDestinations .find((c) => c.chain.id === transaction.chain.id) ?.tokens.find((t) => t.address.toLowerCase() === erc20Value.tokenAddress.toLowerCase())?.icon, }; return { token: currency, decimals: tokenMeta.decimals, walletBalance, gasCostWei, transactionValueWei, }; } const [nativeWalletBalance, chainMetadata, gasCostWei] = await Promise.all([ index.b9({ address: account.address, chain: transaction.chain, client: transaction.client, }), index.F(transaction.chain), index.ba(transaction, account?.address), ]); const walletBalance = nativeWalletBalance; const transactionValueWei = (await index.ap(transaction.value)) || 0n; return { token: { address: index.b2, name: chainMetadata.nativeCurrency.name, symbol: chainMetadata.nativeCurrency.symbol, icon: chainMetadata.icon?.url, }, decimals: 18, walletBalance, gasCostWei, transactionValueWei, }; }, enabled: !!transaction && !!txQueryKey, refetchInterval: () => { if (transaction.erc20Value) { // if erc20 value is set, we don't need to poll return undefined; } return 30_000; }, }); }function TransactionModeScreen(props) { const { payUiOptions, client, payerAccount, supportedDestinations, onContinue, } = props; const { data: chainData, error: chainDataError, isLoading: chainDataLoading, refetch: chainDataRefetch, } = index.aQ(payUiOptions.transaction.chain); const metadata = payUiOptions.metadata; const { data: transactionCostAndData, error: transactionCostAndDataError, isLoading: transactionCostAndDataLoading, refetch: transactionCostAndDataRefetch, } = useTransactionCostAndData({ transaction: payUiOptions.transaction, account: payerAccount, supportedDestinations, }); const theme = index.aO(); const activeWallet = index.aP(); const activeAccount = index.bb(); const sponsoredTransactionsEnabled = index.bc(activeWallet); const balanceQuery = index.bd({ address: activeAccount?.address, chain: payUiOptions.transaction.chain, tokenAddress: index.aS(transactionCostAndData?.token || index.be) ? undefined : transactionCostAndData?.token.address, client: props.client, }, { enabled: !!transactionCostAndData, }); if (transactionCostAndDataLoading || chainDataLoading) { return jsxRuntime.jsx(index.aT, {}); } if (!activeAccount) { return (jsxRuntime.jsx(index.aU, { style: { minHeight: "350px", }, fullHeight: true, flex: "row", center: "both", children: jsxRuntime.jsxs(index.aU, { animate: "fadein", children: [jsxRuntime.jsx(index.aW, { y: "xxl" }), jsxRuntime.jsx(index.aU, { flex: "row", center: "x", children: jsxRuntime.jsx(index.bf, { size: index.a_["3xl"] }) }), jsxRuntime.jsx(index.aW, { y: "lg" }), jsxRuntime.jsx(index.b0, { center: true, color: "primaryText", size: "md", children: "Please connect a wallet to continue" }), jsxRuntime.jsx(index.aW, { y: "xl" }), jsxRuntime.jsx(index.aU, { flex: "row", center: "x", style: { width: "100%" }, children: jsxRuntime.jsx(index.b8, { client: client, theme: theme, ...props.connectOptions }) })] }) })); } if (transactionCostAndDataError || chainDataError) { return (jsxRuntime.jsx(index.aU, { style: { minHeight: "350px", }, fullHeight: true, flex: "row", center: "both", children: jsxRuntime.jsx(index.bg, { title: transactionCostAndDataError?.message || chainDataError?.message || "Something went wrong", onTryAgain: transactionCostAndDataError ? transactionCostAndDataRefetch : chainDataRefetch }) })); } if (!transactionCostAndData || !chainData) { return jsxRuntime.jsx(index.aT, {}); } const insufficientFunds = balanceQuery.data && balanceQuery.data.value < transactionCostAndData.transactionValueWei; return (jsxRuntime.jsxs(index.aU, { p: "lg", children: [jsxRuntime.jsx(index.aV, { title: metadata?.name || "Transaction" }), jsxRuntime.jsx(index.aW, { y: "lg" }), jsxRuntime.jsxs(index.aU, { children: [metadata?.image ? (jsxRuntime.jsx(index.aX, { client: client, src: metadata?.image, style: { width: "100%", borderRadius: index.aY.md, border: `1px solid ${theme.colors.borderColor}`, backgroundColor: theme.colors.tertiaryBg, } })) : activeAccount ? (jsxRuntime.jsxs(index.aU, { flex: "column", gap: "sm", children: [insufficientFunds && (jsxRuntime.jsx(index.b0, { size: "sm", color: "danger", style: { textAlign: "center" }, children: "Insufficient funds" })), jsxRuntime.jsxs(index.aU, { flex: "row", style: { justifyContent: "space-between", padding: index.aY.sm, marginBottom: index.aY.sm, borderRadius: index.aY.md, backgroundColor: theme.colors.tertiaryBg, border: `1px solid ${theme.colors.borderColor}`, }, children: [jsxRuntime.jsx(index.bh, { address: activeAccount?.address, iconSize: "md", client: client }), balanceQuery.data ? (jsxRuntime.jsxs(index.aU, { flex: "row", gap: "3xs", center: "y", children: [jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", weight: 500, children: index.bi(balanceQuery.data, false) }), jsxRuntime.jsx(index.bj, { token: transactionCostAndData.token, chain: payUiOptions.transaction.chain, size: "xs", color: "secondaryText" })] })) : (jsxRuntime.jsx(index.bk, { width: "70px", height: index.bl.xs }))] })] })) : null, jsxRuntime.jsx(index.aW, { y: "md" }), jsxRuntime.jsxs(index.aU, { flex: "row", children: [jsxRuntime.jsx(index.aU, { flex: "column", expand: true, children: jsxRuntime.jsx(index.b0, { size: "md", color: "primaryText", weight: 700, children: "Price" }) }), jsxRuntime.jsx(index.aU, { expand: true, children: jsxRuntime.jsxs(index.aU, { flex: "row", gap: "xs", center: "y", style: { justifyContent: "right" }, children: [jsxRuntime.jsx(index.b1, { chain: payUiOptions.transaction.chain, client: props.client, size: "sm", token: transactionCostAndData.token }), jsxRuntime.jsxs(index.b0, { color: "primaryText", size: "md", weight: 700, children: [String(index.b3(Number(index.Q(transactionCostAndData.transactionValueWei, transactionCostAndData.decimals)), 6)), " ", transactionCostAndData.token.symbol] })] }) })] }), jsxRuntime.jsx(index.aW, { y: "md" }), jsxRuntime.jsx(index.b4, {}), jsxRuntime.jsx(index.aW, { y: "md" }), jsxRuntime.jsxs(index.aU, { flex: "row", children: [jsxRuntime.jsx(index.aU, { flex: "column", expand: true, children: jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", children: "Gas Fees" }) }), jsxRuntime.jsx(index.aU, { expand: true, children: jsxRuntime.jsx(index.aU, { flex: "row", gap: "xs", center: "y", style: { justifyContent: "right" }, children: jsxRuntime.jsx(index.b0, { color: sponsoredTransactionsEnabled ? "success" : "primaryText", size: "xs", children: sponsoredTransactionsEnabled ? "Sponsored" : `${String(index.b3(Number(index.Q(transactionCostAndData.gasCostWei, chainData.nativeCurrency.decimals)), 6))} ${chainData.nativeCurrency.symbol}` }) }) })] }), jsxRuntime.jsx(index.aW, { y: "sm" }), jsxRuntime.jsxs(index.aU, { flex: "row", children: [jsxRuntime.jsx(index.aU, { flex: "column", expand: true, children: jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", children: "Network" }) }), jsxRuntime.jsx(index.aU, { expand: true, children: jsxRuntime.jsxs(index.aU, { flex: "row", gap: "xs", center: "y", style: { justifyContent: "right" }, children: [jsxRuntime.jsx(index.a$, { chainIconUrl: chainData.icon?.url, size: "xs", client: props.client }), jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", style: { textAlign: "right" }, children: chainData.name })] }) })] })] }), jsxRuntime.jsx(index.aW, { y: "xl" }), payerAccount ? (jsxRuntime.jsx(index.b6, { variant: "accent", fullWidth: true, onClick: () => { let totalCostWei = insufficientFunds ? transactionCostAndData.transactionValueWei - (balanceQuery.data?.value || 0n) : transactionCostAndData.transactionValueWei; if (transactionCostAndData.token.address === index.b2 && !sponsoredTransactionsEnabled) { totalCostWei += transactionCostAndData.gasCostWei; } index.b7({ event: "choose_payment_method_transaction_mode", client, walletAddress: payerAccount.address, walletType: activeWallet?.id, }); onContinue(index.Q(totalCostWei, transactionCostAndData.decimals), payUiOptions.transaction.chain, transactionCostAndData.token); }, children: "Choose Payment Method" })) : (jsxRuntime.jsx("div", { children: jsxRuntime.jsx(index.b8, { ...props.connectOptions, client: client, theme: theme, connectButton: { style: { width: "100%", }, } }) }))] })); }function CurrencySelection(props) { return (jsxRuntime.jsxs(index.aU, { children: [jsxRuntime.jsx(index.aU, { p: "lg", children: jsxRuntime.jsx(index.aV, { title: "Pay with", onBack: props.onBack }) }), jsxRuntime.jsx(index.b4, {}), jsxRuntime.jsx(index.aW, { y: "lg" }), jsxRuntime.jsx(index.aU, { flex: "column", gap: "xs", px: "lg", children: index.bm.map((c) => { return (jsxRuntime.jsxs(SelectCurrencyButton, { fullWidth: true, variant: "secondary", onClick: () => props.onSelect(c), gap: "sm", children: [index.bo(c, "lg"), jsxRuntime.jsxs(index.aU, { flex: "column", gap: "xxs", children: [jsxRuntime.jsx(index.b0, { color: "primaryText", children: c.shorthand }), jsxRuntime.jsx(index.b0, { size: "sm", children: c.name })] })] }, c.shorthand)); }) }), jsxRuntime.jsx(index.aW, { y: "lg" })] })); } const SelectCurrencyButton = /* @__PURE__ */ index.bn(index.b6)(() => { const theme = index.aO(); return { background: theme.colors.tertiaryBg, justifyContent: "flex-start", gap: index.aY.sm, padding: index.aY.sm, "&:hover": { background: theme.colors.secondaryButtonBg, transform: "scale(1.01)", }, transition: "background 200ms ease, transform 150ms ease", }; });const defaultMessage = "Unable to get price quote"; // biome-ignore lint/suspicious/noExplicitAny: <explanation> function getErrorMessage(err) { if (typeof err.error === "object" && err.error.code) { if (err.error.code === "MINIMUM_PURCHASE_AMOUNT") { return { code: "MINIMUM_PURCHASE_AMOUNT", message: "Purchase amount is too low", }; } } return { code: "UNABLE_TO_GET_PRICE_QUOTE", message: defaultMessage, }; }/** * * @internal */ const Drawer = /* @__PURE__ */ React.forwardRef(function Drawer_(props, ref) { return (jsxRuntime.jsx(DrawerContainer, { ref: ref, children: jsxRuntime.jsx(index.br, { children: jsxRuntime.jsxs(index.aU, { p: "lg", children: [jsxRuntime.jsx(index.bs, { children: jsxRuntime.jsx(index.bt, { type: "button", "aria-label": "Close", onClick: props.close, children: jsxRuntime.jsx(index.bu, { width: index.a_.md, height: index.a_.md, style: { color: "inherit", } }) }) }), props.children] }) }) })); }); const DrawerContainer = /* @__PURE__ */ index.bp((_) => { const theme = index.aO(); return { zIndex: 10000, borderTopLeftRadius: index.bv.xl, borderTopRightRadius: index.bv.xl, background: theme.colors.modalBg, position: "absolute", bottom: 0, left: 0, right: 0, animation: `${drawerOpenAnimation} 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.1)`, borderTop: `1px solid ${theme.colors.borderColor}`, }; }); const drawerOpenAnimation = index.bw ` from { opacity: 0; transform: translateY(100px); } to { opacity: 1; transform: translateY(0); } `; const DrawerOverlay = /* @__PURE__ */ index.bp((_) => { const theme = index.aO(); return { backgroundColor: theme.colors.modalOverlayBg, zIndex: 9999, position: "absolute", inset: 0, animation: `${index.bq} 400ms cubic-bezier(0.16, 1, 0.3, 1)`, }; }); /** * * @internal */ function useDrawer() { const [isOpen, _setIsOpen] = React.useState(false); const drawerRef = React.useRef(null); const drawerOverlayRef = React.useRef(null); const closeDrawerAnimation = React.useCallback(() => { return new Promise((resolve) => { if (drawerRef.current) { const animOptions = { easing: "cubic-bezier(0.175, 0.885, 0.32, 1.1)", fill: "forwards", duration: 300, }; const closeAnimation = drawerRef.current.animate([{ transform: "translateY(100%)", opacity: 0 }], animOptions); drawerOverlayRef.current?.animate([{ opacity: 0 }], animOptions); closeAnimation.onfinish = () => resolve(); } else { resolve(); } }); }, []); const setIsOpen = React.useCallback(async (value) => { if (value) { _setIsOpen(true); } else { await closeDrawerAnimation(); _setIsOpen(false); } }, [closeDrawerAnimation]); // close on outside click React.useLayoutEffect(() => { if (!isOpen) { return; } const handleClick = (event) => { if (drawerRef.current && event.target instanceof Node && !drawerRef.current.contains(event.target)) { setIsOpen(false); } }; // avoid listening to the click event that opened the drawer by adding a frame delay requestAnimationFrame(() => { document.addEventListener("click", handleClick); }); return () => { document.removeEventListener("click", handleClick); }; }, [isOpen, setIsOpen]); return { drawerRef, drawerOverlayRef, setIsOpen, isOpen, }; }/** * @internal */ function formatSeconds(seconds) { // hours and minutes if (seconds > 3600) { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); return `${hours} Hours ${minutes} Minutes`; } // minutes only if (seconds > 60) { const minutes = Math.ceil(seconds / 60); return `${minutes} Minutes`; } return `${seconds}s`; }function EstimatedTimeAndFees(props) { const { estimatedSeconds, quoteIsLoading } = props; return (jsxRuntime.jsxs(index.aU, { bg: "tertiaryBg", flex: "row", borderColor: "borderColor", style: { borderRadius: index.bv.md, borderTopLeftRadius: 0, borderTopRightRadius: 0, justifyContent: "space-between", alignItems: "center", borderWidth: "1px", borderStyle: "solid", }, children: [jsxRuntime.jsxs(index.aU, { flex: "row", center: "y", gap: "xxs", color: "accentText", p: "sm", children: [jsxRuntime.jsx(index.bx, { width: index.a_.sm, height: index.a_.sm }), quoteIsLoading ? (jsxRuntime.jsx(index.bk, { height: index.bl.xs, width: "50px", color: "borderColor" })) : (jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", children: estimatedSeconds !== undefined ? `~${formatSeconds(estimatedSeconds)}` : "--" }))] }), jsxRuntime.jsxs(index.b6, { variant: "ghost", onClick: props.onViewFees, gap: "xs", children: [jsxRuntime.jsx(index.aU, { color: "accentText", flex: "row", center: "both", children: jsxRuntime.jsx(ViewFeeIcon, { size: index.a_.sm }) }), jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", children: "View Fees" })] })] })); } const ViewFeeIcon = (props) => { return (jsxRuntime.jsxs("svg", { width: props.size, height: props.size, viewBox: "0 0 12 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [jsxRuntime.jsx("path", { d: "M9.5 1.5H2.5C1.94772 1.5 1.5 1.94772 1.5 2.5V9.5C1.5 10.0523 1.94772 10.5 2.5 10.5H9.5C10.0523 10.5 10.5 10.0523 10.5 9.5V2.5C10.5 1.94772 10.0523 1.5 9.5 1.5Z", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round" }), jsxRuntime.jsx("path", { d: "M4.5 7.5L7.5 4.5", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round" })] })); };/** * Shows an amount "value" and renders the selected token and chain * It also renders the buttons to select the token and chain * It also renders the balance of active wallet for the selected token in selected chain * @internal */ function PayWithCreditCard(props) { return (jsxRuntime.jsxs(index.aU, { bg: "tertiaryBg", borderColor: "borderColor", flex: "row", style: { borderRadius: index.bv.md, borderBottomRightRadius: 0, borderBottomLeftRadius: 0, borderWidth: "1px", borderStyle: "solid", borderBottom: "none", flexWrap: "nowrap", justifyContent: "space-between", alignItems: "center", }, children: [jsxRuntime.jsxs(CurrencyButton, { variant: "ghost", onClick: props.onSelectCurrency, style: { minHeight: "64px", justifyContent: "flex-start", minWidth: "50%", }, gap: "sm", children: [index.bo(props.currency, "md"), jsxRuntime.jsxs(index.aU, { flex: "row", center: "y", gap: "xxs", color: "secondaryText", children: [jsxRuntime.jsx(index.b0, { color: "primaryText", children: props.currency.shorthand }), jsxRuntime.jsx(index.by, { width: index.a_.sm, height: index.a_.sm })] })] }), jsxRuntime.jsx("div", { style: { flexGrow: 1, flexShrink: 1, display: "flex", flexDirection: "column", alignItems: "flex-end", gap: index.aY.xxs, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", justifyContent: "center", paddingRight: index.aY.sm, }, children: props.isLoading ? (jsxRuntime.jsx(index.bk, { width: "100px", height: index.bl.lg })) : (jsxRuntime.jsx(index.b0, { size: "lg", color: props.value ? "primaryText" : "secondaryText", children: props.value ? `${props.currency.symbol}${index.b3(Number(props.value), 6)}` : "--" })) })] })); } const CurrencyButton = /* @__PURE__ */ index.bn(index.b6)(() => { return { "&[disabled]:hover": { borderColor: "transparent", }, }; });/** * @internal */ function SwapFees(props) { return (jsxRuntime.jsx(index.aU, { flex: "column", gap: "xs", style: { alignItems: "flex-start", }, children: props.quote.processingFees.map((fee) => { const feeAmount = index.b3(Number(fee.amount), 6); return (jsxRuntime.jsxs(index.aU, { flex: "row", gap: "xxs", children: [jsxRuntime.jsxs(index.b0, { color: "primaryText", size: "sm", children: [feeAmount === 0 ? "~" : "", feeAmount, " ", fee.token.symbol] }), jsxRuntime.jsxs(index.b0, { color: "secondaryText", size: "sm", children: ["($", (fee.amountUSDCents / 100).toFixed(2), ")"] })] }, `${fee.token.chainId}_${fee.token.tokenAddress}_${feeAmount}`)); }) })); } /** * @internal */ function FiatFees(props) { return (jsxRuntime.jsxs(index.aU, { flex: "column", gap: "xs", children: [jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", }, children: [jsxRuntime.jsx(index.b0, { inline: true, color: "secondaryText", children: "Amount" }), jsxRuntime.jsxs(index.b0, { color: "primaryText", inline: true, children: [index.b3(Number(props.quote.fromCurrency.amount), 2), " ", props.quote.fromCurrency.currencySymbol] })] }), props.quote.processingFees.map((fee, i) => { const feeAmount = index.b3(Number(fee.amount), 6); return (jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", }, children: [jsxRuntime.jsx(index.b0, { inline: true, color: "secondaryText", children: fee.feeType === "NETWORK" ? "Network Fee" : "Processing Fee" }), jsxRuntime.jsxs(index.b0, { color: "primaryText", inline: true, children: [feeAmount === 0 ? "~" : "", " ", feeAmount, " ", fee.currencySymbol] })] }, i)); }), jsxRuntime.jsx(index.aW, { y: "xxs" }), jsxRuntime.jsx(index.b4, {}), jsxRuntime.jsx(index.aW, { y: "xxs" }), jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", }, children: [jsxRuntime.jsx(index.b0, { inline: true, color: "secondaryText", children: "Total" }), jsxRuntime.jsxs(index.b0, { color: "primaryText", inline: true, children: [index.b3(Number(props.quote.fromCurrencyWithFees.amount), 6), " ", props.quote.fromCurrencyWithFees.currencySymbol] })] })] })); }const FiatProviders = ["COINBASE", "STRIPE", "TRANSAK", "KADO"];/** * @internal */ function Providers(props) { return (jsxRuntime.jsx(index.aU, { expand: true, flex: "column", gap: "sm", style: { alignItems: "flex-start", }, children: FiatProviders.map((provider) => { return (jsxRuntime.jsx(index.aU, { flex: "row", expand: true, style: { justifyContent: "space-between", }, children: jsxRuntime.jsx(index.b6, { fullWidth: true, onClick: () => props.onSelect(provider), variant: "link", children: jsxRuntime.jsx(index.bz, { color: props.preferredProvider === provider ? "primaryText" : "secondaryText", size: "sm", hoverColor: "primaryText", children: provider.charAt(0).toUpperCase() + provider.slice(1).toLowerCase() }) }) }, provider)); }) })); }function FiatScreenContent(props) { const { toToken, tokenAmount, payer, client, setScreen, toChain, showCurrencySelector, selectedCurrency, } = props; const defaultRecipientAddress = props.payOptions?.paymentInfo?.sellerAddress; const receiverAddress = defaultRecipientAddress || props.payer.account.address; const { drawerRef, drawerOverlayRef, isOpen, setIsOpen } = useDrawer(); const [drawerScreen, setDrawerScreen] = React.useState("fees"); const buyWithFiatOptions = props.payOptions.buyWithFiat; const [preferredProvider, setPreferredProvider] = React.useState(buyWithFiatOptions !== false ? buyWithFiatOptions?.preferredProvider || (localStorage.getItem(index.bA) ?? undefined) : undefined); const fiatQuoteQuery = useBuyWithFiatQuote(buyWithFiatOptions !== false && tokenAmount ? { fromCurrencySymbol: selectedCurrency.shorthand, toChainId: toChain.id, toAddress: receiverAddress, toTokenAddress: index.aS(toToken) ? index.b2 : toToken.address, toAmount: tokenAmount, client, isTestMode: buyWithFiatOptions?.testMode, purchaseData: props.payOptions.purchaseData, fromAddress: payer.account.address, preferredProvider: preferredProvider, } : undefined); function handleSubmit() { if (!fiatQuoteQuery.data) { return; } setScreen({ id: "fiat-flow", quote: fiatQuoteQuery.data, }); } function showFees() { if (!fiatQuoteQuery.data) { return; } setDrawerScreen("fees"); setIsOpen(true); } function showProviders() { setDrawerScreen("providers"); setIsOpen(true); } const disableSubmit = !fiatQuoteQuery.data; const errorMsg = !fiatQuoteQuery.isLoading && fiatQuoteQuery.error ? getErrorMessage(fiatQuoteQuery.error) : undefined; return (jsxRuntime.jsxs(index.aU, { flex: "column", gap: "lg", animate: "fadein", children: [isOpen && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(DrawerOverlay, { ref: drawerOverlayRef }), jsxRuntime.jsxs(Drawer, { ref: drawerRef, close: () => setIsOpen(false), children: [drawerScreen === "fees" && fiatQuoteQuery.data && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(index.b0, { size: "lg", color: "primaryText", children: "Fees" }), jsxRuntime.jsx(index.aW, { y: "lg" }), jsxRuntime.jsx(FiatFees, { quote: fiatQuoteQuery.data })] })), drawerScreen === "providers" && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(index.b0, { size: "lg", color: "primaryText", children: "Providers" }), jsxRuntime.jsx(index.aW, { y: "lg" }), jsxRuntime.jsx(Providers, { preferredProvider: preferredProvider || fiatQuoteQuery.data?.provider, onSelect: (provider) => { setPreferredProvider(provider); // save the pref in local storage localStorage.setItem(index.bA, provider); setIsOpen(false); } })] }))] })] })), jsxRuntime.jsxs(index.aU, { flex: "column", gap: "sm", children: [jsxRuntime.jsx(index.b0, { size: "sm", children: "Pay with credit card" }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(PayWithCreditCard, { isLoading: fiatQuoteQuery.isLoading, value: fiatQuoteQuery.data?.fromCurrencyWithFees.amount, client: client, currency: selectedCurrency, onSelectCurrency: showCurrencySelector }), jsxRuntime.jsxs(index.aU, { bg: "tertiaryBg", flex: "row", borderColor: "borderColor", style: { paddingLeft: index.aY.md, justifyContent: "space-between", alignItems: "center", borderWidth: "1px", borderStyle: "solid", borderBottom: "none", }, children: [jsxRuntime.jsx(index.b0, { size: "xs", color: "secondaryText", children: "Provider" }), jsxRuntime.jsx(index.b6, { variant: "ghost", onClick: showProviders, children: jsxRuntime.jsxs(index.aU, { flex: "row", center: "y", gap: "xxs", color: "secondaryText", children: [jsxRuntime.jsx(index.b0, { size: "xs", children: preferredProvider ? `${preferredProvider.charAt(0).toUpperCase() + preferredProvider.slice(1).toLowerCase()}` : fiatQuoteQuery.data?.provider ? `${fiatQuoteQuery.data?.provider.charAt(0).toUpperCase() + fiatQuoteQuery.data?.provider.slice(1).toLowerCase()}` : "" }), jsxRuntime.jsx(index.by, { width: index.a_.sm, height: index.a_.sm })] }) })] }), jsxRuntime.jsx(EstimatedTimeAndFees, { quoteIsLoading: fiatQuoteQuery.isLoading, estimatedSeconds: fiatQuoteQuery.data?.estimatedDurationSeconds, onViewFees: showFees })