@ledgerhq/live-common 34.54.0-nightly.20251206023719 → 34.54.0-nightly.20251209140356

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 (212) hide show
  1. package/lib/__tests__/test-helpers/environment.js +2 -0
  2. package/lib/__tests__/test-helpers/environment.js.map +1 -1
  3. package/lib/account/serialization.js +1 -1
  4. package/lib/account/serialization.js.map +1 -1
  5. package/lib/account/support.js +1 -1
  6. package/lib/account/support.js.map +1 -1
  7. package/lib/bridge/generic-alpaca/getAccountShape.d.ts.map +1 -1
  8. package/lib/bridge/generic-alpaca/getAccountShape.js +3 -2
  9. package/lib/bridge/generic-alpaca/getAccountShape.js.map +1 -1
  10. package/lib/bridge/generic-alpaca/prepareTransaction.d.ts.map +1 -1
  11. package/lib/bridge/generic-alpaca/prepareTransaction.js +7 -0
  12. package/lib/bridge/generic-alpaca/prepareTransaction.js.map +1 -1
  13. package/lib/domain/getTokensWithFunds.d.ts +7 -1
  14. package/lib/domain/getTokensWithFunds.d.ts.map +1 -1
  15. package/lib/domain/getTokensWithFunds.js +15 -4
  16. package/lib/domain/getTokensWithFunds.js.map +1 -1
  17. package/lib/domain/getTotalStakeableAssets.d.ts +10 -0
  18. package/lib/domain/getTotalStakeableAssets.d.ts.map +1 -0
  19. package/lib/domain/getTotalStakeableAssets.js +35 -0
  20. package/lib/domain/getTotalStakeableAssets.js.map +1 -0
  21. package/lib/e2e/index.d.ts +9 -0
  22. package/lib/e2e/index.d.ts.map +1 -1
  23. package/lib/exchange/swap/api/v5/fetchCurrencyFrom.js +1 -1
  24. package/lib/exchange/swap/api/v5/fetchCurrencyFrom.js.map +1 -1
  25. package/lib/exchange/swap/getIncompatibleCurrencyKeys.d.ts.map +1 -1
  26. package/lib/exchange/swap/getIncompatibleCurrencyKeys.js +4 -0
  27. package/lib/exchange/swap/getIncompatibleCurrencyKeys.js.map +1 -1
  28. package/lib/exchange/swap/transactionStrategies.d.ts +2 -1
  29. package/lib/exchange/swap/transactionStrategies.d.ts.map +1 -1
  30. package/lib/exchange/swap/transactionStrategies.js +7 -6
  31. package/lib/exchange/swap/transactionStrategies.js.map +1 -1
  32. package/lib/featureFlags/defaultFeatures.d.ts +2 -0
  33. package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
  34. package/lib/featureFlags/defaultFeatures.js +3 -0
  35. package/lib/featureFlags/defaultFeatures.js.map +1 -1
  36. package/lib/featureFlags/firebaseFeatureFlags.js +1 -1
  37. package/lib/featureFlags/firebaseFeatureFlags.js.map +1 -1
  38. package/lib/featureFlags/useFeature.d.ts +1 -1
  39. package/lib/featureFlags/useFeature.d.ts.map +1 -1
  40. package/lib/featureFlags/useHasOverriddenFeatureFlags.js +1 -1
  41. package/lib/featureFlags/useHasOverriddenFeatureFlags.js.map +1 -1
  42. package/lib/hw/getBitcoinLikeInfo.js +1 -1
  43. package/lib/hw/getBitcoinLikeInfo.js.map +1 -1
  44. package/lib/mock/account.js +1 -1
  45. package/lib/mock/account.js.map +1 -1
  46. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.d.ts.map +1 -1
  47. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js +6 -0
  48. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js.map +1 -1
  49. package/lib/wallet-api/Exchange/SwapError.d.ts +93 -0
  50. package/lib/wallet-api/Exchange/SwapError.d.ts.map +1 -0
  51. package/lib/wallet-api/Exchange/SwapError.js +142 -0
  52. package/lib/wallet-api/Exchange/SwapError.js.map +1 -0
  53. package/lib/wallet-api/Exchange/handleSwapErrors.d.ts +40 -0
  54. package/lib/wallet-api/Exchange/handleSwapErrors.d.ts.map +1 -0
  55. package/lib/wallet-api/Exchange/handleSwapErrors.js +112 -0
  56. package/lib/wallet-api/Exchange/handleSwapErrors.js.map +1 -0
  57. package/lib/wallet-api/Exchange/index.d.ts +4 -0
  58. package/lib/wallet-api/Exchange/index.d.ts.map +1 -0
  59. package/lib/wallet-api/Exchange/index.js +27 -0
  60. package/lib/wallet-api/Exchange/index.js.map +1 -0
  61. package/lib/wallet-api/Exchange/parser.d.ts +46 -0
  62. package/lib/wallet-api/Exchange/parser.d.ts.map +1 -0
  63. package/lib/wallet-api/Exchange/parser.js +97 -0
  64. package/lib/wallet-api/Exchange/parser.js.map +1 -0
  65. package/lib/wallet-api/Exchange/server.d.ts.map +1 -1
  66. package/lib/wallet-api/Exchange/server.js +226 -177
  67. package/lib/wallet-api/Exchange/server.js.map +1 -1
  68. package/lib/wallet-api/Exchange/tracking.d.ts +7 -6
  69. package/lib/wallet-api/Exchange/tracking.d.ts.map +1 -1
  70. package/lib/wallet-api/Exchange/tracking.js +52 -13
  71. package/lib/wallet-api/Exchange/tracking.js.map +1 -1
  72. package/lib/wallet-api/logic.d.ts +1 -1
  73. package/lib/wallet-api/logic.d.ts.map +1 -1
  74. package/lib/wallet-api/logic.js +5 -5
  75. package/lib/wallet-api/logic.js.map +1 -1
  76. package/lib/wallet-api/react.d.ts.map +1 -1
  77. package/lib/wallet-api/react.js +9 -6
  78. package/lib/wallet-api/react.js.map +1 -1
  79. package/lib/wallet-api/tracking.d.ts +5 -5
  80. package/lib/wallet-api/tracking.d.ts.map +1 -1
  81. package/lib/wallet-api/tracking.js +30 -10
  82. package/lib/wallet-api/tracking.js.map +1 -1
  83. package/lib/wallet-api/useDappLogic.d.ts.map +1 -1
  84. package/lib/wallet-api/useDappLogic.js +31 -20
  85. package/lib/wallet-api/useDappLogic.js.map +1 -1
  86. package/lib/wallet-api/utils/extractDappURLFromManifest.js +3 -3
  87. package/lib/wallet-api/utils/extractDappURLFromManifest.js.map +1 -1
  88. package/lib/wallet-api/utils/extractURLFromManifest.js +1 -1
  89. package/lib/wallet-api/utils/extractURLFromManifest.js.map +1 -1
  90. package/lib-es/__tests__/test-helpers/environment.js +2 -0
  91. package/lib-es/__tests__/test-helpers/environment.js.map +1 -1
  92. package/lib-es/account/serialization.js +1 -1
  93. package/lib-es/account/serialization.js.map +1 -1
  94. package/lib-es/account/support.js +1 -1
  95. package/lib-es/account/support.js.map +1 -1
  96. package/lib-es/bridge/generic-alpaca/getAccountShape.d.ts.map +1 -1
  97. package/lib-es/bridge/generic-alpaca/getAccountShape.js +3 -2
  98. package/lib-es/bridge/generic-alpaca/getAccountShape.js.map +1 -1
  99. package/lib-es/bridge/generic-alpaca/prepareTransaction.d.ts.map +1 -1
  100. package/lib-es/bridge/generic-alpaca/prepareTransaction.js +7 -0
  101. package/lib-es/bridge/generic-alpaca/prepareTransaction.js.map +1 -1
  102. package/lib-es/domain/getTokensWithFunds.d.ts +7 -1
  103. package/lib-es/domain/getTokensWithFunds.d.ts.map +1 -1
  104. package/lib-es/domain/getTokensWithFunds.js +13 -3
  105. package/lib-es/domain/getTokensWithFunds.js.map +1 -1
  106. package/lib-es/domain/getTotalStakeableAssets.d.ts +10 -0
  107. package/lib-es/domain/getTotalStakeableAssets.d.ts.map +1 -0
  108. package/lib-es/domain/getTotalStakeableAssets.js +31 -0
  109. package/lib-es/domain/getTotalStakeableAssets.js.map +1 -0
  110. package/lib-es/e2e/index.d.ts +9 -0
  111. package/lib-es/e2e/index.d.ts.map +1 -1
  112. package/lib-es/exchange/swap/api/v5/fetchCurrencyFrom.js +1 -1
  113. package/lib-es/exchange/swap/api/v5/fetchCurrencyFrom.js.map +1 -1
  114. package/lib-es/exchange/swap/getIncompatibleCurrencyKeys.d.ts.map +1 -1
  115. package/lib-es/exchange/swap/getIncompatibleCurrencyKeys.js +4 -0
  116. package/lib-es/exchange/swap/getIncompatibleCurrencyKeys.js.map +1 -1
  117. package/lib-es/exchange/swap/transactionStrategies.d.ts +2 -1
  118. package/lib-es/exchange/swap/transactionStrategies.d.ts.map +1 -1
  119. package/lib-es/exchange/swap/transactionStrategies.js +7 -6
  120. package/lib-es/exchange/swap/transactionStrategies.js.map +1 -1
  121. package/lib-es/featureFlags/defaultFeatures.d.ts +2 -0
  122. package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -1
  123. package/lib-es/featureFlags/defaultFeatures.js +3 -0
  124. package/lib-es/featureFlags/defaultFeatures.js.map +1 -1
  125. package/lib-es/featureFlags/firebaseFeatureFlags.js +1 -1
  126. package/lib-es/featureFlags/firebaseFeatureFlags.js.map +1 -1
  127. package/lib-es/featureFlags/useFeature.d.ts +1 -1
  128. package/lib-es/featureFlags/useFeature.d.ts.map +1 -1
  129. package/lib-es/featureFlags/useHasOverriddenFeatureFlags.js +1 -1
  130. package/lib-es/featureFlags/useHasOverriddenFeatureFlags.js.map +1 -1
  131. package/lib-es/hw/getBitcoinLikeInfo.js +1 -1
  132. package/lib-es/hw/getBitcoinLikeInfo.js.map +1 -1
  133. package/lib-es/mock/account.js +1 -1
  134. package/lib-es/mock/account.js.map +1 -1
  135. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.d.ts.map +1 -1
  136. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js +6 -0
  137. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js.map +1 -1
  138. package/lib-es/wallet-api/Exchange/SwapError.d.ts +93 -0
  139. package/lib-es/wallet-api/Exchange/SwapError.d.ts.map +1 -0
  140. package/lib-es/wallet-api/Exchange/SwapError.js +128 -0
  141. package/lib-es/wallet-api/Exchange/SwapError.js.map +1 -0
  142. package/lib-es/wallet-api/Exchange/handleSwapErrors.d.ts +40 -0
  143. package/lib-es/wallet-api/Exchange/handleSwapErrors.d.ts.map +1 -0
  144. package/lib-es/wallet-api/Exchange/handleSwapErrors.js +106 -0
  145. package/lib-es/wallet-api/Exchange/handleSwapErrors.js.map +1 -0
  146. package/lib-es/wallet-api/Exchange/index.d.ts +4 -0
  147. package/lib-es/wallet-api/Exchange/index.d.ts.map +1 -0
  148. package/lib-es/wallet-api/Exchange/index.js +7 -0
  149. package/lib-es/wallet-api/Exchange/index.js.map +1 -0
  150. package/lib-es/wallet-api/Exchange/parser.d.ts +46 -0
  151. package/lib-es/wallet-api/Exchange/parser.d.ts.map +1 -0
  152. package/lib-es/wallet-api/Exchange/parser.js +90 -0
  153. package/lib-es/wallet-api/Exchange/parser.js.map +1 -0
  154. package/lib-es/wallet-api/Exchange/server.d.ts.map +1 -1
  155. package/lib-es/wallet-api/Exchange/server.js +223 -177
  156. package/lib-es/wallet-api/Exchange/server.js.map +1 -1
  157. package/lib-es/wallet-api/Exchange/tracking.d.ts +7 -6
  158. package/lib-es/wallet-api/Exchange/tracking.d.ts.map +1 -1
  159. package/lib-es/wallet-api/Exchange/tracking.js +52 -13
  160. package/lib-es/wallet-api/Exchange/tracking.js.map +1 -1
  161. package/lib-es/wallet-api/logic.d.ts +1 -1
  162. package/lib-es/wallet-api/logic.d.ts.map +1 -1
  163. package/lib-es/wallet-api/logic.js +5 -5
  164. package/lib-es/wallet-api/logic.js.map +1 -1
  165. package/lib-es/wallet-api/react.d.ts.map +1 -1
  166. package/lib-es/wallet-api/react.js +9 -6
  167. package/lib-es/wallet-api/react.js.map +1 -1
  168. package/lib-es/wallet-api/tracking.d.ts +5 -5
  169. package/lib-es/wallet-api/tracking.d.ts.map +1 -1
  170. package/lib-es/wallet-api/tracking.js +30 -10
  171. package/lib-es/wallet-api/tracking.js.map +1 -1
  172. package/lib-es/wallet-api/useDappLogic.d.ts.map +1 -1
  173. package/lib-es/wallet-api/useDappLogic.js +31 -20
  174. package/lib-es/wallet-api/useDappLogic.js.map +1 -1
  175. package/lib-es/wallet-api/utils/extractDappURLFromManifest.js +3 -3
  176. package/lib-es/wallet-api/utils/extractDappURLFromManifest.js.map +1 -1
  177. package/lib-es/wallet-api/utils/extractURLFromManifest.js +1 -1
  178. package/lib-es/wallet-api/utils/extractURLFromManifest.js.map +1 -1
  179. package/package.json +73 -73
  180. package/src/__tests__/test-helpers/environment.ts +2 -0
  181. package/src/account/serialization.ts +1 -1
  182. package/src/account/support.ts +1 -1
  183. package/src/bridge/generic-alpaca/getAccountShape.ts +4 -2
  184. package/src/bridge/generic-alpaca/prepareTransaction.ts +7 -0
  185. package/src/bridge/generic-alpaca/tests/prepareTransaction.test.ts +42 -0
  186. package/src/domain/getTokensWithFunds.ts +18 -5
  187. package/src/domain/getTotalStakeableAssets.test.ts +267 -0
  188. package/src/domain/getTotalStakeableAssets.ts +47 -0
  189. package/src/exchange/swap/api/v5/fetchCurrencyFrom.ts +1 -1
  190. package/src/exchange/swap/getIncompatibleCurrencyKeys.ts +4 -0
  191. package/src/exchange/swap/transactionStrategies.ts +8 -7
  192. package/src/featureFlags/defaultFeatures.ts +3 -0
  193. package/src/featureFlags/firebaseFeatureFlags.ts +1 -1
  194. package/src/featureFlags/useHasOverriddenFeatureFlags.ts +1 -1
  195. package/src/hw/getBitcoinLikeInfo.ts +1 -1
  196. package/src/mock/account.ts +1 -1
  197. package/src/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.ts +6 -0
  198. package/src/wallet-api/Exchange/SwapError.test.ts +126 -0
  199. package/src/wallet-api/Exchange/SwapError.ts +159 -0
  200. package/src/wallet-api/Exchange/handleSwapErrors.test.ts +46 -0
  201. package/src/wallet-api/Exchange/handleSwapErrors.ts +161 -0
  202. package/src/wallet-api/Exchange/index.ts +26 -0
  203. package/src/wallet-api/Exchange/parser.test.ts +86 -0
  204. package/src/wallet-api/Exchange/parser.ts +119 -0
  205. package/src/wallet-api/Exchange/server.ts +287 -235
  206. package/src/wallet-api/Exchange/tracking.ts +56 -13
  207. package/src/wallet-api/logic.ts +5 -4
  208. package/src/wallet-api/react.ts +10 -5
  209. package/src/wallet-api/tracking.ts +30 -10
  210. package/src/wallet-api/useDappLogic.ts +32 -20
  211. package/src/wallet-api/utils/extractDappURLFromManifest.ts +3 -3
  212. 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
  }
