@ledgerhq/coin-canton 0.7.0 → 0.8.0-nightly.1

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 (133) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +26 -0
  3. package/lib/api/index.d.ts.map +1 -1
  4. package/lib/api/index.js +3 -0
  5. package/lib/api/index.js.map +1 -1
  6. package/lib/api/lastBlock.integ.test.js +0 -15
  7. package/lib/api/lastBlock.integ.test.js.map +1 -1
  8. package/lib/bridge/getTransactionStatus.test.d.ts +2 -0
  9. package/lib/bridge/getTransactionStatus.test.d.ts.map +1 -0
  10. package/lib/bridge/getTransactionStatus.test.js +365 -0
  11. package/lib/bridge/getTransactionStatus.test.js.map +1 -0
  12. package/lib/bridge/index.d.ts.map +1 -1
  13. package/lib/bridge/index.js +5 -5
  14. package/lib/bridge/index.js.map +1 -1
  15. package/lib/bridge/onboard.d.ts +11 -6
  16. package/lib/bridge/onboard.d.ts.map +1 -1
  17. package/lib/bridge/onboard.integ.test.js +49 -27
  18. package/lib/bridge/onboard.integ.test.js.map +1 -1
  19. package/lib/bridge/onboard.js +45 -152
  20. package/lib/bridge/onboard.js.map +1 -1
  21. package/lib/bridge/signOperation.d.ts.map +1 -1
  22. package/lib/bridge/signOperation.js +5 -5
  23. package/lib/bridge/signOperation.js.map +1 -1
  24. package/lib/bridge/sync.d.ts +3 -2
  25. package/lib/bridge/sync.d.ts.map +1 -1
  26. package/lib/bridge/sync.integ.test.js +39 -17
  27. package/lib/bridge/sync.integ.test.js.map +1 -1
  28. package/lib/bridge/sync.js +71 -57
  29. package/lib/bridge/sync.js.map +1 -1
  30. package/lib/common-logic/utils.d.ts.map +1 -1
  31. package/lib/common-logic/utils.js +3 -1
  32. package/lib/common-logic/utils.js.map +1 -1
  33. package/lib/common-logic/utils.test.d.ts +2 -0
  34. package/lib/common-logic/utils.test.d.ts.map +1 -0
  35. package/lib/common-logic/utils.test.js +104 -0
  36. package/lib/common-logic/utils.test.js.map +1 -0
  37. package/lib/config.d.ts +1 -1
  38. package/lib/config.d.ts.map +1 -1
  39. package/lib/network/gateway.d.ts +14 -10
  40. package/lib/network/gateway.d.ts.map +1 -1
  41. package/lib/network/gateway.integ.test.js +31 -17
  42. package/lib/network/gateway.integ.test.js.map +1 -1
  43. package/lib/network/gateway.js +34 -16
  44. package/lib/network/gateway.js.map +1 -1
  45. package/lib/network/gateway.test.d.ts +2 -0
  46. package/lib/network/gateway.test.d.ts.map +1 -0
  47. package/lib/network/gateway.test.js +59 -0
  48. package/lib/network/gateway.test.js.map +1 -0
  49. package/lib/types/bridge.d.ts +6 -16
  50. package/lib/types/bridge.d.ts.map +1 -1
  51. package/lib/types/onboard.d.ts +5 -5
  52. package/lib/types/onboard.d.ts.map +1 -1
  53. package/lib/types/onboard.js +10 -10
  54. package/lib/types/onboard.js.map +1 -1
  55. package/lib-es/api/index.d.ts.map +1 -1
  56. package/lib-es/api/index.js +3 -0
  57. package/lib-es/api/index.js.map +1 -1
  58. package/lib-es/api/lastBlock.integ.test.js +0 -15
  59. package/lib-es/api/lastBlock.integ.test.js.map +1 -1
  60. package/lib-es/bridge/getTransactionStatus.test.d.ts +2 -0
  61. package/lib-es/bridge/getTransactionStatus.test.d.ts.map +1 -0
  62. package/lib-es/bridge/getTransactionStatus.test.js +360 -0
  63. package/lib-es/bridge/getTransactionStatus.test.js.map +1 -0
  64. package/lib-es/bridge/index.d.ts.map +1 -1
  65. package/lib-es/bridge/index.js +6 -6
  66. package/lib-es/bridge/index.js.map +1 -1
  67. package/lib-es/bridge/onboard.d.ts +11 -6
  68. package/lib-es/bridge/onboard.d.ts.map +1 -1
  69. package/lib-es/bridge/onboard.integ.test.js +37 -15
  70. package/lib-es/bridge/onboard.integ.test.js.map +1 -1
  71. package/lib-es/bridge/onboard.js +44 -152
  72. package/lib-es/bridge/onboard.js.map +1 -1
  73. package/lib-es/bridge/signOperation.d.ts.map +1 -1
  74. package/lib-es/bridge/signOperation.js +5 -5
  75. package/lib-es/bridge/signOperation.js.map +1 -1
  76. package/lib-es/bridge/sync.d.ts +3 -2
  77. package/lib-es/bridge/sync.d.ts.map +1 -1
  78. package/lib-es/bridge/sync.integ.test.js +34 -12
  79. package/lib-es/bridge/sync.integ.test.js.map +1 -1
  80. package/lib-es/bridge/sync.js +71 -56
  81. package/lib-es/bridge/sync.js.map +1 -1
  82. package/lib-es/common-logic/utils.d.ts.map +1 -1
  83. package/lib-es/common-logic/utils.js +3 -1
  84. package/lib-es/common-logic/utils.js.map +1 -1
  85. package/lib-es/common-logic/utils.test.d.ts +2 -0
  86. package/lib-es/common-logic/utils.test.d.ts.map +1 -0
  87. package/lib-es/common-logic/utils.test.js +99 -0
  88. package/lib-es/common-logic/utils.test.js.map +1 -0
  89. package/lib-es/config.d.ts +1 -1
  90. package/lib-es/config.d.ts.map +1 -1
  91. package/lib-es/network/gateway.d.ts +14 -10
  92. package/lib-es/network/gateway.d.ts.map +1 -1
  93. package/lib-es/network/gateway.integ.test.js +31 -17
  94. package/lib-es/network/gateway.integ.test.js.map +1 -1
  95. package/lib-es/network/gateway.js +34 -16
  96. package/lib-es/network/gateway.js.map +1 -1
  97. package/lib-es/network/gateway.test.d.ts +2 -0
  98. package/lib-es/network/gateway.test.d.ts.map +1 -0
  99. package/lib-es/network/gateway.test.js +54 -0
  100. package/lib-es/network/gateway.test.js.map +1 -0
  101. package/lib-es/types/bridge.d.ts +6 -16
  102. package/lib-es/types/bridge.d.ts.map +1 -1
  103. package/lib-es/types/onboard.d.ts +5 -5
  104. package/lib-es/types/onboard.d.ts.map +1 -1
  105. package/lib-es/types/onboard.js +9 -9
  106. package/lib-es/types/onboard.js.map +1 -1
  107. package/package.json +8 -7
  108. package/src/api/index.ts +9 -0
  109. package/src/api/lastBlock.integ.test.ts +0 -18
  110. package/src/bridge/getTransactionStatus.test.ts +446 -0
  111. package/src/bridge/index.ts +6 -6
  112. package/src/bridge/onboard.integ.test.ts +44 -31
  113. package/src/bridge/onboard.ts +61 -209
  114. package/src/bridge/signOperation.ts +5 -6
  115. package/src/bridge/sync.integ.test.ts +38 -13
  116. package/src/bridge/sync.ts +90 -72
  117. package/src/common-logic/utils.test.ts +108 -0
  118. package/src/common-logic/utils.ts +4 -1
  119. package/src/config.ts +1 -1
  120. package/src/network/gateway.integ.test.ts +48 -21
  121. package/src/network/gateway.test.ts +66 -0
  122. package/src/network/gateway.ts +60 -37
  123. package/src/types/bridge.ts +8 -19
  124. package/src/types/onboard.ts +5 -5
  125. package/lib/bridge/serialization.d.ts +0 -4
  126. package/lib/bridge/serialization.d.ts.map +0 -1
  127. package/lib/bridge/serialization.js +0 -31
  128. package/lib/bridge/serialization.js.map +0 -1
  129. package/lib-es/bridge/serialization.d.ts +0 -4
  130. package/lib-es/bridge/serialization.d.ts.map +0 -1
  131. package/lib-es/bridge/serialization.js +0 -27
  132. package/lib-es/bridge/serialization.js.map +0 -1
  133. package/src/bridge/serialization.ts +0 -36
