@ledgerhq/live-common 34.35.1-hotfix.0 → 34.36.0-next.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 (249) hide show
  1. package/lib/apps/support.d.ts +1 -0
  2. package/lib/apps/support.d.ts.map +1 -1
  3. package/lib/apps/support.js +10 -1
  4. package/lib/apps/support.js.map +1 -1
  5. package/lib/e2e/enum/Account.d.ts +64 -58
  6. package/lib/e2e/enum/Account.d.ts.map +1 -1
  7. package/lib/e2e/enum/Account.js +80 -59
  8. package/lib/e2e/enum/Account.js.map +1 -1
  9. package/lib/e2e/enum/Device.d.ts +8 -0
  10. package/lib/e2e/enum/Device.d.ts.map +1 -0
  11. package/lib/e2e/enum/Device.js +14 -0
  12. package/lib/e2e/enum/Device.js.map +1 -0
  13. package/lib/e2e/enum/Swap.d.ts +2 -1
  14. package/lib/e2e/enum/Swap.d.ts.map +1 -1
  15. package/lib/e2e/enum/Swap.js +12 -10
  16. package/lib/e2e/enum/Swap.js.map +1 -1
  17. package/lib/e2e/families/cardano.d.ts.map +1 -1
  18. package/lib/e2e/families/cardano.js +55 -26
  19. package/lib/e2e/families/cardano.js.map +1 -1
  20. package/lib/e2e/families/evm.d.ts.map +1 -1
  21. package/lib/e2e/families/evm.js +2 -1
  22. package/lib/e2e/families/evm.js.map +1 -1
  23. package/lib/e2e/families/solana.d.ts.map +1 -1
  24. package/lib/e2e/families/solana.js +5 -2
  25. package/lib/e2e/families/solana.js.map +1 -1
  26. package/lib/e2e/index.d.ts +2 -0
  27. package/lib/e2e/index.d.ts.map +1 -1
  28. package/lib/e2e/models/BuySell.d.ts +11 -0
  29. package/lib/e2e/models/BuySell.d.ts.map +1 -0
  30. package/lib/{index.js → e2e/models/BuySell.js} +1 -1
  31. package/lib/e2e/models/BuySell.js.map +1 -0
  32. package/lib/e2e/models/Transaction.d.ts +5 -5
  33. package/lib/e2e/models/Transaction.d.ts.map +1 -1
  34. package/lib/e2e/models/Transaction.js.map +1 -1
  35. package/lib/e2e/speculos.d.ts +6 -1
  36. package/lib/e2e/speculos.d.ts.map +1 -1
  37. package/lib/e2e/speculos.js +72 -40
  38. package/lib/e2e/speculos.js.map +1 -1
  39. package/lib/e2e/speculosCI.d.ts +5 -0
  40. package/lib/e2e/speculosCI.d.ts.map +1 -0
  41. package/lib/e2e/speculosCI.js +129 -0
  42. package/lib/e2e/speculosCI.js.map +1 -0
  43. package/lib/families/hedera/logic.d.ts +2 -0
  44. package/lib/families/hedera/logic.d.ts.map +1 -0
  45. package/lib/families/hedera/logic.js +19 -0
  46. package/lib/families/hedera/logic.js.map +1 -0
  47. package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
  48. package/lib/featureFlags/defaultFeatures.js +1 -0
  49. package/lib/featureFlags/defaultFeatures.js.map +1 -1
  50. package/lib/featureFlags/useFeature.d.ts +1 -1
  51. package/lib/featureFlags/useFeature.d.ts.map +1 -1
  52. package/lib/hw/actions/manager.d.ts +1 -1
  53. package/lib/hw/actions/manager.d.ts.map +1 -1
  54. package/lib/hw/connectApp.d.ts.map +1 -1
  55. package/lib/hw/connectApp.js +56 -5
  56. package/lib/hw/connectApp.js.map +1 -1
  57. package/lib/hw/connectAppEventMapper.d.ts +29 -0
  58. package/lib/hw/connectAppEventMapper.d.ts.map +1 -0
  59. package/lib/hw/connectAppEventMapper.js +300 -0
  60. package/lib/hw/connectAppEventMapper.js.map +1 -0
  61. package/lib/hw/connectManager.d.ts +3 -2
  62. package/lib/hw/connectManager.d.ts.map +1 -1
  63. package/lib/hw/connectManager.js +34 -3
  64. package/lib/hw/connectManager.js.map +1 -1
  65. package/lib/hw/connectManagerEventMapper.d.ts +16 -0
  66. package/lib/hw/connectManagerEventMapper.d.ts.map +1 -0
  67. package/lib/hw/connectManagerEventMapper.js +78 -0
  68. package/lib/hw/connectManagerEventMapper.js.map +1 -0
  69. package/lib/market/hooks/useLargeMoverChartData.d.ts +18 -0
  70. package/lib/market/hooks/useLargeMoverChartData.d.ts.map +1 -0
  71. package/lib/market/hooks/useLargeMoverChartData.js +28 -0
  72. package/lib/market/hooks/useLargeMoverChartData.js.map +1 -0
  73. package/lib/market/hooks/useLargeMoverCurrencies.d.ts +13 -0
  74. package/lib/market/hooks/useLargeMoverCurrencies.d.ts.map +1 -0
  75. package/lib/market/hooks/useLargeMoverCurrencies.js +29 -0
  76. package/lib/market/hooks/useLargeMoverCurrencies.js.map +1 -0
  77. package/lib/notifications/AnnouncementProvider/index.d.ts.map +1 -1
  78. package/lib/notifications/AnnouncementProvider/index.js +12 -10
  79. package/lib/notifications/AnnouncementProvider/index.js.map +1 -1
  80. package/lib/notifications/AnnouncementProvider/machine.d.ts +1 -4
  81. package/lib/notifications/AnnouncementProvider/machine.d.ts.map +1 -1
  82. package/lib/notifications/AnnouncementProvider/machine.js +9 -8
  83. package/lib/notifications/AnnouncementProvider/machine.js.map +1 -1
  84. package/lib/notifications/ServiceStatusProvider/index.d.ts.map +1 -1
  85. package/lib/notifications/ServiceStatusProvider/index.js +5 -4
  86. package/lib/notifications/ServiceStatusProvider/index.js.map +1 -1
  87. package/lib/notifications/ServiceStatusProvider/machine.d.ts +1 -4
  88. package/lib/notifications/ServiceStatusProvider/machine.d.ts.map +1 -1
  89. package/lib/notifications/ServiceStatusProvider/machine.js +4 -4
  90. package/lib/notifications/ServiceStatusProvider/machine.js.map +1 -1
  91. package/lib/wallet-api/ModularDrawer/types.d.ts +63 -0
  92. package/lib/wallet-api/ModularDrawer/types.d.ts.map +1 -0
  93. package/lib/wallet-api/ModularDrawer/types.js +25 -0
  94. package/lib/wallet-api/ModularDrawer/types.js.map +1 -0
  95. package/lib/wallet-api/ModularDrawer/utils.d.ts +5 -0
  96. package/lib/wallet-api/ModularDrawer/utils.d.ts.map +1 -0
  97. package/lib/wallet-api/ModularDrawer/utils.js +30 -0
  98. package/lib/wallet-api/ModularDrawer/utils.js.map +1 -0
  99. package/lib/wallet-api/react.d.ts +2 -0
  100. package/lib/wallet-api/react.d.ts.map +1 -1
  101. package/lib/wallet-api/react.js +2 -1
  102. package/lib/wallet-api/react.js.map +1 -1
  103. package/lib-es/apps/support.d.ts +1 -0
  104. package/lib-es/apps/support.d.ts.map +1 -1
  105. package/lib-es/apps/support.js +8 -0
  106. package/lib-es/apps/support.js.map +1 -1
  107. package/lib-es/e2e/enum/Account.d.ts +64 -58
  108. package/lib-es/e2e/enum/Account.d.ts.map +1 -1
  109. package/lib-es/e2e/enum/Account.js +76 -58
  110. package/lib-es/e2e/enum/Account.js.map +1 -1
  111. package/lib-es/e2e/enum/Device.d.ts +8 -0
  112. package/lib-es/e2e/enum/Device.d.ts.map +1 -0
  113. package/lib-es/e2e/enum/Device.js +10 -0
  114. package/lib-es/e2e/enum/Device.js.map +1 -0
  115. package/lib-es/e2e/enum/Swap.d.ts +2 -1
  116. package/lib-es/e2e/enum/Swap.d.ts.map +1 -1
  117. package/lib-es/e2e/enum/Swap.js +12 -10
  118. package/lib-es/e2e/enum/Swap.js.map +1 -1
  119. package/lib-es/e2e/families/cardano.d.ts.map +1 -1
  120. package/lib-es/e2e/families/cardano.js +56 -27
  121. package/lib-es/e2e/families/cardano.js.map +1 -1
  122. package/lib-es/e2e/families/evm.d.ts.map +1 -1
  123. package/lib-es/e2e/families/evm.js +2 -1
  124. package/lib-es/e2e/families/evm.js.map +1 -1
  125. package/lib-es/e2e/families/solana.d.ts.map +1 -1
  126. package/lib-es/e2e/families/solana.js +5 -2
  127. package/lib-es/e2e/families/solana.js.map +1 -1
  128. package/lib-es/e2e/index.d.ts +2 -0
  129. package/lib-es/e2e/index.d.ts.map +1 -1
  130. package/lib-es/e2e/models/BuySell.d.ts +11 -0
  131. package/lib-es/e2e/models/BuySell.d.ts.map +1 -0
  132. package/lib-es/e2e/models/BuySell.js +2 -0
  133. package/lib-es/e2e/models/BuySell.js.map +1 -0
  134. package/lib-es/e2e/models/Transaction.d.ts +5 -5
  135. package/lib-es/e2e/models/Transaction.d.ts.map +1 -1
  136. package/lib-es/e2e/models/Transaction.js.map +1 -1
  137. package/lib-es/e2e/speculos.d.ts +6 -1
  138. package/lib-es/e2e/speculos.d.ts.map +1 -1
  139. package/lib-es/e2e/speculos.js +69 -39
  140. package/lib-es/e2e/speculos.js.map +1 -1
  141. package/lib-es/e2e/speculosCI.d.ts +5 -0
  142. package/lib-es/e2e/speculosCI.d.ts.map +1 -0
  143. package/lib-es/e2e/speculosCI.js +121 -0
  144. package/lib-es/e2e/speculosCI.js.map +1 -0
  145. package/lib-es/families/hedera/logic.d.ts +2 -0
  146. package/lib-es/families/hedera/logic.d.ts.map +1 -0
  147. package/lib-es/families/hedera/logic.js +3 -0
  148. package/lib-es/families/hedera/logic.js.map +1 -0
  149. package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -1
  150. package/lib-es/featureFlags/defaultFeatures.js +1 -0
  151. package/lib-es/featureFlags/defaultFeatures.js.map +1 -1
  152. package/lib-es/featureFlags/useFeature.d.ts +1 -1
  153. package/lib-es/featureFlags/useFeature.d.ts.map +1 -1
  154. package/lib-es/hw/actions/manager.d.ts +1 -1
  155. package/lib-es/hw/actions/manager.d.ts.map +1 -1
  156. package/lib-es/hw/connectApp.d.ts.map +1 -1
  157. package/lib-es/hw/connectApp.js +57 -6
  158. package/lib-es/hw/connectApp.js.map +1 -1
  159. package/lib-es/hw/connectAppEventMapper.d.ts +29 -0
  160. package/lib-es/hw/connectAppEventMapper.d.ts.map +1 -0
  161. package/lib-es/hw/connectAppEventMapper.js +296 -0
  162. package/lib-es/hw/connectAppEventMapper.js.map +1 -0
  163. package/lib-es/hw/connectManager.d.ts +3 -2
  164. package/lib-es/hw/connectManager.d.ts.map +1 -1
  165. package/lib-es/hw/connectManager.js +34 -4
  166. package/lib-es/hw/connectManager.js.map +1 -1
  167. package/lib-es/hw/connectManagerEventMapper.d.ts +16 -0
  168. package/lib-es/hw/connectManagerEventMapper.d.ts.map +1 -0
  169. package/lib-es/hw/connectManagerEventMapper.js +74 -0
  170. package/lib-es/hw/connectManagerEventMapper.js.map +1 -0
  171. package/lib-es/market/hooks/useLargeMoverChartData.d.ts +18 -0
  172. package/lib-es/market/hooks/useLargeMoverChartData.d.ts.map +1 -0
  173. package/lib-es/market/hooks/useLargeMoverChartData.js +24 -0
  174. package/lib-es/market/hooks/useLargeMoverChartData.js.map +1 -0
  175. package/lib-es/market/hooks/useLargeMoverCurrencies.d.ts +13 -0
  176. package/lib-es/market/hooks/useLargeMoverCurrencies.d.ts.map +1 -0
  177. package/lib-es/market/hooks/useLargeMoverCurrencies.js +25 -0
  178. package/lib-es/market/hooks/useLargeMoverCurrencies.js.map +1 -0
  179. package/lib-es/notifications/AnnouncementProvider/index.d.ts.map +1 -1
  180. package/lib-es/notifications/AnnouncementProvider/index.js +12 -10
  181. package/lib-es/notifications/AnnouncementProvider/index.js.map +1 -1
  182. package/lib-es/notifications/AnnouncementProvider/machine.d.ts +1 -4
  183. package/lib-es/notifications/AnnouncementProvider/machine.d.ts.map +1 -1
  184. package/lib-es/notifications/AnnouncementProvider/machine.js +9 -8
  185. package/lib-es/notifications/AnnouncementProvider/machine.js.map +1 -1
  186. package/lib-es/notifications/ServiceStatusProvider/index.d.ts.map +1 -1
  187. package/lib-es/notifications/ServiceStatusProvider/index.js +5 -4
  188. package/lib-es/notifications/ServiceStatusProvider/index.js.map +1 -1
  189. package/lib-es/notifications/ServiceStatusProvider/machine.d.ts +1 -4
  190. package/lib-es/notifications/ServiceStatusProvider/machine.d.ts.map +1 -1
  191. package/lib-es/notifications/ServiceStatusProvider/machine.js +4 -4
  192. package/lib-es/notifications/ServiceStatusProvider/machine.js.map +1 -1
  193. package/lib-es/wallet-api/ModularDrawer/types.d.ts +63 -0
  194. package/lib-es/wallet-api/ModularDrawer/types.d.ts.map +1 -0
  195. package/lib-es/wallet-api/ModularDrawer/types.js +22 -0
  196. package/lib-es/wallet-api/ModularDrawer/types.js.map +1 -0
  197. package/lib-es/wallet-api/ModularDrawer/utils.d.ts +5 -0
  198. package/lib-es/wallet-api/ModularDrawer/utils.d.ts.map +1 -0
  199. package/lib-es/wallet-api/ModularDrawer/utils.js +25 -0
  200. package/lib-es/wallet-api/ModularDrawer/utils.js.map +1 -0
  201. package/lib-es/wallet-api/react.d.ts +2 -0
  202. package/lib-es/wallet-api/react.d.ts.map +1 -1
  203. package/lib-es/wallet-api/react.js +2 -1
  204. package/lib-es/wallet-api/react.js.map +1 -1
  205. package/package.json +54 -53
  206. package/src/apps/support.ts +11 -0
  207. package/src/e2e/enum/Account.ts +363 -362
  208. package/src/e2e/enum/Device.ts +7 -0
  209. package/src/e2e/enum/Swap.ts +10 -9
  210. package/src/e2e/families/cardano.ts +63 -28
  211. package/src/e2e/families/evm.ts +2 -1
  212. package/src/e2e/families/solana.ts +5 -2
  213. package/src/e2e/models/BuySell.ts +12 -0
  214. package/src/e2e/models/Transaction.ts +5 -5
  215. package/src/e2e/speculos.ts +75 -41
  216. package/src/e2e/speculosCI.ts +161 -0
  217. package/src/families/hedera/logic.ts +2 -0
  218. package/src/featureFlags/defaultFeatures.ts +1 -0
  219. package/src/hw/actions/manager.ts +1 -1
  220. package/src/hw/connectApp.ts +245 -178
  221. package/src/hw/connectAppEventMapper.ts +364 -0
  222. package/src/hw/connectManager.ts +116 -74
  223. package/src/hw/connectManagerEventMapper.ts +109 -0
  224. package/src/market/hooks/useLargeMoverChartData.ts +38 -0
  225. package/src/market/hooks/useLargeMoverCurrencies.ts +36 -0
  226. package/src/notifications/AnnouncementProvider/index.tsx +21 -17
  227. package/src/notifications/AnnouncementProvider/machine.ts +9 -8
  228. package/src/notifications/ServiceStatusProvider/index.tsx +11 -8
  229. package/src/notifications/ServiceStatusProvider/machine.ts +4 -4
  230. package/src/wallet-api/ModularDrawer/types.ts +45 -0
  231. package/src/wallet-api/ModularDrawer/utils.ts +37 -0
  232. package/src/wallet-api/react.ts +37 -31
  233. package/lib/index.d.ts +0 -2
  234. package/lib/index.d.ts.map +0 -1
  235. package/lib/index.js.map +0 -1
  236. package/lib/market/hooks/useLargeMoverDataProvider.d.ts +0 -17
  237. package/lib/market/hooks/useLargeMoverDataProvider.d.ts.map +0 -1
  238. package/lib/market/hooks/useLargeMoverDataProvider.js +0 -48
  239. package/lib/market/hooks/useLargeMoverDataProvider.js.map +0 -1
  240. package/lib-es/index.d.ts +0 -1
  241. package/lib-es/index.d.ts.map +0 -1
  242. package/lib-es/index.js +0 -2
  243. package/lib-es/index.js.map +0 -1
  244. package/lib-es/market/hooks/useLargeMoverDataProvider.d.ts +0 -17
  245. package/lib-es/market/hooks/useLargeMoverDataProvider.d.ts.map +0 -1
  246. package/lib-es/market/hooks/useLargeMoverDataProvider.js +0 -44
  247. package/lib-es/market/hooks/useLargeMoverDataProvider.js.map +0 -1
  248. package/src/index.ts +0 -0
  249. package/src/market/hooks/useLargeMoverDataProvider.ts +0 -70
