thirdweb 5.108.1 → 5.108.2

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 (224) hide show
  1. package/dist/cjs/bridge/Buy.js +2 -2
  2. package/dist/cjs/bridge/Chains.js +1 -1
  3. package/dist/cjs/bridge/Routes.js +1 -1
  4. package/dist/cjs/bridge/Sell.js +2 -2
  5. package/dist/cjs/bridge/Status.js +1 -1
  6. package/dist/cjs/bridge/Token.js +3 -3
  7. package/dist/cjs/bridge/Transfer.js +1 -1
  8. package/dist/cjs/bridge/Webhook.js +1 -1
  9. package/dist/cjs/exports/react.js +3 -1
  10. package/dist/cjs/exports/react.js.map +1 -1
  11. package/dist/cjs/exports/thirdweb.js +1 -1
  12. package/dist/cjs/react/core/hooks/useStepExecutor.js +1 -21
  13. package/dist/cjs/react/core/hooks/useStepExecutor.js.map +1 -1
  14. package/dist/cjs/react/web/ui/Bridge/BridgeOrchestrator.js +5 -6
  15. package/dist/cjs/react/web/ui/Bridge/BridgeOrchestrator.js.map +1 -1
  16. package/dist/cjs/react/web/ui/Bridge/StepRunner.js +2 -2
  17. package/dist/cjs/react/web/ui/Bridge/StepRunner.js.map +1 -1
  18. package/dist/cjs/react/web/ui/Bridge/TransactionPayment.js +1 -0
  19. package/dist/cjs/react/web/ui/Bridge/TransactionPayment.js.map +1 -1
  20. package/dist/cjs/react/web/ui/Bridge/bridge-widget/bridge-widget.js +95 -0
  21. package/dist/cjs/react/web/ui/Bridge/bridge-widget/bridge-widget.js.map +1 -0
  22. package/dist/cjs/react/web/ui/Bridge/payment-details/PaymentOverview.js +1 -0
  23. package/dist/cjs/react/web/ui/Bridge/payment-details/PaymentOverview.js.map +1 -1
  24. package/dist/cjs/react/web/ui/Bridge/swap-widget/SwapWidget.js +13 -1
  25. package/dist/cjs/react/web/ui/Bridge/swap-widget/SwapWidget.js.map +1 -1
  26. package/dist/cjs/react/web/ui/Bridge/swap-widget/select-chain.js +12 -1
  27. package/dist/cjs/react/web/ui/Bridge/swap-widget/select-chain.js.map +1 -1
  28. package/dist/cjs/react/web/ui/Bridge/swap-widget/select-token-ui.js +13 -4
  29. package/dist/cjs/react/web/ui/Bridge/swap-widget/select-token-ui.js.map +1 -1
  30. package/dist/cjs/react/web/ui/Bridge/swap-widget/swap-ui.js +6 -10
  31. package/dist/cjs/react/web/ui/Bridge/swap-widget/swap-ui.js.map +1 -1
  32. package/dist/cjs/react/web/ui/ConnectWallet/Modal/ConnectEmbed.js +2 -1
  33. package/dist/cjs/react/web/ui/ConnectWallet/Modal/ConnectEmbed.js.map +1 -1
  34. package/dist/cjs/script-exports/bridge-widget-script.js +17 -0
  35. package/dist/cjs/script-exports/bridge-widget-script.js.map +1 -0
  36. package/dist/cjs/script-exports/bridge-widget.js +13 -0
  37. package/dist/cjs/script-exports/bridge-widget.js.map +1 -0
  38. package/dist/cjs/stories/Bridge/BridgeOrchestrator.stories.js +30 -1
  39. package/dist/cjs/stories/Bridge/BridgeOrchestrator.stories.js.map +1 -1
  40. package/dist/cjs/stories/Bridge/BridgeWidget/bridge-widget-script.stories.js +47 -0
  41. package/dist/cjs/stories/Bridge/BridgeWidget/bridge-widget-script.stories.js.map +1 -0
  42. package/dist/cjs/stories/Bridge/StepRunner.stories.js +1 -21
  43. package/dist/cjs/stories/Bridge/StepRunner.stories.js.map +1 -1
  44. package/dist/cjs/stories/Bridge/UnsupportedTokenScreen.stories.js +4 -4
  45. package/dist/cjs/stories/Bridge/UnsupportedTokenScreen.stories.js.map +1 -1
  46. package/dist/cjs/utils/units.js +3 -0
  47. package/dist/cjs/utils/units.js.map +1 -1
  48. package/dist/cjs/version.js +1 -1
  49. package/dist/cjs/x402/common.js +41 -41
  50. package/dist/cjs/x402/common.js.map +1 -1
  51. package/dist/cjs/x402/facilitator.js +1 -0
  52. package/dist/cjs/x402/facilitator.js.map +1 -1
  53. package/dist/cjs/x402/fetchWithPayment.js +1 -1
  54. package/dist/cjs/x402/fetchWithPayment.js.map +1 -1
  55. package/dist/cjs/x402/schemas.js +3 -0
  56. package/dist/cjs/x402/schemas.js.map +1 -1
  57. package/dist/cjs/x402/settle-payment.js +4 -3
  58. package/dist/cjs/x402/settle-payment.js.map +1 -1
  59. package/dist/cjs/x402/types.js.map +1 -1
  60. package/dist/cjs/x402/verify-payment.js +2 -1
  61. package/dist/cjs/x402/verify-payment.js.map +1 -1
  62. package/dist/esm/bridge/Buy.js +2 -2
  63. package/dist/esm/bridge/Chains.js +1 -1
  64. package/dist/esm/bridge/Routes.js +1 -1
  65. package/dist/esm/bridge/Sell.js +2 -2
  66. package/dist/esm/bridge/Status.js +1 -1
  67. package/dist/esm/bridge/Token.js +3 -3
  68. package/dist/esm/bridge/Transfer.js +1 -1
  69. package/dist/esm/bridge/Webhook.js +1 -1
  70. package/dist/esm/exports/react.js +1 -0
  71. package/dist/esm/exports/react.js.map +1 -1
  72. package/dist/esm/exports/thirdweb.js +1 -1
  73. package/dist/esm/react/core/hooks/useStepExecutor.js +1 -21
  74. package/dist/esm/react/core/hooks/useStepExecutor.js.map +1 -1
  75. package/dist/esm/react/web/ui/Bridge/BridgeOrchestrator.js +5 -6
  76. package/dist/esm/react/web/ui/Bridge/BridgeOrchestrator.js.map +1 -1
  77. package/dist/esm/react/web/ui/Bridge/StepRunner.js +2 -2
  78. package/dist/esm/react/web/ui/Bridge/StepRunner.js.map +1 -1
  79. package/dist/esm/react/web/ui/Bridge/TransactionPayment.js +1 -0
  80. package/dist/esm/react/web/ui/Bridge/TransactionPayment.js.map +1 -1
  81. package/dist/esm/react/web/ui/Bridge/bridge-widget/bridge-widget.js +92 -0
  82. package/dist/esm/react/web/ui/Bridge/bridge-widget/bridge-widget.js.map +1 -0
  83. package/dist/esm/react/web/ui/Bridge/payment-details/PaymentOverview.js +1 -0
  84. package/dist/esm/react/web/ui/Bridge/payment-details/PaymentOverview.js.map +1 -1
  85. package/dist/esm/react/web/ui/Bridge/swap-widget/SwapWidget.js +13 -1
  86. package/dist/esm/react/web/ui/Bridge/swap-widget/SwapWidget.js.map +1 -1
  87. package/dist/esm/react/web/ui/Bridge/swap-widget/select-chain.js +13 -2
  88. package/dist/esm/react/web/ui/Bridge/swap-widget/select-chain.js.map +1 -1
  89. package/dist/esm/react/web/ui/Bridge/swap-widget/select-token-ui.js +13 -4
  90. package/dist/esm/react/web/ui/Bridge/swap-widget/select-token-ui.js.map +1 -1
  91. package/dist/esm/react/web/ui/Bridge/swap-widget/swap-ui.js +6 -10
  92. package/dist/esm/react/web/ui/Bridge/swap-widget/swap-ui.js.map +1 -1
  93. package/dist/esm/react/web/ui/ConnectWallet/Modal/ConnectEmbed.js +2 -1
  94. package/dist/esm/react/web/ui/ConnectWallet/Modal/ConnectEmbed.js.map +1 -1
  95. package/dist/esm/script-exports/bridge-widget-script.js +14 -0
  96. package/dist/esm/script-exports/bridge-widget-script.js.map +1 -0
  97. package/dist/esm/script-exports/bridge-widget.js +10 -0
  98. package/dist/esm/script-exports/bridge-widget.js.map +1 -0
  99. package/dist/esm/stories/Bridge/BridgeOrchestrator.stories.js +29 -0
  100. package/dist/esm/stories/Bridge/BridgeOrchestrator.stories.js.map +1 -1
  101. package/dist/esm/stories/Bridge/BridgeWidget/bridge-widget-script.stories.js +40 -0
  102. package/dist/esm/stories/Bridge/BridgeWidget/bridge-widget-script.stories.js.map +1 -0
  103. package/dist/esm/stories/Bridge/StepRunner.stories.js +2 -22
  104. package/dist/esm/stories/Bridge/StepRunner.stories.js.map +1 -1
  105. package/dist/esm/stories/Bridge/UnsupportedTokenScreen.stories.js +4 -4
  106. package/dist/esm/stories/Bridge/UnsupportedTokenScreen.stories.js.map +1 -1
  107. package/dist/esm/utils/units.js +3 -0
  108. package/dist/esm/utils/units.js.map +1 -1
  109. package/dist/esm/version.js +1 -1
  110. package/dist/esm/x402/common.js +42 -42
  111. package/dist/esm/x402/common.js.map +1 -1
  112. package/dist/esm/x402/facilitator.js +1 -0
  113. package/dist/esm/x402/facilitator.js.map +1 -1
  114. package/dist/esm/x402/fetchWithPayment.js +1 -1
  115. package/dist/esm/x402/fetchWithPayment.js.map +1 -1
  116. package/dist/esm/x402/schemas.js +3 -0
  117. package/dist/esm/x402/schemas.js.map +1 -1
  118. package/dist/esm/x402/settle-payment.js +4 -3
  119. package/dist/esm/x402/settle-payment.js.map +1 -1
  120. package/dist/esm/x402/types.js.map +1 -1
  121. package/dist/esm/x402/verify-payment.js +2 -1
  122. package/dist/esm/x402/verify-payment.js.map +1 -1
  123. package/dist/scripts/bridge-widget.d.ts +1118 -0
  124. package/dist/scripts/bridge-widget.js +532 -0
  125. package/dist/types/bridge/Buy.d.ts +2 -2
  126. package/dist/types/bridge/Chains.d.ts +1 -1
  127. package/dist/types/bridge/Routes.d.ts +1 -1
  128. package/dist/types/bridge/Sell.d.ts +2 -2
  129. package/dist/types/bridge/Status.d.ts +1 -1
  130. package/dist/types/bridge/Token.d.ts +3 -3
  131. package/dist/types/bridge/Transfer.d.ts +1 -1
  132. package/dist/types/bridge/Webhook.d.ts +1 -1
  133. package/dist/types/bridge/types/Chain.d.ts +1 -1
  134. package/dist/types/exports/react.d.ts +1 -0
  135. package/dist/types/exports/react.d.ts.map +1 -1
  136. package/dist/types/exports/thirdweb.d.ts +1 -1
  137. package/dist/types/react/core/hooks/useStepExecutor.d.ts +3 -4
  138. package/dist/types/react/core/hooks/useStepExecutor.d.ts.map +1 -1
  139. package/dist/types/react/core/hooks/useTransactionDetails.d.ts +1 -1
  140. package/dist/types/react/core/hooks/useTransactionDetails.d.ts.map +1 -1
  141. package/dist/types/react/web/ui/Bridge/BridgeOrchestrator.d.ts.map +1 -1
  142. package/dist/types/react/web/ui/Bridge/BuyWidget.d.ts +1 -1
  143. package/dist/types/react/web/ui/Bridge/BuyWidget.d.ts.map +1 -1
  144. package/dist/types/react/web/ui/Bridge/StepRunner.d.ts +6 -2
  145. package/dist/types/react/web/ui/Bridge/StepRunner.d.ts.map +1 -1
  146. package/dist/types/react/web/ui/Bridge/TransactionPayment.d.ts.map +1 -1
  147. package/dist/types/react/web/ui/Bridge/bridge-widget/bridge-widget.d.ts +218 -0
  148. package/dist/types/react/web/ui/Bridge/bridge-widget/bridge-widget.d.ts.map +1 -0
  149. package/dist/types/react/web/ui/Bridge/swap-widget/SwapWidget.d.ts.map +1 -1
  150. package/dist/types/react/web/ui/Bridge/swap-widget/select-chain.d.ts.map +1 -1
  151. package/dist/types/react/web/ui/Bridge/swap-widget/select-token-ui.d.ts +1 -1
  152. package/dist/types/react/web/ui/Bridge/swap-widget/select-token-ui.d.ts.map +1 -1
  153. package/dist/types/react/web/ui/Bridge/swap-widget/swap-ui.d.ts.map +1 -1
  154. package/dist/types/react/web/ui/ConnectWallet/Modal/ConnectEmbed.d.ts.map +1 -1
  155. package/dist/types/script-exports/bridge-widget-script.d.ts +49 -0
  156. package/dist/types/script-exports/bridge-widget-script.d.ts.map +1 -0
  157. package/dist/types/script-exports/bridge-widget.d.ts +4 -0
  158. package/dist/types/script-exports/bridge-widget.d.ts.map +1 -0
  159. package/dist/types/stories/Bridge/BridgeOrchestrator.stories.d.ts +4 -0
  160. package/dist/types/stories/Bridge/BridgeOrchestrator.stories.d.ts.map +1 -1
  161. package/dist/types/stories/Bridge/BridgeWidget/bridge-widget-script.stories.d.ts +10 -0
  162. package/dist/types/stories/Bridge/BridgeWidget/bridge-widget-script.stories.d.ts.map +1 -0
  163. package/dist/types/stories/Bridge/StepRunner.stories.d.ts +0 -6
  164. package/dist/types/stories/Bridge/StepRunner.stories.d.ts.map +1 -1
  165. package/dist/types/utils/domains.d.ts +1 -1
  166. package/dist/types/utils/units.d.ts.map +1 -1
  167. package/dist/types/version.d.ts +1 -1
  168. package/dist/types/x402/common.d.ts.map +1 -1
  169. package/dist/types/x402/facilitator.d.ts +1 -0
  170. package/dist/types/x402/facilitator.d.ts.map +1 -1
  171. package/dist/types/x402/fetchWithPayment.d.ts.map +1 -1
  172. package/dist/types/x402/schemas.d.ts +2 -1
  173. package/dist/types/x402/schemas.d.ts.map +1 -1
  174. package/dist/types/x402/settle-payment.d.ts +4 -2
  175. package/dist/types/x402/settle-payment.d.ts.map +1 -1
  176. package/dist/types/x402/types.d.ts +2 -1
  177. package/dist/types/x402/types.d.ts.map +1 -1
  178. package/dist/types/x402/verify-payment.d.ts +2 -1
  179. package/dist/types/x402/verify-payment.d.ts.map +1 -1
  180. package/package.json +7 -4
  181. package/src/bridge/Buy.ts +2 -2
  182. package/src/bridge/Chains.ts +1 -1
  183. package/src/bridge/Routes.ts +1 -1
  184. package/src/bridge/Sell.ts +2 -2
  185. package/src/bridge/Status.ts +1 -1
  186. package/src/bridge/Token.ts +3 -3
  187. package/src/bridge/Transfer.ts +1 -1
  188. package/src/bridge/Webhook.ts +1 -1
  189. package/src/bridge/types/Chain.ts +1 -1
  190. package/src/exports/react.ts +4 -0
  191. package/src/exports/thirdweb.ts +1 -1
  192. package/src/react/core/hooks/useStepExecutor.ts +5 -30
  193. package/src/react/core/hooks/useTransactionDetails.ts +1 -1
  194. package/src/react/web/ui/Bridge/BridgeOrchestrator.tsx +6 -9
  195. package/src/react/web/ui/Bridge/BuyWidget.tsx +1 -1
  196. package/src/react/web/ui/Bridge/StepRunner.tsx +11 -2
  197. package/src/react/web/ui/Bridge/TransactionPayment.tsx +1 -0
  198. package/src/react/web/ui/Bridge/bridge-widget/bridge-widget.tsx +344 -0
  199. package/src/react/web/ui/Bridge/payment-details/PaymentOverview.tsx +1 -0
  200. package/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx +14 -0
  201. package/src/react/web/ui/Bridge/swap-widget/select-chain.tsx +17 -2
  202. package/src/react/web/ui/Bridge/swap-widget/select-token-ui.tsx +14 -5
  203. package/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx +6 -14
  204. package/src/react/web/ui/ConnectWallet/Modal/ConnectEmbed.tsx +3 -1
  205. package/src/script-exports/bridge-widget-script.tsx +72 -0
  206. package/src/script-exports/bridge-widget.tsx +17 -0
  207. package/src/script-exports/readme.md +72 -0
  208. package/src/stories/Bridge/BridgeOrchestrator.stories.tsx +31 -0
  209. package/src/stories/Bridge/BridgeWidget/bridge-widget-script.stories.tsx +79 -0
  210. package/src/stories/Bridge/StepRunner.stories.tsx +6 -23
  211. package/src/stories/Bridge/UnsupportedTokenScreen.stories.tsx +4 -4
  212. package/src/utils/domains.ts +1 -1
  213. package/src/utils/units.test.ts +13 -0
  214. package/src/utils/units.ts +4 -0
  215. package/src/version.ts +1 -1
  216. package/src/wallets/eip5792/send-calls.ts +1 -1
  217. package/src/wallets/smart/smart-wallet-modular.test.ts +1 -1
  218. package/src/x402/common.ts +46 -52
  219. package/src/x402/facilitator.ts +1 -0
  220. package/src/x402/fetchWithPayment.ts +3 -1
  221. package/src/x402/schemas.ts +5 -1
  222. package/src/x402/settle-payment.ts +4 -3
  223. package/src/x402/types.ts +2 -1
  224. package/src/x402/verify-payment.ts +2 -1