@@ -0,0 +1,446 @@
1
+ import BigNumber from "bignumber.js";
2
+ import { Account } from "@ledgerhq/types-live";
3
+ import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
4
+ import {
5
+ AmountRequired,
6
+ FeeNotLoaded,
7
+ FeeRequired,
8
+ FeeTooHigh,
9
+ InvalidAddress,
10
+ InvalidAddressBecauseDestinationIsAlsoSource,
11
+ NotEnoughBalanceBecauseDestinationNotCreated,
12
+ NotEnoughSpendableBalance,
13
+ RecipientRequired,
14
+ } from "@ledgerhq/errors";
15
+ import { getTransactionStatus } from "./getTransactionStatus";
16
+ import { Transaction } from "../types";
17
+ import coinConfig from "../config";
18
+
19
+ // Mock the coin config
20
+ jest.mock("../config", () => ({
21
+ getCoinConfig: jest.fn(),
22
+ }));
23
+
24
+ const mockCoinConfig = jest.mocked(coinConfig);
25
+
26
+ describe("getTransactionStatus", () => {
27
+ const mockCurrency: CryptoCurrency = {
28
+ id: "canton_network",
29
+ name: "Canton Network",
30
+ family: "canton",
31
+ units: [
32
+ {
33
+ name: "Canton",
34
+ code: "CANTON",
35
+ magnitude: 8,
36
+ },
37
+ ],
38
+ ticker: "CANTON",
39
+ scheme: "canton",
40
+ color: "#000000",
41
+ type: "CryptoCurrency",
42
+ managerAppName: "Canton",
43
+ coinType: 0,
44
+ disableCountervalue: false,
45
+ delisted: false,
46
+ keywords: ["canton"],
47
+ explorerViews: [],
48
+ terminated: {
49
+ link: "",
50
+ },
51
+ };
52
+
53
+ const mockAccount: Account = {
54
+ id: "test-account-id",
55
+ seedIdentifier: "test-seed-identifier",
56
+ currency: mockCurrency,
57
+ balance: new BigNumber(1000), // 1000 units
58
+ spendableBalance: new BigNumber(1000),
59
+ freshAddress: "test::123",
60
+ freshAddressPath: "44'/60'/0'/0/0",
61
+ index: 0,
62
+ derivationMode: "canton",
63
+ used: true,
64
+ operations: [],
65
+ pendingOperations: [],
66
+ lastSyncDate: new Date(),
67
+ creationDate: new Date(),
68
+ operationsCount: 0,
69
+ blockHeight: 100,
70
+ balanceHistoryCache: {
71
+ HOUR: { latestDate: null, balances: [] },
72
+ DAY: { latestDate: null, balances: [] },
73
+ WEEK: { latestDate: null, balances: [] },
74
+ },
75
+ swapHistory: [],
76
+ nfts: [],
77
+ subAccounts: [],
78
+ type: "Account",
79
+ };
80
+
81
+ beforeEach(() => {
82
+ jest.clearAllMocks();
83
+ mockCoinConfig.getCoinConfig.mockReturnValue({
84
+ minReserve: 100, // 100 units minimum reserve
85
+ networkType: "mainnet",
86
+ status: { type: "active" },
87
+ nativeInstrumentId: "Amulet",
88
+ });
89
+ });
90
+
91
+ describe("fee validation", () => {
92
+ it("should return FeeNotLoaded error when fee is not provided", async () => {
93
+ const transaction: Transaction = {
94
+ family: "canton",
95
+ amount: new BigNumber(100),
96
+ recipient: "valid::123",
97
+ fee: null,
98
+ tokenId: "",
99
+ };
100
+
101
+ const result = await getTransactionStatus(mockAccount, transaction);
102
+
103
+ expect(result.errors.fee).toBeInstanceOf(FeeNotLoaded);
104
+ expect(result.warnings).toEqual({});
105
+ });
106
+
107
+ it("should return FeeRequired error when fee is zero", async () => {
108
+ const transaction: Transaction = {
109
+ family: "canton",
110
+ amount: new BigNumber(100),
111
+ recipient: "valid::123",
112
+ fee: new BigNumber(0),
113
+ tokenId: "",
114
+ };
115
+
116
+ const result = await getTransactionStatus(mockAccount, transaction);
117
+
118
+ expect(result.errors.fee).toBeInstanceOf(FeeRequired);
119
+ expect(result.warnings).toEqual({});
120
+ });
121
+
122
+ it("should add FeeTooHigh warning when fee is more than 10 times the amount", async () => {
123
+ const transaction: Transaction = {
124
+ family: "canton",
125
+ amount: new BigNumber(100), // Use larger amount to avoid balance issues
126
+ recipient: "valid::123",
127
+ fee: new BigNumber(1500), // 15x the amount
128
+ tokenId: "",
129
+ };
130
+
131
+ const result = await getTransactionStatus(mockAccount, transaction);
132
+
133
+ expect(result.warnings.feeTooHigh).toBeInstanceOf(FeeTooHigh);
134
+ // Don't check for empty errors since there might be balance issues
135
+ });
136
+
137
+ it("should not add FeeTooHigh warning when fee is reasonable", async () => {
138
+ const transaction: Transaction = {
139
+ family: "canton",
140
+ amount: new BigNumber(100),
141
+ recipient: "valid::123",
142
+ fee: new BigNumber(10), // 0.1x the amount
143
+ tokenId: "",
144
+ };
145
+
146
+ const result = await getTransactionStatus(mockAccount, transaction);
147
+
148
+ expect(result.warnings).toEqual({});
149
+ expect(result.errors).toEqual({});
150
+ });
151
+ });
152
+
153
+ describe("balance validation", () => {
154
+ it("should return NotEnoughSpendableBalance error when total spent exceeds balance minus reserve", async () => {
155
+ const transaction: Transaction = {
156
+ family: "canton",
157
+ amount: new BigNumber(950), // 950 + 10 fee = 960, but balance is 1000 and reserve is 100
158
+ recipient: "valid::123",
159
+ fee: new BigNumber(10),
160
+ tokenId: "",
161
+ };
162
+
163
+ const result = await getTransactionStatus(mockAccount, transaction);
164
+
165
+ expect(result.errors.amount).toBeInstanceOf(NotEnoughSpendableBalance);
166
+ });
167
+
168
+ it("should return NotEnoughBalanceBecauseDestinationNotCreated error when amount is below reserve", async () => {
169
+ const transaction: Transaction = {
170
+ family: "canton",
171
+ amount: new BigNumber(50), // Below reserve amount of 100
172
+ recipient: "valid::123",
173
+ fee: new BigNumber(10),
174
+ tokenId: "",
175
+ };
176
+
177
+ const result = await getTransactionStatus(mockAccount, transaction);
178
+
179
+ expect(result.errors.amount).toBeInstanceOf(NotEnoughBalanceBecauseDestinationNotCreated);
180
+ });
181
+
182
+ it("should pass balance validation when transaction is within limits", async () => {
183
+ const transaction: Transaction = {
184
+ family: "canton",
185
+ amount: new BigNumber(800), // 800 + 10 fee = 810, balance is 1000, reserve is 100, so 900 available
186
+ recipient: "valid::123",
187
+ fee: new BigNumber(10),
188
+ tokenId: "",
189
+ };
190
+
191
+ const result = await getTransactionStatus(mockAccount, transaction);
192
+
193
+ expect(result.errors.amount).toBeUndefined();
194
+ });
195
+ });
196
+
197
+ describe("recipient validation", () => {
198
+ it("should return RecipientRequired error when recipient is missing", async () => {
199
+ const transaction: Transaction = {
200
+ family: "canton",
201
+ amount: new BigNumber(100),
202
+ recipient: "",
203
+ fee: new BigNumber(10),
204
+ tokenId: "",
205
+ };
206
+
207
+ const result = await getTransactionStatus(mockAccount, transaction);
208
+
209
+ expect(result.errors.recipient).toBeInstanceOf(RecipientRequired);
210
+ });
211
+
212
+ it("should return InvalidAddressBecauseDestinationIsAlsoSource error when sending to self", async () => {
213
+ const transaction: Transaction = {
214
+ family: "canton",
215
+ amount: new BigNumber(100),
216
+ recipient: "test::123", // Same as account.freshAddress
217
+ fee: new BigNumber(10),
218
+ tokenId: "",
219
+ };
220
+
221
+ const result = await getTransactionStatus(mockAccount, transaction);
222
+
223
+ expect(result.errors.recipient).toBeInstanceOf(InvalidAddressBecauseDestinationIsAlsoSource);
224
+ });
225
+
226
+ it("should return InvalidAddress error when recipient is invalid", async () => {
227
+ const transaction: Transaction = {
228
+ family: "canton",
229
+ amount: new BigNumber(100),
230
+ recipient: "invalid-address",
231
+ fee: new BigNumber(10),
232
+ tokenId: "",
233
+ };
234
+
235
+ const result = await getTransactionStatus(mockAccount, transaction);
236
+
237
+ expect(result.errors.recipient).toBeInstanceOf(InvalidAddress);
238
+ });
239
+
240
+ it("should pass recipient validation when recipient is valid", async () => {
241
+ const transaction: Transaction = {
242
+ family: "canton",
243
+ amount: new BigNumber(100),
244
+ recipient: "valid::456",
245
+ fee: new BigNumber(10),
246
+ tokenId: "",
247
+ };
248
+
249
+ const result = await getTransactionStatus(mockAccount, transaction);
250
+
251
+ expect(result.errors.recipient).toBeUndefined();
252
+ });
253
+ });
254
+
255
+ describe("amount validation", () => {
256
+ it("should return AmountRequired error when amount is zero", async () => {
257
+ // Create a scenario where there are no other amount errors
258
+ // Use a high balance and amount above reserve to avoid other amount errors
259
+ const accountWithHighBalance = {
260
+ ...mockAccount,
261
+ balance: new BigNumber(10000), // High balance to avoid balance errors
262
+ };
263
+
264
+ // Set a high reserve to avoid the NotEnoughBalanceBecauseDestinationNotCreated error
265
+ mockCoinConfig.getCoinConfig.mockReturnValue({
266
+ minReserve: 0, // Set reserve to 0 to avoid reserve-related errors
267
+ networkType: "mainnet",
268
+ status: { type: "active" },
269
+ nativeInstrumentId: "Amulet",
270
+ });
271
+
272
+ const transaction: Transaction = {
273
+ family: "canton",
274
+ amount: new BigNumber(0),
275
+ recipient: "valid::123",
276
+ fee: new BigNumber(10),
277
+ tokenId: "",
278
+ };
279
+
280
+ const result = await getTransactionStatus(accountWithHighBalance, transaction);
281
+
282
+ expect(result.errors.amount).toBeInstanceOf(AmountRequired);
283
+ });
284
+
285
+ it("should not return AmountRequired error when amount is positive", async () => {
286
+ const transaction: Transaction = {
287
+ family: "canton",
288
+ amount: new BigNumber(100),
289
+ recipient: "valid::123",
290
+ fee: new BigNumber(10),
291
+ tokenId: "",
292
+ };
293
+
294
+ const result = await getTransactionStatus(mockAccount, transaction);
295
+
296
+ expect(result.errors.amount).toBeUndefined();
297
+ });
298
+ });
299
+
300
+ describe("return values", () => {
301
+ it("should return correct estimatedFees, amount, and totalSpent", async () => {
302
+ const transaction: Transaction = {
303
+ family: "canton",
304
+ amount: new BigNumber(100),
305
+ recipient: "valid::123",
306
+ fee: new BigNumber(10),
307
+ tokenId: "",
308
+ };
309
+
310
+ const result = await getTransactionStatus(mockAccount, transaction);
311
+
312
+ expect(result.estimatedFees).toEqual(new BigNumber(10));
313
+ expect(result.amount).toEqual(new BigNumber(100));
314
+ expect(result.totalSpent).toEqual(new BigNumber(110));
315
+ });
316
+
317
+ it("should return empty errors and warnings when transaction is valid", async () => {
318
+ const transaction: Transaction = {
319
+ family: "canton",
320
+ amount: new BigNumber(100),
321
+ recipient: "valid::123",
322
+ fee: new BigNumber(10),
323
+ tokenId: "",
324
+ };
325
+
326
+ const result = await getTransactionStatus(mockAccount, transaction);
327
+
328
+ expect(result.errors).toEqual({});
329
+ expect(result.warnings).toEqual({});
330
+ });
331
+ });
332
+
333
+ describe("edge cases", () => {
334
+ it("should handle account with zero balance", async () => {
335
+ const accountWithZeroBalance = {
336
+ ...mockAccount,
337
+ balance: new BigNumber(0),
338
+ };
339
+
340
+ const transaction: Transaction = {
341
+ family: "canton",
342
+ amount: new BigNumber(50),
343
+ recipient: "valid::123",
344
+ fee: new BigNumber(10),
345
+ tokenId: "",
346
+ };
347
+
348
+ const result = await getTransactionStatus(accountWithZeroBalance, transaction);
349
+
350
+ expect(result.errors.amount).toBeInstanceOf(NotEnoughSpendableBalance);
351
+ });
352
+
353
+ it("should handle account with balance exactly equal to reserve", async () => {
354
+ const accountWithReserveBalance = {
355
+ ...mockAccount,
356
+ balance: new BigNumber(100), // Exactly equal to reserve
357
+ };
358
+
359
+ const transaction: Transaction = {
360
+ family: "canton",
361
+ amount: new BigNumber(50),
362
+ recipient: "valid::123",
363
+ fee: new BigNumber(10),
364
+ tokenId: "",
365
+ };
366
+
367
+ const result = await getTransactionStatus(accountWithReserveBalance, transaction);
368
+
369
+ expect(result.errors.amount).toBeInstanceOf(NotEnoughSpendableBalance);
370
+ });
371
+
372
+ it("should handle zero reserve amount", async () => {
373
+ mockCoinConfig.getCoinConfig.mockReturnValue({
374
+ minReserve: 0,
375
+ networkType: "mainnet",
376
+ status: { type: "active" },
377
+ nativeInstrumentId: "Amulet",
378
+ });
379
+
380
+ const transaction: Transaction = {
381
+ family: "canton",
382
+ amount: new BigNumber(50),
383
+ recipient: "valid::123",
384
+ fee: new BigNumber(10),
385
+ tokenId: "",
386
+ };
387
+
388
+ const result = await getTransactionStatus(mockAccount, transaction);
389
+
390
+ expect(result.errors.amount).toBeUndefined();
391
+ });
392
+
393
+ it("should handle undefined reserve amount", async () => {
394
+ mockCoinConfig.getCoinConfig.mockReturnValue({
395
+ networkType: "mainnet",
396
+ status: { type: "active" },
397
+ nativeInstrumentId: "Amulet",
398
+ });
399
+
400
+ const transaction: Transaction = {
401
+ family: "canton",
402
+ amount: new BigNumber(50),
403
+ recipient: "valid::123",
404
+ fee: new BigNumber(10),
405
+ tokenId: "",
406
+ };
407
+
408
+ const result = await getTransactionStatus(mockAccount, transaction);
409
+
410
+ expect(result.errors.amount).toBeUndefined();
411
+ });
412
+ });
413
+
414
+ describe("multiple validation errors", () => {
415
+ it("should return multiple errors when multiple validations fail", async () => {
416
+ const transaction: Transaction = {
417
+ family: "canton",
418
+ amount: new BigNumber(0), // AmountRequired
419
+ recipient: "", // RecipientRequired
420
+ fee: null, // FeeNotLoaded
421
+ tokenId: "",
422
+ };
423
+
424
+ const result = await getTransactionStatus(mockAccount, transaction);
425
+
426
+ expect(result.errors.amount).toBeInstanceOf(AmountRequired);
427
+ expect(result.errors.recipient).toBeInstanceOf(RecipientRequired);
428
+ expect(result.errors.fee).toBeInstanceOf(FeeNotLoaded);
429
+ });
430
+
431
+ it("should return both errors and warnings", async () => {
432
+ const transaction: Transaction = {
433
+ family: "canton",
434
+ amount: new BigNumber(5), // Small amount
435
+ recipient: "valid::123",
436
+ fee: new BigNumber(100), // High fee relative to amount
437
+ tokenId: "",
438
+ };
439
+
440
+ const result = await getTransactionStatus(mockAccount, transaction);
441
+
442
+ expect(result.warnings.feeTooHigh).toBeInstanceOf(FeeTooHigh);
443
+ expect(result.errors.amount).toBeInstanceOf(NotEnoughBalanceBecauseDestinationNotCreated);
444
+ });
445
+ });
446
+ });
@@ -18,10 +18,9 @@ import { estimateMaxSpendable } from "./estimateMaxSpendable";
18
18
  import { getTransactionStatus } from "./getTransactionStatus";
