Skip to content

Commit a94f229

Browse files
committed
[MNY-204] Dashboard: Add tracking for BuyWidget, SDK: update callback types in BuyWidget (#8100)
<!-- ## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes" If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000): ## Notes for the reviewer Anything important to call out? Be sure to also clarify these in your comments. ## How to test Unit tests, playground, etc. --> <!-- start pr-codex --> --- ## PR-Codex overview This PR enhances the `BuyWidget` and related components by updating the callback props to include a `quote` object, allowing for better tracking of token buy events and improving error handling. ### Detailed summary - Updated `onSuccess`, `onError`, and `onCancel` props in `BuyWidget` to accept a `quote` object. - Enhanced error reporting with detailed information in `reportTokenBuyFailed`, `reportTokenBuyCancelled`, and `reportTokenBuySuccessful`. - Modified `BuyAndSwapEmbed` component to handle the new callback signatures. - Adjusted `BridgeOrchestrator` to utilize the `quote` object in its flow. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Buy and Bridge flows now provide quote details to success, error, and cancel callbacks. - Token-level analytics added for buy flows (success, failure, cancel). - Breaking Changes - Callback signatures changed to include quote parameters; client implementations must be updated. - Documentation - Examples updated to show new callback parameters and usage. - Chores - Standardized analytics for asset purchases where contract type may be unspecified. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 5249cb7 commit a94f229

File tree

5 files changed

+186
-53
lines changed

5 files changed

+186
-53
lines changed

.changeset/better-lines-rule.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Update the `onSuccess`, `onError`, and `onCancel` callback props of the `BuyWidget` to be called with the `quote` object
6+
7+
```tsx
8+
<BuyWidget
9+
onSuccess={(quote) => console.log("Swap completed:", quote)}
10+
onError={(error, quote) => console.error("Swap failed:", error, quote)}
11+
onCancel={(quote) => console.log("Swap cancelled:", quote)}
12+
/>
13+
```

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

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ type AssetContractType =
225225
*/
226226
export function reportAssetBuySuccessful(properties: {
227227
chainId: number;
228-
contractType: AssetContractType;
228+
contractType: AssetContractType | undefined;
229229
assetType: "nft" | "coin";
230230
}) {
231231
posthog.capture("asset buy successful", {
@@ -243,9 +243,51 @@ type TokenSwapParams = {
243243
pageType: "asset" | "bridge" | "chain";
244244
};
245245

246+
type TokenBuyParams = {
247+
buyTokenChainId: number | undefined;
248+
buyTokenAddress: string | undefined;
249+
pageType: "asset" | "bridge" | "chain";
250+
};
251+
252+
/**
253+
* ### Why do we need to report this event?
254+
* - To track number of successful token buys
255+
* - To track which tokens are being bought the most
256+
*
257+
* ### Who is responsible for this event?
258+
* @MananTank
259+
*/
260+
export function reportTokenBuySuccessful(properties: TokenBuyParams) {
261+
posthog.capture("token buy successful", properties);
262+
}
263+
264+
/**
265+
* ### Why do we need to report this event?
266+
* - To track number of failed token buys
267+
* - To track which token buys are failing
268+
*
269+
* ### Who is responsible for this event?
270+
* @MananTank
271+
*/
272+
export function reportTokenBuyFailed(properties: TokenBuyParams) {
273+
posthog.capture("token buy failed", properties);
274+
}
275+
246276
/**
247277
* ### Why do we need to report this event?
248-
* - To track number of successful token swaps from the token page
278+
* - To track number of cancelled token buys
279+
* - To track which token buys are being cancelled
280+
*
281+
* ### Who is responsible for this event?
282+
* @MananTank
283+
*/
284+
export function reportTokenBuyCancelled(properties: TokenBuyParams) {
285+
posthog.capture("token buy cancelled", properties);
286+
}
287+
288+
/**
289+
* ### Why do we need to report this event?
290+
* - To track number of successful token swaps
249291
* - To track which tokens are being swapped the most
250292
*
251293
* ### Who is responsible for this event?
@@ -271,7 +313,7 @@ export function reportSwapWidgetShown(properties: {
271313

272314
/**
273315
* ### Why do we need to report this event?
274-
* - To track number of failed token swaps from the token page
316+
* - To track number of failed token swaps
275317
* - To track which tokens are being swapped the most
276318
*
277319
* ### Who is responsible for this event?
@@ -287,7 +329,7 @@ export function reportTokenSwapFailed(
287329

288330
/**
289331
* ### Why do we need to report this event?
290-
* - To track number of cancelled token swaps from the token page
332+
* - To track number of cancelled token swaps
291333
* - To track which tokens are being swapped the most
292334
*
293335
* ### Who is responsible for this event?
@@ -299,15 +341,15 @@ export function reportTokenSwapCancelled(properties: TokenSwapParams) {
299341

300342
/**
301343
* ### Why do we need to report this event?
302-
* - To track number of failed asset purchases from the token page
344+
* - To track number of failed asset purchases
303345
* - To track the errors that users encounter when trying to purchase an asset
304346
*
305347
* ### Who is responsible for this event?
306348
* @MananTank
307349
*/
308350
export function reportAssetBuyFailed(properties: {
309351
chainId: number;
310-
contractType: AssetContractType;
352+
contractType: AssetContractType | undefined;
311353
assetType: "nft" | "coin";
312354
error: string;
313355
}) {
@@ -329,7 +371,7 @@ export function reportAssetBuyFailed(properties: {
329371
*/
330372
export function reportAssetBuyCancelled(properties: {
331373
chainId: number;
332-
contractType: AssetContractType;
374+
contractType: AssetContractType | undefined;
333375
assetType: "nft" | "coin";
334376
}) {
335377
posthog.capture("asset buy cancelled", {

apps/dashboard/src/@/components/blocks/BuyAndSwapEmbed.tsx

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import {
99
reportAssetBuyFailed,
1010
reportAssetBuySuccessful,
1111
reportSwapWidgetShown,
12+
reportTokenBuyCancelled,
13+
reportTokenBuyFailed,
14+
reportTokenBuySuccessful,
1215
reportTokenSwapCancelled,
1316
reportTokenSwapFailed,
1417
reportTokenSwapSuccessful,
@@ -66,32 +69,81 @@ export function BuyAndSwapEmbed(props: {
6669
connectOptions={{
6770
autoConnect: false,
6871
}}
69-
onError={(e) => {
72+
onError={(e, quote) => {
7073
const errorMessage = parseError(e);
74+
75+
reportTokenBuyFailed({
76+
buyTokenChainId:
77+
quote?.type === "buy"
78+
? quote.intent.destinationChainId
79+
: quote?.type === "onramp"
80+
? quote.intent.chainId
81+
: undefined,
82+
buyTokenAddress:
83+
quote?.type === "buy"
84+
? quote.intent.destinationTokenAddress
85+
: quote?.type === "onramp"
86+
? quote.intent.tokenAddress
87+
: undefined,
88+
pageType: props.pageType,
89+
});
90+
7191
if (props.pageType === "asset") {
7292
reportAssetBuyFailed({
7393
assetType: "coin",
7494
chainId: props.chain.id,
75-
contractType: "DropERC20",
7695
error: errorMessage,
96+
contractType: undefined,
7797
});
7898
}
7999
}}
80-
onCancel={() => {
100+
onCancel={(quote) => {
101+
reportTokenBuyCancelled({
102+
buyTokenChainId:
103+
quote?.type === "buy"
104+
? quote.intent.destinationChainId
105+
: quote?.type === "onramp"
106+
? quote.intent.chainId
107+
: undefined,
108+
buyTokenAddress:
109+
quote?.type === "buy"
110+
? quote.intent.destinationTokenAddress
111+
: quote?.type === "onramp"
112+
? quote.intent.tokenAddress
113+
: undefined,
114+
pageType: props.pageType,
115+
});
116+
81117
if (props.pageType === "asset") {
82118
reportAssetBuyCancelled({
83119
assetType: "coin",
84120
chainId: props.chain.id,
85-
contractType: "DropERC20",
121+
contractType: undefined,
86122
});
87123
}
88124
}}
89-
onSuccess={() => {
125+
onSuccess={(quote) => {
126+
reportTokenBuySuccessful({
127+
buyTokenChainId:
128+
quote.type === "buy"
129+
? quote.intent.destinationChainId
130+
: quote.type === "onramp"
131+
? quote.intent.chainId
132+
: undefined,
133+
buyTokenAddress:
134+
quote.type === "buy"
135+
? quote.intent.destinationTokenAddress
136+
: quote.type === "onramp"
137+
? quote.intent.tokenAddress
138+
: undefined,
139+
pageType: props.pageType,
140+
});
141+
90142
if (props.pageType === "asset") {
91143
reportAssetBuySuccessful({
92144
assetType: "coin",
93145
chainId: props.chain.id,
94-
contractType: "DropERC20",
146+
contractType: undefined,
95147
});
96148
}
97149
}}

packages/thirdweb/src/react/web/ui/Bridge/BridgeOrchestrator.tsx

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,17 @@ export interface BridgeOrchestratorProps {
8282
/**
8383
* Called when the flow is completed successfully
8484
*/
85-
onComplete: () => void;
85+
onComplete: (quote: BridgePrepareResult) => void;
8686

8787
/**
8888
* Called when the flow encounters an error
8989
*/
90-
onError: (error: Error) => void;
90+
onError: (error: Error, quote: BridgePrepareResult | undefined) => void;
9191

9292
/**
9393
* Called when the user cancels the flow
9494
*/
95-
onCancel: () => void;
95+
onCancel: (quote: BridgePrepareResult | undefined) => void;
9696

9797
/**
9898
* Connect options for wallet connection
@@ -189,19 +189,22 @@ export function BridgeOrchestrator({
189189
}, [send, uiOptions.mode]);
190190

191191
// Handle post-buy transaction completion
192-
const handlePostBuyTransactionComplete = useCallback(() => {
193-
onComplete?.();
194-
send({ type: "RESET" });
195-
}, [onComplete, send]);
192+
const handlePostBuyTransactionComplete = useCallback(
193+
(quote: BridgePrepareResult) => {
194+
onComplete?.(quote);
195+
send({ type: "RESET" });
196+
},
197+
[onComplete, send],
198+
);
196199

197200
// Handle errors
198201
const handleError = useCallback(
199202
(error: Error) => {
200203
console.error(error);
201-
onError?.(error);
204+
onError?.(error, state.context.quote);
202205
send({ error, type: "ERROR_OCCURRED" });
203206
},
204-
[onError, send],
207+
[onError, send, state.context.quote],
205208
);
206209

207210
// Handle payment method selection
@@ -227,10 +230,13 @@ export function BridgeOrchestrator({
227230

228231
// Handle execution complete
229232
const handleExecutionComplete = useCallback(
230-
(completedStatuses: CompletedStatusResult[]) => {
233+
(
234+
completedStatuses: CompletedStatusResult[],
235+
quote: BridgePrepareResult,
236+
) => {
231237
send({ completedStatuses, type: "EXECUTION_COMPLETE" });
232238
if (uiOptions.mode !== "transaction") {
233-
onComplete?.();
239+
onComplete?.(quote);
234240
}
235241
},
236242
[send, onComplete, uiOptions.mode],
@@ -241,6 +247,8 @@ export function BridgeOrchestrator({
241247
send({ type: "RETRY" });
242248
}, [send]);
243249

250+
const quote = state.context.quote;
251+
244252
// Handle requirements resolved from FundWallet and DirectPayment
245253
const handleRequirementsResolved = useCallback(
246254
(amount: string, token: TokenWithPrices, receiverAddress: Address) => {
@@ -263,7 +271,7 @@ export function BridgeOrchestrator({
263271
error={state.context.currentError}
264272
onCancel={() => {
265273
send({ type: "RESET" });
266-
onCancel?.();
274+
onCancel?.(quote);
267275
}}
268276
onRetry={handleRetry}
269277
/>
@@ -369,31 +377,33 @@ export function BridgeOrchestrator({
369377
/>
370378
)}
371379

372-
{state.value === "execute" &&
373-
state.context.quote &&
374-
state.context.request && (
375-
<StepRunner
376-
autoStart={true}
377-
client={client}
378-
onBack={() => {
379-
send({ type: "BACK" });
380-
}}
381-
onCancel={onCancel}
382-
onComplete={handleExecutionComplete}
383-
request={state.context.request}
384-
wallet={state.context.selectedPaymentMethod?.payerWallet}
385-
windowAdapter={webWindowAdapter}
386-
/>
387-
)}
380+
{state.value === "execute" && quote && state.context.request && (
381+
<StepRunner
382+
autoStart={true}
383+
client={client}
384+
onBack={() => {
385+
send({ type: "BACK" });
386+
}}
387+
onCancel={() => {
388+
onCancel(quote);
389+
}}
390+
onComplete={(completedStatuses) => {
391+
handleExecutionComplete(completedStatuses, quote);
392+
}}
393+
request={state.context.request}
394+
wallet={state.context.selectedPaymentMethod?.payerWallet}
395+
windowAdapter={webWindowAdapter}
396+
/>
397+
)}
388398

389399
{state.value === "success" &&
390-
state.context.quote &&
400+
quote &&
391401
state.context.completedStatuses && (
392402
<SuccessScreen
393403
client={client}
394404
completedStatuses={state.context.completedStatuses}
395405
onDone={handleDoneOrContinueClick}
396-
preparedQuote={state.context.quote}
406+
preparedQuote={quote}
397407
uiOptions={uiOptions}
398408
windowAdapter={webWindowAdapter}
399409
hasPaymentId={!!paymentLinkId}
@@ -402,9 +412,10 @@ export function BridgeOrchestrator({
402412

403413
{state.value === "post-buy-transaction" &&
404414
uiOptions.mode === "transaction" &&
415+
quote &&
405416
uiOptions.transaction && (
406417
<ExecutingTxScreen
407-
closeModal={handlePostBuyTransactionComplete}
418+
closeModal={() => handlePostBuyTransactionComplete(quote)}
408419
onTxSent={() => {
409420
// Do nothing
410421
}}

0 commit comments

Comments
 (0)