@@ -83,6 +83,10 @@ const INCOMPATIBLE_NANO_S_CURRENCY_KEYS: Keys = {
83
83
  title: "swap.incompatibility.celo_title",
84
84
  description: "swap.incompatibility.celo_description",
85
85
  },
86
+ monad: {
87
+ title: "swap.incompatibility.monad_title",
88
+ description: "swap.incompatibility.monad_description",
89
+ },
86
90
  };
87
91
 
88
92
  export const getIncompatibleCurrencyKeys = (exchange: ExchangeSwap) => {
@@ -2,6 +2,7 @@ import { BigNumber } from "bignumber.js";
2
2
 
3
3
  import { Transaction } from "../../generated/types";
4
4
  import { TransactionCommon } from "@ledgerhq/types-live";
5
+ import { createStepError, StepError, CustomErrorType } from "../../wallet-api/Exchange";
5
6
  export type { SwapLiveError } from "@ledgerhq/wallet-api-exchange-module";
6
7
 
7
8
  export function defaultTransaction({
@@ -85,11 +86,11 @@ export function stellarTransaction({
85
86
  customErrorType,
86
87
  }: TransactionWithCustomFee): Extract<Transaction, { family: "stellar" }> {
87
88
  if (!payinExtraId)
88
- throw {
89
+ throw createStepError({
89
90
  error: new Error("Missing payinExtraId"),
90
- step: "PayinExtraIdStepError",
91
+ step: StepError.PAYIN_EXTRA_ID,
91
92
  customErrorType,
92
- };
93
+ });
93
94
 
94
95
  return {
95
96
  family: "stellar",
@@ -110,11 +111,11 @@ export function rippleTransaction({
110
111
  customErrorType,
111
112
  }: TransactionWithCustomFee): Partial<Extract<Transaction, { family: "xrp" }>> {
112
113
  if (!payinExtraId)
113
- throw {
114
+ throw createStepError({
114
115
  error: new Error("Missing payinExtraId"),
115
- step: "PayinExtraIdStepError",
116
+ step: StepError.PAYIN_EXTRA_ID,
116
117
  customErrorType,
117
- };
118
+ });
118
119
 
119
120
  return {
120
121
  family: "xrp",
@@ -257,7 +258,7 @@ export type TransactionWithCustomFee = TransactionCommon & {
257
258
  [key: string]: BigNumber;
258
259
  };
259
260
  payinExtraId?: string;
260
- customErrorType?: "swap";
261
+ customErrorType?: CustomErrorType;
261
262
  extraTransactionParameters?: string;
262
263
  family: string;
263
264
  sponsored?: boolean;
@@ -110,6 +110,8 @@ export const CURRENCY_DEFAULT_FEATURES = {
110
110
  currencyMonadTestnet: DEFAULT_FEATURE,
111
111
  currencySomnia: DEFAULT_FEATURE,
112
112
  currencyZeroGravity: DEFAULT_FEATURE,
113
+ currencyConcordium: DEFAULT_FEATURE,
114
+ currencyConcordiumTestnet: DEFAULT_FEATURE,
113
115
  };
114
116
 
115
117
  /**
@@ -735,6 +737,7 @@ export const DEFAULT_FEATURES: Features = {
735
737
  zcashShielded: DEFAULT_FEATURE,
736
738
  llmNanoOnboardingFundWallet: DEFAULT_FEATURE,
737
739
  lldRebornABtest: DEFAULT_FEATURE,
740
+ llmRebornABtest: DEFAULT_FEATURE,
738
741
  };
739
742
 
740
743
  // 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
  }
@@ -83,6 +83,8 @@ export function useCurrenciesUnderFeatureFlag() {
83
83
  const monadTestnet = useFeature("currencyMonadTestnet");
84
84
  const somnia = useFeature("currencySomnia");
85
85
  const zeroGravity = useFeature("currencyZeroGravity");
86
+ const concordium = useFeature("currencyConcordium");
87
+ const concordiumTestnet = useFeature("currencyConcordiumTestnet");
86
88
 
87
89
  const featureFlaggedCurrencies = useMemo(
88
90
  (): Partial<Record<CryptoCurrencyId, Feature<unknown> | null>> => ({
@@ -162,6 +164,8 @@ export function useCurrenciesUnderFeatureFlag() {
162
164
  monad_testnet: monadTestnet,
163
165
  somnia,
164
166
  zero_gravity: zeroGravity,
167
+ concordium,
168
+ concordium_testnet: concordiumTestnet,
165
169
  }),
166
170
  [
167
171
  aptos,
@@ -240,6 +244,8 @@ export function useCurrenciesUnderFeatureFlag() {
240
244
  monadTestnet,
241
245
  somnia,
242
246
  zeroGravity,
247
+ concordium,
248
+ concordiumTestnet,
243
249
  ],
244
250
  );
245
251
 
@@ -0,0 +1,126 @@
1
+ /* eslint-env jest */
2
+ import {
3
+ IgnoredSignatureStepError,
4
+ ListAccountError,
5
+ ListCurrencyError,
6
+ NonceStepError,
7
+ NotEnoughFunds,
8
+ PayloadStepError,
9
+ PayinExtraIdError,
10
+ SignatureStepError,
11
+ SwapError,
12
+ UnknownAccountError,
13
+ } from "./SwapError";
14
+
15
+ describe("SwapError", () => {
16
+ it("captures nested error metadata", () => {
17
+ const nested = new Error("payload failed");
18
+ Object.assign(nested, { code: "E500" });
19
+
20
+ const error = new SwapError("swap999", nested);
21
+
22
+ expect(error).toBeInstanceOf(SwapError);
23
+ expect(error.cause.swapCode).toBe("swap999");
24
+ expect(error.cause.message).toBe(String(nested));
25
+ expect(error.cause.code).toBe("E500");
26
+ expect(error.message).toBe("payload failed");
27
+ });
28
+
29
+ it("defaults to swap000 when no code provided", () => {
30
+ const error = new SwapError();
31
+
32
+ expect(error.cause.swapCode).toBe("swap000");
33
+ expect(error.message).toBe("undefined");
34
+ });
35
+ });
36
+
37
+ type DerivedErrorCase = {
38
+ label: string;
39
+ create: (nested?: Error) => SwapError;
40
+ swapCode: string;
41
+ name: string;
42
+ propagatesMessage?: boolean;
43
+ };
44
+
45
+ const DERIVED_ERROR_CASES: DerivedErrorCase[] = [
46
+ {
47
+ label: "NonceStepError",
48
+ create: nested => new NonceStepError(nested),
49
+ swapCode: "swap001",
50
+ name: "NonceStepError",
51
+ propagatesMessage: true,
52
+ },
53
+ {
54
+ label: "PayloadStepError",
55
+ create: nested => new PayloadStepError(nested),
56
+ swapCode: "swap002",
57
+ name: "PayloadStepError",
58
+ propagatesMessage: true,
59
+ },
60
+ {
61
+ label: "SignatureStepError",
62
+ create: nested => new SignatureStepError(nested),
63
+ swapCode: "swap003",
64
+ name: "SignatureStepError",
65
+ propagatesMessage: true,
66
+ },
67
+ {
68
+ label: "IgnoredSignatureStepError",
69
+ create: nested => new IgnoredSignatureStepError(nested),
70
+ swapCode: "swap003Ignored",
71
+ name: "SignatureStepError",
72
+ propagatesMessage: true,
73
+ },
74
+ {
75
+ label: "NotEnoughFunds",
76
+ create: () => new NotEnoughFunds(),
77
+ swapCode: "swap004",
78
+ name: "NotEnoughFunds",
79
+ },
80
+ {
81
+ label: "ListAccountError",
82
+ create: nested => new ListAccountError(nested),
83
+ swapCode: "swap005",
84
+ name: "ListAccountError",
85
+ propagatesMessage: true,
86
+ },
87
+ {
88
+ label: "ListCurrencyError",
89
+ create: nested => new ListCurrencyError(nested),
90
+ swapCode: "swap006",
91
+ name: "ListCurrencyError",
92
+ propagatesMessage: true,
93
+ },
94
+ {
95
+ label: "UnknownAccountError",
96
+ create: nested => new UnknownAccountError(nested),
97
+ swapCode: "swap007",
98
+ name: "UnknownAccountError",
99
+ propagatesMessage: true,
100
+ },
101
+ {
102
+ label: "PayinExtraIdError",
103
+ create: nested => new PayinExtraIdError(nested),
104
+ swapCode: "swap010",
105
+ name: "PayinExtraIdError",
106
+ propagatesMessage: true,
107
+ },
108
+ ];
109
+
110
+ describe.each(DERIVED_ERROR_CASES)(
111
+ "Derived $label",
112
+ ({ create, swapCode, name, propagatesMessage }) => {
113
+ it("inherits SwapError defaults", () => {
114
+ const nested = new Error("step failure");
115
+ const error = create(propagatesMessage ? nested : undefined);
116
+
117
+ expect(error).toBeInstanceOf(SwapError);
118
+ expect(error.name).toBe(name);
119
+ expect(error.cause.swapCode).toBe(swapCode);
120
+
121
+ if (propagatesMessage) {
122
+ expect(error.message).toBe("step failure");
123
+ }
124
+ });
125
+ },
126
+ );