thirdweb 5.87.3 → 5.88.0-nightly-e50d77d28fd866efdfce706b73320541d260728d-20250208000322

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/dist/cjs/client/client.js +2 -1
  2. package/dist/cjs/client/client.js.map +1 -1
  3. package/dist/cjs/contract/deployment/zksync/implementations.js +3 -0
  4. package/dist/cjs/contract/deployment/zksync/implementations.js.map +1 -1
  5. package/dist/cjs/contract/deployment/zksync/zkDeployContract.js +4 -2
  6. package/dist/cjs/contract/deployment/zksync/zkDeployContract.js.map +1 -1
  7. package/dist/cjs/pay/buyWithCrypto/getQuote.js +4 -14
  8. package/dist/cjs/pay/buyWithCrypto/getQuote.js.map +1 -1
  9. package/dist/cjs/pay/buyWithCrypto/getTransfer.js +1 -13
  10. package/dist/cjs/pay/buyWithCrypto/getTransfer.js.map +1 -1
  11. package/dist/cjs/pay/buyWithFiat/getQuote.js.map +1 -1
  12. package/dist/cjs/pay/utils/commonTypes.js +2 -0
  13. package/dist/cjs/pay/utils/commonTypes.js.map +1 -1
  14. package/dist/cjs/react/core/utils/storage.js +2 -1
  15. package/dist/cjs/react/core/utils/storage.js.map +1 -1
  16. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +50 -223
  17. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  18. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.js +111 -0
  19. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.js.map +1 -0
  20. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatStatusScreen.js +1 -1
  21. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatStatusScreen.js.map +1 -1
  22. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.js +30 -2
  23. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.js.map +1 -1
  24. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.js +24 -0
  25. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.js.map +1 -0
  26. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js +2 -1
  27. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js.map +1 -1
  28. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js +19 -16
  29. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js.map +1 -1
  30. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js +37 -0
  31. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js.map +1 -0
  32. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.js +1 -1
  33. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.js.map +1 -1
  34. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.js +165 -0
  35. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.js.map +1 -0
  36. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapStatusScreen.js +1 -1
  37. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/SwapStatusScreen.js.map +1 -1
  38. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.js +33 -6
  39. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.js.map +1 -1
  40. package/dist/cjs/react/web/ui/ConnectWallet/screens/nativeToken.js +8 -0
  41. package/dist/cjs/react/web/ui/ConnectWallet/screens/nativeToken.js.map +1 -1
  42. package/dist/cjs/react/web/utils/errors.js +16 -0
  43. package/dist/cjs/react/web/utils/errors.js.map +1 -0
  44. package/dist/cjs/version.js +1 -1
  45. package/dist/cjs/version.js.map +1 -1
  46. package/dist/cjs/wallets/smart/index.js +27 -0
  47. package/dist/cjs/wallets/smart/index.js.map +1 -1
  48. package/dist/cjs/wallets/smart/types.js.map +1 -1
  49. package/dist/esm/client/client.js +2 -1
  50. package/dist/esm/client/client.js.map +1 -1
  51. package/dist/esm/contract/deployment/zksync/implementations.js +3 -0
  52. package/dist/esm/contract/deployment/zksync/implementations.js.map +1 -1
  53. package/dist/esm/contract/deployment/zksync/zkDeployContract.js +4 -2
  54. package/dist/esm/contract/deployment/zksync/zkDeployContract.js.map +1 -1
  55. package/dist/esm/pay/buyWithCrypto/getQuote.js +4 -14
  56. package/dist/esm/pay/buyWithCrypto/getQuote.js.map +1 -1
  57. package/dist/esm/pay/buyWithCrypto/getTransfer.js +1 -13
  58. package/dist/esm/pay/buyWithCrypto/getTransfer.js.map +1 -1
  59. package/dist/esm/pay/buyWithFiat/getQuote.js.map +1 -1
  60. package/dist/esm/pay/utils/commonTypes.js +1 -1
  61. package/dist/esm/pay/utils/commonTypes.js.map +1 -1
  62. package/dist/esm/react/core/utils/storage.js +1 -0
  63. package/dist/esm/react/core/utils/storage.js.map +1 -1
  64. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +50 -223
  65. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  66. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.js +108 -0
  67. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.js.map +1 -0
  68. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatStatusScreen.js +1 -1
  69. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatStatusScreen.js.map +1 -1
  70. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.js +30 -2
  71. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.js.map +1 -1
  72. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.js +21 -0
  73. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.js.map +1 -0
  74. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js +2 -1
  75. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.js.map +1 -1
  76. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js +19 -16
  77. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.js.map +1 -1
  78. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js +34 -0
  79. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.js.map +1 -0
  80. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.js +1 -1
  81. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.js.map +1 -1
  82. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.js +162 -0
  83. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.js.map +1 -0
  84. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapStatusScreen.js +1 -1
  85. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/SwapStatusScreen.js.map +1 -1
  86. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.js +33 -6
  87. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.js.map +1 -1
  88. package/dist/esm/react/web/ui/ConnectWallet/screens/nativeToken.js +7 -0
  89. package/dist/esm/react/web/ui/ConnectWallet/screens/nativeToken.js.map +1 -1
  90. package/dist/esm/react/web/utils/errors.js +12 -0
  91. package/dist/esm/react/web/utils/errors.js.map +1 -0
  92. package/dist/esm/version.js +1 -1
  93. package/dist/esm/version.js.map +1 -1
  94. package/dist/esm/wallets/smart/index.js +27 -0
  95. package/dist/esm/wallets/smart/index.js.map +1 -1
  96. package/dist/esm/wallets/smart/types.js.map +1 -1
  97. package/dist/types/client/client.d.ts.map +1 -1
  98. package/dist/types/contract/deployment/zksync/implementations.d.ts.map +1 -1
  99. package/dist/types/contract/deployment/zksync/zkDeployContract.d.ts.map +1 -1
  100. package/dist/types/pay/buyWithCrypto/getQuote.d.ts +2 -2
  101. package/dist/types/pay/buyWithCrypto/getQuote.d.ts.map +1 -1
  102. package/dist/types/pay/buyWithCrypto/getTransfer.d.ts +2 -2
  103. package/dist/types/pay/buyWithCrypto/getTransfer.d.ts.map +1 -1
  104. package/dist/types/pay/buyWithFiat/getQuote.d.ts +4 -0
  105. package/dist/types/pay/buyWithFiat/getQuote.d.ts.map +1 -1
  106. package/dist/types/pay/utils/commonTypes.d.ts +2 -1
  107. package/dist/types/pay/utils/commonTypes.d.ts.map +1 -1
  108. package/dist/types/react/core/utils/storage.d.ts +1 -0
  109. package/dist/types/react/core/utils/storage.d.ts.map +1 -1
  110. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.d.ts.map +1 -1
  111. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.d.ts +25 -0
  112. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.d.ts.map +1 -0
  113. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.d.ts.map +1 -1
  114. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.d.ts +9 -0
  115. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.d.ts.map +1 -0
  116. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/types.d.ts +1 -0
  117. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/main/types.d.ts.map +1 -1
  118. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.d.ts.map +1 -1
  119. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.d.ts +1 -0
  120. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.d.ts.map +1 -1
  121. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.d.ts +11 -0
  122. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.d.ts.map +1 -0
  123. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.d.ts +1 -0
  124. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.d.ts.map +1 -1
  125. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.d.ts +31 -0
  126. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.d.ts.map +1 -0
  127. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/SwapStatusScreen.d.ts.map +1 -1
  128. package/dist/types/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.d.ts.map +1 -1
  129. package/dist/types/react/web/ui/ConnectWallet/screens/nativeToken.d.ts +2 -0
  130. package/dist/types/react/web/ui/ConnectWallet/screens/nativeToken.d.ts.map +1 -1
  131. package/dist/types/react/web/ui/components/text.d.ts +1 -1
  132. package/dist/types/react/web/ui/components/text.d.ts.map +1 -1
  133. package/dist/types/react/web/utils/errors.d.ts +14 -0
  134. package/dist/types/react/web/utils/errors.d.ts.map +1 -0
  135. package/dist/types/version.d.ts +1 -1
  136. package/dist/types/version.d.ts.map +1 -1
  137. package/dist/types/wallets/smart/index.d.ts.map +1 -1
  138. package/dist/types/wallets/smart/types.d.ts +5 -0
  139. package/dist/types/wallets/smart/types.d.ts.map +1 -1
  140. package/package.json +2 -2
  141. package/src/client/client.test.ts +2 -2
  142. package/src/client/client.ts +2 -1
  143. package/src/contract/deployment/zksync/implementations.ts +3 -0
  144. package/src/contract/deployment/zksync/zkDeployContract.ts +5 -2
  145. package/src/pay/buyWithCrypto/getQuote.ts +6 -15
  146. package/src/pay/buyWithCrypto/getTransfer.ts +2 -14
  147. package/src/pay/buyWithFiat/getQuote.ts +5 -0
  148. package/src/pay/utils/commonTypes.ts +3 -1
  149. package/src/react/core/utils/storage.ts +1 -0
  150. package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +70 -556
  151. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatScreenContent.tsx +307 -0
  152. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatStatusScreen.tsx +3 -5
  153. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/PostOnRampSwap.tsx +33 -1
  154. package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/Providers.tsx +57 -0
  155. package/src/react/web/ui/ConnectWallet/screens/Buy/main/types.ts +1 -0
  156. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/BuyTokenInput.tsx +12 -2
  157. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/ConfirmationScreen.tsx +22 -19
  158. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/FiatValue.tsx +51 -0
  159. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.tsx +2 -0
  160. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapScreenContent.tsx +353 -0
  161. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapStatusScreen.tsx +3 -5
  162. package/src/react/web/ui/ConnectWallet/screens/Buy/swap/TransferConfirmationScreen.tsx +43 -6
  163. package/src/react/web/ui/ConnectWallet/screens/nativeToken.ts +8 -0
  164. package/src/react/web/ui/components/text.tsx +1 -1
  165. package/src/react/web/utils/errors.ts +22 -0
  166. package/src/version.ts +1 -1
  167. package/src/wallets/smart/index.ts +28 -0
  168. package/src/wallets/smart/smart-wallet-integration.test.ts +25 -0
  169. package/src/wallets/smart/types.ts +5 -0
