@ledgerhq/live-common 34.52.0-nightly.0 → 34.52.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 (76) hide show
  1. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts +2 -1
  2. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts.map +1 -1
  3. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.js +3 -0
  4. package/lib/bridge/generic-alpaca/alpaca/network/network-alpaca.js.map +1 -1
  5. package/lib/bridge/generic-alpaca/buildSubAccounts.d.ts +5 -8
  6. package/lib/bridge/generic-alpaca/buildSubAccounts.d.ts.map +1 -1
  7. package/lib/bridge/generic-alpaca/buildSubAccounts.js +37 -9
  8. package/lib/bridge/generic-alpaca/buildSubAccounts.js.map +1 -1
  9. package/lib/bridge/generic-alpaca/getAccountShape.d.ts.map +1 -1
  10. package/lib/bridge/generic-alpaca/getAccountShape.js +18 -17
  11. package/lib/bridge/generic-alpaca/getAccountShape.js.map +1 -1
  12. package/lib/bridge/generic-alpaca/types.d.ts +4 -1
  13. package/lib/bridge/generic-alpaca/types.d.ts.map +1 -1
  14. package/lib/bridge/generic-alpaca/utils.d.ts +2 -1
  15. package/lib/bridge/generic-alpaca/utils.d.ts.map +1 -1
  16. package/lib/bridge/generic-alpaca/utils.js +35 -3
  17. package/lib/bridge/generic-alpaca/utils.js.map +1 -1
  18. package/lib/e2e/data/deviceLabelsData.d.ts.map +1 -1
  19. package/lib/e2e/data/deviceLabelsData.js +3 -4
  20. package/lib/e2e/data/deviceLabelsData.js.map +1 -1
  21. package/lib/e2e/speculos.d.ts.map +1 -1
  22. package/lib/e2e/speculos.js +12 -14
  23. package/lib/e2e/speculos.js.map +1 -1
  24. package/lib/modularDrawer/__mocks__/currencies.mock.d.ts +3 -0
  25. package/lib/modularDrawer/__mocks__/currencies.mock.d.ts.map +1 -1
  26. package/lib/modularDrawer/__mocks__/currencies.mock.js +40 -1
  27. package/lib/modularDrawer/__mocks__/currencies.mock.js.map +1 -1
  28. package/lib/modularDrawer/utils/index.d.ts +3 -2
  29. package/lib/modularDrawer/utils/index.d.ts.map +1 -1
  30. package/lib/modularDrawer/utils/index.js +6 -10
  31. package/lib/modularDrawer/utils/index.js.map +1 -1
  32. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts +2 -1
  33. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.d.ts.map +1 -1
  34. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.js +3 -0
  35. package/lib-es/bridge/generic-alpaca/alpaca/network/network-alpaca.js.map +1 -1
  36. package/lib-es/bridge/generic-alpaca/buildSubAccounts.d.ts +5 -8
  37. package/lib-es/bridge/generic-alpaca/buildSubAccounts.d.ts.map +1 -1
  38. package/lib-es/bridge/generic-alpaca/buildSubAccounts.js +35 -7
  39. package/lib-es/bridge/generic-alpaca/buildSubAccounts.js.map +1 -1
  40. package/lib-es/bridge/generic-alpaca/getAccountShape.d.ts.map +1 -1
  41. package/lib-es/bridge/generic-alpaca/getAccountShape.js +20 -19
  42. package/lib-es/bridge/generic-alpaca/getAccountShape.js.map +1 -1
  43. package/lib-es/bridge/generic-alpaca/types.d.ts +4 -1
  44. package/lib-es/bridge/generic-alpaca/types.d.ts.map +1 -1
  45. package/lib-es/bridge/generic-alpaca/utils.d.ts +2 -1
  46. package/lib-es/bridge/generic-alpaca/utils.d.ts.map +1 -1
  47. package/lib-es/bridge/generic-alpaca/utils.js +33 -2
  48. package/lib-es/bridge/generic-alpaca/utils.js.map +1 -1
  49. package/lib-es/e2e/data/deviceLabelsData.d.ts.map +1 -1
  50. package/lib-es/e2e/data/deviceLabelsData.js +3 -4
  51. package/lib-es/e2e/data/deviceLabelsData.js.map +1 -1
  52. package/lib-es/e2e/speculos.d.ts.map +1 -1
  53. package/lib-es/e2e/speculos.js +12 -14
  54. package/lib-es/e2e/speculos.js.map +1 -1
  55. package/lib-es/modularDrawer/__mocks__/currencies.mock.d.ts +3 -0
  56. package/lib-es/modularDrawer/__mocks__/currencies.mock.d.ts.map +1 -1
  57. package/lib-es/modularDrawer/__mocks__/currencies.mock.js +39 -0
  58. package/lib-es/modularDrawer/__mocks__/currencies.mock.js.map +1 -1
  59. package/lib-es/modularDrawer/utils/index.d.ts +3 -2
  60. package/lib-es/modularDrawer/utils/index.d.ts.map +1 -1
  61. package/lib-es/modularDrawer/utils/index.js +4 -9
  62. package/lib-es/modularDrawer/utils/index.js.map +1 -1
  63. package/package.json +38 -38
  64. package/src/bridge/generic-alpaca/alpaca/network/network-alpaca.ts +4 -0
  65. package/src/bridge/generic-alpaca/buildSubAccounts.test.ts +537 -0
  66. package/src/bridge/generic-alpaca/buildSubAccounts.ts +58 -21
  67. package/src/bridge/generic-alpaca/getAccountShape.ts +26 -23
  68. package/src/bridge/generic-alpaca/tests/getAccountShape.test.ts +10 -1
  69. package/src/bridge/generic-alpaca/types.ts +5 -1
  70. package/src/bridge/generic-alpaca/utils.test.ts +31 -1
  71. package/src/bridge/generic-alpaca/utils.ts +48 -4
  72. package/src/e2e/data/deviceLabelsData.ts +3 -4
  73. package/src/e2e/speculos.ts +12 -15
  74. package/src/modularDrawer/__mocks__/currencies.mock.ts +40 -0
  75. package/src/modularDrawer/utils/index.ts +6 -10
  76. package/src/modularDrawer/utils/index.test.ts +0 -43