19
19
  import { prepareTransaction } from "./prepareTransaction";
20
20
  import { buildSignOperation } from "./signOperation";
21
- import { getAccountShape } from "./sync";
21
+ import { makeGetAccountShape } from "./sync";
22
22
  import { updateTransaction } from "./updateTransaction";
23
23
  import { buildOnboardAccount, buildAuthorizePreapproval } from "./onboard";
24
- import { assignFromAccountRaw, assignToAccountRaw } from "./serialization";
25
24
 
26
25
  export function createBridges(
27
26
  signerContext: SignerContext<CantonSigner>,
@@ -33,7 +32,7 @@ export function createBridges(
33
32
  const receive = makeAccountBridgeReceive(getAddressWrapper(getAddress));
34
33
 
35
34
  const scanAccounts = makeScanAccounts({
36
- getAccountShape: getAccountShape,
35
+ getAccountShape: makeGetAccountShape(signerContext),
37
36
  getAddressFn: getAddress,
38
37
  });
39
38
 
@@ -49,7 +48,7 @@ export function createBridges(
49
48
  };
50
49
 
51
50
  const signOperation = buildSignOperation(signerContext);
52
- const sync = makeSync({ getAccountShape });
51
+ const sync = makeSync({ getAccountShape: makeGetAccountShape(signerContext) });
53
52
  // we want one method per file
54
53
  const accountBridge: AccountBridge<Transaction> = {
55
54
  broadcast,
@@ -63,8 +62,9 @@ export function createBridges(
63
62
  sync,
64
63
  receive,
65
64
  signOperation,
66
- assignToAccountRaw,
67
- assignFromAccountRaw,
65
+ signRawOperation: () => {
66
+ throw new Error("signRawOperation is not supported");
67
+ },
68
68
  getSerializedAddressParameters,
69
69
  };
70
70
 
@@ -1,23 +1,45 @@
1
+ import BigNumber from "bignumber.js";
1
2
  import { firstValueFrom, toArray } from "rxjs";
3
+ import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
4
+ import { emptyHistoryCache } from "@ledgerhq/coin-framework/account/index";
2
5
  import { generateMockKeyPair, createMockSigner } from "../test/cantonTestUtils";
3
- import { buildOnboardAccount, isAccountOnboarded, buildAuthorizePreapproval } from "./onboard";
4
6
  import {
7
+ AuthorizeStatus,
5
8
  OnboardStatus,
6
- PreApprovalStatus,
9
+ CantonAuthorizeProgress,
10
+ CantonAuthorizeResult,
7
11
  CantonOnboardProgress,
8
12
  CantonOnboardResult,
9
- CantonPreApprovalProgress,
10
- CantonPreApprovalResult,
11
13
  } from "../types/onboard";
12
14
  import coinConfig from "../config";
13
- import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
15
+ import { buildOnboardAccount, isAccountOnboarded, buildAuthorizePreapproval } from "./onboard";
14
16
 
15
17
  describe("onboard (devnet)", () => {
16
18
  const mockDeviceId = "test-device-id";
17
- const mockDerivationPath = "44'/6767'/0'/0'/0'";
18
19
  const mockCurrency = {
19
20
  id: "canton_network",
20
21
  } as unknown as CryptoCurrency;
22
+ const mockAccount = {
23
+ type: "Account" as const,
24
+ id: "js:2:canton_network:canton_3f5c9d9a:canton",
25
+ seedIdentifier: "canton_3f5c9d9a",
26
+ derivationMode: "canton" as const,
27
+ index: 0,
28
+ freshAddress: "canton_3f5c9d9a",
29
+ freshAddressPath: "44'/6767'/0'/0'/0'",
30
+ used: false,
31
+ balance: BigNumber(10000),
32
+ spendableBalance: BigNumber(10000),
33
+ creationDate: new Date(),
34
+ blockHeight: 1,
35
+ currency: mockCurrency,
36
+ operationsCount: 0,
37
+ operations: [],
38
+ pendingOperations: [],
39
+ lastSyncDate: new Date(),
40
+ balanceHistoryCache: emptyHistoryCache,
41
+ swapHistory: [],
42
+ };
21
43
 
22
44
  let onboardedAccount: {
23
45
  keyPair: ReturnType<typeof generateMockKeyPair>;
@@ -58,7 +80,7 @@ describe("onboard (devnet)", () => {
58
80
 
59
81
  const onboardObservable = buildOnboardAccount(mockSignerContext);
60
82
  const onboardValues = await firstValueFrom(
61
- onboardObservable(mockCurrency, mockDeviceId, mockDerivationPath).pipe(toArray()),
83
+ onboardObservable(mockCurrency, mockDeviceId, mockAccount).pipe(toArray()),
62
84
  );
63
85
  const onboardResult = onboardValues.find(
64
86
  (value): value is CantonOnboardResult => "partyId" in value,
@@ -82,10 +104,10 @@ describe("onboard (devnet)", () => {
82
104
  // THEN
83
105
  expect(result).not.toBe(false);
84
106
  if (typeof result === "object") {
85
- expect(result.party_id).toBeDefined();
86
- expect(result.party_id).toBe(onboardResult!.partyId);
107
+ expect(result.partyId).toBeDefined();
108
+ expect(result.partyId).toBe(onboardResult.partyId);
87
109
  }
88
- }, 30000);
110
+ }, 40000);
89
111
 
90
112
  it("should return false for non-onboarded account with fresh keypair", async () => {
91
113
  // GIVEN
@@ -122,7 +144,7 @@ describe("onboard (devnet)", () => {
122
144
 
123
145
  // WHEN
124
146
  const allValues = await firstValueFrom(
125
- onboardObservable(mockCurrency, mockDeviceId, mockDerivationPath).pipe(toArray()),
147
+ onboardObservable(mockCurrency, mockDeviceId, mockAccount).pipe(toArray()),
126
148
  );
127
149
  const progressValues = allValues.filter(
128
150
  (value): value is CantonOnboardProgress => "status" in value && !("partyId" in value),
@@ -149,12 +171,12 @@ describe("onboard (devnet)", () => {
149
171
 
150
172
  it("should complete full onboarding flow with already onboarded account", async () => {
151
173
  // GIVEN
152
- const { keyPair, mockSignerContext, onboardResult: firstResult } = getOnboardedAccount();
174
+ const { mockSignerContext, onboardResult: firstResult } = getOnboardedAccount();
153
175
  const secondOnboardObservable = buildOnboardAccount(mockSignerContext);
154
176
 
155
177
  // WHEN
156
178
  const secondOnboardValues = await firstValueFrom(
157
- secondOnboardObservable(mockCurrency, mockDeviceId, mockDerivationPath).pipe(toArray()),
179
+ secondOnboardObservable(mockCurrency, mockDeviceId, mockAccount).pipe(toArray()),
158
180
  );
159
181
  const secondResult = secondOnboardValues.find(
160
182
  (value): value is CantonOnboardResult => "partyId" in value,
@@ -175,27 +197,23 @@ describe("onboard (devnet)", () => {
175
197
 
176
198
  // WHEN
177
199
  const preapprovalValues = await firstValueFrom(
178
- preapprovalObservable(
179
- mockCurrency,
180
- mockDeviceId,
181
- mockDerivationPath,
182
- onboardResult.partyId,
183
- ).pipe(toArray()),
200
+ preapprovalObservable(mockCurrency, mockDeviceId, mockAccount, onboardResult.partyId).pipe(
201
+ toArray(),
202
+ ),
184
203
  );
185
204
 
186
205
  const progressValues = preapprovalValues.filter(
187
- (value): value is CantonPreApprovalProgress =>
188
- "status" in value && !("isApproved" in value),
206
+ (value): value is CantonAuthorizeProgress => "status" in value && !("isApproved" in value),
189
207
  );
190
208
  const resultValues = preapprovalValues.filter(
191
- (value): value is CantonPreApprovalResult => "isApproved" in value,
209
+ (value): value is CantonAuthorizeResult => "isApproved" in value,
192
210
  );
193
211
 
194
212
  // THEN
195
213
  // Check expected status progression
196
- expect(progressValues.some(p => p.status === PreApprovalStatus.PREPARE)).toBe(true);
197
- expect(progressValues.some(p => p.status === PreApprovalStatus.SIGN)).toBe(true);
198
- expect(progressValues.some(p => p.status === PreApprovalStatus.SUBMIT)).toBe(true);
214
+ expect(progressValues.some(p => p.status === AuthorizeStatus.PREPARE)).toBe(true);
215
+ expect(progressValues.some(p => p.status === AuthorizeStatus.SIGN)).toBe(true);
216
+ expect(progressValues.some(p => p.status === AuthorizeStatus.SUBMIT)).toBe(true);
199
217
 
200
218
  // Check final result (should be approved)
201
219
  expect(resultValues.length).toBeGreaterThan(0);
@@ -216,12 +234,7 @@ describe("onboard (devnet)", () => {
216
234
  // WHEN & THEN
217
235
  try {
218
236
  await firstValueFrom(
219
- preapprovalObservable(
220
- mockCurrency,
221
- mockDeviceId,
222
- mockDerivationPath,
223
- "invalid-party-id-123",
224
- ),
237
+ preapprovalObservable(mockCurrency, mockDeviceId, mockAccount, "invalid-party-id-123"),
225
238
  );
226
239
  expect(true).toBe(true);
227
240
  } catch (error) {