@@ -0,0 +1,307 @@
1
+ import { ChevronDownIcon } from "@radix-ui/react-icons";
2
+ import { useState } from "react";
3
+ import type { Chain } from "../../../../../../../chains/types.js";
4
+ import type { ThirdwebClient } from "../../../../../../../client/client.js";
5
+ import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.js";
6
+ import { isSwapRequiredPostOnramp } from "../../../../../../../pay/buyWithFiat/isSwapRequiredPostOnramp.js";
7
+ import type { FiatProvider } from "../../../../../../../pay/utils/commonTypes.js";
8
+ import { formatNumber } from "../../../../../../../utils/formatNumber.js";
9
+ import {
10
+ type Theme,
11
+ iconSize,
12
+ spacing,
13
+ } from "../../../../../../core/design-system/index.js";
14
+ import type { PayUIOptions } from "../../../../../../core/hooks/connection/ConnectButtonProps.js";
15
+ import { useBuyWithFiatQuote } from "../../../../../../core/hooks/pay/useBuyWithFiatQuote.js";
16
+ import { PREFERRED_FIAT_PROVIDER_STORAGE_KEY } from "../../../../../../core/utils/storage.js";
17
+ import {
18
+ defaultMessage,
19
+ getErrorMessage,
20
+ } from "../../../../../utils/errors.js";
21
+ import {
22
+ Drawer,
23
+ DrawerOverlay,
24
+ useDrawer,
25
+ } from "../../../../components/Drawer.js";
26
+ import { Spacer } from "../../../../components/Spacer.js";
27
+ import { Spinner } from "../../../../components/Spinner.js";
28
+ import { Container } from "../../../../components/basic.js";
29
+ import { Button } from "../../../../components/buttons.js";
30
+ import { Text } from "../../../../components/text.js";
31
+ import { TokenSymbol } from "../../../../components/token/TokenSymbol.js";
32
+ import { type ERC20OrNativeToken, isNativeToken } from "../../nativeToken.js";
33
+ import { EstimatedTimeAndFees } from "../EstimatedTimeAndFees.js";
34
+ import { PayWithCreditCard } from "../PayWIthCreditCard.js";
35
+ import type { SelectedScreen } from "../main/types.js";
36
+ import { openOnrampPopup } from "../openOnRamppopup.js";
37
+ import { FiatFees } from "../swap/Fees.js";
38
+ import { addPendingTx } from "../swap/pendingSwapTx.js";
39
+ import type { PayerInfo } from "../types.js";
40
+ import { Providers } from "./Providers.js";
41
+ import type { CurrencyMeta } from "./currencies.js";
42
+
43
+ export function FiatScreenContent(props: {
44
+ setScreen: (screen: SelectedScreen) => void;
45
+ tokenAmount: string;
46
+ toToken: ERC20OrNativeToken;
47
+ toChain: Chain;
48
+ selectedCurrency: CurrencyMeta;
49
+ showCurrencySelector: () => void;
50
+ payOptions: PayUIOptions;
51
+ theme: "light" | "dark" | Theme;
52
+ client: ThirdwebClient;
53
+ onDone: () => void;
54
+ isEmbed: boolean;
55
+ payer: PayerInfo;
56
+ setTokenAmount: (amount: string) => void;
57
+ setHasEditedAmount: (hasEdited: boolean) => void;
58
+ }) {
59
+ const {
60
+ toToken,
61
+ tokenAmount,
62
+ payer,
63
+ client,
64
+ setScreen,
65
+ toChain,
66
+ showCurrencySelector,
67
+ selectedCurrency,
68
+ } = props;
69
+ const defaultRecipientAddress = (
70
+ props.payOptions as Extract<PayUIOptions, { mode: "direct_payment" }>
71
+ )?.paymentInfo?.sellerAddress;
72
+ const receiverAddress =
73
+ defaultRecipientAddress || props.payer.account.address;
74
+ const { drawerRef, drawerOverlayRef, isOpen, setIsOpen } = useDrawer();
75
+ const [drawerScreen, setDrawerScreen] = useState<"fees" | "providers">(
76
+ "fees",
77
+ );
78
+
79
+ const buyWithFiatOptions = props.payOptions.buyWithFiat;
80
+ const [preferredProvider, setPreferredProvider] = useState<
81
+ FiatProvider | undefined
82
+ >(
83
+ buyWithFiatOptions !== false
84
+ ? buyWithFiatOptions?.preferredProvider ||
85
+ ((localStorage.getItem(
86
+ PREFERRED_FIAT_PROVIDER_STORAGE_KEY,
87
+ ) as FiatProvider | null) ??
88
+ undefined)
89
+ : undefined,
90
+ );
91
+
92
+ const fiatQuoteQuery = useBuyWithFiatQuote(
93
+ buyWithFiatOptions !== false && tokenAmount
94
+ ? {
95
+ fromCurrencySymbol: selectedCurrency.shorthand,
96
+ toChainId: toChain.id,
97
+ toAddress: receiverAddress,
98
+ toTokenAddress: isNativeToken(toToken)
99
+ ? NATIVE_TOKEN_ADDRESS
100
+ : toToken.address,
101
+ toAmount: tokenAmount,
102
+ client,
103
+ isTestMode: buyWithFiatOptions?.testMode,
104
+ purchaseData: props.payOptions.purchaseData,
105
+ fromAddress: payer.account.address,
106
+ preferredProvider: preferredProvider,
107
+ }
108
+ : undefined,
109
+ );
110
+
111
+ function handleSubmit() {
112
+ if (!fiatQuoteQuery.data) {
113
+ return;
114
+ }
115
+
116
+ const hasTwoSteps = isSwapRequiredPostOnramp(fiatQuoteQuery.data);
117
+ let openedWindow: Window | null = null;
118
+
119
+ if (!hasTwoSteps) {
120
+ openedWindow = openOnrampPopup(
121
+ fiatQuoteQuery.data.onRampLink,
122
+ typeof props.theme === "string" ? props.theme : props.theme.type,
123
+ );
124
+
125
+ addPendingTx({
126
+ type: "fiat",
127
+ intentId: fiatQuoteQuery.data.intentId,
128
+ });
129
+ }
130
+
131
+ setScreen({
132
+ id: "fiat-flow",
133
+ quote: fiatQuoteQuery.data,
134
+ openedWindow,
135
+ });
136
+ }
137
+
138
+ function showFees() {
139
+ if (!fiatQuoteQuery.data) {
140
+ return;
141
+ }
142
+
143
+ setDrawerScreen("fees");
144
+ setIsOpen(true);
145
+ }
146
+
147
+ function showProviders() {
148
+ setDrawerScreen("providers");
149
+ setIsOpen(true);
150
+ }
151
+
152
+ const disableSubmit = !fiatQuoteQuery.data;
153
+
154
+ const errorMsg =
155
+ !fiatQuoteQuery.isLoading && fiatQuoteQuery.error
156
+ ? getErrorMessage(fiatQuoteQuery.error)
157
+ : undefined;
158
+
159
+ return (
160
+ <Container flex="column" gap="md" animate="fadein">
161
+ {isOpen && (
162
+ <>
163
+ <DrawerOverlay ref={drawerOverlayRef} />
164
+ <Drawer ref={drawerRef} close={() => setIsOpen(false)}>
165
+ {drawerScreen === "fees" && fiatQuoteQuery.data && (
166
+ <div>
167
+ <Text size="lg" color="primaryText">
168
+ Fees
169
+ </Text>
170
+
171
+ <Spacer y="lg" />
172
+ <FiatFees quote={fiatQuoteQuery.data} />
173
+ </div>
174
+ )}
175
+ {drawerScreen === "providers" && (
176
+ <div>
177
+ <Text size="lg" color="primaryText">
178
+ Providers
179
+ </Text>
180
+ <Spacer y="lg" />
181
+ <Providers
182
+ preferredProvider={
183
+ preferredProvider || fiatQuoteQuery.data?.provider
184
+ }
185
+ onSelect={(provider) => {
186
+ setPreferredProvider(provider);
187
+ // save the pref in local storage
188
+ localStorage.setItem(
189
+ PREFERRED_FIAT_PROVIDER_STORAGE_KEY,
190
+ provider,
191
+ );
192
+ setIsOpen(false);
193
+ }}
194
+ />
195
+ </div>
196
+ )}
197
+ </Drawer>
198
+ </>
199
+ )}
200
+
201
+ <div>
202
+ <PayWithCreditCard
203
+ isLoading={fiatQuoteQuery.isLoading}
204
+ value={fiatQuoteQuery.data?.fromCurrencyWithFees.amount}
205
+ client={client}
206
+ currency={selectedCurrency}
207
+ onSelectCurrency={showCurrencySelector}
208
+ />
209
+ <Container
210
+ bg="tertiaryBg"
211
+ flex="row"
212
+ borderColor="borderColor"
213
+ style={{
214
+ paddingLeft: spacing.md,
215
+ justifyContent: "space-between",
216
+ alignItems: "center",
217
+ borderWidth: "1px",
218
+ borderStyle: "solid",
219
+ borderBottom: "none",
220
+ }}
221
+ >
222
+ <Text size="xs" color="secondaryText">
223
+ Provider
224
+ </Text>
225
+ <Button variant="ghost" onClick={showProviders}>
226
+ <Container flex="row" center="y" gap="xxs" color="secondaryText">
227
+ <Text size="xs">
228
+ {preferredProvider
229
+ ? `${preferredProvider.charAt(0).toUpperCase() + preferredProvider.slice(1).toLowerCase()}`
230
+ : fiatQuoteQuery.data?.provider
231
+ ? `${fiatQuoteQuery.data?.provider.charAt(0).toUpperCase() + fiatQuoteQuery.data?.provider.slice(1).toLowerCase()}`
232
+ : ""}
233
+ </Text>
234
+ <ChevronDownIcon width={iconSize.sm} height={iconSize.sm} />
235
+ </Container>
236
+ </Button>
237
+ </Container>
238
+ {/* Estimated time + View fees button */}
239
+ <EstimatedTimeAndFees
240
+ quoteIsLoading={fiatQuoteQuery.isLoading}
241
+ estimatedSeconds={fiatQuoteQuery.data?.estimatedDurationSeconds}
242
+ onViewFees={showFees}
243
+ />
244
+ <Spacer y="md" />
245
+ </div>
246
+
247
+ {/* Error message */}
248
+ {errorMsg && (
249
+ <div>
250
+ {errorMsg.data?.minimumAmountEth ? (
251
+ <Text color="danger" size="sm" center multiline>
252
+ Minimum amount is{" "}
253
+ {formatNumber(Number(errorMsg.data.minimumAmountEth), 6)}{" "}
254
+ <TokenSymbol
255
+ token={toToken}
256
+ chain={toChain}
257
+ size="sm"
258
+ inline
259
+ color="danger"
260
+ />
261
+ </Text>
262
+ ) : (
263
+ <Text color="danger" size="sm" center multiline>
264
+ {errorMsg.message || defaultMessage}
265
+ </Text>
266
+ )}
267
+ </div>
268
+ )}
269
+
270
+ {errorMsg?.data?.minimumAmountEth ? (
271
+ <Button
272
+ variant="accent"
273
+ fullWidth
274
+ onClick={() => {
275
+ props.setTokenAmount(
276
+ formatNumber(
277
+ Number(errorMsg.data?.minimumAmountEth),
278
+ 6,
279
+ ).toString(),
280
+ );
281
+ props.setHasEditedAmount(true);
282
+ }}
283
+ >
284
+ Set Minimum
285
+ </Button>
286
+ ) : (
287
+ <Button
288
+ variant={disableSubmit ? "outline" : "accent"}
289
+ data-disabled={disableSubmit}
290
+ disabled={disableSubmit}
291
+ fullWidth
292
+ onClick={handleSubmit}
293
+ gap="xs"
294
+ >
295
+ {fiatQuoteQuery.isLoading ? (
296
+ <>
297
+ Getting price quote
298
+ <Spinner size="sm" color="accentText" />
299
+ </>
300
+ ) : (
301
+ "Continue"
302
+ )}
303
+ </Button>
304
+ )}
305
+ </Container>
306
+ );
307
+ }
@@ -248,11 +248,9 @@ function OnrampStatusScreenUI(props: {
248
248
  </>
249
249
  )}
