@ledgerhq/live-common 34.54.0-nightly.20251205111238 → 34.54.0-nightly.20251209023841

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 (132) hide show
  1. package/lib/account/serialization.js +1 -1
  2. package/lib/account/serialization.js.map +1 -1
  3. package/lib/account/support.js +1 -1
  4. package/lib/account/support.js.map +1 -1
  5. package/lib/domain/getTokensWithFunds.d.ts +7 -1
  6. package/lib/domain/getTokensWithFunds.d.ts.map +1 -1
  7. package/lib/domain/getTokensWithFunds.js +15 -4
  8. package/lib/domain/getTokensWithFunds.js.map +1 -1
  9. package/lib/domain/getTotalStakeableAssets.d.ts +10 -0
  10. package/lib/domain/getTotalStakeableAssets.d.ts.map +1 -0
  11. package/lib/domain/getTotalStakeableAssets.js +35 -0
  12. package/lib/domain/getTotalStakeableAssets.js.map +1 -0
  13. package/lib/e2e/index.d.ts +6 -0
  14. package/lib/e2e/index.d.ts.map +1 -1
  15. package/lib/exchange/swap/api/v5/fetchCurrencyFrom.js +1 -1
  16. package/lib/exchange/swap/api/v5/fetchCurrencyFrom.js.map +1 -1
  17. package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
  18. package/lib/featureFlags/defaultFeatures.js +2 -0
  19. package/lib/featureFlags/defaultFeatures.js.map +1 -1
  20. package/lib/featureFlags/firebaseFeatureFlags.js +1 -1
  21. package/lib/featureFlags/firebaseFeatureFlags.js.map +1 -1
  22. package/lib/featureFlags/useFeature.d.ts +1 -1
  23. package/lib/featureFlags/useFeature.d.ts.map +1 -1
  24. package/lib/featureFlags/useHasOverriddenFeatureFlags.js +1 -1
  25. package/lib/featureFlags/useHasOverriddenFeatureFlags.js.map +1 -1
  26. package/lib/hw/getBitcoinLikeInfo.js +1 -1
  27. package/lib/hw/getBitcoinLikeInfo.js.map +1 -1
  28. package/lib/mock/account.js +1 -1
  29. package/lib/mock/account.js.map +1 -1
  30. package/lib/postOnboarding/reducer.d.ts +2 -0
  31. package/lib/postOnboarding/reducer.d.ts.map +1 -1
  32. package/lib/wallet-api/Exchange/server.d.ts.map +1 -1
  33. package/lib/wallet-api/Exchange/server.js +3 -1
  34. package/lib/wallet-api/Exchange/server.js.map +1 -1
  35. package/lib/wallet-api/Exchange/tracking.d.ts +7 -6
  36. package/lib/wallet-api/Exchange/tracking.d.ts.map +1 -1
  37. package/lib/wallet-api/Exchange/tracking.js +52 -13
  38. package/lib/wallet-api/Exchange/tracking.js.map +1 -1
  39. package/lib/wallet-api/logic.d.ts +1 -1
  40. package/lib/wallet-api/logic.d.ts.map +1 -1
  41. package/lib/wallet-api/logic.js +5 -5
  42. package/lib/wallet-api/logic.js.map +1 -1
  43. package/lib/wallet-api/react.d.ts.map +1 -1
  44. package/lib/wallet-api/react.js +9 -6
  45. package/lib/wallet-api/react.js.map +1 -1
  46. package/lib/wallet-api/tracking.d.ts +5 -5
  47. package/lib/wallet-api/tracking.d.ts.map +1 -1
  48. package/lib/wallet-api/tracking.js +30 -10
  49. package/lib/wallet-api/tracking.js.map +1 -1
  50. package/lib/wallet-api/useDappLogic.d.ts.map +1 -1
  51. package/lib/wallet-api/useDappLogic.js +31 -20
  52. package/lib/wallet-api/useDappLogic.js.map +1 -1
  53. package/lib/wallet-api/utils/extractDappURLFromManifest.js +3 -3
  54. package/lib/wallet-api/utils/extractDappURLFromManifest.js.map +1 -1
  55. package/lib/wallet-api/utils/extractURLFromManifest.js +1 -1
  56. package/lib/wallet-api/utils/extractURLFromManifest.js.map +1 -1
  57. package/lib-es/account/serialization.js +1 -1
  58. package/lib-es/account/serialization.js.map +1 -1
  59. package/lib-es/account/support.js +1 -1
  60. package/lib-es/account/support.js.map +1 -1
  61. package/lib-es/domain/getTokensWithFunds.d.ts +7 -1
  62. package/lib-es/domain/getTokensWithFunds.d.ts.map +1 -1
  63. package/lib-es/domain/getTokensWithFunds.js +13 -3
  64. package/lib-es/domain/getTokensWithFunds.js.map +1 -1
  65. package/lib-es/domain/getTotalStakeableAssets.d.ts +10 -0
  66. package/lib-es/domain/getTotalStakeableAssets.d.ts.map +1 -0
  67. package/lib-es/domain/getTotalStakeableAssets.js +31 -0
  68. package/lib-es/domain/getTotalStakeableAssets.js.map +1 -0
  69. package/lib-es/e2e/index.d.ts +6 -0
  70. package/lib-es/e2e/index.d.ts.map +1 -1
  71. package/lib-es/exchange/swap/api/v5/fetchCurrencyFrom.js +1 -1
  72. package/lib-es/exchange/swap/api/v5/fetchCurrencyFrom.js.map +1 -1
  73. package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -1
  74. package/lib-es/featureFlags/defaultFeatures.js +2 -0
  75. package/lib-es/featureFlags/defaultFeatures.js.map +1 -1
  76. package/lib-es/featureFlags/firebaseFeatureFlags.js +1 -1
  77. package/lib-es/featureFlags/firebaseFeatureFlags.js.map +1 -1
  78. package/lib-es/featureFlags/useFeature.d.ts +1 -1
  79. package/lib-es/featureFlags/useFeature.d.ts.map +1 -1
  80. package/lib-es/featureFlags/useHasOverriddenFeatureFlags.js +1 -1
  81. package/lib-es/featureFlags/useHasOverriddenFeatureFlags.js.map +1 -1
  82. package/lib-es/hw/getBitcoinLikeInfo.js +1 -1
  83. package/lib-es/hw/getBitcoinLikeInfo.js.map +1 -1
  84. package/lib-es/mock/account.js +1 -1
  85. package/lib-es/mock/account.js.map +1 -1
  86. package/lib-es/postOnboarding/reducer.d.ts +2 -0
  87. package/lib-es/postOnboarding/reducer.d.ts.map +1 -1
  88. package/lib-es/wallet-api/Exchange/server.d.ts.map +1 -1
  89. package/lib-es/wallet-api/Exchange/server.js +3 -1
  90. package/lib-es/wallet-api/Exchange/server.js.map +1 -1
  91. package/lib-es/wallet-api/Exchange/tracking.d.ts +7 -6
  92. package/lib-es/wallet-api/Exchange/tracking.d.ts.map +1 -1
  93. package/lib-es/wallet-api/Exchange/tracking.js +52 -13
  94. package/lib-es/wallet-api/Exchange/tracking.js.map +1 -1
  95. package/lib-es/wallet-api/logic.d.ts +1 -1
  96. package/lib-es/wallet-api/logic.d.ts.map +1 -1
  97. package/lib-es/wallet-api/logic.js +5 -5
  98. package/lib-es/wallet-api/logic.js.map +1 -1
  99. package/lib-es/wallet-api/react.d.ts.map +1 -1
  100. package/lib-es/wallet-api/react.js +9 -6
  101. package/lib-es/wallet-api/react.js.map +1 -1
  102. package/lib-es/wallet-api/tracking.d.ts +5 -5
  103. package/lib-es/wallet-api/tracking.d.ts.map +1 -1
  104. package/lib-es/wallet-api/tracking.js +30 -10
  105. package/lib-es/wallet-api/tracking.js.map +1 -1
  106. package/lib-es/wallet-api/useDappLogic.d.ts.map +1 -1
  107. package/lib-es/wallet-api/useDappLogic.js +31 -20
  108. package/lib-es/wallet-api/useDappLogic.js.map +1 -1
  109. package/lib-es/wallet-api/utils/extractDappURLFromManifest.js +3 -3
  110. package/lib-es/wallet-api/utils/extractDappURLFromManifest.js.map +1 -1
  111. package/lib-es/wallet-api/utils/extractURLFromManifest.js +1 -1
  112. package/lib-es/wallet-api/utils/extractURLFromManifest.js.map +1 -1
  113. package/package.json +76 -76
  114. package/src/account/serialization.ts +1 -1
  115. package/src/account/support.ts +1 -1
  116. package/src/domain/getTokensWithFunds.ts +18 -5
  117. package/src/domain/getTotalStakeableAssets.test.ts +267 -0
  118. package/src/domain/getTotalStakeableAssets.ts +47 -0
  119. package/src/exchange/swap/api/v5/fetchCurrencyFrom.ts +1 -1
  120. package/src/featureFlags/defaultFeatures.ts +2 -0
  121. package/src/featureFlags/firebaseFeatureFlags.ts +1 -1
  122. package/src/featureFlags/useHasOverriddenFeatureFlags.ts +1 -1
  123. package/src/hw/getBitcoinLikeInfo.ts +1 -1
  124. package/src/mock/account.ts +1 -1
  125. package/src/wallet-api/Exchange/server.ts +3 -0
  126. package/src/wallet-api/Exchange/tracking.ts +56 -13
  127. package/src/wallet-api/logic.ts +5 -4
  128. package/src/wallet-api/react.ts +10 -5
  129. package/src/wallet-api/tracking.ts +30 -10
  130. package/src/wallet-api/useDappLogic.ts +32 -20
  131. package/src/wallet-api/utils/extractDappURLFromManifest.ts +3 -3
  132. package/src/wallet-api/utils/extractURLFromManifest.ts +1 -1