@@ -0,0 +1,537 @@
1
+ import { TokenCurrency } from "@ledgerhq/types-cryptoassets";
2
+ import { buildSubAccounts, mergeSubAccounts } from "./buildSubAccounts";
3
+ import { SyncConfig, TokenAccount } from "@ledgerhq/types-live";
4
+ import BigNumber from "bignumber.js";
5
+ import { AssetInfo } from "@ledgerhq/coin-framework/api/types";
6
+
7
+ describe("buildSubAccounts", () => {
8
+ it("builds sub accounts from asset operations and balances, preserving operations order", async () => {
9
+ const subAccounts = await buildSubAccounts({
10
+ accountId: "accountId",
11
+ allTokenAssetsBalances: [
12
+ {
13
+ value: 20n,
14
+ locked: 5n,
15
+ asset: { type: "token", assetReference: "usdc", assetOwner: "owner" },
16
+ },
17
+ { value: 30n, asset: { type: "token", assetReference: "usdt", assetOwner: "owner" } },
18
+ ],
19
+ syncConfig: { blacklistedTokenIds: [] } as unknown as SyncConfig,
20
+ operations: [
21
+ {
22
+ hash: "tx-hash1",
23
+ extra: {
24
+ assetReference: "usdc",
25
+ assetOwner: "owner",
26
+ ledgerOpType: "OUT",
27
+ assetSenders: ["owner"],
28
+ assetRecipients: ["other"],
29
+ },
30
+ },
31
+ {
32
+ hash: "tx-hash2",
33
+ extra: {
34
+ assetReference: "usdt",
35
+ assetOwner: "owner",
36
+ ledgerOpType: "OUT",
37
+ assetSenders: ["owner"],
38
+ assetRecipients: ["other"],
39
+ },
40
+ },
41
+ {
42
+ hash: "tx-hash3",
43
+ extra: {
44
+ assetReference: "usdc",
45
+ assetOwner: "owner",
46
+ ledgerOpType: "IN",
47
+ assetSenders: ["other"],
48
+ assetRecipients: ["owner"],
49
+ },
50
+ },
51
+ {
52
+ hash: "tx-hash4",
53
+ extra: {
54
+ assetReference: "usdt",
55
+ assetOwner: "owner",
56
+ ledgerOpType: "OUT",
57
+ assetSenders: ["owner"],
58
+ assetRecipients: ["other"],
59
+ },
60
+ },
61
+ {
62
+ senders: ["other-as-parent"],
63
+ recipients: ["owner-as-parent"],
64
+ hash: "tx-hash5",
65
+ extra: { assetReference: "usdt", assetOwner: "owner", ledgerOpType: "IN" },
66
+ },
67
+ ] as any,
68
+ getTokenFromAsset: async asset =>
69
+ asset.type === "token" ? ({ id: asset.assetReference } as TokenCurrency) : undefined,
70
+ });
71
+
72
+ expect(subAccounts).toMatchObject([
73
+ {
74
+ id: "accountId+usdc",
75
+ type: "TokenAccount",
76
+ parentId: "accountId",
77
+ token: { id: "usdc" },
78
+ balance: new BigNumber(20),
79
+ spendableBalance: new BigNumber(15),
80
+ operations: [
81
+ {
82
+ id: "accountId+usdc-tx-hash1-OUT",
83
+ type: "OUT",
84
+ senders: ["owner"],
85
+ recipients: ["other"],
86
+ },
87
+ {
88
+ id: "accountId+usdc-tx-hash3-IN",
89
+ type: "IN",
90
+ senders: ["other"],
91
+ recipients: ["owner"],
92
+ },
93
+ ],
94
+ operationsCount: 2,
95
+ },
96
+ {
97
+ id: "accountId+usdt",
98
+ type: "TokenAccount",
99
+ parentId: "accountId",
100
+ token: { id: "usdt" },
101
+ balance: new BigNumber(30),
102
+ spendableBalance: new BigNumber(30),
103
+ operations: [
104
+ {
105
+ id: "accountId+usdt-tx-hash2-OUT",
106
+ type: "OUT",
107
+ senders: ["owner"],
108
+ recipients: ["other"],
109
+ },
110
+ {
111
+ id: "accountId+usdt-tx-hash4-OUT",
112
+ type: "OUT",
113
+ senders: ["owner"],
114
+ recipients: ["other"],
115
+ },
116
+ {
117
+ id: "accountId+usdt-tx-hash5-IN",
118
+ type: "IN",
119
+ senders: ["other-as-parent"],
120
+ recipients: ["owner-as-parent"],
121
+ },
122
+ ],
123
+ operationsCount: 3,
124
+ },
125
+ ]);
126
+ });
127
+
128
+ it.each([
129
+ [
130
+ "blacklisted tokens",
131
+ {
132
+ blacklistedTokenIds: ["other-token"],
133
+ getTokenFromAsset: async (asset: AssetInfo) =>
134
+ asset.type === "token" ? ({ id: asset.assetReference } as TokenCurrency) : undefined,
135
+ },
136
+ ],
137
+ [
138
+ "unknown tokens",
139
+ {
140
+ blacklistedTokenIds: [],
141
+ getTokenFromAsset: async (asset: AssetInfo) =>
142
+ asset.type === "token" && asset.assetReference !== "other-token"
143
+ ? ({ id: asset.assetReference } as TokenCurrency)
144
+ : undefined,
145
+ },
146
+ ],
147
+ ])("does not build accounts from %s", async (_s, config) => {
148
+ const subAccounts = await buildSubAccounts({
149
+ accountId: "accountId",
150
+ allTokenAssetsBalances: [
151
+ {
152
+ value: 20n,
153
+ locked: 5n,
154
+ asset: { type: "token", assetReference: "usdc", assetOwner: "owner" },
155
+ },
156
+ {
157
+ value: 30n,
158
+ asset: { type: "token", assetReference: "other-token", assetOwner: "owner" },
159
+ },
160
+ ],
161
+ syncConfig: { blacklistedTokenIds: config.blacklistedTokenIds } as unknown as SyncConfig,
162
+ operations: [
163
+ {
164
+ hash: "tx-hash1",
165
+ extra: {
166
+ assetReference: "usdc",
167
+ assetOwner: "owner",
168
+ ledgerOpType: "OUT",
169
+ assetSenders: ["owner"],
170
+ assetRecipients: ["other"],
171
+ },
172
+ },
173
+ {
174
+ hash: "tx-hash2",
175
+ extra: {
176
+ assetReference: "other-token",
177
+ assetOwner: "owner",
178
+ ledgerOpType: "OUT",
179
+ assetSenders: ["owner"],
180
+ assetRecipients: ["other"],
181
+ },
182
+ },
183
+ {
184
+ hash: "tx-hash3",
185
+ extra: {
186
+ assetReference: "usdc",
187
+ assetOwner: "owner",
188
+ ledgerOpType: "IN",
189
+ assetSenders: ["other"],
190
+ assetRecipients: ["owner"],
191
+ },
192
+ },
193
+ {
194
+ hash: "tx-hash4",
195
+ extra: {
196
+ assetReference: "other-token",
197
+ assetOwner: "owner",
198
+ ledgerOpType: "OUT",
199
+ assetSenders: ["owner"],
200
+ assetRecipients: ["other"],
201
+ },
202
+ },
203
+ {
204
+ senders: ["other-as-parent"],
205
+ recipients: ["owner-as-parent"],
206
+ hash: "tx-hash5",
207
+ extra: { assetReference: "other-token", assetOwner: "owner", ledgerOpType: "IN" },
208
+ },
209
+ ] as any,
210
+ getTokenFromAsset: config.getTokenFromAsset,
211
+ });
212
+
213
+ expect(subAccounts).toMatchObject([
214
+ {
215
+ id: "accountId+usdc",
216
+ type: "TokenAccount",
217
+ parentId: "accountId",
218
+ token: { id: "usdc" },
219
+ balance: new BigNumber(20),
220
+ spendableBalance: new BigNumber(15),
221
+ operations: [
222
+ {
223
+ id: "accountId+usdc-tx-hash1-OUT",
224
+ type: "OUT",
225
+ senders: ["owner"],
226
+ recipients: ["other"],
227
+ },
228
+ {
229
+ id: "accountId+usdc-tx-hash3-IN",
230
+ type: "IN",
231
+ senders: ["other"],
232
+ recipients: ["owner"],
233
+ },
234
+ ],
235
+ operationsCount: 2,
236
+ },
237
+ ]);
238
+ });
239
+ });
240
+
241
+ describe("mergeSubAccounts", () => {
242
+ it("only keeps new sub accounts", () => {
243
+ const oldSubAccounts = [];
244
+ const newSubAccounts = [
245
+ {
246
+ id: "accountId+usdc",
247
+ type: "TokenAccount",
248
+ parentId: "accountId",
249
+ token: { id: "usdc" },
250
+ balance: new BigNumber(20),
251
+ spendableBalance: new BigNumber(15),
252
+ operations: [
253
+ {
254
+ id: "accountId+usdc-tx-hash1-OUT",
255
+ type: "OUT",
256
+ senders: ["owner"],
257
+ recipients: ["other"],
258
+ },
259
+ {
260
+ id: "accountId+usdc-tx-hash3-IN",
261
+ type: "IN",
262
+ senders: ["other"],
263
+ recipients: ["owner"],
264
+ },
265
+ ],
266
+ operationsCount: 2,
267
+ },
268
+ {
269
+ id: "accountId+usdt",
270
+ type: "TokenAccount",
271
+ parentId: "accountId",
272
+ token: { id: "usdt" },
273
+ balance: new BigNumber(30),
274
+ spendableBalance: new BigNumber(30),
275
+ operations: [
276
+ {
277
+ id: "accountId+usdt-tx-hash2-OUT",
278
+ type: "OUT",
279
+ senders: ["owner"],
280
+ recipients: ["other"],
281
+ },
282
+ {
283
+ id: "accountId+usdt-tx-hash4-OUT",
284
+ type: "OUT",
285
+ senders: ["owner"],
286
+ recipients: ["other"],
287
+ },
288
+ {
289
+ id: "accountId+usdt-tx-hash5-IN",
290
+ type: "IN",
291
+ senders: ["other-as-parent"],
292
+ recipients: ["owner-as-parent"],
293
+ },
294
+ ],
295
+ operationsCount: 3,
296
+ },
297
+ ] as Array<TokenAccount>;
298
+ const merged = mergeSubAccounts(oldSubAccounts, newSubAccounts);
299
+
300
+ expect(merged).toEqual(newSubAccounts);
301
+ });
302
+
303
+ it("adds new unexisting sub accounts as is", () => {
304
+ const oldSubAccounts = [
305
+ {
306
+ id: "accountId+usdc",
307
+ type: "TokenAccount",
308
+ parentId: "accountId",
309
+ token: { id: "usdc" },
310
+ balance: new BigNumber(20),
311
+ spendableBalance: new BigNumber(15),
312
+ operations: [
313
+ {
314
+ id: "accountId+usdc-tx-hash1-OUT",
315
+ type: "OUT",
316
+ senders: ["owner"],
317
+ recipients: ["other"],
318
+ },
319
+ {
320
+ id: "accountId+usdc-tx-hash3-IN",
321
+ type: "IN",
322
+ senders: ["other"],
323
+ recipients: ["owner"],
324
+ },
325
+ ],
326
+ operationsCount: 2,
327
+ },
328
+ {
329
+ id: "accountId+usdt",
330
+ type: "TokenAccount",
331
+ parentId: "accountId",
332
+ token: { id: "usdt" },
333
+ balance: new BigNumber(30),
334
+ spendableBalance: new BigNumber(30),
335
+ operations: [
336
+ {
337
+ id: "accountId+usdt-tx-hash2-OUT",
338
+ type: "OUT",
339
+ senders: ["owner"],
340
+ recipients: ["other"],
341
+ },
342
+ {
343
+ id: "accountId+usdt-tx-hash4-OUT",
344
+ type: "OUT",
345
+ senders: ["owner"],
346
+ recipients: ["other"],
347
+ },
348
+ {
349
+ id: "accountId+usdt-tx-hash5-IN",
350
+ type: "IN",
351
+ senders: ["other-as-parent"],
352
+ recipients: ["owner-as-parent"],
353
+ },
354
+ ],
355
+ operationsCount: 3,
356
+ },
357
+ ] as Array<TokenAccount>;
358
+ const newSubAccounts = [
359
+ {
360
+ id: "accountId+other-token",
361
+ type: "TokenAccount",
362
+ parentId: "accountId",
363
+ token: { id: "other-token" },
364
+ balance: new BigNumber(20),
365
+ spendableBalance: new BigNumber(20),
366
+ operations: [
367
+ {
368
+ id: "accountId+other-token-tx-hash6-OUT",
369
+ type: "OUT",
370
+ senders: ["owner"],
371
+ recipients: ["other"],
372
+ },
373
+ {
374
+ id: "accountId+other-token-tx-hash7-IN",
375
+ type: "IN",
376
+ senders: ["other"],
377
+ recipients: ["owner"],
378
+ },
379
+ ],
380
+ operationsCount: 2,
381
+ },
382
+ ] as Array<TokenAccount>;
383
+ const merged = mergeSubAccounts(oldSubAccounts, newSubAccounts);
384
+
385
+ expect(merged).toEqual([...oldSubAccounts, ...newSubAccounts]);
386
+ });
387
+
388
+ it("updates existing sub accounts with new data", () => {
389
+ const oldSubAccounts = [
390
+ {
391
+ id: "accountId+usdc",
392
+ type: "TokenAccount",
393
+ parentId: "accountId",
394
+ token: { id: "usdc" },
395
+ balance: new BigNumber(20),
396
+ spendableBalance: new BigNumber(15),
397
+ operations: [
398
+ {
399
+ id: "accountId+usdc-tx-hash1-OUT",
400
+ type: "OUT",
401
+ senders: ["owner"],
402
+ recipients: ["other"],
403
+ date: new Date("2019-04-01"),
404
+ },
405
+ {
406
+ id: "accountId+usdc-tx-hash3-IN",
407
+ type: "IN",
408
+ senders: ["other"],
409
+ recipients: ["owner"],
410
+ date: new Date("2019-04-02"),
411
+ },
412
+ ],
413
+ operationsCount: 2,
414
+ },
415
+ {
416
+ id: "accountId+usdt",
417
+ type: "TokenAccount",
418
+ parentId: "accountId",
419
+ token: { id: "usdt" },
420
+ balance: new BigNumber(30),
421
+ spendableBalance: new BigNumber(30),
422
+ operations: [
423
+ {
424
+ id: "accountId+usdt-tx-hash2-OUT",
425
+ type: "OUT",
426
+ senders: ["owner"],
427
+ recipients: ["other"],
428
+ date: new Date("2019-04-02"),
429
+ },
430
+ {
431
+ id: "accountId+usdt-tx-hash4-OUT",
432
+ type: "OUT",
433
+ senders: ["owner"],
434
+ recipients: ["other"],
435
+ date: new Date("2019-04-02"),
436
+ },
437
+ {
438
+ id: "accountId+usdt-tx-hash5-IN",
439
+ type: "IN",
440
+ senders: ["other-as-parent"],
441
+ recipients: ["owner-as-parent"],
442
+ date: new Date("2019-04-03"),
443
+ },
444
+ ],
445
+ operationsCount: 3,
446
+ },
447
+ ] as Array<TokenAccount>;
448
+ const newSubAccounts = [
449
+ {
450
+ id: "accountId+usdt",
451
+ type: "TokenAccount",
452
+ parentId: "accountId",
453
+ token: { id: "usdt" },
454
+ balance: new BigNumber(20),
455
+ spendableBalance: new BigNumber(20),
456
+ operations: [
457
+ {
458
+ id: "accountId+usdt-tx-hash6-OUT",
459
+ type: "OUT",
460
+ senders: ["owner"],
461
+ recipients: ["other"],
462
+ date: new Date("2019-04-04"),
463
+ },
464
+ ],
465
+ operationsCount: 1,
466
+ },
467
+ ] as Array<TokenAccount>;
468
+ const merged = mergeSubAccounts(oldSubAccounts, newSubAccounts);
469
+
470
+ expect(merged).toEqual([
471
+ {
472
+ id: "accountId+usdc",
473
+ type: "TokenAccount",
474
+ parentId: "accountId",
475
+ token: { id: "usdc" },
476
+ balance: new BigNumber(20),
477
+ spendableBalance: new BigNumber(15),
478
+ operations: [
479
+ {
480
+ id: "accountId+usdc-tx-hash1-OUT",
481
+ type: "OUT",
482
+ senders: ["owner"],
483
+ recipients: ["other"],
484
+ date: new Date("2019-04-01"),
485
+ },
486
+ {
487
+ id: "accountId+usdc-tx-hash3-IN",
488
+ type: "IN",
489
+ senders: ["other"],
490
+ recipients: ["owner"],
491
+ date: new Date("2019-04-02"),
492
+ },
493
+ ],
494
+ operationsCount: 2,
495
+ },
496
+ {
497
+ id: "accountId+usdt",
498
+ type: "TokenAccount",
499
+ parentId: "accountId",
500
+ token: { id: "usdt" },
501
+ balance: new BigNumber(20),
502
+ spendableBalance: new BigNumber(20),
503
+ operations: [
504
+ {
505
+ id: "accountId+usdt-tx-hash6-OUT",
506
+ type: "OUT",
507
+ senders: ["owner"],
508
+ recipients: ["other"],
509
+ date: new Date("2019-04-04"),
510
+ },
511
+ {
512
+ id: "accountId+usdt-tx-hash2-OUT",
513
+ type: "OUT",
514
+ senders: ["owner"],
515
+ recipients: ["other"],
516
+ date: new Date("2019-04-02"),
517
+ },
518
+ {
519
+ id: "accountId+usdt-tx-hash4-OUT",
520
+ type: "OUT",
521
+ senders: ["owner"],
522
+ recipients: ["other"],
523
+ date: new Date("2019-04-02"),
524
+ },
525
+ {
526
+ id: "accountId+usdt-tx-hash5-IN",
527
+ type: "IN",
528
+ senders: ["other-as-parent"],
529
+ recipients: ["owner-as-parent"],
530
+ date: new Date("2019-04-03"),
531
+ },
532
+ ],
533
+ operationsCount: 4,
534
+ },
535
+ ]);
536
+ });
537
+ });
@@ -1,16 +1,12 @@
1
1
  import BigNumber from "bignumber.js";