250
250
 
251
- {!props.isEmbed && (
252
- <Button variant="accent" fullWidth onClick={props.onDone}>
253
- {props.transactionMode ? "Continue Transaction" : "Done"}
254
- </Button>
255
- )}
251
+ <Button variant="accent" fullWidth onClick={props.onDone}>
252
+ {props.transactionMode ? "Continue Transaction" : "Done"}
253
+ </Button>
256
254
  </>
257
255
  )}
258
256
  </Container>
@@ -1,6 +1,9 @@
1
1
  import { useQuery } from "@tanstack/react-query";
2
2
  import { useEffect, useState } from "react";
3
+ import { getCachedChain } from "../../../../../../../chains/utils.js";
3
4
  import type { ThirdwebClient } from "../../../../../../../client/client.js";
5
+ import { getContract } from "../../../../../../../contract/contract.js";
6
+ import { allowance } from "../../../../../../../extensions/erc20/__generated__/IERC20/read/allowance.js";
4
7
  import type { BuyWithCryptoQuote } from "../../../../../../../pay/buyWithCrypto/getQuote.js";
5
8
  import type { BuyWithCryptoStatus } from "../../../../../../../pay/buyWithCrypto/getStatus.js";
6
9
  import { getPostOnRampQuote } from "../../../../../../../pay/buyWithFiat/getPostOnRampQuote.js";