@@ -0,0 +1,267 @@
1
+ import { genAccount } from "@ledgerhq/coin-framework/lib/mocks/account";
2
+ import { getCryptoCurrencyById } from "../currencies/index";
3
+ import { Account } from "@ledgerhq/types-live";
4
+ import type { TokenCurrency } from "@ledgerhq/types-cryptoassets";
5
+ import BigNumber from "bignumber.js";
6
+ import { getTotalStakeableAssets } from "./getTotalStakeableAssets";
7
+ import { setupMockCryptoAssetsStore } from "@ledgerhq/cryptoassets/cal-client/test-helpers";
8
+
9
+ // Setup mock store for unit tests
10
+ setupMockCryptoAssetsStore();
11
+
12
+ const ETH = getCryptoCurrencyById("ethereum");
13
+ const BTC = getCryptoCurrencyById("bitcoin");
14
+
15
+ // Create mock tokens for tests
16
+ const ZRX_TOKEN: TokenCurrency = {
17
+ type: "TokenCurrency",
18
+ id: "ethereum/erc20/0x_project",
19
+ contractAddress: "0xE41d2489571d322189246DaFA5ebDe1F4699F498",
20
+ parentCurrency: ETH,
21
+ tokenType: "erc20",
22
+ name: "0x Project",
23
+ ticker: "ZRX",
24
+ delisted: false,
25
+ disableCountervalue: false,
26
+ units: [{ name: "ZRX", code: "ZRX", magnitude: 18 }],
27
+ };
28
+
29
+ const REP_TOKEN: TokenCurrency = {
30
+ type: "TokenCurrency",
31
+ id: "ethereum/erc20/augur",
32
+ contractAddress: "0x1985365e9f78359a9B6AD760e32412f4a445E862",
33
+ parentCurrency: ETH,
34
+ tokenType: "erc20",
35
+ name: "Augur",
36
+ ticker: "REP",
37
+ delisted: false,
38
+ disableCountervalue: false,
39
+ units: [{ name: "REP", code: "REP", magnitude: 18 }],
40
+ };
41
+
42
+ const mockedAccounts: Account[] = [
43
+ genAccount("mocked-account-1", {
44
+ currency: ETH,
45
+ tokensData: [ZRX_TOKEN, REP_TOKEN],
46
+ }),
47
+ ];
48
+
49
+ describe("getTotalStakeableAssets", () => {
50
+ it("should return empty Set if no accounts", () => {
51
+ const result = getTotalStakeableAssets([], [], []);
52
+ expect(result.combinedIds).toBeInstanceOf(Set);
53
+ expect(result.combinedIds.size).toBe(0);
54
+ expect(result.stakeableAssets).toEqual([]);
55
+ });
56
+
57
+ it("should return empty Set if accounts is null", () => {
58
+ const result = getTotalStakeableAssets(null, [], []);
59
+ expect(result.combinedIds).toBeInstanceOf(Set);
60
+ expect(result.combinedIds.size).toBe(0);
61
+ expect(result.stakeableAssets).toEqual([]);
62
+ });
63
+
64
+ it("should return empty Set if accounts is undefined", () => {
65
+ const result = getTotalStakeableAssets(undefined, [], []);
66
+ expect(result.combinedIds).toBeInstanceOf(Set);
67
+ expect(result.combinedIds.size).toBe(0);
68
+ expect(result.stakeableAssets).toEqual([]);
69
+ });
70
+
71
+ it("should return empty Set if no staking currencies enabled", () => {
72
+ const result = getTotalStakeableAssets(mockedAccounts, [], []);
73
+ expect(result.combinedIds).toBeInstanceOf(Set);
74
+ expect(result.combinedIds.size).toBe(0);
75
+ expect(result.stakeableAssets).toEqual([]);
76
+ });
77
+
78
+ it("should return Set with matching currency ID when staking currency is enabled", () => {
79
+ const account = mockedAccounts[0];
80
+ const stakingCurrenciesEnabled = [ETH.id]; // "ethereum"
81
+
82
+ expect(account.balance).toBeTruthy();
83
+ expect(account.balance instanceof BigNumber).toBe(true);
84
+ expect(account.balance.gt(0)).toBe(true);
85
+
86
+ const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
87
+
88
+ expect(result.combinedIds).toBeInstanceOf(Set);
89
+ expect(result.combinedIds.size).toBe(1);
90
+ expect(result.combinedIds.has(ETH.id)).toBe(true);
91
+ expect(result.stakeableAssets.length).toBe(1);
92
+ expect(result.stakeableAssets[0]).toEqual({
93
+ ticker: ETH.ticker,
94
+ networkName: ETH.name,
95
+ id: ETH.id,
96
+ });
97
+ });
98
+
99
+ it("should return Set with matching token IDs when staking tokens are enabled", () => {
100
+ const account = mockedAccounts[0];
101
+ const stakingCurrenciesEnabled = [ZRX_TOKEN.id, REP_TOKEN.id];
102
+
103
+ expect(account.subAccounts).toBeDefined();
104
+ expect(account.subAccounts?.length).toBe(2);
105
+
106
+ const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
107
+
108
+ expect(result.combinedIds).toBeInstanceOf(Set);
109
+ expect(result.combinedIds.size).toBe(2);
110
+ expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
111
+ expect(result.combinedIds.has(REP_TOKEN.id)).toBe(true);
112
+ expect(result.stakeableAssets.length).toBe(2);
113
+ expect(result.stakeableAssets).toEqual(
114
+ expect.arrayContaining([
115
+ expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
116
+ expect.objectContaining({ id: REP_TOKEN.id, ticker: REP_TOKEN.ticker }),
117
+ ]),
118
+ );
119
+ });
120
+
121
+ it("should return Set with both currency and token IDs when both are enabled", () => {
122
+ const account = mockedAccounts[0];
123
+ const stakingCurrenciesEnabled = [ETH.id, ZRX_TOKEN.id, REP_TOKEN.id];
124
+
125
+ const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
126
+
127
+ expect(result.combinedIds).toBeInstanceOf(Set);
128
+ expect(result.combinedIds.size).toBe(3);
129
+ expect(result.combinedIds.has(ETH.id)).toBe(true);
130
+ expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
131
+ expect(result.combinedIds.has(REP_TOKEN.id)).toBe(true);
132
+ expect(result.stakeableAssets.length).toBe(3);
133
+ expect(result.stakeableAssets).toEqual(
134
+ expect.arrayContaining([
135
+ expect.objectContaining({ id: ETH.id, ticker: ETH.ticker }),
136
+ expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
137
+ expect.objectContaining({ id: REP_TOKEN.id, ticker: REP_TOKEN.ticker }),
138
+ ]),
139
+ );
140
+ });
141
+
142
+ it("should filter out currencies without funds", () => {
143
+ const account = mockedAccounts[0];
144
+ const accountWithZeroBalance = { ...account, balance: new BigNumber(0) };
145
+ const stakingCurrenciesEnabled = [ETH.id];
146
+
147
+ const result = getTotalStakeableAssets([accountWithZeroBalance], stakingCurrenciesEnabled, []);
148
+
149
+ expect(result.combinedIds).toBeInstanceOf(Set);
150
+ expect(result.combinedIds.size).toBe(0);
151
+ expect(result.stakeableAssets).toEqual([]);
152
+ });
153
+
154
+ it("should filter out tokens without funds", () => {
155
+ const account = mockedAccounts[0];
156
+ const [zrxAccount, repAccount] = account.subAccounts || [];
157
+ const emptyRepAccount = { ...repAccount, balance: new BigNumber(0) };
158
+ const accountWithEmptyToken = { ...account, subAccounts: [zrxAccount, emptyRepAccount] };
159
+ const stakingCurrenciesEnabled = [ZRX_TOKEN.id, REP_TOKEN.id];
160
+
161
+ const result = getTotalStakeableAssets([accountWithEmptyToken], stakingCurrenciesEnabled, []);
162
+
163
+ expect(result.combinedIds).toBeInstanceOf(Set);
164
+ expect(result.combinedIds.size).toBe(1);
165
+ expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
166
+ expect(result.combinedIds.has(REP_TOKEN.id)).toBe(false);
167
+ expect(result.stakeableAssets.length).toBe(1);
168
+ expect(result.stakeableAssets[0]).toEqual(
169
+ expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
170
+ );
171
+ });
172
+
173
+ it("should include partner staking currencies enabled", () => {
174
+ const account = mockedAccounts[0];
175
+ const stakingCurrenciesEnabled = [ETH.id];
176
+ const partnerStakingCurrenciesEnabled = [ZRX_TOKEN.id];
177
+
178
+ const result = getTotalStakeableAssets(
179
+ [account],
180
+ stakingCurrenciesEnabled,
181
+ partnerStakingCurrenciesEnabled,
182
+ );
183
+
184
+ expect(result.combinedIds).toBeInstanceOf(Set);
185
+ expect(result.combinedIds.size).toBe(2);
186
+ expect(result.combinedIds.has(ETH.id)).toBe(true);
187
+ expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
188
+ expect(result.stakeableAssets.length).toBe(2);
189
+ expect(result.stakeableAssets).toEqual(
190
+ expect.arrayContaining([
191
+ expect.objectContaining({ id: ETH.id, ticker: ETH.ticker }),
192
+ expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
193
+ ]),
194
+ );
195
+ });
196
+
197
+ it("should deduplicate IDs when same currency appears in both lists", () => {
198
+ const account = mockedAccounts[0];
199
+ const stakingCurrenciesEnabled = [ETH.id];
200
+ const partnerStakingCurrenciesEnabled = [ETH.id]; // Same currency
201
+
202
+ const result = getTotalStakeableAssets(
203
+ [account],
204
+ stakingCurrenciesEnabled,
205
+ partnerStakingCurrenciesEnabled,
206
+ );
207
+
208
+ expect(result.combinedIds).toBeInstanceOf(Set);
209
+ expect(result.combinedIds.size).toBe(1);
210
+ expect(result.combinedIds.has(ETH.id)).toBe(true);
211
+ expect(result.stakeableAssets.length).toBe(1);
212
+ expect(result.stakeableAssets[0]).toEqual({
213
+ ticker: ETH.ticker,
214
+ networkName: ETH.name,
215
+ id: ETH.id,
216
+ });
217
+ });
218
+
219
+ it("should handle multiple accounts with different currencies", () => {
220
+ const ethAccount = mockedAccounts[0];
221
+ const btcAccount = genAccount("mocked-account-2", {
222
+ currency: BTC,
223
+ });
224
+ const accounts = [ethAccount, btcAccount];
225
+ const stakingCurrenciesEnabled = [ETH.id, BTC.id];
226
+
227
+ const result = getTotalStakeableAssets(accounts, stakingCurrenciesEnabled, []);
228
+
229
+ expect(result.combinedIds).toBeInstanceOf(Set);
230
+ expect(result.combinedIds.size).toBe(2);
231
+ expect(result.combinedIds.has(ETH.id)).toBe(true);
232
+ expect(result.combinedIds.has(BTC.id)).toBe(true);
233
+ expect(result.stakeableAssets.length).toBe(2);
234
+ expect(result.stakeableAssets).toEqual(
235
+ expect.arrayContaining([
236
+ expect.objectContaining({ id: ETH.id, ticker: ETH.ticker }),
237
+ expect.objectContaining({ id: BTC.id, ticker: BTC.ticker }),
238
+ ]),
239
+ );
240
+ });
241
+
242
+ it("should only include IDs that match staking currencies enabled", () => {
243
+ const account = mockedAccounts[0];
244
+ const stakingCurrenciesEnabled = [ZRX_TOKEN.id]; // Only ZRX enabled, not ETH or REP
245
+
246
+ const result = getTotalStakeableAssets([account], stakingCurrenciesEnabled, []);
247
+
248
+ expect(result.combinedIds).toBeInstanceOf(Set);
249
+ expect(result.combinedIds.size).toBe(1);
250
+ expect(result.combinedIds.has(ZRX_TOKEN.id)).toBe(true);
251
+ expect(result.combinedIds.has(ETH.id)).toBe(false);
252
+ expect(result.combinedIds.has(REP_TOKEN.id)).toBe(false);
253
+ expect(result.stakeableAssets.length).toBe(1);
254
+ expect(result.stakeableAssets[0]).toEqual(
255
+ expect.objectContaining({ id: ZRX_TOKEN.id, ticker: ZRX_TOKEN.ticker }),
256
+ );
257
+ });
258
+
259
+ it("should handle empty arrays for staking currencies", () => {
260
+ const account = mockedAccounts[0];
261
+ const result = getTotalStakeableAssets([account], [], []);
262
+
263
+ expect(result.combinedIds).toBeInstanceOf(Set);
264
+ expect(result.combinedIds.size).toBe(0);
265
+ expect(result.stakeableAssets).toEqual([]);
266
+ });
267
+ });
@@ -0,0 +1,47 @@
1
+ import { getTokensWithFundsMap } from "./getTokensWithFunds";
2
+ import { Account } from "@ledgerhq/types-live";
3
+
4
+ export function getTotalStakeableAssets(
5
+ accounts: Account[] | null | undefined,
6
+ stakingCurrenciesEnabled: string[],
7
+ partnerStakingCurrenciesEnabled: string[],
8
+ ): {
9
+ combinedIds: Set<string>;
10
+ stakeableAssets: { ticker: string; networkName: string; id: string }[];
11
+ } {
12
+ if (!accounts) return { combinedIds: new Set<string>(), stakeableAssets: [] };
13
+
14
+ const accountsWithFundsCurrencies = accounts
15
+ .filter(account => account?.balance.isGreaterThan(0))
16
+ .map(account => account?.currency);
17
+
18
+ const allStakingCurrenciesEnabled = new Set([
19
+ ...stakingCurrenciesEnabled,
20
+ ...partnerStakingCurrenciesEnabled,
21
+ ]);
22
+
23
+ const tokenWithFundsMap = getTokensWithFundsMap(accounts);
24
+ const filteredAccountCurrencyIds = [...accountsWithFundsCurrencies].filter(currency =>
25
+ allStakingCurrenciesEnabled.has(currency.id),
26
+ );
27
+ const filteredTokenWithFunds = [...tokenWithFundsMap.values()].filter(token =>
28
+ allStakingCurrenciesEnabled.has(token.id),
29
+ );
30
+
31
+ const combined = new Map<string, { ticker: string; networkName: string; id: string }>();
32
+ for (const currency of filteredAccountCurrencyIds) {
33
+ combined.set(currency.id, {
34
+ ticker: currency.ticker,
35
+ networkName: currency.name,
36
+ id: currency.id,
37
+ });
38
+ }
39
+ for (const token of filteredTokenWithFunds) {
40
+ combined.set(token.id, token);
41
+ }
42
+
43
+ return {
44
+ combinedIds: new Set(Array.from(combined.values(), details => details.id)),
45
+ stakeableAssets: Array.from(combined.values()),
46
+ };
47
+ }
@@ -45,7 +45,7 @@ export async function fetchCurrencyFrom({
45
45
  ...(headers !== undefined ? { headers } : {}),
46
46
  });
