Skip to content

Commit 0d2d39d

Browse files
committed
pass quote to callbacks, add events
1 parent 33fa31a commit 0d2d39d

File tree

5 files changed

+151
-69
lines changed

5 files changed

+151
-69
lines changed

apps/dashboard/src/@/analytics/report.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,53 @@ export function reportAssetBuySuccessful(properties: {
250250
});
251251
}
252252

253+
type TokenSwapParams = {
254+
buyTokenChainId: number;
255+
buyTokenAddress: string;
256+
sellTokenChainId: number;
257+
sellTokenAddress: string;
258+
};
259+
260+
/**
261+
* ### Why do we need to report this event?
262+
* - To track number of successful token swaps from the token page
263+
* - To track which tokens are being swapped the most
264+
*
265+
* ### Who is responsible for this event?
266+
* @MananTank
267+
*/
268+
export function reportTokenSwapSuccessful(properties: TokenSwapParams) {
269+
posthog.capture("token swap successful", properties);
270+
}
271+
272+
/**
273+
* ### Why do we need to report this event?
274+
* - To track number of failed token swaps from the token page
275+
* - To track which tokens are being swapped the most
276+
*
277+
* ### Who is responsible for this event?
278+
* @MananTank
279+
*/
280+
export function reportTokenSwapFailed(
281+
properties: TokenSwapParams & {
282+
errorMessage: string;
283+
},
284+
) {
285+
posthog.capture("token swap failed", properties);
286+
}
287+
288+
/**
289+
* ### Why do we need to report this event?
290+
* - To track number of cancelled token swaps from the token page
291+
* - To track which tokens are being swapped the most
292+
*
293+
* ### Who is responsible for this event?
294+
* @MananTank
295+
*/
296+
export function reportTokenSwapCancelled(properties: TokenSwapParams) {
297+
posthog.capture("token swap cancelled", properties);
298+
}
299+
253300
/**
254301
* ### Why do we need to report this event?
255302
* - To track number of failed asset purchases from the token page

apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/PayEmbedSection.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import { BuyWidget, SwapWidget } from "thirdweb/react";
77
import {
88
reportAssetBuyFailed,
99
reportAssetBuySuccessful,
10+
reportTokenSwapCancelled,
11+
reportTokenSwapFailed,
12+
reportTokenSwapSuccessful,
1013
} from "@/analytics/report";
1114
import { Button } from "@/components/ui/button";
1215
import { cn } from "@/lib/utils";
@@ -82,6 +85,31 @@ export function BuyTokenEmbed(props: {
8285
chainId: props.chain.id,
8386
},
8487
}}
88+
onError={(error, quote) => {
89+
reportTokenSwapFailed({
90+
errorMessage: error.message,
91+
buyTokenChainId: quote.intent.destinationChainId,
92+
buyTokenAddress: quote.intent.destinationTokenAddress,
93+
sellTokenChainId: quote.intent.originChainId,
94+
sellTokenAddress: quote.intent.originTokenAddress,
95+
});
96+
}}
97+
onSuccess={(quote) => {
98+
reportTokenSwapSuccessful({
99+
buyTokenChainId: quote.intent.destinationChainId,
100+
buyTokenAddress: quote.intent.destinationTokenAddress,
101+
sellTokenChainId: quote.intent.originChainId,
102+
sellTokenAddress: quote.intent.originTokenAddress,
103+
});
104+
}}
105+
onCancel={(quote) => {
106+
reportTokenSwapCancelled({
107+
buyTokenChainId: quote.intent.destinationChainId,
108+
buyTokenAddress: quote.intent.destinationTokenAddress,
109+
sellTokenChainId: quote.intent.originChainId,
110+
sellTokenAddress: quote.intent.originTokenAddress,
111+
});
112+
}}
85113
/>
86114
)}
87115
</div>

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/SwapWidget.tsx

Lines changed: 65 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ import type { SupportedFiatCurrency } from "../../../../../pay/convert/type.js";
99
import { getAddress } from "../../../../../utils/address.js";
1010
import { CustomThemeProvider } from "../../../../core/design-system/CustomThemeProvider.js";
1111
import type { Theme } from "../../../../core/design-system/index.js";
12-
import type {
13-
BridgePrepareRequest,
14-
BridgePrepareResult,
15-
} from "../../../../core/hooks/useBridgePrepare.js";
12+
import type { BridgePrepareRequest } from "../../../../core/hooks/useBridgePrepare.js";
1613
import type { CompletedStatusResult } from "../../../../core/hooks/useStepExecutor.js";
1714
import { webWindowAdapter } from "../../../adapters/WindowAdapter.js";
1815
import { EmbedContainer } from "../../ConnectWallet/Modal/ConnectEmbed.js";
@@ -24,7 +21,11 @@ import { StepRunner } from "../StepRunner.js";
2421
import { useActiveWalletInfo } from "./hooks.js";
2522
import { getLastUsedTokens, setLastUsedTokens } from "./storage.js";
2623
import { SwapUI } from "./swap-ui.js";
27-
import type { SwapWidgetConnectOptions, TokenSelection } from "./types.js";
24+
import type {
25+
SwapPreparedQuote,
26+
SwapWidgetConnectOptions,
27+
TokenSelection,
28+
} from "./types.js";
2829
import { useBridgeChains } from "./use-bridge-chains.js";
2930

3031
export type SwapWidgetProps = {
@@ -44,54 +45,6 @@ export type SwapWidgetProps = {
4445
* ```
4546
*/
4647
client: ThirdwebClient;
47-
/**
48-
* Set the theme for the `SwapWidget` component. By default it is set to `"dark"`
49-
*
50-
* theme can be set to either `"dark"`, `"light"` or a custom theme object.
51-
* You can also import [`lightTheme`](https://portal.thirdweb.com/references/typescript/v5/lightTheme)
52-
* or [`darkTheme`](https://portal.thirdweb.com/references/typescript/v5/darkTheme)
53-
* functions from `thirdweb/react` to use the default themes as base and overrides parts of it.
54-
* @example
55-
* ```ts
56-
* import { lightTheme } from "thirdweb/react";
57-
*
58-
* const customTheme = lightTheme({
59-
* colors: {
60-
* modalBg: 'red'
61-
* }
62-
* })
63-
*
64-
* function Example() {
65-
* return <SwapWidget client={client} theme={customTheme} />
66-
* }
67-
* ```
68-
*/
69-
theme?: "light" | "dark" | Theme;
70-
className?: string;
71-
/**
72-
* The currency to use for the payment.
73-
* @default "USD"
74-
*/
75-
currency?: SupportedFiatCurrency;
76-
style?: React.CSSProperties;
77-
/**
78-
* Whether to show thirdweb branding in the widget.
79-
* @default true
80-
*/
81-
showThirdwebBranding?: boolean;
82-
/**
83-
* Callback to be called when the swap is successful.
84-
*/
85-
onSuccess?: () => void;
86-
/**
87-
* Callback to be called when user encounters an error when swapping.
88-
*/
89-
onError?: (error: Error) => void;
90-
/**
91-
* Callback to be called when the user cancels the purchase.
92-
*/
93-
onCancel?: () => void;
94-
connectOptions?: SwapWidgetConnectOptions;
9548
/**
9649
* The prefill Buy and/or Sell tokens for the swap widget. If `tokenAddress` is not provided, the native token will be used
9750
*
@@ -153,6 +106,54 @@ export type SwapWidgetProps = {
153106
amount?: string;
154107
};
155108
};
109+
/**
110+
* Set the theme for the `SwapWidget` component. By default it is set to `"dark"`
111+
*
112+
* theme can be set to either `"dark"`, `"light"` or a custom theme object.
113+
* You can also import [`lightTheme`](https://portal.thirdweb.com/references/typescript/v5/lightTheme)
114+
* or [`darkTheme`](https://portal.thirdweb.com/references/typescript/v5/darkTheme)
115+
* functions from `thirdweb/react` to use the default themes as base and overrides parts of it.
116+
* @example
117+
* ```ts
118+
* import { lightTheme } from "thirdweb/react";
119+
*
120+
* const customTheme = lightTheme({
121+
* colors: {
122+
* modalBg: 'red'
123+
* }
124+
* })
125+
*
126+
* function Example() {
127+
* return <SwapWidget client={client} theme={customTheme} />
128+
* }
129+
* ```
130+
*/
131+
theme?: "light" | "dark" | Theme;
132+
/**
133+
* The currency to use for the payment.
134+
* @default "USD"
135+
*/
136+
currency?: SupportedFiatCurrency;
137+
connectOptions?: SwapWidgetConnectOptions;
138+
/**
139+
* Whether to show thirdweb branding in the widget.
140+
* @default true
141+
*/
142+
showThirdwebBranding?: boolean;
143+
/**
144+
* Callback to be called when the swap is successful.
145+
*/
146+
onSuccess?: (quote: SwapPreparedQuote) => void;
147+
/**
148+
* Callback to be called when user encounters an error when swapping.
149+
*/
150+
onError?: (error: Error, quote: SwapPreparedQuote) => void;
151+
/**
152+
* Callback to be called when the user cancels the purchase.
153+
*/
154+
onCancel?: (quote: SwapPreparedQuote) => void;
155+
style?: React.CSSProperties;
156+
className?: string;
156157
};
157158