@@ -43,11 +46,38 @@ export function PostOnRampSwap(props: {
43
46
  refetchOnWindowFocus: false,
44
47
  });
45
48
 
49
+ const allowanceQuery = useQuery({
50
+ queryKey: [
51
+ "allowance",
52
+ props.payer.account.address,
53
+ postOnRampQuoteQuery.data?.approvalData,
54
+ ],
55
+ queryFn: () => {
56
+ if (!postOnRampQuoteQuery.data?.approvalData) {
57
+ return null;
58
+ }
59
+ return allowance({
60
+ contract: getContract({
61
+ client: props.client,
62
+ address: postOnRampQuoteQuery.data.swapDetails.fromToken.tokenAddress,
63
+ chain: getCachedChain(
64
+ postOnRampQuoteQuery.data.swapDetails.fromToken.chainId,
65
+ ),
66
+ }),
67
+ spender: postOnRampQuoteQuery.data.approvalData.spenderAddress,
68
+ owner: props.payer.account.address,
69
+ });
70
+ },
71
+ enabled: !!postOnRampQuoteQuery.data?.approvalData,
72
+ refetchOnMount: true,
73
+ });
74
+
46
75
  useEffect(() => {
47
76
  if (
48
77
  postOnRampQuoteQuery.data &&
49
78
  !lockedOnRampQuote &&
50
- !postOnRampQuoteQuery.isRefetching
79
+ !postOnRampQuoteQuery.isRefetching &&
80
+ !allowanceQuery.isLoading
51
81
  ) {
52
82
  setLockedOnRampQuote(postOnRampQuoteQuery.data);
53
83
  }
@@ -55,6 +85,7 @@ export function PostOnRampSwap(props: {
55
85
  postOnRampQuoteQuery.data,
56
86
  lockedOnRampQuote,
57
87
  postOnRampQuoteQuery.isRefetching,
88
+ allowanceQuery.isLoading,
58
89
  ]);
59
90
 
60
91
  if (postOnRampQuoteQuery.isError) {
@@ -133,6 +164,7 @@ export function PostOnRampSwap(props: {
133
164
  transactionMode={props.transactionMode}
134
165
  isEmbed={props.isEmbed}
135
166
  onSuccess={props.onSuccess}
167
+ approvalAmount={allowanceQuery.data ?? undefined}
136
168
  />
137
169
  );
138
170
  }
@@ -0,0 +1,57 @@
1
+ import {
2
+ type FiatProvider,
3
+ FiatProviders,
4
+ } from "../../../../../../../pay/utils/commonTypes.js";
5
+ import { Container } from "../../../../components/basic.js";
6
+ import { Button } from "../../../../components/buttons.js";
7
+ import { Link } from "../../../../components/text.js";
8
+ /**
9
+ * @internal
10
+ */
11
+ export function Providers(props: {
12
+ preferredProvider?: FiatProvider;
13
+ onSelect: (provider: FiatProvider) => void;
14
+ }) {
15
+ return (
16
+ <Container
17
+ expand
18
+ flex="column"
19
+ gap="sm"
20
+ style={{
21
+ alignItems: "flex-start",
22
+ }}
23
+ >
24
+ {FiatProviders.map((provider) => {
25
+ return (
26
+ <Container
27
+ key={provider}
28
+ flex="row"
29
+ expand
30
+ style={{
31
+ justifyContent: "space-between",
32
+ }}
33
+ >
34
+ <Button
35
+ fullWidth
36
+ onClick={() => props.onSelect(provider)}
37
+ variant={"link"}
38
+ >
39
+ <Link
40
+ color={
41
+ props.preferredProvider === provider
42
+ ? "primaryText"
43
+ : "secondaryText"
44
+ }
45
+ size="sm"
46
+ hoverColor="primaryText"
47
+ >
48
+ {provider.charAt(0).toUpperCase() +
49
+ provider.slice(1).toLowerCase()}
50
+ </Link>
51
+ </Button>
52
+ </Container>
53
+ );
54
+ })}
55
+ </Container>
56
+ );
57
+ }
@@ -34,6 +34,7 @@ export type SelectedScreen =
34
34
  | {
35
35
  id: "swap-flow";
36
36
  quote: BuyWithCryptoQuote;
37
+ approvalAmount?: bigint;
37
38
  }
38
39
  | {
39
40
  id: "fiat-flow";
@@ -19,6 +19,7 @@ import { Text } from "../../../../components/text.js";
19
19
  import { TokenSymbol } from "../../../../components/token/TokenSymbol.js";
20
20
  import type { ERC20OrNativeToken } from "../../nativeToken.js";
21
21
  import { getBuyTokenAmountFontSize } from "../utils.js";
22
+ import { FiatValue } from "./FiatValue.js";
22
23
 
23
24
  /**
24
25
  * @internal
@@ -35,7 +36,6 @@ export function BuyTokenInput(props: {
35
36
  freezeChainAndToken?: boolean;
36
37
  }) {
37
38
  const { name } = useChainName(props.chain);
38
-
39
39
  const getWidth = () => {
40
40
  let chars = props.value.replace(".", "").length;
41
41
  const hasDot = props.value.includes(".");
@@ -122,9 +122,19 @@ export function BuyTokenInput(props: {
122
122
  </Container>
123
123
  </div>
124
124
 
125
+ <Container flex="row" center="both">
126
+ <FiatValue
127
+ tokenAmount={props.value}
128
+ token={props.token}
129
+ chain={props.chain}
130
+ client={props.client}
131
+ size="md"
132
+ />
133
+ </Container>
134
+
125
135
  {!props.hideTokenSelector && (
126
136
  <>
127
- <Spacer y="sm" />
137
+ <Spacer y="md" />
128
138
 
129
139
  {/* Token / Chain selector */}
130
140
  <Container flex="row" center="x">
@@ -3,6 +3,8 @@ import { useState } from "react";
3
3
  import { trackPayEvent } from "../../../../../../../analytics/track/pay.js";
4
4
  import type { Chain } from "../../../../../../../chains/types.js";
5
5
  import type { ThirdwebClient } from "../../../../../../../client/client.js";
6
+ import { getContract } from "../../../../../../../contract/contract.js";
7
+ import { approve } from "../../../../../../../extensions/erc20/write/approve.js";
6
8
  import type { BuyWithCryptoQuote } from "../../../../../../../pay/buyWithCrypto/getQuote.js";
7
9
  import { sendTransaction } from "../../../../../../../transaction/actions/send-transaction.js";
8
10
  import { waitForReceipt } from "../../../../../../../transaction/actions/wait-for-tx-receipt.js";
@@ -51,9 +53,13 @@ export function SwapConfirmationScreen(props: {
51
53
  fromTokenSymbol: string;
52
54
  isFiatFlow: boolean;
53
55
  payer: PayerInfo;
56
+ preApprovedAmount?: bigint;
54
57
  }) {
55
- const isApprovalRequired = props.quote.approval !== undefined;
56
- const initialStep = isApprovalRequired ? "approval" : "swap";
58
+ const needsApproval =
59
+ props.quote.approvalData &&
60
+ props.preApprovedAmount !== undefined &&
61
+ props.preApprovedAmount < BigInt(props.quote.approvalData.amountWei);
62
+ const initialStep = needsApproval ? "approval" : "swap";
57
63
 
58
64
  const [step, setStep] = useState<"approval" | "swap">(initialStep);
59
65
  const [status, setStatus] = useState<
@@ -136,7 +142,7 @@ export function SwapConfirmationScreen(props: {
136
142
  <Spacer y="xl" />
137
143
 
138
144
  {/* Show 2 steps - Approve and confirm */}
139
- {isApprovalRequired && (
145
+ {needsApproval && (
140
146
  <>
141
147
  <Spacer y="sm" />
142
148
  <Container
@@ -187,7 +193,7 @@ export function SwapConfirmationScreen(props: {
187
193
  fullWidth
188
194
  disabled={status === "pending"}
189
195
  onClick={async () => {
190
- if (step === "approval" && props.quote.approval) {
196
+ if (step === "approval" && props.quote.approvalData) {
191
197
  try {
192
198
  setStatus("pending");
193
199
 
@@ -204,13 +210,22 @@ export function SwapConfirmationScreen(props: {
204
210
  dstChainId: props.quote.swapDetails.toToken.chainId,
205
211
  });
206
212
 
213
+ const transaction = approve({
214
+ contract: getContract({
215
+ client: props.client,
216
+ address: props.quote.swapDetails.fromToken.tokenAddress,
217
+ chain: props.fromChain,
218
+ }),
219
+ spender: props.quote.approvalData.spenderAddress,
220
+ amountWei: BigInt(props.quote.approvalData.amountWei),
221
+ });
222
+
207
223
  const tx = await sendTransaction({
208
224
  account: props.payer.account,
209
- transaction: props.quote.approval,
225
+ transaction,
210
226
  });
211
227
 
212
228
  await waitForReceipt({ ...tx, maxBlocksWaitTime: 50 });
213
- // props.onQuoteFinalized(props.quote);
214
229
 
215
230
  trackPayEvent({
216
231
  event: "swap_approval_success",
@@ -236,19 +251,7 @@ export function SwapConfirmationScreen(props: {
236
251
  if (step === "swap") {
237
252
  setStatus("pending");
238
253
  try {
239
- let tx = props.quote.transactionRequest;
240
-
241
- // Fix for inApp wallet
242
- // Ideally - the pay server sends a non-legacy transaction to avoid this issue
243
- if (
244
- props.payer.wallet.id === "inApp" ||
245
- props.payer.wallet.id === "embedded"
246
- ) {
247
- tx = {
248
- ...props.quote.transactionRequest,
249
- gasPrice: undefined,
250
- };
251
- }
254
+ const tx = props.quote.transactionRequest;
252
255
 
253
256
  trackPayEvent({
254
257
  event: "prompt_swap_execution",
@@ -0,0 +1,51 @@
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import type { Chain } from "../../../../../../../chains/types.js";
3
+ import type { ThirdwebClient } from "../../../../../../../client/client.js";
4
+ import { convertCryptoToFiat } from "../../../../../../../pay/convert/cryptoToFiat.js";
5
+ import { formatNumber } from "../../../../../../../utils/formatNumber.js";
6
+ import { fontSize } from "../../../../../../core/design-system/index.js";
7
+ import { Skeleton } from "../../../../components/Skeleton.js";
8
+ import { Text } from "../../../../components/text.js";
9
+ import type { TextProps } from "../../../../components/text.js";
10
+ import { useDebouncedValue } from "../../../../hooks/useDebouncedValue.js";
11
+ import type { ERC20OrNativeToken } from "../../nativeToken.js";
12
+ import { getTokenAddress } from "../../nativeToken.js";
13
+
14
+ export function FiatValue(
15
+ props: {
16
+ tokenAmount: string;
17
+ token: ERC20OrNativeToken;
18
+ chain: Chain;
19
+ client: ThirdwebClient;
20
+ } & TextProps,
21
+ ) {
22
+ const deferredTokenAmount = useDebouncedValue(props.tokenAmount, 500);
23
+ const cryptoToFiatQuery = useQuery({
24
+ queryKey: [
25
+ "cryptoToFiat",
26
+ props.chain.id,
27
+ getTokenAddress(props.token),
28
+ deferredTokenAmount,
29
+ ],
30
+ queryFn: () =>
31
+ convertCryptoToFiat({
32
+ client: props.client,
33
+ chain: props.chain,
34
+ fromTokenAddress: getTokenAddress(props.token),
35
+ fromAmount: Number(deferredTokenAmount),
36
+ to: "USD",
37
+ }),
38
+ });
39
+
40
+ if (cryptoToFiatQuery.isLoading) {
41
+ return <Skeleton width={"50px"} height={fontSize.lg} />;
42
+ }
43
+
44
+ return (
45
+ <Text {...props}>
46
+ {cryptoToFiatQuery.data?.result
47
+ ? `$${formatNumber(cryptoToFiatQuery.data.result, 2)}`
48
+ : "$0.00"}
49
+ </Text>
50
+ );
51
+ }
@@ -22,6 +22,7 @@ type SwapFlowProps = {
22
22
  transactionMode: boolean;
23
23
  isEmbed: boolean;
24
24
  onSuccess: ((status: BuyWithCryptoStatus) => void) | undefined;
25
+ approvalAmount?: bigint;
25
26
  };
26
27
 
27
28
  export function SwapFlow(props: SwapFlowProps) {
@@ -109,6 +110,7 @@ export function SwapFlow(props: SwapFlowProps) {
109
110
  quote={quote}
110
111
  isFiatFlow={props.isFiatFlow}
111
112
  payer={props.payer}
113
+ preApprovedAmount={props.approvalAmount}
112
114
  />
113
115
  );
114
116
  }