@ledgerhq/live-common 34.51.0-nightly.0 → 34.51.0-nightly.2

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 (266) hide show
  1. package/lib/bridge/generic-alpaca/accountBridge.d.ts.map +1 -1
  2. package/lib/bridge/generic-alpaca/accountBridge.js +2 -0
  3. package/lib/bridge/generic-alpaca/accountBridge.js.map +1 -1
  4. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts +1 -0
  5. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts.map +1 -1
  6. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.js +3 -0
  7. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.js.map +1 -1
  8. package/lib/bridge/generic-alpaca/prepareTransaction.d.ts.map +1 -1
  9. package/lib/bridge/generic-alpaca/prepareTransaction.js +37 -45
  10. package/lib/bridge/generic-alpaca/prepareTransaction.js.map +1 -1
  11. package/lib/bridge/generic-alpaca/signOperation.d.ts.map +1 -1
  12. package/lib/bridge/generic-alpaca/signOperation.js +0 -20
  13. package/lib/bridge/generic-alpaca/signOperation.js.map +1 -1
  14. package/lib/bridge/generic-alpaca/signRawOperation.d.ts +8 -0
  15. package/lib/bridge/generic-alpaca/signRawOperation.d.ts.map +1 -0
  16. package/lib/bridge/generic-alpaca/signRawOperation.js +55 -0
  17. package/lib/bridge/generic-alpaca/signRawOperation.js.map +1 -0
  18. package/lib/bridge/generic-alpaca/tests/getAccountShape.test.js +1 -0
  19. package/lib/bridge/generic-alpaca/tests/getAccountShape.test.js.map +1 -1
  20. package/lib/bridge/generic-alpaca/tests/prepareTransaction.test.js +186 -88
  21. package/lib/bridge/generic-alpaca/tests/prepareTransaction.test.js.map +1 -1
  22. package/lib/bridge/generic-alpaca/utils.d.ts.map +1 -1
  23. package/lib/bridge/generic-alpaca/utils.js +1 -0
  24. package/lib/bridge/generic-alpaca/utils.js.map +1 -1
  25. package/lib/bridge/mockHelpers.d.ts +1 -0
  26. package/lib/bridge/mockHelpers.d.ts.map +1 -1
  27. package/lib/bridge/mockHelpers.js +53 -1
  28. package/lib/bridge/mockHelpers.js.map +1 -1
  29. package/lib/bridge/react/BridgeSync.d.ts +1 -0
  30. package/lib/bridge/react/BridgeSync.d.ts.map +1 -1
  31. package/lib/bridge/react/BridgeSync.js +19 -16
  32. package/lib/bridge/react/BridgeSync.js.map +1 -1
  33. package/lib/bridge/react/BridgeSync.test.js +403 -66
  34. package/lib/bridge/react/BridgeSync.test.js.map +1 -1
  35. package/lib/dada-client/entities/index.d.ts +1 -1
  36. package/lib/dada-client/entities/index.d.ts.map +1 -1
  37. package/lib/e2e/index.d.ts +8 -0
  38. package/lib/e2e/index.d.ts.map +1 -1
  39. package/lib/families/algorand/bridge/mock.d.ts.map +1 -1
  40. package/lib/families/algorand/bridge/mock.js +1 -0
  41. package/lib/families/algorand/bridge/mock.js.map +1 -1
  42. package/lib/families/bitcoin/bridge/mock.d.ts.map +1 -1
  43. package/lib/families/bitcoin/bridge/mock.js +1 -0
  44. package/lib/families/bitcoin/bridge/mock.js.map +1 -1
  45. package/lib/families/canton/bridge/mock.d.ts.map +1 -1
  46. package/lib/families/canton/bridge/mock.js +3 -0
  47. package/lib/families/canton/bridge/mock.js.map +1 -1
  48. package/lib/families/cardano/bridge/mock.d.ts.map +1 -1
  49. package/lib/families/cardano/bridge/mock.js +1 -0
  50. package/lib/families/cardano/bridge/mock.js.map +1 -1
  51. package/lib/families/casper/bridge/mock.d.ts.map +1 -1
  52. package/lib/families/casper/bridge/mock.js +1 -0
  53. package/lib/families/casper/bridge/mock.js.map +1 -1
  54. package/lib/families/cosmos/bridge/mock.d.ts.map +1 -1
  55. package/lib/families/cosmos/bridge/mock.js +1 -0
  56. package/lib/families/cosmos/bridge/mock.js.map +1 -1
  57. package/lib/families/evm/bridge/mock.d.ts.map +1 -1
  58. package/lib/families/evm/bridge/mock.js +1 -0
  59. package/lib/families/evm/bridge/mock.js.map +1 -1
  60. package/lib/families/icon/bridge/mock.d.ts.map +1 -1
  61. package/lib/families/icon/bridge/mock.js +1 -0
  62. package/lib/families/icon/bridge/mock.js.map +1 -1
  63. package/lib/families/multiversx/bridge/mock.d.ts.map +1 -1
  64. package/lib/families/multiversx/bridge/mock.js +1 -0
  65. package/lib/families/multiversx/bridge/mock.js.map +1 -1
  66. package/lib/families/polkadot/bridge/mock.d.ts.map +1 -1
  67. package/lib/families/polkadot/bridge/mock.js +1 -0
  68. package/lib/families/polkadot/bridge/mock.js.map +1 -1
  69. package/lib/families/polkadot/config.d.ts.map +1 -1
  70. package/lib/families/polkadot/config.js +84 -0
  71. package/lib/families/polkadot/config.js.map +1 -1
  72. package/lib/families/polkadot/setup.d.ts.map +1 -1
  73. package/lib/families/polkadot/setup.js +5 -4
  74. package/lib/families/polkadot/setup.js.map +1 -1
  75. package/lib/families/solana/bridge/mock.d.ts +1 -0
  76. package/lib/families/solana/bridge/mock.d.ts.map +1 -1
  77. package/lib/families/stellar/bridge/mock.d.ts.map +1 -1
  78. package/lib/families/stellar/bridge/mock.js +1 -0
  79. package/lib/families/stellar/bridge/mock.js.map +1 -1
  80. package/lib/families/tezos/bridge/mock.d.ts.map +1 -1
  81. package/lib/families/tezos/bridge/mock.js +1 -0
  82. package/lib/families/tezos/bridge/mock.js.map +1 -1
  83. package/lib/families/tron/bridge/mock.d.ts.map +1 -1
  84. package/lib/families/tron/bridge/mock.js +1 -0
  85. package/lib/families/tron/bridge/mock.js.map +1 -1
  86. package/lib/families/xrp/bridge/mock.d.ts.map +1 -1
  87. package/lib/families/xrp/bridge/mock.js +1 -0
  88. package/lib/families/xrp/bridge/mock.js.map +1 -1
  89. package/lib/featureFlags/defaultFeatures.d.ts +3 -0
  90. package/lib/featureFlags/defaultFeatures.d.ts.map +1 -1
  91. package/lib/featureFlags/defaultFeatures.js +10 -1
  92. package/lib/featureFlags/defaultFeatures.js.map +1 -1
  93. package/lib/featureFlags/useFeature.d.ts +1 -1
  94. package/lib/featureFlags/useFeature.d.ts.map +1 -1
  95. package/lib/generated/bridge/mock.d.ts +1 -0
  96. package/lib/generated/bridge/mock.d.ts.map +1 -1
  97. package/lib/hw/actions/rawTransaction.d.ts +37 -0
  98. package/lib/hw/actions/rawTransaction.d.ts.map +1 -0
  99. package/lib/hw/actions/rawTransaction.js +107 -0
  100. package/lib/hw/actions/rawTransaction.js.map +1 -0
  101. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.d.ts.map +1 -1
  102. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js +9 -0
  103. package/lib/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js.map +1 -1
  104. package/lib/wallet-api/logic.d.ts +1 -0
  105. package/lib/wallet-api/logic.d.ts.map +1 -1
  106. package/lib/wallet-api/logic.js +21 -1
  107. package/lib/wallet-api/logic.js.map +1 -1
  108. package/lib/wallet-api/react.d.ts +9 -1
  109. package/lib/wallet-api/react.d.ts.map +1 -1
  110. package/lib/wallet-api/react.js +60 -2
  111. package/lib/wallet-api/react.js.map +1 -1
  112. package/lib/wallet-api/tracking.d.ts +3 -0
  113. package/lib/wallet-api/tracking.d.ts.map +1 -1
  114. package/lib/wallet-api/tracking.js +12 -0
  115. package/lib/wallet-api/tracking.js.map +1 -1
  116. package/lib-es/bridge/generic-alpaca/accountBridge.d.ts.map +1 -1
  117. package/lib-es/bridge/generic-alpaca/accountBridge.js +2 -0
  118. package/lib-es/bridge/generic-alpaca/accountBridge.js.map +1 -1
  119. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts +1 -0
  120. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts.map +1 -1
  121. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.js +3 -0
  122. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.js.map +1 -1
  123. package/lib-es/bridge/generic-alpaca/prepareTransaction.d.ts.map +1 -1
  124. package/lib-es/bridge/generic-alpaca/prepareTransaction.js +37 -45
  125. package/lib-es/bridge/generic-alpaca/prepareTransaction.js.map +1 -1
  126. package/lib-es/bridge/generic-alpaca/signOperation.d.ts.map +1 -1
  127. package/lib-es/bridge/generic-alpaca/signOperation.js +0 -17
  128. package/lib-es/bridge/generic-alpaca/signOperation.js.map +1 -1
  129. package/lib-es/bridge/generic-alpaca/signRawOperation.d.ts +8 -0
  130. package/lib-es/bridge/generic-alpaca/signRawOperation.d.ts.map +1 -0
  131. package/lib-es/bridge/generic-alpaca/signRawOperation.js +48 -0
  132. package/lib-es/bridge/generic-alpaca/signRawOperation.js.map +1 -0
  133. package/lib-es/bridge/generic-alpaca/tests/getAccountShape.test.js +1 -0
  134. package/lib-es/bridge/generic-alpaca/tests/getAccountShape.test.js.map +1 -1
  135. package/lib-es/bridge/generic-alpaca/tests/prepareTransaction.test.js +163 -88
  136. package/lib-es/bridge/generic-alpaca/tests/prepareTransaction.test.js.map +1 -1
  137. package/lib-es/bridge/generic-alpaca/utils.d.ts.map +1 -1
  138. package/lib-es/bridge/generic-alpaca/utils.js +1 -0
  139. package/lib-es/bridge/generic-alpaca/utils.js.map +1 -1
  140. package/lib-es/bridge/mockHelpers.d.ts +1 -0
  141. package/lib-es/bridge/mockHelpers.d.ts.map +1 -1
  142. package/lib-es/bridge/mockHelpers.js +51 -0
  143. package/lib-es/bridge/mockHelpers.js.map +1 -1
  144. package/lib-es/bridge/react/BridgeSync.d.ts +1 -0
  145. package/lib-es/bridge/react/BridgeSync.d.ts.map +1 -1
  146. package/lib-es/bridge/react/BridgeSync.js +17 -15
  147. package/lib-es/bridge/react/BridgeSync.js.map +1 -1
  148. package/lib-es/bridge/react/BridgeSync.test.js +382 -65
  149. package/lib-es/bridge/react/BridgeSync.test.js.map +1 -1
  150. package/lib-es/dada-client/entities/index.d.ts +1 -1
  151. package/lib-es/dada-client/entities/index.d.ts.map +1 -1
  152. package/lib-es/e2e/index.d.ts +8 -0
  153. package/lib-es/e2e/index.d.ts.map +1 -1
  154. package/lib-es/families/algorand/bridge/mock.d.ts.map +1 -1
  155. package/lib-es/families/algorand/bridge/mock.js +2 -1
  156. package/lib-es/families/algorand/bridge/mock.js.map +1 -1
  157. package/lib-es/families/bitcoin/bridge/mock.d.ts.map +1 -1
  158. package/lib-es/families/bitcoin/bridge/mock.js +2 -1
  159. package/lib-es/families/bitcoin/bridge/mock.js.map +1 -1
  160. package/lib-es/families/canton/bridge/mock.d.ts.map +1 -1
  161. package/lib-es/families/canton/bridge/mock.js +3 -0
  162. package/lib-es/families/canton/bridge/mock.js.map +1 -1
  163. package/lib-es/families/cardano/bridge/mock.d.ts.map +1 -1
  164. package/lib-es/families/cardano/bridge/mock.js +2 -1
  165. package/lib-es/families/cardano/bridge/mock.js.map +1 -1
  166. package/lib-es/families/casper/bridge/mock.d.ts.map +1 -1
  167. package/lib-es/families/casper/bridge/mock.js +2 -1
  168. package/lib-es/families/casper/bridge/mock.js.map +1 -1
  169. package/lib-es/families/cosmos/bridge/mock.d.ts.map +1 -1
  170. package/lib-es/families/cosmos/bridge/mock.js +2 -1
  171. package/lib-es/families/cosmos/bridge/mock.js.map +1 -1
  172. package/lib-es/families/evm/bridge/mock.d.ts.map +1 -1
  173. package/lib-es/families/evm/bridge/mock.js +2 -1
  174. package/lib-es/families/evm/bridge/mock.js.map +1 -1
  175. package/lib-es/families/icon/bridge/mock.d.ts.map +1 -1
  176. package/lib-es/families/icon/bridge/mock.js +2 -1
  177. package/lib-es/families/icon/bridge/mock.js.map +1 -1
  178. package/lib-es/families/multiversx/bridge/mock.d.ts.map +1 -1
  179. package/lib-es/families/multiversx/bridge/mock.js +2 -1
  180. package/lib-es/families/multiversx/bridge/mock.js.map +1 -1
  181. package/lib-es/families/polkadot/bridge/mock.d.ts.map +1 -1
  182. package/lib-es/families/polkadot/bridge/mock.js +2 -1
  183. package/lib-es/families/polkadot/bridge/mock.js.map +1 -1
  184. package/lib-es/families/polkadot/config.d.ts.map +1 -1
  185. package/lib-es/families/polkadot/config.js +84 -0
  186. package/lib-es/families/polkadot/config.js.map +1 -1
  187. package/lib-es/families/polkadot/setup.d.ts.map +1 -1
  188. package/lib-es/families/polkadot/setup.js +5 -4
  189. package/lib-es/families/polkadot/setup.js.map +1 -1
  190. package/lib-es/families/solana/bridge/mock.d.ts +1 -0
  191. package/lib-es/families/solana/bridge/mock.d.ts.map +1 -1
  192. package/lib-es/families/stellar/bridge/mock.d.ts.map +1 -1
  193. package/lib-es/families/stellar/bridge/mock.js +2 -1
  194. package/lib-es/families/stellar/bridge/mock.js.map +1 -1
  195. package/lib-es/families/tezos/bridge/mock.d.ts.map +1 -1
  196. package/lib-es/families/tezos/bridge/mock.js +2 -1
  197. package/lib-es/families/tezos/bridge/mock.js.map +1 -1
  198. package/lib-es/families/tron/bridge/mock.d.ts.map +1 -1
  199. package/lib-es/families/tron/bridge/mock.js +2 -1
  200. package/lib-es/families/tron/bridge/mock.js.map +1 -1
  201. package/lib-es/families/xrp/bridge/mock.d.ts.map +1 -1
  202. package/lib-es/families/xrp/bridge/mock.js +2 -1
  203. package/lib-es/families/xrp/bridge/mock.js.map +1 -1
  204. package/lib-es/featureFlags/defaultFeatures.d.ts +3 -0
  205. package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -1
  206. package/lib-es/featureFlags/defaultFeatures.js +10 -1
  207. package/lib-es/featureFlags/defaultFeatures.js.map +1 -1
  208. package/lib-es/featureFlags/useFeature.d.ts +1 -1
  209. package/lib-es/featureFlags/useFeature.d.ts.map +1 -1
  210. package/lib-es/generated/bridge/mock.d.ts +1 -0
  211. package/lib-es/generated/bridge/mock.d.ts.map +1 -1
  212. package/lib-es/hw/actions/rawTransaction.d.ts +37 -0
  213. package/lib-es/hw/actions/rawTransaction.d.ts.map +1 -0
  214. package/lib-es/hw/actions/rawTransaction.js +103 -0
  215. package/lib-es/hw/actions/rawTransaction.js.map +1 -0
  216. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.d.ts.map +1 -1
  217. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js +9 -0
  218. package/lib-es/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.js.map +1 -1
  219. package/lib-es/wallet-api/logic.d.ts +1 -0
  220. package/lib-es/wallet-api/logic.d.ts.map +1 -1
  221. package/lib-es/wallet-api/logic.js +19 -0
  222. package/lib-es/wallet-api/logic.js.map +1 -1
  223. package/lib-es/wallet-api/react.d.ts +9 -1
  224. package/lib-es/wallet-api/react.d.ts.map +1 -1
  225. package/lib-es/wallet-api/react.js +61 -3
  226. package/lib-es/wallet-api/react.js.map +1 -1
  227. package/lib-es/wallet-api/tracking.d.ts +3 -0
  228. package/lib-es/wallet-api/tracking.d.ts.map +1 -1
  229. package/lib-es/wallet-api/tracking.js +12 -0
  230. package/lib-es/wallet-api/tracking.js.map +1 -1
  231. package/package.json +54 -54
  232. package/src/bridge/generic-alpaca/accountBridge.ts +2 -0
  233. package/src/bridge/generic-alpaca/alpaca/network/network-alpaca.ts +8 -0
  234. package/src/bridge/generic-alpaca/prepareTransaction.ts +46 -69
  235. package/src/bridge/generic-alpaca/signOperation.ts +0 -20
  236. package/src/bridge/generic-alpaca/signRawOperation.ts +86 -0
  237. package/src/bridge/generic-alpaca/tests/getAccountShape.test.ts +1 -0
  238. package/src/bridge/generic-alpaca/tests/prepareTransaction.test.ts +191 -109
  239. package/src/bridge/generic-alpaca/utils.ts +1 -0
  240. package/src/bridge/mockHelpers.ts +57 -0
  241. package/src/bridge/react/BridgeSync.test.tsx +513 -82
  242. package/src/bridge/react/BridgeSync.tsx +18 -17
  243. package/src/dada-client/MIGRATION_GUIDE.md +215 -0
  244. package/src/dada-client/entities/index.ts +1 -1
  245. package/src/families/algorand/bridge/mock.ts +2 -0
  246. package/src/families/bitcoin/bridge/mock.ts +2 -0
  247. package/src/families/canton/bridge/mock.ts +3 -0
  248. package/src/families/cardano/bridge/mock.ts +2 -0
  249. package/src/families/casper/bridge/mock.ts +2 -0
  250. package/src/families/cosmos/bridge/mock.ts +2 -0
  251. package/src/families/evm/bridge/mock.ts +2 -0
  252. package/src/families/icon/bridge/mock.ts +2 -0
  253. package/src/families/multiversx/bridge/mock.ts +2 -0
  254. package/src/families/polkadot/bridge/mock.ts +2 -0
  255. package/src/families/polkadot/config.ts +84 -0
  256. package/src/families/polkadot/setup.ts +6 -4
  257. package/src/families/stellar/bridge/mock.ts +2 -0
  258. package/src/families/tezos/bridge/mock.ts +2 -0
  259. package/src/families/tron/bridge/mock.ts +2 -0
  260. package/src/families/xrp/bridge/mock.ts +2 -0
  261. package/src/featureFlags/defaultFeatures.ts +10 -1
  262. package/src/hw/actions/rawTransaction.ts +190 -0
  263. package/src/modularDrawer/hooks/useCurrenciesUnderFeatureFlag.ts +9 -0
  264. package/src/wallet-api/logic.ts +35 -0
  265. package/src/wallet-api/react.ts +87 -1
  266. package/src/wallet-api/tracking.ts +15 -0
