@rango-dev/widget-embedded 0.61.0 → 0.62.0

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 (52) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/components/ConfirmWalletsModal/ConfirmWalletsModal.d.ts.map +1 -1
  3. package/dist/components/CustomDestination/CustomDestination.d.ts.map +1 -1
  4. package/dist/components/Quote/QuoteCostDetails.d.ts.map +1 -1
  5. package/dist/components/Slippage/Slippage.d.ts.map +1 -1
  6. package/dist/components/SwapDetails/SwapDetails.d.ts.map +1 -1
  7. package/dist/containers/Settings/Lists.d.ts.map +1 -1
  8. package/dist/containers/Wallets/useUpdates.d.ts.map +1 -1
  9. package/dist/hooks/useSwapInput.d.ts.map +1 -1
  10. package/dist/hooks/useSyncNotifications/useSyncNotifications.d.ts.map +1 -1
  11. package/dist/hooks/useWalletList.d.ts.map +1 -1
  12. package/dist/index.js +2 -2
  13. package/dist/index.js.map +4 -4
  14. package/dist/pages/ConfirmSwapPage.d.ts.map +1 -1
  15. package/dist/pages/Home.d.ts.map +1 -1
  16. package/dist/pages/LiquiditySourcePage.d.ts.map +1 -1
  17. package/dist/pages/SelectBlockchainPage.d.ts.map +1 -1
  18. package/dist/pages/SelectSwapItemPage/SelectSwapItemPage.helpers.d.ts +1 -0
  19. package/dist/pages/SelectSwapItemPage/SelectSwapItemPage.helpers.d.ts.map +1 -1
  20. package/dist/pages/SelectSwapItemPage/SelectSwapItemsPage.d.ts.map +1 -1
  21. package/dist/pages/SwapDetailsPage.d.ts.map +1 -1
  22. package/dist/store/slices/wallets.d.ts +3 -1
  23. package/dist/store/slices/wallets.d.ts.map +1 -1
  24. package/dist/types/event.d.ts +160 -6
  25. package/dist/types/event.d.ts.map +1 -1
  26. package/dist/utils/eventPayloads.d.ts +8 -0
  27. package/dist/utils/eventPayloads.d.ts.map +1 -0
  28. package/dist/utils/events.d.ts +8 -5
  29. package/dist/utils/events.d.ts.map +1 -1
  30. package/dist/widget-embedded.build.json +1 -1
  31. package/package.json +2 -2
  32. package/src/components/ConfirmWalletsModal/ConfirmWalletsModal.tsx +43 -1
  33. package/src/components/CustomDestination/CustomDestination.tsx +18 -0
  34. package/src/components/Quote/QuoteCostDetails.tsx +8 -0
  35. package/src/components/Slippage/Slippage.tsx +21 -0
  36. package/src/components/SwapDetails/SwapDetails.tsx +6 -0
  37. package/src/containers/Settings/Lists.tsx +13 -1
  38. package/src/containers/Wallets/useUpdates.ts +3 -1
  39. package/src/hooks/useSwapInput.ts +37 -1
  40. package/src/hooks/useSyncNotifications/useSyncNotifications.ts +33 -1
  41. package/src/hooks/useWalletList.ts +36 -0
  42. package/src/pages/ConfirmSwapPage.tsx +12 -1
  43. package/src/pages/Home.tsx +39 -14
  44. package/src/pages/LiquiditySourcePage.tsx +28 -0
  45. package/src/pages/SelectBlockchainPage.tsx +10 -0
  46. package/src/pages/SelectSwapItemPage/SelectSwapItemPage.helpers.ts +9 -0
  47. package/src/pages/SelectSwapItemPage/SelectSwapItemsPage.tsx +30 -0
  48. package/src/pages/SwapDetailsPage.tsx +6 -0
  49. package/src/store/slices/wallets.ts +10 -4
  50. package/src/types/event.ts +189 -10
  51. package/src/utils/eventPayloads.ts +39 -0
  52. package/src/utils/events.ts +33 -10