@@ -12,7 +12,10 @@ import {
12
12
  radius,
13
13
  spacing,
14
14
  } from "../../../core/design-system/index.js";
15
- import type { BridgePrepareRequest } from "../../../core/hooks/useBridgePrepare.js";
15
+ import type {
16
+ BridgePrepareRequest,
17
+ BridgePrepareResult,
18
+ } from "../../../core/hooks/useBridgePrepare.js";
16
19
  import {
17
20
  type CompletedStatusResult,
18
21
  useStepExecutor,
@@ -62,6 +65,11 @@ interface StepRunnerProps {
62
65
  * Called when user clicks the back button
63
66
  */
64
67
  onBack?: () => void;
68
+
69
+ /**
70
+ * Prepared quote to use
71
+ */
72
+ preparedQuote: BridgePrepareResult;
65
73
  }
66
74
 
67
75
  export function StepRunner({
@@ -74,6 +82,7 @@ export function StepRunner({
74
82
  onCancel,
75
83
  onBack,
76
84
  autoStart,
85
+ preparedQuote,
77
86
  }: StepRunnerProps) {
78
87
  const theme = useCustomTheme();
79
88
 
@@ -94,8 +103,8 @@ export function StepRunner({
94
103
  onComplete: (completedStatuses: CompletedStatusResult[]) => {
95
104
  onComplete(completedStatuses);
96
105
  },
97
- request,
98
106
  wallet,
107
+ preparedQuote,
99
108
  windowAdapter,
100
109
  });
101
110
 
@@ -89,6 +89,7 @@ export function TransactionPayment({
89
89
  client,
90
90
  transaction: uiOptions.transaction,
91
91
  wallet,
92
+ currency: uiOptions.currency,
92
93
  });
93
94
 
94
95
  // We can't use useWalletBalance here because erc20Value is a possibly async value
@@ -0,0 +1,344 @@
1
+ import { useState } from "react";
2
+ import { defineChain } from "../../../../../chains/utils.js";
3
+ import type { ThirdwebClient } from "../../../../../client/client.js";
4
+ import type { SupportedFiatCurrency } from "../../../../../pay/convert/type.js";
5
+ import type { PurchaseData } from "../../../../../pay/types.js";
6
+ import {
7
+ CustomThemeProvider,
8
+ useCustomTheme,
9
+ } from "../../../../core/design-system/CustomThemeProvider.js";
10
+ import {
11
+ fontSize,
12
+ radius,
13
+ spacing,
14
+ type Theme,
15
+ } from "../../../../core/design-system/index.js";
16
+ import { EmbedContainer } from "../../ConnectWallet/Modal/ConnectEmbed.js";
17
+ import { Container } from "../../components/basic.js";
18
+ import { Button } from "../../components/buttons.js";
19
+ import { type BuyOrOnrampPrepareResult, BuyWidget } from "../BuyWidget.js";
20
+ import { SwapWidget } from "../swap-widget/SwapWidget.js";
21
+ import type { SwapPreparedQuote } from "../swap-widget/types.js";
22
+
23
+ /**
24
+ * Props for the `BridgeWidget` component.
25
+ */
26
+ export type BridgeWidgetProps = {
27
+ /**
28
+ * A client is the entry point to the thirdweb SDK. It is required for all other actions.
29
+ * You can create a client using the `createThirdwebClient` function. Refer to the
30
+ * [Creating a Client](https://portal.thirdweb.com/typescript/v5/client) documentation for more information.
31
+ *
32
+ * You must provide a `clientId` or `secretKey` in order to initialize a client. Pass `clientId` for client-side usage and `secretKey` for server-side usage.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { createThirdwebClient } from "thirdweb";
37
+ *
38
+ * const client = createThirdwebClient({
39
+ * clientId: "<your_client_id>",
40
+ * });
41
+ * ```
42
+ */
43
+ client: ThirdwebClient;
44
+
45
+ /**
46
+ * Set the theme for the widget. By default it is set to `"dark"`.
47
+ *
48
+ * Theme can be set to either `"dark"`, `"light"` or a custom theme object.
49
+ * You can also import [`lightTheme`](https://portal.thirdweb.com/references/typescript/v5/lightTheme)
50
+ * or [`darkTheme`](https://portal.thirdweb.com/references/typescript/v5/darkTheme) from `thirdweb/react`
51
+ * to use the default themes as base and override parts of it.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * import { lightTheme } from "thirdweb/react";
56
+ *
57
+ * const customTheme = lightTheme({
58
+ * colors: { modalBg: "red" },
59
+ * });
60
+ * ```
61
+ */
62
+ theme?: "light" | "dark" | Theme;
63
+
64
+ /**
65
+ * Whether to show thirdweb branding in the widget.
66
+ * @default true
67
+ */
68
+ showThirdwebBranding?: boolean;
69
+
70
+ /**
71
+ * The currency to use for fiat pricing in the widget.
72
+ * @default "USD"
73
+ */
74
+ currency?: SupportedFiatCurrency;
75
+
76
+ /**
77
+ * Configuration for the Swap tab. This mirrors {@link SwapWidget} options where applicable.
78
+ */
79
+ swap?: {
80
+ /** Optional class name applied to the Swap tab content container. */
81
+ className?: string;
82
+ /** Optional style overrides applied to the Swap tab content container. */
83
+ style?: React.CSSProperties;
84
+ /** Callback invoked when a swap is successful. */
85
+ onSuccess?: (quote: SwapPreparedQuote) => void;
86
+ /** Callback invoked when an error occurs during swapping. */
87
+ onError?: (error: Error, quote: SwapPreparedQuote) => void;
88
+ /** Callback invoked when the user cancels the swap. */
89
+ onCancel?: (quote: SwapPreparedQuote) => void;
90
+ /** Callback invoked when the user disconnects the active wallet. */
91
+ onDisconnect?: () => void;
92
+ /**
93
+ * Whether to persist token selections to localStorage so that revisits pre-select last used tokens.
94
+ * Prefill values take precedence over persisted selections.
95
+ * @default true
96
+ */
97
+ persistTokenSelections?: boolean;
98
+ /**
99
+ * Prefill initial buy/sell token selections. If `tokenAddress` is not provided, the native token will be used.
100
+ *
101
+ * @example
102
+ * ### Set an ERC20 token as the buy token
103
+ * ```tsx
104
+ * <BridgeWidget
105
+ * client={client}
106
+ * buy={{ amount: "0.1", chainId: 8453 }}
107
+ * swap={{
108
+ * prefill: {
109
+ * buyToken: {
110
+ * chainId: 8453,
111
+ * tokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
112
+ * },
113
+ * },
114
+ * }}
115
+ * />
116
+ * ```
117
+ *
118
+ * ### Set a native token as the sell token
119
+ * ```tsx
120
+ * <BridgeWidget
121
+ * client={client}
122
+ * buy={{ amount: "0.1", chainId: 8453 }}
123
+ * swap={{
124
+ * prefill: {
125
+ * sellToken: { chainId: 8453 },
126
+ * },
127
+ * }}
128
+ * />
129
+ * ```
130
+ */
131
+ prefill?: {
132
+ /** Buy token selection. If `tokenAddress` is omitted, the native token will be used. */
133
+ buyToken?: {
134
+ tokenAddress?: string;
135
+ chainId: number;
136
+ /** Optional human-readable amount to prefill for buy. */
137
+ amount?: string;
138
+ };
139
+ /** Sell token selection. If `tokenAddress` is omitted, the native token will be used. */
140
+ sellToken?: {
141
+ tokenAddress?: string;
142
+ chainId: number;
143
+ /** Optional human-readable amount to prefill for sell. */
144
+ amount?: string;
145
+ };
146
+ };
147
+ };
148
+
149
+ /**
150
+ * Configuration for the Buy tab. This mirrors {@link BuyWidget} options where applicable.
151
+ */
152
+ buy: {
153
+ /**
154
+ * The amount to buy (as a decimal string), e.g. "1.5" for 1.5 tokens.
155
+ */
156
+ amount: string; // TODO - make it optional
157
+ /**
158
+ * The chain the accepted token is on.
159
+ */
160
+ chainId: number; // TODO - make it optional
161
+ /**
162
+ * Address of the token to buy. Leave undefined for the native token, or use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.
163
+ */
164
+ tokenAddress?: string;
165
+ /** Custom label for the main action button. */
166
+ buttonLabel?: string;
167
+ /** Callback triggered when the user cancels the purchase. */
168
+ onCancel?: (quote: BuyOrOnrampPrepareResult | undefined) => void;
169
+ /** Callback triggered when the purchase encounters an error. */
170
+ onError?: (
171
+ error: Error,
172
+ quote: BuyOrOnrampPrepareResult | undefined,
173
+ ) => void;
174
+ /** Callback triggered when the purchase is successful. */
175
+ onSuccess?: (quote: BuyOrOnrampPrepareResult) => void;
176
+ /** Optional class name applied to the Buy tab content container. */
177
+ className?: string;
178
+ /** The user's ISO 3166 alpha-2 country code. Used to determine onramp provider support. */
179
+ country?: string;
180
+ /** Preset fiat amounts to display in the UI. Defaults to [5, 10, 20]. */
181
+ presetOptions?: [number, number, number];
182
+ /** Arbitrary data to be included in returned status and webhook events. */
183
+ purchaseData?: PurchaseData;
184
+ };
185
+ };
186
+
187
+ /**
188
+ * A combined widget for swapping or buying tokens with cross-chain support.
189
+ *
190
+ * This component renders two tabs – "Swap" and "Buy" – and orchestrates the appropriate flow
191
+ * by composing {@link SwapWidget} and {@link BuyWidget} under the hood.
192
+ *
193
+ * - The Swap tab enables token-to-token swaps (including cross-chain).
194
+ * - The Buy tab enables purchasing a specific token; by default, it uses card onramp in this widget.
195
+ *
196
+ * @param props - Props of type {@link BridgeWidgetProps} to configure the BridgeWidget component.
197
+ *
198
+ * @example
199
+ * ### Basic usage
200
+ * ```tsx
201
+ * <BridgeWidget
202
+ * client={client}
203
+ * currency="USD"
204
+ * theme="dark"
205
+ * showThirdwebBranding
206
+ * buy={{
207
+ * // Buy 0.1 native tokens on Base
208
+ * amount: "0.1",
209
+ * chainId: 8453,
210
+ * }}
211
+ * />
212
+ * ```
213
+ *
214
+ * ### Prefill swap tokens and configure buy
215
+ * ```tsx
216
+ * <BridgeWidget
217
+ * client={client}
218
+ * swap={{
219
+ * prefill: {
220
+ * buyToken: {
221
+ * // Base USDC
222
+ * chainId: 8453,
223
+ * tokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
224
+ * },
225
+ * sellToken: {
226
+ * // Polygon native token (MATIC)
227
+ * chainId: 137,
228
+ * },
229
+ * },
230
+ * }}
231
+ * buy={{
232
+ * amount: "100",
233
+ * chainId: 8453,
234
+ * tokenAddress: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
235
+ * buttonLabel: "Buy USDC",
236
+ * }}
237
+ * />
238
+ * ```
239
+ *
240
+ * @bridge
241
+ */
242
+ export function BridgeWidget(props: BridgeWidgetProps) {
243
+ const [tab, setTab] = useState<"swap" | "buy">("swap");
244
+
245
+ return (
246
+ <CustomThemeProvider theme={props.theme}>
247
+ <EmbedContainer
248
+ modalSize="compact"
249
+ style={{
250
+ borderRadius: radius.xl,
251
+ }}
252
+ >
253
+ <Container
254
+ px="md"
255
+ py="md"
256
+ flex="row"
257
+ gap="xs"
258
+ borderColor="borderColor"
259
+ style={{
260
+ borderBottomWidth: 1,
261
+ borderBottomStyle: "dashed",
262
+ }}
263
+ >
264
+ <TabButton isActive={tab === "swap"} onClick={() => setTab("swap")}>
265
+ Swap
266
+ </TabButton>
267
+ <TabButton isActive={tab === "buy"} onClick={() => setTab("buy")}>
268
+ Buy
269
+ </TabButton>
270
+ </Container>
271
+
272
+ {tab === "swap" && (
273
+ <SwapWidget
274
+ client={props.client}
275
+ prefill={props.swap?.prefill}
276
+ className={props.swap?.className}
277
+ showThirdwebBranding={props.showThirdwebBranding}
278
+ currency={props.currency}
279
+ theme={props.theme}
280
+ onSuccess={props.swap?.onSuccess}
281
+ onError={props.swap?.onError}
282
+ onCancel={props.swap?.onCancel}
283
+ onDisconnect={props.swap?.onDisconnect}
284
+ persistTokenSelections={props.swap?.persistTokenSelections}
285
+ style={{
286
+ border: "none",
287
+ ...props.swap?.style,
288
+ }}
289
+ />
290
+ )}
291
+ {tab === "buy" && (
292
+ <BuyWidget
293
+ client={props.client}
294
+ amount={props.buy.amount}
295
+ showThirdwebBranding={props.showThirdwebBranding}
296
+ chain={defineChain(props.buy.chainId)}
297
+ currency={props.currency}
298
+ theme={props.theme}
299
+ title="" // Keep it empty string to hide the title
300
+ tokenAddress={props.buy.tokenAddress as `0x${string}` | undefined}
301
+ buttonLabel={props.buy.buttonLabel}
302
+ className={props.buy.className}
303
+ country={props.buy.country}
304
+ onCancel={props.buy.onCancel}
305
+ onError={props.buy.onError}
306
+ onSuccess={props.buy.onSuccess}
307
+ presetOptions={props.buy.presetOptions}
308
+ purchaseData={props.buy.purchaseData}
309
+ paymentMethods={["card"]}
310
+ style={{
311
+ border: "none",
312
+ }}
313
+ />
314
+ )}
315
+ </EmbedContainer>
316
+ </CustomThemeProvider>
317
+ );
318
+ }
319
+
320
+ function TabButton(props: {
321
+ isActive: boolean;
322
+ onClick: () => void;
323
+ children: React.ReactNode;
324
+ }) {
325
+ const theme = useCustomTheme();
326
+ return (
327
+ <Button
328
+ variant="secondary"
329
+ onClick={props.onClick}
330
+ style={{
331
+ borderRadius: radius.full,
332
+ fontSize: fontSize.sm,
333
+ fontWeight: 500,
334
+ paddingInline: spacing["md+"],
335
+ paddingBlock: spacing.sm,
336
+ border: `1px solid ${
337
+ props.isActive ? theme.colors.secondaryText : theme.colors.borderColor
338
+ }`,
339
+ }}
340
+ >
341
+ {props.children}
342
+ </Button>
343
+ );
344
+ }
@@ -210,6 +210,7 @@ const TransactionOverViewCompact = (props: {
210
210
  client: props.client,
211
211
  transaction: props.uiOptions.transaction,
212
212
  wallet: props.paymentMethod.payerWallet,
213
+ currency: props.uiOptions.currency,
213
214
  });
214
215
 
215
216
  if (!txInfo.data) {
@@ -1,6 +1,8 @@
1
1
  "use client";
2
2
 
3
+ import { useQuery } from "@tanstack/react-query";
3
4
  import { useCallback, useEffect, useState } from "react";
5
+ import { trackPayEvent } from "../../../../../analytics/track/pay.js";
4
6
  import type { Buy, Sell } from "../../../../../bridge/index.js";
5
7
  import type { TokenWithPrices } from "../../../../../bridge/types/Token.js";
6
8
  import type { ThirdwebClient } from "../../../../../client/client.js";
@@ -241,6 +243,17 @@ export type SwapWidgetProps = {
241
243
  * @bridge
242
244
  */
243
245
  export function SwapWidget(props: SwapWidgetProps) {
246
+ useQuery({
247
+ queryFn: () => {
248
+ trackPayEvent({
249
+ client: props.client,
250
+ event: "ub:ui:swap_widget:render",
251
+ });
252
+ return true;
253
+ },
254
+ queryKey: ["swap_widget:render"],
255
+ });
256
+
244
257
  return (
245
258
  <SwapWidgetContainer
246
259
  theme={props.theme}
@@ -435,6 +448,7 @@ function SwapWidgetContent(props: SwapWidgetProps) {
435
448
  <StepRunner
436
449
  title="Processing Swap"
437
450
  autoStart={true}
451
+ preparedQuote={screen.preparedQuote}
438
452
  client={props.client}
439
453
  onBack={() => {
440
454
  setScreen({
@@ -1,4 +1,4 @@
1
- import { useState } from "react";
1
+ import { useMemo, useState } from "react";
2
2
  import type { Chain as BridgeChain } from "../../../../../bridge/index.js";
3
3
  import type { ThirdwebClient } from "../../../../../client/client.js";
4
4
  import {
@@ -53,7 +53,22 @@ export function SelectBridgeChainUI(
53
53
  },
54
54
  ) {
55
55
  const [search, setSearch] = useState("");
56
- const filteredChains = props.chains.filter((chain) => {
56
+ const [initiallySelectedChain] = useState(props.selectedChain);
57
+
58
+ // put the initially selected chain first
59
+ const sortedChains = useMemo(() => {
60
+ if (initiallySelectedChain) {
61
+ return [
62
+ initiallySelectedChain,
63
+ ...props.chains.filter(
64
+ (chain) => chain.chainId !== initiallySelectedChain.chainId,
65
+ ),
66
+ ];
67
+ }
68
+ return props.chains;
69
+ }, [props.chains, initiallySelectedChain]);
70
+
71
+ const filteredChains = sortedChains.filter((chain) => {
57
72
  return chain.name.toLowerCase().includes(search.toLowerCase());
58
73
  });
59
74
 
@@ -37,7 +37,7 @@ import { tokenAmountFormatter } from "./utils.js";
37
37
  * @internal
38
38
  */
39
39
  type SelectTokenUIProps = {
40
- onBack: () => void;
40
+ onClose: () => void;
41
41
  client: ThirdwebClient;
42
42
  selectedToken: TokenSelection | undefined;
43
43
  setSelectedToken: (token: TokenSelection) => void;
@@ -182,6 +182,7 @@ function SelectTokenUI(
182
182
  });
183
183
  }, [otherTokens]);
184
184
 
185
+ // desktop
185
186
  if (!isMobile) {
186
187
  return (
187
188
  <Container
@@ -205,7 +206,10 @@ function SelectTokenUI(
205
206
  </LeftContainer>
206
207
  <Container flex="column" relative scrollY>
207
208
  <TokenSelectionScreen
208
- onSelectToken={props.setSelectedToken}
209
+ onSelectToken={(token) => {
210
+ props.setSelectedToken(token);
211
+ props.onClose();
212
+ }}
209
213
  isMobile={false}
210
214
  selectedToken={props.selectedToken}
211
215
  isFetching={props.isFetching}
@@ -226,7 +230,10 @@ function SelectTokenUI(
226
230
  if (screen === "select-token") {
227
231
  return (
228
232
  <TokenSelectionScreen
229
- onSelectToken={props.setSelectedToken}
233
+ onSelectToken={(token) => {
234
+ props.setSelectedToken(token);
235
+ props.onClose();
236
+ }}
230
237
  selectedToken={props.selectedToken}
231
238
  isFetching={props.isFetching}
232
239
  ownedTokens={props.ownedTokens}
@@ -581,8 +588,10 @@ function TokenSelectionScreen(props: {
581
588
  client={props.client}
582
589
  onSelect={props.onSelectToken}
583
590
  isSelected={
584
- props.selectedToken?.tokenAddress.toLowerCase() ===
585
- token.address.toLowerCase()
591
+ !!props.selectedToken &&
592
+ props.selectedToken.tokenAddress.toLowerCase() ===
593
+ token.address.toLowerCase() &&
594
+ token.chainId === props.selectedToken.chainId
586
595
  }
587
596
  />
588
597
  ))}
@@ -235,20 +235,16 @@ export function SwapUI(props: SwapUIProps) {
235
235
  {modalState.screen === "select-buy-token" && (
236
236
  <SelectToken
237
237
  activeWalletInfo={props.activeWalletInfo}
238
- onBack={() =>
238
+ onClose={() => {
239
239
  setModalState((v) => ({
240
240
  ...v,
241
241
  isOpen: false,
242
- }))
243
- }
242
+ }));
243
+ }}
244
244
  client={props.client}
245
245
  selectedToken={props.buyToken}
246
246
  setSelectedToken={(token) => {
247
247
  props.setBuyToken(token);
248
- setModalState((v) => ({
249
- ...v,
250
- isOpen: false,
251
- }));
252
248
  // if buy token is same as sell token, unset sell token
253
249
  if (
254
250
  props.sellToken &&
@@ -264,20 +260,16 @@ export function SwapUI(props: SwapUIProps) {
264
260
 
265
261
  {modalState.screen === "select-sell-token" && (
266
262
  <SelectToken
267
- onBack={() =>
263
+ onClose={() => {
268
264
  setModalState((v) => ({
269
265
  ...v,
270
266
  isOpen: false,
271
- }))
272
- }
267
+ }));
268
+ }}
273
269
  client={props.client}
274
270
  selectedToken={props.sellToken}
275
271
  setSelectedToken={(token) => {
276
272
  props.setSellToken(token);
277
- setModalState((v) => ({
278
- ...v,
279
- isOpen: false,
280
- }));
281
273
  // if sell token is same as buy token, unset buy token
282
274
  if (
283
275
  props.buyToken &&
@@ -479,6 +479,8 @@ export const EmbedContainer = /* @__PURE__ */ StyledDiv<{
479
479
  lineHeight: "normal",
480
480
  overflow: "hidden",
481
481
  position: "relative",
482
- width: modalSize === "compact" ? modalMaxWidthCompact : modalMaxWidthWide,
482
+ width: "100vw",
483
+ maxWidth:
484
+ modalSize === "compact" ? modalMaxWidthCompact : modalMaxWidthWide,
483
485
  };
484
486
  });
@@ -0,0 +1,72 @@
1
+ import { createThirdwebClient } from "../client/client.js";
2
+ import type { SupportedFiatCurrency } from "../pay/convert/type.js";
3
+ import type { PurchaseData } from "../pay/types.js";
4
+ import {
5
+ darkTheme,
6
+ lightTheme,
7
+ type Theme,
8
+ type ThemeOverrides,
9
+ } from "../react/core/design-system/index.js";
10
+ import type { BuyOrOnrampPrepareResult } from "../react/web/ui/Bridge/BuyWidget.js";
11
+ import { BridgeWidget } from "../react/web/ui/Bridge/bridge-widget/bridge-widget.js";
12
+ import type { SwapPreparedQuote } from "../react/web/ui/Bridge/swap-widget/types.js";
13
+
14
+ // Note: do not use SwapWidgetProps or BuyWidgetProps references here to keep the output for bridge-widget.d.ts as simple as possible
15
+ // Note: these props will be configured buy user in a <script> tag, so they need to be as simple as possible and can not rely on utils like `darkTheme`, `createThirdwebClient` etc..
16
+ // For example, instead of having for a `Chain` prop, use `chainId` instead
17
+
18
+ export type BridgeWidgetScriptProps = {
19
+ clientId: string;
20
+ theme?: "light" | "dark" | ({ type: "light" | "dark" } & ThemeOverrides);
21
+ showThirdwebBranding?: boolean;
22
+ currency?: SupportedFiatCurrency;
23
+ swap?: {
24
+ className?: string;
25
+ style?: React.CSSProperties;
26
+ onSuccess?: (quote: SwapPreparedQuote) => void;
27
+ onError?: (error: Error, quote: SwapPreparedQuote) => void;
28
+ onCancel?: (quote: SwapPreparedQuote) => void;
29
+ onDisconnect?: () => void;
30
+ persistTokenSelections?: boolean;
31
+ prefill?: {
32
+ buyToken?: {
33
+ tokenAddress?: string;
34
+ chainId: number;
35
+ amount?: string;
36
+ };
37
+ sellToken?: {
38
+ tokenAddress?: string;
39
+ chainId: number;
40
+ amount?: string;
41
+ };
42
+ };
43
+ };
44
+ buy: {
45
+ amount: string; // TODO - make it optional
46
+ chainId: number; // TODO - make it optional
47
+ tokenAddress?: string;
48
+ buttonLabel?: string;
49
+ onCancel?: (quote: BuyOrOnrampPrepareResult | undefined) => void;
50
+ onError?: (
51
+ error: Error,
52
+ quote: BuyOrOnrampPrepareResult | undefined,
53
+ ) => void;
54
+ onSuccess?: (quote: BuyOrOnrampPrepareResult) => void;
55
+ className?: string;
56
+ country?: string;
57
+ presetOptions?: [number, number, number];
58
+ purchaseData?: PurchaseData;
59
+ };
60
+ };
61
+
62
+ export function BridgeWidgetScript(props: BridgeWidgetScriptProps) {
63
+ const client = createThirdwebClient({ clientId: props.clientId });
64
+ const themeObj: Theme | "light" | "dark" | undefined =
65
+ typeof props.theme === "object"
66
+ ? props.theme.type === "dark"
67
+ ? darkTheme(props.theme)
68
+ : lightTheme(props.theme)
69
+ : props.theme;
70
+
71
+ return <BridgeWidget {...props} theme={themeObj} client={client} />;
72
+ }
@@ -0,0 +1,17 @@
1
+ import { type Container, createRoot } from "react-dom/client";
2
+ import { ThirdwebProvider } from "../react/web/providers/thirdweb-provider.js";
3
+ import {
4
+ BridgeWidgetScript,
5
+ type BridgeWidgetScriptProps,
6
+ } from "./bridge-widget-script.js";
7
+
8
+ // Note: This file is built as a UMD module with globalName "BridgeWidget"
9
+ // This will be available as a global function called `BridgeWidget.render`
10
+
11
+ export function render(element: Container, props: BridgeWidgetScriptProps) {
12
+ createRoot(element).render(
13
+ <ThirdwebProvider>
14
+ <BridgeWidgetScript {...props} />
15
+ </ThirdwebProvider>,
16
+ );
17
+ }