@@ -134,6 +134,7 @@ export function transactionToIntent(
134
134
  const res: TransactionIntent & { memo?: { type: string; value?: string } } & {
135
135
  data?: { type: string; value?: unknown };
136
136
  } = {
137
+ intentType: isStaking ? "staking" : "transaction",
137
138
  type: intentType,
138
139
  sender: account.freshAddress,
139
140
  recipient: transaction.recipient,
@@ -183,3 +183,60 @@ export const makeAccountBridgeReceive: () => (
183
183
  path: account.freshAddressPath,
184
184
  publicKey: "mockPublickKey", // We could probably keep the publicKey in `account.freshPublicKey`
185
185
  });
186
+
187
+ export const signRawOperation: AccountBridge<any>["signRawOperation"] = ({ account }) =>
188
+ new Observable(o => {
189
+ let cancelled = false;
190
+
191
+ async function main() {
192
+ await delay(1000);
193
+ if (cancelled) return;
194
+
195
+ for (let i = 0; i <= 1; i += 0.1) {
196
+ o.next({
197
+ type: "device-streaming",
198
+ progress: i,
199
+ index: i,
200
+ total: 10,
201
+ });
202
+ await delay(300);
203
+ }
204
+
205
+ o.next({
206
+ type: "device-signature-requested",
207
+ });
208
+ await delay(2000);
209
+ if (cancelled) return;
210
+ o.next({
211
+ type: "device-signature-granted",
212
+ });
213
+ const rng = new Prando("");
214
+ const op = genOperation(account, account, account.operations, rng);
215
+ op.type = "OUT";
216
+ op.value = new BigNumber(0);
217
+ op.blockHash = null;
218
+ op.blockHeight = null;
219
+ op.senders = [account.freshAddress];
220
+ op.recipients = [];
221
+ op.blockHeight = account.blockHeight;
222
+ op.date = new Date();
223
+ await delay(1000);
224
+ if (cancelled) return;
225
+ broadcasted[account.id] = (broadcasted[account.id] || []).concat(op);
226
+ o.next({
227
+ type: "signed",
228
+ signedOperation: {
229
+ operation: { ...op },
230
+ signature: "",
231
+ },
232
+ });
233
+ }
234
+
235
+ main().then(
236
+ () => o.complete(),
237
+ e => o.error(e),
238
+ );
239
+ return () => {
240
+ cancelled = true;
241
+ };
242
+ });
@@ -2,13 +2,19 @@
2
2
  * @jest-environment jsdom
3
3
  */
4
4
  import "../../__tests__/test-helpers/dom-polyfill";
5
- import React from "react";
5
+ import React, { useEffect } from "react";
6
6
  import { render, screen } from "@testing-library/react";
7
+ import type { Account } from "@ledgerhq/types-live";
8
+ import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
9
+ import { Observable } from "rxjs";
10
+ import type { Observer } from "rxjs";
7
11
  import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets";
8
12
  import { genAccount } from "../../mock/account";
9
- import { BridgeSync } from "./BridgeSync";
13
+ import { BridgeSync, resetStates } from "./BridgeSync";
10
14
  import { setSupportedCurrencies } from "../../currencies";
11
- import { getAccountBridge } from "..";
15
+ import * as Bridge from "..";
16
+ import { useBridgeSync, useBridgeSyncState } from "./context";
17
+ import type { Sync, BridgeSyncState } from "./types";
12
18
 
13
19
  jest.setTimeout(30000);
14
20
 
@@ -24,96 +30,521 @@ const defaultsBridgeSyncOpts = {
24
30
 
25
31
  setSupportedCurrencies(["bitcoin", "ethereum"]);
26
32
 
33
+ const bitcoin = getCryptoCurrencyById("bitcoin");
34
+ const ethereum = getCryptoCurrencyById("ethereum");
35
+
36
+ const createAccount = (
37
+ id: string,
38
+ currency: CryptoCurrency,
39
+ options: Parameters<typeof genAccount>[1] = {},
40
+ ) => genAccount(id, { ...options, currency });
41
+
42
+ type BridgeSyncRenderProps = Partial<Omit<React.ComponentProps<typeof BridgeSync>, "children">>;
43
+
44
+ const renderBridgeSync = (props: BridgeSyncRenderProps = {}, children: React.ReactNode = null) =>
45
+ render(
46
+ <BridgeSync {...defaultsBridgeSyncOpts} {...props}>
47
+ {children}
48
+ </BridgeSync>,
49
+ );
50
+
51
+ type AccountUpdater = (arg0: Account) => Account;
52
+
53
+ const baseGetAccountBridge = Bridge.getAccountBridge;
54
+
55
+ const withMockedAccountBridge = (
56
+ account: Account,
57
+ syncFactory: () => Observable<AccountUpdater>,
58
+ ) => {
59
+ const originalBridge = baseGetAccountBridge(account);
60
+ const mockBridge = {
61
+ ...originalBridge,
62
+ sync: syncFactory,
63
+ };
64
+ return jest.spyOn(Bridge, "getAccountBridge").mockImplementation(acc => {
65
+ if (acc.id === account.id) {
66
+ return mockBridge;
67
+ }
68
+ return baseGetAccountBridge(acc);
69
+ });
70
+ };
71
+
72
+ const mockBridgeSync = (
73
+ account: Account,
74
+ producer: (observer: Observer<AccountUpdater>) => void | (() => void),
75
+ ) =>
76
+ withMockedAccountBridge(
77
+ account,
78
+ () =>
79
+ new Observable<AccountUpdater>(observer => {
80
+ const cleanup = producer(observer);
81
+ return typeof cleanup === "function" ? cleanup : undefined;
82
+ }),
83
+ );
84
+
27
85
  describe("BridgeSync", () => {
86
+ afterEach(() => {
87
+ jest.restoreAllMocks();
88
+ resetStates();
89
+ });
90
+
28
91
  test("initialize without an error", async () => {
29
- render(<BridgeSync {...defaultsBridgeSyncOpts}>LOADED</BridgeSync>);
92
+ renderBridgeSync({}, "LOADED");
30
93
  expect(screen.getByText("LOADED")).not.toBeNull();
31
94
  });
32
95
 
33
- test("executes a sync at start tracked as reason=initial", async () => {
34
- await new Promise(resolve => {
35
- const BTC = getCryptoCurrencyById("bitcoin");
36
- const account = genAccount("btc1", { currency: BTC });
37
- const futureOpLength = account.operations.length;
38
- // we remove the first operation to feed it back as a broadcasted one, the mock impl will make it go back to operations
39
- const lastOp = account.operations.splice(0, 1)[0];
40
- getAccountBridge(account).broadcast({
41
- account,
42
- signedOperation: {
43
- operation: lastOp,
44
- signature: "",
45
- },
46
- });
47
- const accounts = [account];
48
- expect(accounts[0].operations.length).toBe(futureOpLength - 1);
49
-
50
- function track(type, opts) {
51
- if (type === "SyncSuccess") {
52
- expect(opts).toMatchObject({
53
- reason: "initial",
54
- currencyName: "Bitcoin",
55
- operationsLength: futureOpLength,
56
- });
57
- resolve(null);
58
- }
96
+ test("executes a sync at start tracked as reason=initial", done => {
97
+ const account = createAccount("btc1", bitcoin);
98
+ const futureOpLength = account.operations.length;
99
+ // we remove the first operation to feed it back as a broadcasted one, the mock impl will make it go back to operations
100
+ const lastOp = account.operations.splice(0, 1)[0];
101
+ Bridge.getAccountBridge(account).broadcast({
102
+ account,
103
+ signedOperation: {
104
+ operation: lastOp,
105
+ signature: "",
106
+ },
107
+ });
108
+ const accounts = [account];
109
+ expect(accounts[0].operations.length).toBe(futureOpLength - 1);
110
+
111
+ function track(type, opts) {
112
+ if (type === "SyncSuccess") {
113
+ expect(opts).toMatchObject({
114
+ reason: "initial",
115
+ currencyName: "Bitcoin",
116
+ operationsLength: futureOpLength,
117
+ });
118
+ done();
59
119
  }
60
- render(
61
- <BridgeSync {...defaultsBridgeSyncOpts} accounts={accounts} trackAnalytics={track}>
62
- {null}
63
- </BridgeSync>,
64
- );
120
+ }
121
+ renderBridgeSync({ accounts, trackAnalytics: track });
122
+ });
123
+
124
+ test("sync all accounts in parallel at start tracked as reason=initial", done => {
125
+ const accounts = [
126
+ createAccount("2btc1", bitcoin),
127
+ createAccount("2btc2", bitcoin),
128
+ createAccount("2eth1", ethereum),
129
+ ];
130
+ const synced: Array<Record<string, unknown>> = [];
131
+ let resolveFirst;
132
+ function prepareCurrency() {
133
+ if (!resolveFirst) {
134
+ return new Promise((resolve, reject) => {
135
+ resolveFirst = resolve;
136
+ setTimeout(
137
+ reject,
138
+ 5000,
139
+ new Error("prepareCurrency doesn't seem to be called in parallel"),
140
+ );
141
+ });
142
+ }
143
+ // if we reach here, it means, we managed to have
144
+ // a SECOND sync that need to prepare currency
145
+ // so it's a proof that sync correctly runs in parallel
146
+ // otherwise it would timeout
147
+ resolveFirst();
148
+ return Promise.resolve();
149
+ }
150
+ function track(type, opts) {
151
+ expect(type).not.toEqual("SyncError");
152
+ if (type === "SyncSuccess") {
153
+ synced.push(opts);
154
+ expect(opts).toMatchObject({
155
+ reason: "initial",
156
+ });
157
+ if (synced.length === accounts.length) done();
158
+ }
159
+ }
160
+ renderBridgeSync({
161
+ accounts,
162
+ prepareCurrency,
163
+ trackAnalytics: track,
65
164
  });
66
165
  });
67
166
 
68
- test("sync all accounts in parallel at start tracked as reason=initial", async () => {
69
- await new Promise(resolve => {
70
- const BTC = getCryptoCurrencyById("bitcoin");
71
- const ETH = getCryptoCurrencyById("ethereum");
72
- const accounts = [
73
- genAccount("2btc1", { currency: BTC }),
74
- genAccount("2btc2", { currency: BTC }),
75
- genAccount("2eth1", { currency: ETH }),
76
- ];
77
- const synced: Array<any> = [];
78
- let resolveFirst;
79
- function prepareCurrency() {
80
- if (!resolveFirst) {
81
- return new Promise((resolve, reject) => {
82
- resolveFirst = resolve;
83
- setTimeout(
84
- reject,
85
- 5000,
86
- new Error("prepareCurrency doesn't seem to be called in parallel"),
87
- );
88
- });
167
+ test("provides context values correctly", () => {
168
+ const account = createAccount("btc1", bitcoin);
169
+ const accounts = [account];
170
+
171
+ let syncFunction: Sync | undefined;
172
+ let syncState: BridgeSyncState | undefined;
173
+
174
+ function TestComponent() {
175
+ syncFunction = useBridgeSync();
176
+ syncState = useBridgeSyncState();
177
+ return <div data-testid="test-component">Test</div>;
178
+ }
179
+
180
+ renderBridgeSync({ accounts }, <TestComponent />);
181
+
182
+ expect(syncFunction).toBeDefined();
183
+ expect(typeof syncFunction).toBe("function");
184
+ expect(syncState).toBeDefined();
185
+ expect(typeof syncState).toBe("object");
186
+ });
187
+
188
+ test("handles sync errors with recoverError function", done => {
189
+ const account = createAccount("btc1", bitcoin);
190
+ const accounts = [account];
191
+
192
+ const mockError = new Error("Sync failed");
193
+ const recoverError = jest.fn((error: Error) => {
194
+ expect(error.message).toBe("Sync failed");
195
+ return error; // Return error to treat as actual error
196
+ });
197
+
198
+ // Mock the account bridge to return an Observable that emits an error
199
+ mockBridgeSync(account, observer => {
200
+ const timeout = setTimeout(() => observer.error(mockError), 100);
201
+ return () => clearTimeout(timeout);
202
+ });
203
+
204
+ let syncStateChecked = false;
205
+ let syncStateRef: BridgeSyncState;
206
+ function TestComponent() {
207
+ const syncState = useBridgeSyncState();
208
+ syncStateRef = syncState;
209
+
210
+ // After the error is silenced, the sync state should show no error
211
+ setTimeout(() => {
212
+ if (!syncStateChecked && syncStateRef[account.id]) {
213
+ syncStateChecked = true;
214
+ expect(syncStateRef[account.id].error).toBe(mockError);
215
+ expect(recoverError).toHaveBeenCalledWith(mockError);
216
+ done();
89
217
  }
90
- // if we reach here, it means, we managed to have
91
- // a SECOND sync that need to prepare currency
92
- // so it's a proof that sync correctly runs in parallel
93
- // otherwise it would timeout
94
- resolveFirst();
95
- return Promise.resolve();
96
- }
97
- function track(type, opts) {
98
- expect(type).not.toEqual("SyncError");
99
- if (type === "SyncSuccess") {
100
- synced.push(opts);
101
- expect(opts).toMatchObject({
102
- reason: "initial",
103
- });
104
- if (synced.length === accounts.length) resolve(null);
218
+ }, 200);
219
+
220
+ return <div>Test</div>;
221
+ }
222
+
223
+ renderBridgeSync({ accounts, recoverError }, <TestComponent />);
224
+ });
225
+
226
+ test("silences errors when recoverError returns null", done => {
227
+ const account = createAccount("btc1", bitcoin);
228
+ const accounts = [account];
229
+
230
+ const mockError = new Error("Sync failed but should be silenced");
231
+ const recoverError = jest.fn(() => null); // Return null to silence the error
232
+
233
+ // Mock the account bridge to return an Observable that emits an error
234
+ mockBridgeSync(account, observer => {
235
+ const timeout = setTimeout(() => observer.error(mockError), 100);
236
+ return () => clearTimeout(timeout);
237
+ });
238
+
239
+ let syncStateChecked = false;
240
+ let syncStateRef: BridgeSyncState;
241
+ function TestComponent() {
242
+ const syncState = useBridgeSyncState();
243
+ syncStateRef = syncState;
244
+
245
+ // After the error is silenced, the sync state should show no error
246
+ setTimeout(() => {
247
+ if (!syncStateChecked && syncStateRef[account.id]) {
248
+ syncStateChecked = true;
249
+ expect(syncStateRef[account.id].error).toBeNull();
250
+ expect(recoverError).toHaveBeenCalledWith(mockError);
251
+ done();
105
252
  }
106
- }
107
- render(
108
- <BridgeSync
109
- {...defaultsBridgeSyncOpts}
110
- prepareCurrency={prepareCurrency}
111
- accounts={accounts}
112
- trackAnalytics={track}
113
- >
114
- {null}
115
- </BridgeSync>,
116
- );
253
+ }, 200);
254
+
255
+ return <div>Test</div>;
256
+ }
257
+
258
+ renderBridgeSync({ accounts, recoverError }, <TestComponent />);
259
+ });
260
+
261
+ test("handles blacklisted token IDs in sync config", () => {
262
+ const account = createAccount("btc1", bitcoin);
263
+ const blacklistedTokenIds = ["token1", "token2"];
264
+
265
+ renderBridgeSync({ accounts: [account], blacklistedTokenIds });
266
+
267
+ // Test passes if component renders without errors with blacklisted tokens
268
+ expect(blacklistedTokenIds).toHaveLength(2);
269
+ });
270
+
271
+ test("handles sync actions correctly", () => {
272
+ const account1 = createAccount("btc1", bitcoin);
273
+ const account2 = createAccount("eth1", ethereum);
274
+ const accounts = [account1, account2];
275
+
276
+ let sync: Sync | undefined;
277
+
278
+ function TestComponent() {
279
+ sync = useBridgeSync();
280
+ return <div>Test</div>;
281
+ }
282
+
283
+ renderBridgeSync({ accounts }, <TestComponent />);
284
+
285
+ expect(sync).toBeDefined();
286
+
287
+ // Test different sync actions
288
+ expect(() => {
289
+ sync?.({ type: "SYNC_ALL_ACCOUNTS", priority: 1, reason: "manual" });
290
+ }).not.toThrow();
291
+
292
+ expect(() => {
293
+ sync?.({ type: "SYNC_ONE_ACCOUNT", accountId: account1.id, priority: 1, reason: "manual" });
294
+ }).not.toThrow();
295
+
296
+ expect(() => {
297
+ sync?.({
298
+ type: "SYNC_SOME_ACCOUNTS",
299
+ accountIds: [account1.id],
300
+ priority: 1,
301
+ reason: "manual",
302
+ });
303
+ }).not.toThrow();
304
+
305
+ expect(() => {
306
+ sync?.({ type: "SET_SKIP_UNDER_PRIORITY", priority: 5 });
307
+ }).not.toThrow();
308
+
309
+ expect(() => {
310
+ sync?.({ type: "BACKGROUND_TICK", reason: "background" });
311
+ }).not.toThrow();
312
+ });
313
+
314
+ test("handles pending operations sync", () => {
315
+ const account = createAccount("btc1", bitcoin);
316
+
317
+ // Create account with pending operations
318
+ const accountWithPending = {
319
+ ...account,
320
+ pendingOperations: [
321
+ {
322
+ id: "pending1",
323
+ hash: "hash1",
324
+ type: "OUT" as const,
325
+ value: account.balance,
326
+ fee: account.balance.dividedBy(10),
327
+ blockHash: null,
328
+ blockHeight: null,
329
+ senders: [account.freshAddress],
330
+ recipients: ["recipient1"],
331
+ accountId: account.id,
332
+ date: new Date(),
333
+ extra: {},
334
+ },
335
+ ],
336
+ };
337
+
338
+ const accounts = [accountWithPending];
339
+
340
+ let sync: Sync | undefined;
341
+
342
+ function TestComponent() {
343
+ sync = useBridgeSync();
344
+ return <div>Test</div>;
345
+ }
346
+
347
+ renderBridgeSync({ accounts }, <TestComponent />);
348
+
349
+ expect(sync).toBeDefined();
350
+
351
+ // The component should automatically sync accounts with pending operations
352
+ // This is tested by checking that the component renders without errors
353
+ // and that pending operations are handled properly
354
+ expect(accountWithPending.pendingOperations.length).toBeGreaterThan(0);
355
+ });
356
+
357
+ test("hydrates currencies only once", async () => {
358
+ const account1 = createAccount("btc1", bitcoin);
359
+ const account2 = createAccount("btc2", bitcoin); // Same currency
360
+ const account3 = createAccount("eth1", ethereum);
361
+ const accounts = [account1, account2, account3];
362
+
363
+ const hydrateCurrency = jest.fn(() => Promise.resolve());
364
+
365
+ renderBridgeSync({ accounts, hydrateCurrency });
366
+
367
+ // Wait for hydration to complete
368
+ await new Promise(resolve => setTimeout(resolve, 50));
369
+
370
+ // Should only hydrate each currency once, not once per account
371
+ expect(hydrateCurrency).toHaveBeenCalledTimes(2); // BTC and ETH
372
+ expect(hydrateCurrency).toHaveBeenCalledWith(bitcoin);
373
+ expect(hydrateCurrency).toHaveBeenCalledWith(ethereum);
374
+ });
375
+
376
+ test("handles different sync actions", () => {
377
+ const account = createAccount("btc1", bitcoin);
378
+ const accounts = [account];
379
+
380
+ let sync: Sync | undefined;
381
+
382
+ function TestComponent() {
383
+ sync = useBridgeSync();
384
+ return <div>Test</div>;
385
+ }
386
+
387
+ renderBridgeSync({ accounts }, <TestComponent />);
388
+
389
+ expect(sync).toBeDefined();
390
+
391
+ // Test that sync actions can be called without throwing
392
+ expect(sync).toBeDefined();
393
+ const syncFn = sync!; // Assert non-null since we just checked
394
+
395
+ expect(() =>
396
+ syncFn({ type: "SYNC_ALL_ACCOUNTS", priority: 1, reason: "manual" }),
397
+ ).not.toThrow();
398
+ expect(() =>
399
+ syncFn({ type: "SYNC_ONE_ACCOUNT", accountId: account.id, priority: 1, reason: "manual" }),
400
+ ).not.toThrow();
401
+ expect(() => syncFn({ type: "SET_SKIP_UNDER_PRIORITY", priority: 5 })).not.toThrow();
402
+ expect(() => syncFn({ type: "BACKGROUND_TICK", reason: "background" })).not.toThrow();
403
+ });
404
+
405
+ test("tracks session analytics when all accounts complete", async () => {
406
+ const account1 = createAccount("btc1", bitcoin, { operationsSize: 3 });
407
+ const account2 = createAccount("eth1", ethereum, { operationsSize: 5 });
408
+ const accounts = [account1, account2];
409
+
410
+ const trackAnalytics = jest.fn();
411
+
412
+ renderBridgeSync({ accounts, trackAnalytics });
413
+
414
+ // Wait for potential analytics calls
415
+ await new Promise(resolve => setTimeout(resolve, 100));
416
+
417
+ // The component should not throw when tracking analytics
418
+ expect(accounts).toHaveLength(2);
419
+ });
420
+
421
+ test("handles non-existent account sync gracefully", () => {
422
+ const account = createAccount("btc1", bitcoin);
423
+ const accounts = [account];
424
+
425
+ let sync: Sync | undefined;
426
+
427
+ function TestComponent() {
428
+ sync = useBridgeSync();
429
+ return <div>Test</div>;
430
+ }
431
+
432
+ renderBridgeSync({ accounts }, <TestComponent />);
433
+
434
+ // Try to sync an account that doesn't exist - should not throw
435
+ expect(sync).toBeDefined();
436
+ const syncFn = sync!;
437
+
438
+ expect(() => {
439
+ syncFn({
440
+ type: "SYNC_ONE_ACCOUNT",
441
+ accountId: "non-existent-account",
442
+ priority: 1,
443
+ reason: "manual",
444
+ });
445
+ }).not.toThrow();
446
+ });
447
+
448
+ test("does not send analytics for background sync reason", done => {
449
+ const account = createAccount("btc1", bitcoin);
450
+ const accounts = [account];
451
+
452
+ const trackAnalytics = jest.fn();
453
+
454
+ // Mock the account bridge to complete successfully
455
+ mockBridgeSync(account, observer => {
456
+ observer.next((acc: typeof account) => acc);
457
+ observer.complete();
458
+ });
459
+
460
+ function TestComponent() {
461
+ const sync = useBridgeSync();
462
+
463
+ useEffect(() => {
464
+ // Trigger a background sync
465
+ sync({
466
+ type: "SYNC_ONE_ACCOUNT",
467
+ accountId: account.id,
468
+ priority: 1,
469
+ reason: "background",
470
+ });
471
+ }, [sync]);
472
+ return <div>Test</div>;
473
+ }
474
+
475
+ renderBridgeSync({ accounts, trackAnalytics }, <TestComponent />);
476
+
477
+ // Wait for sync to complete and verify no analytics were sent
478
+ setTimeout(() => {
479
+ // Should not have called trackAnalytics with SyncSuccess for background syncs
480
+ const syncSuccessCalls = trackAnalytics.mock.calls.filter(call => call[0] === "SyncSuccess");
481
+ expect(syncSuccessCalls).toHaveLength(0);
482
+
483
+ // Verify trackAnalytics was not called at all with SyncSuccess
484
+ expect(trackAnalytics).not.toHaveBeenCalledWith("SyncSuccess", expect.anything());
485
+
486
+ done();
487
+ }, 200);
488
+ });
489
+
490
+ test("sends analytics for non-background sync reason", done => {
491
+ const account = createAccount("btc1", bitcoin);
492
+ const accounts = [account];
493
+
494
+ const trackAnalytics = jest.fn();
495
+
496
+ // Mock the account bridge to complete successfully
497
+ mockBridgeSync(account, observer => {
498
+ observer.next((acc: typeof account) => acc);
499
+ observer.complete();
117
500
  });
501
+
502
+ function TestComponent() {
503
+ const sync = useBridgeSync();
504
+
505
+ useEffect(() => {
506
+ // Trigger a manual (non-background) sync
507
+ sync({
508
+ type: "SYNC_ONE_ACCOUNT",
509
+ accountId: account.id,
510
+ priority: 1,
511
+ reason: "manual",
512
+ });
513
+ }, [sync]);
514
+ return <div>Test</div>;
515
+ }
516
+
517
+ renderBridgeSync({ accounts, trackAnalytics }, <TestComponent />);
518
+
519
+ // Wait for sync to complete and verify analytics were sent
520
+ setTimeout(() => {
521
+ // Should have called trackAnalytics with SyncSuccess for manual syncs
522
+ expect(trackAnalytics).toHaveBeenCalledWith(
523
+ "SyncSuccess",
524
+ expect.objectContaining({
525
+ reason: "manual",
526
+ currencyName: account.currency.name,
527
+ }),
528
+ );
529
+
530
+ done();
531
+ }, 400);
532
+ });
533
+
534
+ test("provides sync state context", () => {
535
+ const account = createAccount("btc1", bitcoin);
536
+ const accounts = [account];
537
+
538
+ let syncState: BridgeSyncState | undefined;
539
+
540
+ function TestComponent() {
541
+ syncState = useBridgeSyncState();
542
+ return <div>Test</div>;
543
+ }
544
+
545
+ renderBridgeSync({ accounts }, <TestComponent />);
546
+
547
+ expect(syncState).toBeDefined();
548
+ expect(typeof syncState).toBe("object");
118
549
  });
119
550
  });