2
2
  import { emptyHistoryCache, encodeTokenAccountId } from "@ledgerhq/coin-framework/account/index";
3
- import type { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets";
4
- import type { Operation, SyncConfig, TokenAccount } from "@ledgerhq/types-live";
3
+ import type { TokenCurrency } from "@ledgerhq/types-cryptoassets";
4
+ import type { SyncConfig, TokenAccount } from "@ledgerhq/types-live";
5
5
  import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
6
- import { listTokensForCryptoCurrency } from "@ledgerhq/cryptoassets";
7
6
  import { AssetInfo, Balance } from "@ledgerhq/coin-framework/api/types";
8
-
9
- export interface OperationCommon extends Operation {
10
- extra: Record<string, any>;
11
- }
12
-
13
- export const getAssetIdFromTokenId = (tokenId: string): string => tokenId.split("/")[2];
7
+ import { mergeOps } from "../jsHelpers";
8
+ import { cleanedOperation } from "./utils";
9
+ import { OperationCommon } from "./types";
14
10
 
15
11
  function buildTokenAccount({
16
12
  parentAccountId,
@@ -31,13 +27,18 @@ function buildTokenAccount({
31
27
  new BigNumber(assetBalance.locked?.toString() || "0"),
32
28
  );
33
29
 
34
- const tokenOperations = operations.map(op => ({
35
- ...op,
36
- id: encodeOperationId(id, op.hash, op.extra?.ledgerOpType),
37
- accountId: id,
38
- type: op.extra?.ledgerOpType,
39
- value: op.extra?.assetAmount ? new BigNumber(op.extra?.assetAmount) : op.value,
40
- }));
30
+ const tokenOperations = operations.map(op =>
31
+ cleanedOperation({
32
+ ...op,
33
+ id: encodeOperationId(id, op.hash, op.extra?.ledgerOpType),
34
+ accountId: id,
35
+ type: op.extra?.ledgerOpType,
36
+ contract: token.contractAddress,
37
+ value: op.extra?.assetAmount ? new BigNumber(op.extra?.assetAmount) : op.value,
38
+ senders: op.extra?.assetSenders ?? op.senders,
39
+ recipients: op.extra?.assetRecipients ?? op.recipients,
40
+ }),
41
+ );
41
42
 
42
43
  return {
43
44
  type: "TokenAccount",
@@ -56,14 +57,12 @@ function buildTokenAccount({
56
57
  }
57
58
 
58
59
  export async function buildSubAccounts({
59
- currency,
60
60
  accountId,
61
61
  allTokenAssetsBalances,
62
62
  syncConfig,
63
63
  operations,
64
64
  getTokenFromAsset,
65
65
  }: {
66
- currency: CryptoCurrency;
67
66
  accountId: string;
68
67
  allTokenAssetsBalances: Balance[];
69
68
  syncConfig: SyncConfig;
@@ -71,15 +70,14 @@ export async function buildSubAccounts({
71
70
  getTokenFromAsset?: (asset: AssetInfo) => Promise<TokenCurrency | undefined>;
72
71
  }): Promise<TokenAccount[]> {
73
72
  const { blacklistedTokenIds = [] } = syncConfig;
74
- const allTokens = listTokensForCryptoCurrency(currency);
75
73
  const tokenAccounts: TokenAccount[] = [];
76
74
 
77
- if (allTokens.length === 0 || allTokenAssetsBalances.length === 0) {
75
+ if (allTokenAssetsBalances.length === 0 || !getTokenFromAsset) {
78
76
  return tokenAccounts;
79
77
  }
80
78
 
81
79
  for (const balance of allTokenAssetsBalances) {
82
- const token = getTokenFromAsset && (await getTokenFromAsset(balance.asset));
80
+ const token = await getTokenFromAsset(balance.asset);
83
81
  // NOTE: for future tokens, will need to check over currencyName/standard(erc20,trc10,trc20, etc)/id
84
82
  if (token && !blacklistedTokenIds.includes(token.id)) {
85
83
  tokenAccounts.push(
@@ -99,3 +97,42 @@ export async function buildSubAccounts({
99
97
 
100
98
  return tokenAccounts;
101
99
  }
100
+
101
+ export function mergeSubAccounts(
102
+ oldSubAccounts: Array<TokenAccount>,
103
+ newSubAccounts: Array<TokenAccount>,
104
+ ): Array<TokenAccount> {
105
+ if (!oldSubAccounts.length) {
106
+ return newSubAccounts;
107
+ }
108
+
109
+ const oldSubAccountsById = Object.fromEntries(
110
+ oldSubAccounts.map(account => [account.id, account]),
111
+ );
112
+
113
+ const newSubAccountsToAdd: Array<TokenAccount> = [];
114
+
115
+ for (const newSubAccount of newSubAccounts) {
116
+ const existingSubAccount = oldSubAccountsById[newSubAccount.id];
117
+
118
+ if (!existingSubAccount) {
119
+ // New sub account does not exist yet. Just add it as is.
120
+ newSubAccountsToAdd.push(newSubAccount);
121
+ continue;
122
+ }
123
+
124
+ // New sub account is already known, probably outdated
125
+ const operations = mergeOps(existingSubAccount.operations, newSubAccount.operations);
126
+ oldSubAccountsById[newSubAccount.id] = {
127
+ ...existingSubAccount,
128
+ balance: newSubAccount.balance,
129
+ spendableBalance: newSubAccount.spendableBalance,
130
+ operations,
131
+ operationsCount: operations.length,
132
+ };
133
+ }
134
+
135
+ const updatedOldSubAccounts = Object.values(oldSubAccountsById);
136
+
137
+ return [...updatedOldSubAccounts, ...newSubAccountsToAdd];
138
+ }