47
47
  return flattenV5CurrenciesToAndFrom(data);
48
- } catch (e) {
48
+ } catch {
49
49
  throw Error("Something went wrong in fetchCurrencyFrom call");
50
50
  }
51
51
  }
@@ -734,6 +734,8 @@ export const DEFAULT_FEATURES: Features = {
734
734
  },
735
735
  zcashShielded: DEFAULT_FEATURE,
736
736
  llmNanoOnboardingFundWallet: DEFAULT_FEATURE,
737
+ lldRebornABtest: DEFAULT_FEATURE,
738
+ llmRebornABtest: DEFAULT_FEATURE,
737
739
  };
738
740
 
739
741
  // Firebase SDK treat JSON values as strings
@@ -59,7 +59,7 @@ export const isFeature = (key: string): boolean => {
59
59
  return false;
60
60
  }
61
61
  return true;
62
- } catch (error) {
62
+ } catch {
63
63
  console.error(`Failed to check if feature "${key}" exists`);
64
64
  return false;
65
65
  }
@@ -15,7 +15,7 @@ export function useHasLocallyOverriddenFeatureFlags(): boolean {
15
15
  try {
16
16
  const val = getFeature(featureId as FeatureId);
17
17
  return val?.overridesRemote || val?.overriddenByEnv;
18
- } catch (e) {
18
+ } catch {
19
19
  return false;
20
20
  }
21
21
  }),