@@ -0,0 +1,161 @@
1
+ import axios from "axios";
2
+ import {
3
+ conventionalAppSubpath,
4
+ DeviceParams,
5
+ reverseModelMap,
6
+ } from "@ledgerhq/speculos-transport";
7
+ import { SpeculosDevice } from "./speculos";
8
+ import https from "https";
9
+
10
+ const { SEED, GITHUB_TOKEN, AWS_ROLE, CLUSTER } = process.env;
11
+ const GIT_API_URL = "https://api.github.com/repos/LedgerHQ/actions/actions/";
12
+ const START_WORKFLOW_ID = "workflows/161487603/dispatches";
13
+ const STOP_WORKFLOW_ID = "workflows/161487604/dispatches";
14
+ const GITHUB_REF = "main";
15
+ const getSpeculosAddress = (runId: string) => `https://${runId}.speculos.aws.stg.ldg-tech.com`;
16
+ const speculosPort = 443;
17
+
18
+ function uniqueId(): string {
19
+ const timestamp = Date.now().toString(36);
20
+ const randomString = Math.random().toString(36).slice(2, 7);
21
+ return timestamp + randomString;
22
+ }
23
+
24
+ /**
25
+ * Helper function to make API requests with error handling
26
+ */
27
+ async function githubApiRequest<T = unknown>({
28
+ method = "POST",
29
+ urlSuffix,
30
+ data,
31
+ params,
32
+ }: {
33
+ method?: "GET" | "POST";
34
+ urlSuffix: string;
35
+ data?: Record<string, unknown>;
36
+ params?: Record<string, unknown>;
37
+ }): Promise<T> {
38
+ const url = `${GIT_API_URL}${urlSuffix}`;
39
+ try {
40
+ const response = await axios({
41
+ method,
42
+ url,
43
+ headers: {
44
+ Authorization: `Bearer ${GITHUB_TOKEN}`,
45
+ Accept: "application/vnd.github+json",
46
+ "X-GitHub-Api-Version": "2022-11-28",
47
+ },
48
+ data,
49
+ params,
50
+ });
51
+ return response.data;
52
+ } catch (error) {
53
+ console.warn(
54
+ `API Request failed: ${method} ${url}`,
55
+ axios.isAxiosError(error) ? error.response?.data : (error as Error).message,
56
+ );
57
+ throw error;
58
+ }
59
+ }
60
+
61
+ function waitForSpeculosReady(url: string, { interval = 2000, timeout = 120_000 } = {}) {
62
+ return new Promise((resolve, reject) => {
63
+ const startTime = Date.now();
64
+
65
+ function check() {
66
+ https
67
+ .get(url, res => {
68
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 400) {
69
+ process.env.SPECULOS_ADDRESS = url;
70
+ resolve(true);
71
+ } else {
72
+ retry();
73
+ }
74
+ })
75
+ .on("error", retry);
76
+ }
77
+
78
+ function retry() {
79
+ if (Date.now() - startTime >= timeout) {
80
+ reject(new Error(`Timeout: ${url} did not become available within ${timeout}ms`));
81
+ } else {
82
+ setTimeout(check, interval);
83
+ }
84
+ }
85
+
86
+ check();
87
+ });
88
+ }
89
+
90
+ function createStartPayload(deviceParams: DeviceParams, runId: string) {
91
+ const { model, firmware, appName, appVersion, dependency, dependencies } = deviceParams;
92
+
93
+ let additional_args = "-p";
94
+
95
+ if (dependency) {
96
+ additional_args = `${additional_args} -l ${dependency}:/apps/${conventionalAppSubpath(model, firmware, dependency, appVersion)}`;
97
+ } else if (dependencies) {
98
+ additional_args = [
99
+ ...new Set(
100
+ dependencies.map(
101
+ dep =>
102
+ `${additional_args} -l ${dep.name}:/apps/${conventionalAppSubpath(
103
+ model,
104
+ firmware,
105
+ dep.name,
106
+ dep.appVersion ?? "1.0.0",
107
+ )}`,
108
+ ),
109
+ ),
110
+ ].join(" ");
111
+ }
112
+
113
+ return {
114
+ ref: GITHUB_REF,
115
+ inputs: {
116
+ coin_app: appName,
117
+ coin_app_version: appVersion,
118
+ device: reverseModelMap[model],
119
+ device_os_version: firmware,
120
+ aws_role: AWS_ROLE,
121
+ cluster: CLUSTER,
122
+ seed: SEED,
123
+ run_id: runId,
124
+ additional_args,
125
+ },
126
+ };
127
+ }
128
+
129
+ export async function createSpeculosDeviceCI(
130
+ deviceParams: DeviceParams,
131
+ ): Promise<SpeculosDevice | undefined> {
132
+ try {
133
+ const runId = uniqueId();
134
+ console.warn("Creating remote speculos:", runId);
135
+ const data = createStartPayload(deviceParams, runId);
136
+ await githubApiRequest({ urlSuffix: START_WORKFLOW_ID, data });
137
+ await waitForSpeculosReady(getSpeculosAddress(runId));
138
+
139
+ return {
140
+ id: runId,
141
+ port: speculosPort,
142
+ };
143
+ } catch (e: unknown) {
144
+ console.error(e);
145
+ console.warn(
146
+ `Creating remote speculos ${deviceParams.appName}:${deviceParams.appVersion} failed with ${String(e)}`,
147
+ );
148
+ }
149
+ }
150
+
151
+ export async function releaseSpeculosDeviceCI(runId: string) {
152
+ const data = {
153
+ ref: GITHUB_REF,
154
+ inputs: {
155
+ run_id: runId.toString(),
156
+ aws_role: AWS_ROLE,
157
+ cluster: CLUSTER,
158
+ },
159
+ };
160
+ await githubApiRequest({ urlSuffix: STOP_WORKFLOW_ID, data });
161
+ }
@@ -0,0 +1,2 @@
1
+ // Encapsulate for LLD & LLM
2
+ export * from "@ledgerhq/coin-hedera/logic";
@@ -617,6 +617,7 @@ export const DEFAULT_FEATURES: Features = {
617
617
  },