@@ -9,6 +9,8 @@ import { SwapDetails } from '../components/SwapDetails';
9
9
  import { SwapDetailsPlaceholder } from '../components/SwapDetails/SwapDetails.Placeholder';
10
10
  import { useNavigateBack } from '../hooks/useNavigateBack';
11
11
  import { useAppStore } from '../store/AppStore';
12
+ import { UiEventTypes } from '../types';
13
+ import { emitUiEvent } from '../utils/events';
12
14
  import { getPendingSwaps } from '../utils/queue';
13
15
 
14
16
  export function SwapDetailsPage() {
@@ -41,6 +43,10 @@ export function SwapDetailsPage() {
41
43
  if (selectedSwap?.id) {
42
44
  const swap = manager?.get(selectedSwap.id);
43
45
  if (swap) {
46
+ emitUiEvent({
47
+ type: UiEventTypes.SWAP_CANCELLED,
48
+ payload: { routeId: requestId },
49
+ });
44
50
  cancelSwap(swap);
45
51
  }
46
52
  }
@@ -114,7 +114,8 @@ export interface WalletsSlice {
114
114
  newWalletConnected: (
115
115
  accounts: Wallet[],
116
116
  namespace?: Namespace,
117
- derivationPath?: string
117
+ derivationPath?: string,
118
+ meta?: { walletName?: string }
118
119
  ) => Promise<void>;
119
120
  disconnectNamespaces: (walletType: string, namespaces: Namespace[]) => void;
120
121
  /**
@@ -443,14 +444,19 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
443
444
  connectedWallets: nextConnectedWalletsWithUpdatedSelectedStatus,
444
445
  });
445
446
  },
446
- newWalletConnected: async (accounts, namespace, derivationPath) => {
447
+ newWalletConnected: async (accounts, namespace, derivationPath, meta) => {
447
448
  const newAccount = accounts[0];
448
449
  if (!newAccount) {
449
450
  return;
450
451
  }
451
452
  eventEmitter.emit(WidgetEvents.WalletEvent, {
452
453
  type: WalletEventTypes.CONNECT,
453
- payload: { walletType: newAccount.walletType, accounts },
454
+ payload: {
455
+ walletType: newAccount.walletType,
456
+ accounts,
457
+ chain: newAccount.chain ?? null,
458
+ walletName: meta?.walletName ?? newAccount.walletType,
459
+ },
454
460
  });
455
461
 
456
462
  get().addConnectedWallet(accounts, namespace, derivationPath);
@@ -526,7 +532,7 @@ export const createWalletsSlice = keepLastUpdated<AppStoreState, WalletsSlice>(
526
532
  */
527
533
  eventEmitter.emit(WidgetEvents.WalletEvent, {
528
534
  type: WalletEventTypes.DISCONNECT,
529
- payload: { walletType },
535
+ payload: { walletType, walletName: walletType },
530
536
  });
531
537
  if (isTargetWalletExistsInConnectedWallets) {
532
538
  // This should be called before updating connectedWallets since we need the old state to remove balances.
@@ -5,8 +5,6 @@ import type {
5
5
  StepEventData,
6
6
  } from '@rango-dev/queue-manager-rango-preset';
7
7
 
8
- import { WidgetEvents as QueueManagerEvents } from '@rango-dev/queue-manager-rango-preset';
9
-
10
8
  type EventData<
11
9
  T extends QuoteEventTypes | WalletEventTypes | UiEventTypes,
12
10
  U extends Record<string, unknown> | null
@@ -23,11 +21,20 @@ type Account = Wallet;
23
21
  export enum QuoteEventTypes {
24
22
  QUOTE_INPUT_UPDATE = 'quoteInputUpdate',
25
23
  QUOTE_OUTPUT_UPDATE = 'quoteOutputUpdate',
24
+ /** A route/quote request was made with a valid source, destination and amount. */
25
+ ROUTE_REQUESTED = 'routeRequested',
26
+ /** The route API returned zero results for the requested pair. */
27
+ ROUTE_NOT_FOUND = 'routeNotFound',
28
+ /** The route API returned a 4xx/5xx error. */
29
+ ROUTE_FETCH_FAILED = 'routeFetchFailed',
30
+ /** The user overrode the auto-selected route. */
31
+ ROUTE_CHANGED = 'routeChanged',
26
32
  }
27
33
 
28
34
  export enum WalletEventTypes {
29
35
  CONNECT = 'connect',
30
36
  DISCONNECT = 'disconnect',
37
+ DETECTED = 'detected',
31
38
  }
32
39
 
33
40
  /**
@@ -36,6 +43,20 @@ export enum WalletEventTypes {
36
43
  */
37
44
  export enum UiEventTypes {
38
45
  CLICK_CONNECT_WALLET = 'clickConnectWallet',
46
+ TOKEN_SELECTED = 'tokenSelected',
47
+ CHAIN_FILTER_APPLIED = 'chainFilterApplied',
48
+ SETTINGS_CHANGED = 'settingsChanged',
49
+ ROUTE_FEE_VIEWED = 'routeFeeViewed',
50
+ DESTINATION_ADDRESS_SET = 'destinationAddressSet',
51
+ GAS_WARNING_SHOWN = 'gasWarningShown',
52
+ GAS_WARNING_BYPASSED = 'gasWarningBypassed',
53
+ SWAP_INITIATED = 'swapInitiated',
54
+ SWAP_WALLETS_MODAL_SHOWN = 'swapWalletsModalShown',
55
+ SWAP_WALLETS_CONFIRMED = 'swapWalletsConfirmed',
56
+ SWAP_STARTED = 'swapStarted',
57
+ SWAP_RESUMED = 'swapResumed',
58
+ SWAP_RETRIED = 'swapRetried',
59
+ SWAP_CANCELLED = 'swapCancelled',
39
60
  }
40
61
 
41
62
  export type QuoteInputUpdateEventPayload = {
@@ -54,30 +75,188 @@ export type QuoteUpdateEventPayload = Pick<
54
75
  export type ConnectWalletEventPayload = {
55
76
  walletType: string;
56
77
  accounts: Account[];
78
+ /** Blockchain of the first connected account. */
79
+ chain: string | null;
80
+ /** wallet type (e.g. "metamask"). */
81
+ walletName: string;
57
82
  };
58
83
 
59
84
  export type DisconnectWalletEventPayload = {
60
85
  walletType: string;
86
+ walletName: string;
87
+ };
88
+
89
+ export type WalletDetectedEventPayload = {
90
+ walletName: string;
61
91
  };
62
92
 
63
93
  export type ClickConnectWalletPayload = PreventableEventPayload;
64
94
 
95
+ /** Shared shape describing a route/quote, used by several swap events. */
96
+ export type SwapEstimateEventPayload = {
97
+ sourceChain: string;
98
+ destinationChain: string;
99
+ sourceTokenSymbol: string;
100
+ sourceTokenAddress: string | null;
101
+ destinationTokenSymbol: string;
102
+ destinationTokenAddress: string | null;
103
+ inputAmountUsd: number | null;
104
+ outputAmountUsd: number | null;
105
+ sourceTokenAmount: number | null;
106
+ destinationTokenAmount: number | null;
107
+ routeId: string;
108
+ };
109
+
110
+ export type RouteRequestedEventPayload = SwapEstimateEventPayload & {
111
+ routeCount: number;
112
+ };
113
+
114
+ export type RouteNotFoundEventPayload = {
115
+ sourceChain: string;
116
+ destinationChain: string;
117
+ sourceTokenSymbol: string;
118
+ sourceTokenAddress: string | null;
119
+ destinationTokenSymbol: string;
120
+ destinationTokenAddress: string | null;
121
+ inputAmountUsd: number | null;
122
+ };
123
+
124
+ export type RouteFetchFailedEventPayload = {
125
+ sourceChain: string;
126
+ destinationChain: string;
127
+ /** HTTP status code returned by the route API, as a string. */
128
+ errorCode: string;
129
+ };
130
+
131
+ export type RouteChangedEventPayload = {
132
+ sourceChain: string;
133
+ destinationChain: string;
134
+ fromRouteId: string;
135
+ toRouteId: string;
136
+ };
137
+
138
+ export type TokenSelectedEventPayload = {
139
+ side: 'from' | 'to';
140
+ tokenName: string | null;
141
+ tokenSymbol: string;
142
+ tokenAddress: string | null;
143
+ chain: string;
144
+ selectionMethod: 'search' | 'default ';
145
+ /** `all` when no chain filter is active, otherwise the filtered chain name. */
146
+ activeChainFilter: string;
147
+ };
148
+
149
+ export type ChainFilterAppliedEventPayload = {
150
+ side: 'from' | 'to';
151
+ chain: string;
152
+ filterSource: 'featured' | 'expanded';
153
+ };
154
+
155
+ export type LiquiditySourceType = 'exchanges' | 'bridges';
156
+
157
+ export type SettingsChangedEventPayload =
158
+ | { setting: 'slippage'; previousValue: number; newValue: number }
159
+ | { setting: 'infiniteApproval'; previousValue: boolean; newValue: boolean }
160
+ | {
161
+ setting: 'liquiditySource';
162
+ sourceType: LiquiditySourceType;
163
+ /** A single source was toggled on/off from the list. */
164
+ changeType: 'individual';
165
+ /** The sources whose enabled state changed, with their new state. */
166
+ sources: { id: string; enabled: boolean }[];
167
+ }
168
+ | {
169
+ setting: 'liquiditySource';
170
+ sourceType: LiquiditySourceType;
171
+ /** Every source was enabled or disabled at once via the header button. */
172
+ changeType: 'selectAll' | 'deselectAll';
173
+ /**
174
+ * Selection state before the bulk action, so the consumer can summarise
175
+ * it as all/some/none.
176
+ */
177
+ previousSelectedCount: number;
178
+ totalCount: number;
179
+ };
180
+
181
+ export type RouteFeeViewedEventPayload = { routeId: string };
182
+
183
+ export type DestinationAddressSetEventPayload = { destinationChain: string };
184
+
185
+ export type GasWarningEventPayload = { routeId: string };
186
+
187
+ export type SwapInitiatedEventPayload = SwapEstimateEventPayload & {
188
+ walletConnected: boolean;
189
+ };
190
+
191
+ export type SwapStartedEventPayload = SwapEstimateEventPayload & {
192
+ stepCount: number;
193
+ };
194
+
195
+ export type SwapWalletsModalShownEventPayload = {
196
+ chainsRequired: number;
197
+ chainsPending: number;
198
+ };
199
+
200
+ export type SwapWalletsConfirmedEventPayload = { routeId: string };
201
+
202
+ export type SwapResumedEventPayload = {
203
+ routeId: string;
204
+ stepCount: number;
205
+ stepNumber: number;
206
+ };
207
+
208
+ export type SwapRetriedEventPayload = { routeId: string };
209
+
210
+ export type SwapCancelledEventPayload = { routeId: string };
211
+
65
212
  export type QuoteEventData =
66
213
  | EventData<QuoteEventTypes.QUOTE_INPUT_UPDATE, QuoteInputUpdateEventPayload>
67
- | EventData<QuoteEventTypes.QUOTE_OUTPUT_UPDATE, QuoteUpdateEventPayload>;
214
+ | EventData<QuoteEventTypes.QUOTE_OUTPUT_UPDATE, QuoteUpdateEventPayload>
215
+ | EventData<QuoteEventTypes.ROUTE_REQUESTED, RouteRequestedEventPayload>
216
+ | EventData<QuoteEventTypes.ROUTE_NOT_FOUND, RouteNotFoundEventPayload>
217
+ | EventData<QuoteEventTypes.ROUTE_FETCH_FAILED, RouteFetchFailedEventPayload>
218
+ | EventData<QuoteEventTypes.ROUTE_CHANGED, RouteChangedEventPayload>;
68
219
 
69
220
  export type WalletEventData =
70
221
  | EventData<WalletEventTypes.CONNECT, ConnectWalletEventPayload>
71
- | EventData<WalletEventTypes.DISCONNECT, DisconnectWalletEventPayload>;
222
+ | EventData<WalletEventTypes.DISCONNECT, DisconnectWalletEventPayload>
223
+ | EventData<WalletEventTypes.DETECTED, WalletDetectedEventPayload>;
72
224
 
73
- export type UiEventData = EventData<
74
- UiEventTypes.CLICK_CONNECT_WALLET,
75
- ClickConnectWalletPayload
76
- >;
225
+ export type UiEventData =
226
+ | EventData<UiEventTypes.CLICK_CONNECT_WALLET, ClickConnectWalletPayload>
227
+ | EventData<UiEventTypes.TOKEN_SELECTED, TokenSelectedEventPayload>
228
+ | EventData<UiEventTypes.CHAIN_FILTER_APPLIED, ChainFilterAppliedEventPayload>
229
+ | EventData<UiEventTypes.SETTINGS_CHANGED, SettingsChangedEventPayload>
230
+ | EventData<UiEventTypes.ROUTE_FEE_VIEWED, RouteFeeViewedEventPayload>
231
+ | EventData<
232
+ UiEventTypes.DESTINATION_ADDRESS_SET,
233
+ DestinationAddressSetEventPayload
234
+ >
235
+ | EventData<UiEventTypes.GAS_WARNING_SHOWN, GasWarningEventPayload>
236
+ | EventData<UiEventTypes.GAS_WARNING_BYPASSED, GasWarningEventPayload>
237
+ | EventData<UiEventTypes.SWAP_INITIATED, SwapInitiatedEventPayload>
238
+ | EventData<
239
+ UiEventTypes.SWAP_WALLETS_MODAL_SHOWN,
240
+ SwapWalletsModalShownEventPayload
241
+ >
242
+ | EventData<
243
+ UiEventTypes.SWAP_WALLETS_CONFIRMED,
244
+ SwapWalletsConfirmedEventPayload
245
+ >
246
+ | EventData<UiEventTypes.SWAP_STARTED, SwapStartedEventPayload>
247
+ | EventData<UiEventTypes.SWAP_RESUMED, SwapResumedEventPayload>
248
+ | EventData<UiEventTypes.SWAP_RETRIED, SwapRetriedEventPayload>
249
+ | EventData<UiEventTypes.SWAP_CANCELLED, SwapCancelledEventPayload>;
77
250
 
251
+ /**
252
+ * RouteEvent/StepEvent must match the queue-manager's `WidgetEvents` string
253
+ * values (`QueueManagerEvents`) so events route correctly. They're inlined as
254
+ * literals rather than referencing the other enum to keep this a pure string
255
+ * enum (a cross-enum reference makes `no-mixed-enums` read them as numeric).
256
+ */
78
257
  export enum WidgetEvents {
79
- RouteEvent = QueueManagerEvents.RouteEvent,
80
- StepEvent = QueueManagerEvents.StepEvent,
258
+ RouteEvent = 'routeEvent',
259
+ StepEvent = 'stepEvent',
81
260
  QuoteEvent = 'quoteEvent',
82
261
  WalletEvent = 'walletEvent',
83
262
  UiEvent = 'uiEvent',
@@ -0,0 +1,39 @@
1
+ import type { SelectedQuote, SwapEstimateEventPayload } from '../types';
2
+
3
+ import { getUsdInputFrom, getUsdOutputFrom } from './swap';
4
+
5
+ function toNumberOrNull(value: string | null | undefined): number | null {
6
+ if (value === null || value === undefined || value === '') {
7
+ return null;
8
+ }
9
+ const parsed = Number(value);
10
+ return Number.isFinite(parsed) ? parsed : null;
11
+ }
12
+
13
+ /**
14
+ * Derives the shared route/quote descriptor used by several swap
15
+ * events (swapInitiated, swapStarted, routeRequested, ...) from a quote.
16
+ * Amounts are estimates taken from the quote, not on-chain actuals.
17
+ */
18
+ export function buildSwapEstimatePayload(
19
+ quote: SelectedQuote
20
+ ): SwapEstimateEventPayload {
21
+ const firstSwap = quote.swaps[0];
22
+ const lastSwap = quote.swaps[quote.swaps.length - 1];
23
+ const inputUsd = getUsdInputFrom(quote);
24
+ const outputUsd = getUsdOutputFrom(quote);
25
+
26
+ return {
27
+ routeId: quote.requestId,
28
+ sourceChain: firstSwap?.from.blockchain ?? '',
29
+ destinationChain: lastSwap?.to.blockchain ?? '',
30
+ sourceTokenSymbol: firstSwap?.from.symbol ?? '',
31
+ sourceTokenAddress: firstSwap?.from.address ?? null,
32
+ destinationTokenSymbol: lastSwap?.to.symbol ?? '',
33
+ destinationTokenAddress: lastSwap?.to.address ?? null,
34
+ sourceTokenAmount: toNumberOrNull(quote.requestAmount),
35
+ destinationTokenAmount: toNumberOrNull(quote.outputAmount),
36
+ inputAmountUsd: inputUsd ? inputUsd.toNumber() : null,
37
+ outputAmountUsd: outputUsd ? outputUsd.toNumber() : null,
38
+ };
39
+ }
@@ -1,27 +1,50 @@
1
1
  import { eventEmitter } from '../services/eventEmitter';
2
- import { type UiEventData, WidgetEvents } from '../types';
2
+ import {
3
+ type ClickConnectWalletPayload,
4
+ type QuoteEventData,
5
+ type UiEventData,
6
+ type UiEventTypes,
7
+ type WalletDetectedEventPayload,
8
+ WalletEventTypes,
9
+ WidgetEvents,
10
+ } from '../types';
3
11
 
4
- type UiEvent = {
5
- type: UiEventData['type'];
6
- payload?: Omit<UiEventData['payload'], 'preventDefault'>;
12
+ type PreventableUiEvent = {
13
+ type: UiEventTypes.CLICK_CONNECT_WALLET;
14
+ payload?: Omit<ClickConnectWalletPayload, 'preventDefault'>;
7
15
  };
8
16
 
9
- export function emitPreventableEvent(event: UiEvent, action: () => void): void {
17
+ export function emitUiEvent(event: UiEventData): void {
18
+ eventEmitter.emit(WidgetEvents.UiEvent, event);
19
+ }
20
+
21
+ export function emitPreventableEvent(
22
+ event: PreventableUiEvent,
23
+ action: () => void
24
+ ): void {
10
25
  let defaultPrevented = false;
11
26
 
12
27
  const extendedPayload = {
28
+ ...event.payload,
13
29
  preventDefault() {
14
30
  defaultPrevented = true;
15
31
  },
16
- ...(event.payload === undefined && { payload: event.payload }),
17
32
  };
18
33
 
19
- eventEmitter.emit(WidgetEvents.UiEvent, {
20
- type: event.type,
21
- payload: extendedPayload,
22
- });
34
+ emitUiEvent({ type: event.type, payload: extendedPayload });
23
35
 
24
36
  if (!defaultPrevented) {
25
37
  action();
26
38
  }
27
39
  }
40
+
41
+ export function emitQuoteEvent(event: QuoteEventData): void {
42
+ eventEmitter.emit(WidgetEvents.QuoteEvent, event);
43
+ }
44
+
45
+ export function emitWalletDetected(payload: WalletDetectedEventPayload): void {
46
+ eventEmitter.emit(WidgetEvents.WalletEvent, {
47
+ type: WalletEventTypes.DETECTED,
48
+ payload,
49
+ });
50
+ }