@@ -26,7 +26,7 @@ const getBitcoinLikeInfo = (
26
26
  message,
27
27
  short,
28
28
  };
29
- } catch (e) {
29
+ } catch {
30
30
  // in such case, we are in an old firmware we no longer support
31
31
  return null;
32
32
  }
@@ -199,7 +199,7 @@ export function genAccount(id: number | string, opts: GenAccountOptions = {}): A
199
199
  if (initAccount) {
200
200
  initAccount(account);
201
201
  }
202
- } catch (e: any) {
202
+ } catch {
203
203
  // to fix /src/__tests__/cross.ts, skip bridge error if there is no bridge in such currency
204
204
  }
205
205
  }
@@ -390,11 +390,13 @@ export const handlers = ({
390
390
  customFeeConfig,
391
391
  swapAppVersion,
392
392
  sponsored,
393
+ isEmbedded,
393
394
  } = params;
394
395
 
395
396
  const trackingParams = {
396
397
  provider: params.provider,
397
398
  exchangeType: params.exchangeType,
399
+ isEmbeddedSwap: isEmbedded,
398
400
  };
399
401
 
400
402
  tracking.startExchangeRequested(trackingParams);
@@ -472,6 +474,7 @@ export const handlers = ({
472
474
  const trackingCompleteParams = {
473
475
  provider: params.provider,
474
476
  exchangeType: params.exchangeType,
477
+ isEmbeddedSwap: isEmbedded,
475
478
  };
476
479
  tracking.completeExchangeRequested(trackingCompleteParams);
477
480
 
@@ -14,8 +14,15 @@ type TrackExchange = (
14
14
  interface TrackEventPayload {
15
15
  exchangeType: "SELL" | "FUND" | "SWAP";
16
16
  provider: string;
17
+ isEmbeddedSwap?: boolean;
17
18
  }
18
19
 
20
+ /**
21
+ * Converts isEmbeddedSwap boolean to string for analytics consistency
22
+ */
23
+ const formatIsEmbeddedSwap = (isEmbeddedSwap?: boolean): string | undefined =>
24
+ isEmbeddedSwap !== undefined ? String(isEmbeddedSwap) : undefined;
25
+
19
26
  function getEventData(manifest: AppManifest) {
20
27
  return { walletAPI: manifest.name };
21
28
  }
@@ -29,24 +36,46 @@ function getEventData(manifest: AppManifest) {
29
36
  // in order to get the exact type matching the tracking wrapper API
30
37
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
31
38
  export default function trackingWrapper(trackCall: TrackExchange) {
32
- const track = (event: string, properties: Record<string, string> | null) => {
33
- return trackCall(event, properties, null);
39
+ const track = (event: string, properties: Record<string, string | undefined> | null) => {
40
+ // Filter out undefined values before passing to trackCall
41
+ if (!properties) {
42
+ return trackCall(event, null, null);
43
+ }
44
+ const filteredProperties: Record<string, string> = {};
45
+ for (const [key, value] of Object.entries(properties)) {
46
+ if (value !== undefined) {
47
+ filteredProperties[key] = value;
48
+ }
49
+ }
50
+ return trackCall(event, filteredProperties, null);
34
51
  };
35
52
 
36
53
  return {
37
54
  // Generate Exchange nonce modal open
38
- startExchangeRequested: ({ provider, exchangeType }: TrackEventPayload) => {
39
- track(`Starts Exchange ${exchangeType} Nonce request`, { provider, exchangeType });
55
+ startExchangeRequested: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
56
+ track(`Starts Exchange ${exchangeType} Nonce request`, {
57
+ provider,
58
+ exchangeType,
59
+ isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
60
+ });
40
61
  },
41
62
 
42
63
  // Successfully generated an Exchange app nonce
43
- startExchangeSuccess: ({ provider, exchangeType }: TrackEventPayload) => {
44
- track(`Starts Exchange ${exchangeType} Nonce success`, { provider, exchangeType });
64
+ startExchangeSuccess: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
65
+ track(`Starts Exchange ${exchangeType} Nonce success`, {
66
+ provider,
67
+ exchangeType,
68
+ isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
69
+ });
45
70
  },
46
71
 
47
72
  // Failed to generate an Exchange app nonce
48
- startExchangeFail: ({ provider, exchangeType }: TrackEventPayload) => {
49
- track(`Starts Exchange ${exchangeType} Nonce fail`, { provider, exchangeType });
73
+ startExchangeFail: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
74
+ track(`Starts Exchange ${exchangeType} Nonce fail`, {
75
+ provider,
76
+ exchangeType,
77
+ isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
78
+ });
50
79
  },
51
80
 
52
81
  // No Params to generate an Exchange app nonce
@@ -54,8 +83,12 @@ export default function trackingWrapper(trackCall: TrackExchange) {
54
83
  track("Starts Exchange no params", getEventData(manifest));
55
84
  },
56
85
 
57
- completeExchangeRequested: ({ provider, exchangeType }: TrackEventPayload) => {
58
- track(`Completes Exchange ${exchangeType} requested`, { provider, exchangeType });
86
+ completeExchangeRequested: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
87
+ track(`Completes Exchange ${exchangeType} requested`, {
88
+ provider,
89
+ exchangeType,
90
+ isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
91
+ });
59
92
  },
60
93
 
61
94
  // Successfully completed an Exchange
@@ -63,13 +96,23 @@ export default function trackingWrapper(trackCall: TrackExchange) {
63
96
  provider,
64
97
  exchangeType,
65
98
  currency,
99
+ isEmbeddedSwap,
66
100
  }: TrackEventPayload & { currency: string }) => {
67
- track(`Completes Exchange ${exchangeType} success`, { provider, exchangeType, currency });
101
+ track(`Completes Exchange ${exchangeType} success`, {
102
+ provider,
103
+ exchangeType,
104
+ currency,
105
+ isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
106
+ });
68
107
  },
69
108
 
70
109
  // Failed to complete an Exchange
71
- completeExchangeFail: ({ provider, exchangeType }: TrackEventPayload) => {
72
- track(`Completes Exchange ${exchangeType} Nonce fail`, { provider, exchangeType });
110
+ completeExchangeFail: ({ provider, exchangeType, isEmbeddedSwap }: TrackEventPayload) => {
111
+ track(`Completes Exchange ${exchangeType} Nonce fail`, {
112
+ provider,
113
+ exchangeType,
114
+ isEmbeddedSwap: formatIsEmbeddedSwap(isEmbeddedSwap),
115
+ });
73
116
  },
74
117
 
75
118
  // No Params to complete an Exchange
@@ -88,24 +88,25 @@ export async function signTransactionLogic(
88
88
  },
89
89
  ) => Promise<SignedOperation>,
90
90
  tokenCurrency?: string,
91
+ isEmbeddedSwap?: boolean,
91
92
  ): Promise<SignedOperation> {
92
- tracking.signTransactionRequested(manifest);
93
+ tracking.signTransactionRequested(manifest, isEmbeddedSwap);
93
94
 
94
95
  if (!transaction) {
95
- tracking.signTransactionFail(manifest);
96
+ tracking.signTransactionFail(manifest, isEmbeddedSwap);
96
97
  throw new Error("Transaction required");
97
98
  }
98
99
 
99
100
  const accountId = getAccountIdFromWalletAccountId(walletAccountId);
100
101
  if (!accountId) {
101
- tracking.signTransactionFail(manifest);
102
+ tracking.signTransactionFail(manifest, isEmbeddedSwap);
102
103
  throw new Error(`accountId ${walletAccountId} unknown`);
103
104
  }
104
105
 
105
106
  const account = accounts.find(account => account.id === accountId);
106
107
 
107
108
  if (!account) {
108
- tracking.signTransactionFail(manifest);
109
+ tracking.signTransactionFail(manifest, isEmbeddedSwap);
109
110
  throw new Error("Account required");
110
111
  }
111
112
 
@@ -806,8 +806,12 @@ export function useWalletAPIServer({
806
806
 
807
807
  server.setHandler(
808
808
  "transaction.signAndBroadcast",
809
- async ({ accountId, tokenCurrency, transaction, options }) => {
809
+ async ({ accountId, tokenCurrency, transaction, options, meta }) => {
810
810
  const sponsored = transaction.family === "ethereum" && transaction.sponsored;
811
+ // isEmbedded is passed via meta (not transaction) as it's a tracking param, not a tx property
812
+ const isEmbeddedSwap =
813
+ transaction.family === "ethereum" &&
814
+ (meta as { isEmbedded?: boolean } | undefined)?.isEmbedded;
811
815
 
812
816
  const signedTransaction = await signTransactionLogic(
813
817
  { manifest, accounts, tracking },
@@ -824,18 +828,19 @@ export function useWalletAPIServer({
824
828
  onSuccess: signedOperation => {
825
829
  if (done) return;
826
830
  done = true;
827
- tracking.signTransactionSuccess(manifest);
831
+ tracking.signTransactionSuccess(manifest, isEmbeddedSwap);
828
832
  resolve(signedOperation);
829
833
  },
830
834
  onError: error => {
831
835
  if (done) return;
832
836
  done = true;
833
- tracking.signTransactionFail(manifest);
837
+ tracking.signTransactionFail(manifest, isEmbeddedSwap);
834
838
  reject(error);
835
839
  },
836
840
  });
837
841
  }),
838
842
  tokenCurrency,
843
+ isEmbeddedSwap,
839
844
  );
840
845
 
841
846
  return broadcastTransactionLogic(
@@ -858,9 +863,9 @@ export function useWalletAPIServer({
858
863
  sponsored,
859
864
  },
860
865
  });
861
- tracking.broadcastSuccess(manifest);
866
+ tracking.broadcastSuccess(manifest, isEmbeddedSwap);
862
867
  } catch (error) {
863
- tracking.broadcastFail(manifest);
868
+ tracking.broadcastFail(manifest, isEmbeddedSwap);
864
869
  throw error;
865
870
  }
866
871
  }
@@ -56,18 +56,30 @@ export default function trackingWrapper(trackCall: TrackWalletAPI) {
56
56
  },
57
57
 
58
58
  // Sign transaction modal open
59
- signTransactionRequested: (manifest: AppManifest) => {
60
- track("WalletAPI SignTransaction", getEventData(manifest));
59
+ signTransactionRequested: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
60
+ const properties = {
61
+ ...getEventData(manifest),
62
+ ...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
63
+ };
64
+ track("WalletAPI SignTransaction", properties);
61
65
  },
62
66
 
63
67
  // Failed to sign transaction (cancel or error)
64
- signTransactionFail: (manifest: AppManifest) => {
65
- track("WalletAPI SignTransaction Fail", getEventData(manifest));
68
+ signTransactionFail: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
69
+ const properties = {
70
+ ...getEventData(manifest),
71
+ ...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
72
+ };
73
+ track("WalletAPI SignTransaction Fail", properties);
66
74
  },
67
75
 
68
76
  // Successfully signed transaction
69
- signTransactionSuccess: (manifest: AppManifest) => {
70
- track("WalletAPI SignTransaction Success", getEventData(manifest));
77
+ signTransactionSuccess: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
78
+ const properties = {
79
+ ...getEventData(manifest),
80
+ ...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
81
+ };
82
+ track("WalletAPI SignTransaction Success", properties);
71
83
  },
72
84
 
73
85
  // Sign Raw transaction modal open
@@ -116,13 +128,21 @@ export default function trackingWrapper(trackCall: TrackWalletAPI) {
116
128
  },
117
129
 
118
130
  // Failed to broadcast a signed transaction
119
- broadcastFail: (manifest: AppManifest) => {
120
- track("WalletAPI Broadcast Fail", getEventData(manifest));
131
+ broadcastFail: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
132
+ const properties = {
133
+ ...getEventData(manifest),
134
+ ...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
135
+ };
136
+ track("WalletAPI Broadcast Fail", properties);
121
137
  },
122
138
 
123
139
  // Successfully broadcast a signed transaction
124
- broadcastSuccess: (manifest: AppManifest) => {
125
- track("WalletAPI Broadcast Success", getEventData(manifest));
140
+ broadcastSuccess: (manifest: AppManifest, isEmbeddedSwap?: boolean) => {
141
+ const properties = {
142
+ ...getEventData(manifest),
143
+ ...(isEmbeddedSwap !== undefined && { isEmbeddedSwap: String(isEmbeddedSwap) }),
144
+ };
145
+ track("WalletAPI Broadcast Success", properties);
126
146
  },
127
147
 
128
148
  // Successfully broadcast a signed transaction