618
618
  },
619
619
  ldmkConnectApp: DEFAULT_FEATURE,
620
+ lldNetworkBasedAddAccount: DEFAULT_FEATURE,
620
621
  };
621
622
 
622
623
  // Firebase SDK treat JSON values as strings
@@ -24,7 +24,7 @@ type State = {
24
24
  isLocked: boolean;
25
25
  };
26
26
 
27
- type ManagerState = State & {
27
+ export type ManagerState = State & {
28
28
  repairModalOpened:
29
29
  | {
30
30
  auto: boolean;
@@ -26,10 +26,18 @@ import getDeviceInfo from "./getDeviceInfo";
26
26
  import getAddress from "./getAddress";
27
27
  import openApp from "./openApp";
28
28
  import quitApp from "./quitApp";
29
- import { mustUpgrade } from "../apps";
29
+ import { mustUpgrade, getMinVersion } from "../apps";
30
30
  import isUpdateAvailable from "./isUpdateAvailable";
31
31
  import { LockedDeviceEvent } from "./actions/types";
32
32
  import { getLatestFirmwareForDeviceUseCase } from "../device/use-cases/getLatestFirmwareForDeviceUseCase";
33
+ import {
34
+ type ApplicationDependency,
35
+ type ApplicationConstraint,
36
+ type ApplicationVersionConstraint,
37
+ type DeviceManagementKit,
38
+ } from "@ledgerhq/device-management-kit";
39
+ import { ConnectAppDeviceAction } from "@ledgerhq/live-dmk-shared";
40
+ import { ConnectAppEventMapper } from "./connectAppEventMapper";
33
41
 
34
42
  export type RequiresDerivation = {
35
43
  currencyId: string;
@@ -274,7 +282,7 @@ const derivationLogic = (
274
282
  * @param allowPartialDependencies If some dependencies need to be installed, and if set to true,
275
283
  * skip any app install if the app is not found from the provider.
276
284
  */
277
- const cmd = ({ deviceId, request }: Input): Observable<ConnectAppEvent> => {
285
+ const cmd = (transport: Transport, { request }: Input): Observable<ConnectAppEvent> => {
278
286
  const {
279
287
  appName,
280
288
  requiresDerivation,
@@ -283,202 +291,222 @@ const cmd = ({ deviceId, request }: Input): Observable<ConnectAppEvent> => {
283
291
  outdatedApp,
284
292
  allowPartialDependencies = false,
285
293
  } = request;
286
- return withDevice(deviceId)(
287
- transport =>
288
- new Observable(o => {
289
- const timeoutSub = of({
290
- type: "unresponsiveDevice",
291
- })
292
- .pipe(delay(1000))
293
- .subscribe(e => o.next(e as ConnectAppEvent));
294
- const innerSub = ({
295
- appName,
296
- dependencies,
297
- requireLatestFirmware,
298
- }: ConnectAppRequest): Observable<ConnectAppEvent> =>
299
- defer(() => from(getAppAndVersion(transport))).pipe(
300
- concatMap((appAndVersion): Observable<ConnectAppEvent> => {
301
- timeoutSub.unsubscribe();
294
+ return new Observable(o => {
295
+ const timeoutSub = of({
296
+ type: "unresponsiveDevice",
297
+ })
298
+ .pipe(delay(1000))
299
+ .subscribe(e => o.next(e as ConnectAppEvent));
300
+ const innerSub = ({
301
+ appName,
302
+ dependencies,
303
+ requireLatestFirmware,
304
+ }: ConnectAppRequest): Observable<ConnectAppEvent> =>
305
+ defer(() => from(getAppAndVersion(transport))).pipe(
306
+ concatMap((appAndVersion): Observable<ConnectAppEvent> => {
307
+ timeoutSub.unsubscribe();
302
308
 
303
- if (isDashboardName(appAndVersion.name)) {
304
- // check if we meet minimum fw
305
- if (requireLatestFirmware || outdatedApp) {
306
- return from(getDeviceInfo(transport)).pipe(
307
- mergeMap((deviceInfo: DeviceInfo) =>
308
- from(getLatestFirmwareForDeviceUseCase(deviceInfo)).pipe(
309
- mergeMap((latest: FirmwareUpdateContext | undefined | null) => {
310
- const isLatest =
311
- !latest || semver.eq(deviceInfo.version, latest.final.version);
309
+ if (isDashboardName(appAndVersion.name)) {
310
+ // check if we meet minimum fw
311
+ if (requireLatestFirmware || outdatedApp) {
312
+ return from(getDeviceInfo(transport)).pipe(
313
+ mergeMap((deviceInfo: DeviceInfo) =>
314
+ from(getLatestFirmwareForDeviceUseCase(deviceInfo)).pipe(
315
+ mergeMap((latest: FirmwareUpdateContext | undefined | null) => {
316
+ const isLatest =
317
+ !latest || semver.eq(deviceInfo.version, latest.final.version);
312
318
 
313
- if (
314
- (!requireLatestFirmware || (requireLatestFirmware && isLatest)) &&
315
- outdatedApp
316
- ) {
317
- return from(isUpdateAvailable(deviceInfo, outdatedApp)).pipe(
318
- mergeMap(isAvailable =>
319
- isAvailable
320
- ? throwError(
321
- () =>
322
- new UpdateYourApp(undefined, {
323
- managerAppName: outdatedApp.name,
324
- }),
325
- )
326
- : throwError(
327
- () =>
328
- new LatestFirmwareVersionRequired(
329
- "LatestFirmwareVersionRequired",
330
- {
331
- latest: latest?.final.version,
332
- current: deviceInfo.version,
333
- },
334
- ),
319
+ if (
320
+ (!requireLatestFirmware || (requireLatestFirmware && isLatest)) &&
321
+ outdatedApp
322
+ ) {
323
+ return from(isUpdateAvailable(deviceInfo, outdatedApp)).pipe(
324
+ mergeMap(isAvailable =>
325
+ isAvailable
326
+ ? throwError(
327
+ () =>
328
+ new UpdateYourApp(undefined, {
329
+ managerAppName: outdatedApp.name,
330
+ }),
331
+ )
332
+ : throwError(
333
+ () =>
334
+ new LatestFirmwareVersionRequired(
335
+ "LatestFirmwareVersionRequired",
336
+ {
337
+ latest: latest?.final.version,
338
+ current: deviceInfo.version,
339
+ },
335
340
  ),
336
- ),
337
- );
338
- }
341
+ ),
342
+ ),
343
+ );
344
+ }
339
345
 
340
- if (isLatest) {
341
- o.next({ type: "latest-firmware-resolved" });
342
- return innerSub({
343
- appName,
344
- dependencies,
345
- allowPartialDependencies,
346
- // requireLatestFirmware // Resolved!.
347
- });
348
- } else {
349
- return throwError(
350
- () =>
351
- new LatestFirmwareVersionRequired("LatestFirmwareVersionRequired", {
352
- latest: latest.final.version,
353
- current: deviceInfo.version,
354
- }),
355
- );
356
- }
357
- }),
358
- ),
359
- ),
360
- );
361
- }
362
- // check if we meet dependencies
363
- if (dependencies?.length) {
364
- const completesInDashboard = isDashboardName(appName);
365
- return inlineAppInstall({
366
- transport,
367
- appNames: [...(completesInDashboard ? [] : [appName]), ...dependencies],
368
- onSuccessObs: () => {
369
- o.next({
370
- type: "dependencies-resolved",
371
- });
372
- return innerSub({
373
- appName,
374
- allowPartialDependencies,
375
- // dependencies // Resolved!
376
- });
377
- },
346
+ if (isLatest) {
347
+ o.next({ type: "latest-firmware-resolved" });
348
+ return innerSub({
349
+ appName,
350
+ dependencies,
351
+ allowPartialDependencies,
352
+ // requireLatestFirmware // Resolved!.
353
+ });
354
+ } else {
355
+ return throwError(
356
+ () =>
357
+ new LatestFirmwareVersionRequired("LatestFirmwareVersionRequired", {
358
+ latest: latest.final.version,
359
+ current: deviceInfo.version,
360
+ }),
361
+ );
362
+ }
363
+ }),
364
+ ),
365
+ ),
366
+ );
367
+ }
368
+ // check if we meet dependencies
369
+ if (dependencies?.length) {
370
+ const completesInDashboard = isDashboardName(appName);
371
+ return inlineAppInstall({
372
+ transport,
373
+ appNames: [...(completesInDashboard ? [] : [appName]), ...dependencies],
374
+ onSuccessObs: () => {
375
+ o.next({
376
+ type: "dependencies-resolved",
377
+ });
378
+ return innerSub({
379
+ appName,
378
380
  allowPartialDependencies,
381
+ // dependencies // Resolved!
379
382
  });
380
- }
383
+ },
384
+ allowPartialDependencies,
385
+ });
386
+ }
381
387
 
382
- // maybe we want to be in the dashboard
383
- if (appName === appAndVersion.name) {
384
- const e: ConnectAppEvent = {
385
- type: "opened",
386
- app: appAndVersion,
387
- };
388
- return of(e);
389
- }
388
+ // maybe we want to be in the dashboard
389
+ if (appName === appAndVersion.name) {
390
+ const e: ConnectAppEvent = {
391
+ type: "opened",
392
+ app: appAndVersion,
393
+ };
394
+ return of(e);
395
+ }
390
396
 
391
- // we're in dashboard
392
- return openAppFromDashboard(transport, appName);
393
- }
397
+ // we're in dashboard
398
+ return openAppFromDashboard(transport, appName);
399
+ }
394
400
 
395
- const appNeedsUpgrade = mustUpgrade(appAndVersion.name, appAndVersion.version);
396
- if (appNeedsUpgrade) {
397
- // quit app, check provider's app update for device's minimum requirements.
398
- o.next({
399
- type: "has-outdated-app",
400
- outdatedApp: appAndVersion,
401
- });
402
- }
401
+ const appNeedsUpgrade = mustUpgrade(appAndVersion.name, appAndVersion.version);
402
+ if (appNeedsUpgrade) {
403
+ // quit app, check provider's app update for device's minimum requirements.
404
+ o.next({
405
+ type: "has-outdated-app",
406
+ outdatedApp: appAndVersion,
407
+ });
408
+ }
403
409
 
404
- // need dashboard to check firmware, install dependencies, or verify app update
405
- if (
406
- dependencies?.length ||
407
- requireLatestFirmware ||
408
- appAndVersion.name !== appName ||
409
- appNeedsUpgrade
410
- ) {
411
- return attemptToQuitApp(transport, appAndVersion as AppAndVersion);
412
- }
410
+ // need dashboard to check firmware, install dependencies, or verify app update
411
+ if (
412
+ dependencies?.length ||
413
+ requireLatestFirmware ||
414
+ appAndVersion.name !== appName ||
415
+ appNeedsUpgrade
416
+ ) {
417
+ return attemptToQuitApp(transport, appAndVersion as AppAndVersion);
418
+ }
419
+
420
+ if (requiresDerivation) {
421
+ return derivationLogic(transport, {
422
+ requiresDerivation,
423
+ appAndVersion: appAndVersion as AppAndVersion,
424
+ appName,
425
+ });
426
+ } else {
427
+ const e: ConnectAppEvent = {
428
+ type: "opened",
429
+ app: appAndVersion,
430
+ };
431
+ return of(e);
432
+ }
433
+ }),
434
+ catchError((e: unknown) => {
435
+ if (
436
+ (typeof e === "object" &&
437
+ e !== null &&
438
+ "_tag" in e &&
439
+ e._tag === "DeviceDisconnectedWhileSendingError") ||
440
+ e instanceof DisconnectedDeviceDuringOperation ||
441
+ e instanceof DisconnectedDevice
442
+ ) {
443
+ return of(<ConnectAppEvent>{
444
+ type: "disconnected",
445
+ });
446
+ }
447
+
448
+ if (e && e instanceof TransportStatusError) {
449
+ switch (e.statusCode) {
450
+ case StatusCodes.CLA_NOT_SUPPORTED: // in 1.3.1 dashboard
451
+ case StatusCodes.INS_NOT_SUPPORTED: // in 1.3.1 and bitcoin app
452
+ // fallback on "old way" because device does not support getAppAndVersion
453
+ if (!requiresDerivation) {
454
+ // if there is no derivation, there is nothing we can do to check an app (e.g. requiring non coin app)
455
+ return throwError(() => new FirmwareOrAppUpdateRequired());
456
+ }
413
457
 
414
- if (requiresDerivation) {
415
458
  return derivationLogic(transport, {
416
459
  requiresDerivation,
417
- appAndVersion: appAndVersion as AppAndVersion,
418
460
  appName,
419
461
  });
420
- } else {
421
- const e: ConnectAppEvent = {
422
- type: "opened",
423
- app: appAndVersion,
424
- };
425
- return of(e);
426
- }
427
- }),
428
- catchError((e: unknown) => {
429
- if (
430
- (typeof e === "object" &&
431
- e !== null &&
432
- "_tag" in e &&
433
- e._tag === "DeviceDisconnectedWhileSendingError") ||
434
- e instanceof DisconnectedDeviceDuringOperation ||
435
- e instanceof DisconnectedDevice
436
- ) {
437
- return of(<ConnectAppEvent>{
438
- type: "disconnected",
439
- });
440
- }
462
+ }
463
+ } else if (e instanceof LockedDeviceError) {
464
+ return of({
465
+ type: "lockedDevice",
466
+ } as ConnectAppEvent);
467
+ }
441
468
 
442
- if (e && e instanceof TransportStatusError) {
443
- switch (e.statusCode) {
444
- case StatusCodes.CLA_NOT_SUPPORTED: // in 1.3.1 dashboard
445
- case StatusCodes.INS_NOT_SUPPORTED: // in 1.3.1 and bitcoin app
446
- // fallback on "old way" because device does not support getAppAndVersion
447
- if (!requiresDerivation) {
448
- // if there is no derivation, there is nothing we can do to check an app (e.g. requiring non coin app)
449
- return throwError(() => new FirmwareOrAppUpdateRequired());
450
- }
469
+ return throwError(() => e);
470
+ }),
471
+ );
451
472
 
452
- return derivationLogic(transport, {
453
- requiresDerivation,
454
- appName,
455
- });
456
- }
457
- } else if (e instanceof LockedDeviceError) {
458
- return of({
459
- type: "lockedDevice",
460
- } as ConnectAppEvent);
461
- }
473
+ const sub = innerSub({
474
+ appName,
475
+ dependencies,
476
+ requireLatestFirmware,
477
+ allowPartialDependencies,
478
+ }).subscribe(o);
462
479
 
463
- return throwError(() => e);
464
- }),
465
- );
466
-
467
- const sub = innerSub({
468
- appName,
469
- dependencies,
470
- requireLatestFirmware,
471
- allowPartialDependencies,
472
- }).subscribe(o);
480
+ return () => {
481
+ timeoutSub.unsubscribe();
482
+ sub.unsubscribe();
483
+ };
484
+ });
485
+ };
473
486
 
474
- return () => {
475
- timeoutSub.unsubscribe();
476
- sub.unsubscribe();
477
- };
478
- }),
487
+ const isDmkTransport = (
488
+ transport: Transport,
489
+ ): transport is Transport & { dmk: DeviceManagementKit; sessionId: string } => {
490
+ return (
491
+ "dmk" in transport &&
492
+ transport.dmk !== undefined &&
493
+ "sessionId" in transport &&
494
+ transport.sessionId !== undefined
479
495
  );
480
496
  };
481
497
 
498
+ const appNameToDependency = (appName: string): ApplicationDependency => {
499
+ let constraints: ApplicationConstraint[] | undefined = undefined;
500
+ const minVersion = getMinVersion(appName);
501
+ if (minVersion !== undefined) {
502
+ constraints = [{ minVersion: minVersion as ApplicationVersionConstraint }];
503
+ }
504
+ return {
505
+ name: appName,
506
+ constraints,
507
+ };
508
+ };
509
+
482
510
  export default function connectAppFactory(
483
511
  {
484
512
  isLdmkConnectAppEnabled,
@@ -487,7 +515,46 @@ export default function connectAppFactory(
487
515
  } = { isLdmkConnectAppEnabled: false },
488
516
  ) {
489
517
  if (!isLdmkConnectAppEnabled) {
490
- return cmd;
518
+ return ({ deviceId, request }: Input): Observable<ConnectAppEvent> =>
519
+ withDevice(deviceId)(transport => cmd(transport, { deviceId, request }));
491
520
  }
492
- throw new Error("LdkmConnectApp is not supported yet");
521
+ return ({ deviceId, request }: Input): Observable<ConnectAppEvent> => {
522
+ const {
523
+ appName,
524
+ requiresDerivation,
525
+ dependencies,
526
+ requireLatestFirmware,
527
+ allowPartialDependencies = false,
528
+ } = request;
529
+ return withDevice(deviceId)(transport => {
530
+ if (!isDmkTransport(transport)) {
531
+ return cmd(transport, { deviceId, request });
532
+ }
533
+ const { dmk, sessionId } = transport;
534
+ const deviceAction = new ConnectAppDeviceAction({
535
+ input: {
536
+ application: appNameToDependency(appName),
537
+ dependencies: dependencies ? dependencies.map(name => ({ name })) : [],
538
+ requireLatestFirmware,
539
+ allowMissingApplication: allowPartialDependencies,
540
+ unlockTimeout: 0, // Expect to fail immediately when device is locked
541
+ requiredDerivation: requiresDerivation
542
+ ? async () => {
543
+ const { currencyId, ...derivationRest } = requiresDerivation;
544
+ const derivation = await getAddress(transport, {
545
+ currency: getCryptoCurrencyById(currencyId),
546
+ ...derivationRest,
547
+ });
548
+ return derivation.address;
549
+ }
550
+ : undefined,
551
+ },
552
+ });
553
+ const observable = dmk.executeDeviceAction({
554
+ sessionId,
555
+ deviceAction,
556
+ });
557
+ return new ConnectAppEventMapper(dmk, sessionId, appName, observable).map();
558
+ });
559
+ };
493
560
  }