158159
/**
@@ -274,7 +275,7 @@ type SwapWidgetScreen =
274275
}
275276
| {
276277
id: "2:preview";
277-
preparedQuote: Extract<BridgePrepareResult, { type: "buy" | "sell" }>;
278+
preparedQuote: SwapPreparedQuote;
278279
request: BridgePrepareRequest;
279280
quote: Buy.quote.Result | Sell.quote.Result;
280281
buyToken: TokenWithPrices;
@@ -286,7 +287,7 @@ type SwapWidgetScreen =
286287
id: "3:execute";
287288
request: BridgePrepareRequest;
288289
quote: Buy.quote.Result | Sell.quote.Result;
289-
preparedQuote: Extract<BridgePrepareResult, { type: "buy" | "sell" }>;
290+
preparedQuote: SwapPreparedQuote;
290291
buyToken: TokenWithPrices;
291292
sellToken: TokenWithPrices;
292293
sellTokenBalance: bigint;
@@ -295,12 +296,13 @@ type SwapWidgetScreen =
295296
| {
296297
id: "4:success";
297298
completedStatuses: CompletedStatusResult[];
298-
preparedQuote: Extract<BridgePrepareResult, { type: "buy" | "sell" }>;
299+
preparedQuote: SwapPreparedQuote;
299300
buyToken: TokenWithPrices;
300301
sellToken: TokenWithPrices;
301302
}
302303
| {
303304
id: "error";
305+
preparedQuote: SwapPreparedQuote;
304306
error: Error;
305307
};
306308

@@ -377,11 +379,12 @@ function SwapWidgetContent(props: SwapWidgetProps) {
377379
useBridgeChains(props.client);
378380

379381
const handleError = useCallback(
380-
(error: Error) => {
382+
(error: Error, quote: SwapPreparedQuote) => {
381383
console.error(error);
382-
props.onError?.(error);
384+
props.onError?.(error, quote);
383385
setScreen({
384386
id: "error",
387+
preparedQuote: quote,
385388
error,
386389
});
387390
},
@@ -439,7 +442,7 @@ function SwapWidgetContent(props: SwapWidgetProps) {
439442
id: "3:execute",
440443
});
441444
}}
442-
onError={handleError}
445+
onError={(error) => handleError(error, screen.preparedQuote)}
443446
paymentMethod={{
444447
quote: screen.quote,
445448
type: "wallet",
@@ -471,9 +474,9 @@ function SwapWidgetContent(props: SwapWidgetProps) {
471474
sellTokenBalance: screen.sellTokenBalance,
472475
});
473476
}}
474-
onCancel={props.onCancel}
477+
onCancel={() => props.onCancel?.(screen.preparedQuote)}
475478
onComplete={(completedStatuses) => {
476-
props.onSuccess?.();
479+
props.onSuccess?.(screen.preparedQuote);
477480
setScreen({
478481
...screen,
479482
id: "4:success",
@@ -519,7 +522,7 @@ function SwapWidgetContent(props: SwapWidgetProps) {
519522
error={screen.error}
520523
onCancel={() => {
521524
setScreen({ id: "1:swap-ui" });
522-
props.onCancel?.();
525+
props.onCancel?.(screen.preparedQuote);
523526
}}
524527
onRetry={() => {
525528
setScreen({ id: "1:swap-ui" });

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/swap-ui.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@ import {
3030
type Theme,
3131
} from "../../../../core/design-system/index.js";
3232
import { useWalletBalance } from "../../../../core/hooks/others/useWalletBalance.js";
33-
import type {
34-
BridgePrepareRequest,
35-
BridgePrepareResult,
36-
} from "../../../../core/hooks/useBridgePrepare.js";
33+
import type { BridgePrepareRequest } from "../../../../core/hooks/useBridgePrepare.js";
3734
import { ConnectButton } from "../../ConnectWallet/ConnectButton.js";
3835
import { ArrowUpDownIcon } from "../../ConnectWallet/icons/ArrowUpDownIcon.js";
3936
import { WalletDotIcon } from "../../ConnectWallet/icons/WalletDotIcon.js";
@@ -51,6 +48,7 @@ import { DecimalRenderer } from "./common.js";
5148
import { SelectToken } from "./select-token-ui.js";
5249
import type {
5350
ActiveWalletInfo,
51+
SwapPreparedQuote,
5452
SwapWidgetConnectOptions,
5553
TokenSelection,
5654
} from "./types.js";
@@ -65,8 +63,8 @@ type SwapUIProps = {
6563
currency: SupportedFiatCurrency;
6664
showThirdwebBranding: boolean;
6765
onSwap: (data: {
68-
result: Extract<BridgePrepareResult, { type: "buy" | "sell" }>;
69-
request: Extract<BridgePrepareRequest, { type: "buy" | "sell" }>;
66+
result: SwapPreparedQuote;
67+
request: BridgePrepareRequest;
7068
buyToken: TokenWithPrices;
7169
sellTokenBalance: bigint;
7270
sellToken: TokenWithPrices;
@@ -439,7 +437,7 @@ function useSwapQuote(params: {
439437
queryFn: async (): Promise<
440438
| {
441439
type: "preparedResult";
442-
result: Extract<BridgePrepareResult, { type: "buy" | "sell" }>;
440+
result: SwapPreparedQuote;
443441
request: Extract<BridgePrepareRequest, { type: "buy" | "sell" }>;
444442
}
445443
| {

packages/thirdweb/src/react/web/ui/Bridge/swap-widget/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { SmartWalletOptions } from "../../../../../wallets/smart/types.js";
77
import type { AppMetadata } from "../../../../../wallets/types.js";
88
import type { SiweAuthOptions } from "../../../../core/hooks/auth/useSiweAuth.js";
99
import type { ConnectButton_connectModalOptions } from "../../../../core/hooks/connection/ConnectButtonProps.js";
10+
import type { BridgePrepareResult } from "../../../../core/hooks/useBridgePrepare.js";
1011

1112
/**
1213
* Connection options for the `SwapWidget` component
@@ -149,3 +150,8 @@ export type TokenSelection = {
149150
tokenAddress: string;
150151
chainId: number;
151152
};
153+
154+
export type SwapPreparedQuote = Extract<
155+
BridgePrepareResult,
156+
{ type: "buy" | "sell" }
157+
>;

0 commit comments

Comments
 (0)