@ledgerhq/coin-canton 0.11.0 → 0.12.0-nightly.20251210100832

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 (84) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +1 -1
  3. package/lib/bridge/acceptOffer.d.ts.map +1 -1
  4. package/lib/bridge/acceptOffer.js +8 -0
  5. package/lib/bridge/acceptOffer.js.map +1 -1
  6. package/lib/bridge/getTransactionStatus.d.ts +1 -0
  7. package/lib/bridge/getTransactionStatus.d.ts.map +1 -1
  8. package/lib/bridge/getTransactionStatus.js +48 -17
  9. package/lib/bridge/getTransactionStatus.js.map +1 -1
  10. package/lib/bridge/onboard.d.ts.map +1 -1
  11. package/lib/bridge/onboard.js +4 -1
  12. package/lib/bridge/onboard.js.map +1 -1
  13. package/lib/bridge/serialization.d.ts.map +1 -1
  14. package/lib/bridge/serialization.js +7 -1
  15. package/lib/bridge/serialization.js.map +1 -1
  16. package/lib/bridge/sync.d.ts.map +1 -1
  17. package/lib/bridge/sync.js +19 -14
  18. package/lib/bridge/sync.js.map +1 -1
  19. package/lib/network/gateway.d.ts +20 -3
  20. package/lib/network/gateway.d.ts.map +1 -1
  21. package/lib/network/gateway.js +75 -16
  22. package/lib/network/gateway.js.map +1 -1
  23. package/lib/test/cantonTestUtils.d.ts +3 -1
  24. package/lib/test/cantonTestUtils.d.ts.map +1 -1
  25. package/lib/test/cantonTestUtils.js +1 -1
  26. package/lib/test/cantonTestUtils.js.map +1 -1
  27. package/lib/types/bridge.d.ts +6 -0
  28. package/lib/types/bridge.d.ts.map +1 -1
  29. package/lib/types/errors.d.ts +3 -0
  30. package/lib/types/errors.d.ts.map +1 -1
  31. package/lib/types/errors.js +2 -1
  32. package/lib/types/errors.js.map +1 -1
  33. package/lib-es/bridge/acceptOffer.d.ts.map +1 -1
  34. package/lib-es/bridge/acceptOffer.js +8 -0
  35. package/lib-es/bridge/acceptOffer.js.map +1 -1
  36. package/lib-es/bridge/getTransactionStatus.d.ts +1 -0
  37. package/lib-es/bridge/getTransactionStatus.d.ts.map +1 -1
  38. package/lib-es/bridge/getTransactionStatus.js +47 -17
  39. package/lib-es/bridge/getTransactionStatus.js.map +1 -1
  40. package/lib-es/bridge/onboard.d.ts.map +1 -1
  41. package/lib-es/bridge/onboard.js +5 -2
  42. package/lib-es/bridge/onboard.js.map +1 -1
  43. package/lib-es/bridge/serialization.d.ts.map +1 -1
  44. package/lib-es/bridge/serialization.js +7 -1
  45. package/lib-es/bridge/serialization.js.map +1 -1
  46. package/lib-es/bridge/sync.d.ts.map +1 -1
  47. package/lib-es/bridge/sync.js +19 -14
  48. package/lib-es/bridge/sync.js.map +1 -1
  49. package/lib-es/network/gateway.d.ts +20 -3
  50. package/lib-es/network/gateway.d.ts.map +1 -1
  51. package/lib-es/network/gateway.js +70 -15
  52. package/lib-es/network/gateway.js.map +1 -1
  53. package/lib-es/test/cantonTestUtils.d.ts +3 -1
  54. package/lib-es/test/cantonTestUtils.d.ts.map +1 -1
  55. package/lib-es/test/cantonTestUtils.js +1 -1
  56. package/lib-es/test/cantonTestUtils.js.map +1 -1
  57. package/lib-es/types/bridge.d.ts +6 -0
  58. package/lib-es/types/bridge.d.ts.map +1 -1
  59. package/lib-es/types/errors.d.ts +3 -0
  60. package/lib-es/types/errors.d.ts.map +1 -1
  61. package/lib-es/types/errors.js +1 -0
  62. package/lib-es/types/errors.js.map +1 -1
  63. package/package.json +10 -10
  64. package/src/api/getBalance.integ.test.ts +1 -1
  65. package/src/api/lastBlock.integ.test.ts +1 -1
  66. package/src/api/listOperations.integ.test.ts +1 -1
  67. package/src/bridge/acceptOffer.test.ts +43 -4
  68. package/src/bridge/acceptOffer.ts +9 -1
  69. package/src/bridge/getTransactionStatus.test.ts +95 -3
  70. package/src/bridge/getTransactionStatus.ts +61 -24
  71. package/src/bridge/onboard.integ.test.ts +85 -4
  72. package/src/bridge/onboard.test.ts +107 -1
  73. package/src/bridge/onboard.ts +6 -1
  74. package/src/bridge/prepareTransaction.test.ts +1 -1
  75. package/src/bridge/serialization.ts +7 -1
  76. package/src/bridge/sync.integ.test.ts +1 -1
  77. package/src/bridge/sync.test.ts +156 -1
  78. package/src/bridge/sync.ts +22 -15
  79. package/src/network/gateway.integ.test.ts +24 -1
  80. package/src/network/gateway.test.ts +64 -2
  81. package/src/network/gateway.ts +98 -26
  82. package/src/test/cantonTestUtils.ts +1 -1
  83. package/src/types/bridge.ts +6 -0
  84. package/src/types/errors.ts +2 -0
@@ -1,5 +1,6 @@
1
1
  import network from "@ledgerhq/live-network";
2
- import type { LiveNetworkRequest } from "@ledgerhq/live-network/network";
2
+ import type { LiveNetworkRequest, LiveNetworkResponse } from "@ledgerhq/live-network/network";
3
+ import { makeLRUCache, minutes } from "@ledgerhq/live-network/cache";
3
4
  import { getEnv } from "@ledgerhq/live-env";
4
5
  import coinConfig from "../config";
5
6
  import {
@@ -11,6 +12,7 @@ import {
11
12
  } from "../types/onboard";
12
13
  import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
13
14
  import type { CantonSignature } from "../types/signer";
15
+ import { TopologyChangeError } from "../types/errors";
14
16
 
15
17
  export type OnboardingPrepareResponse = {
16
18
  party_id: string;
@@ -19,17 +21,29 @@ export type OnboardingPrepareResponse = {
19
21
  transactions: {
20
22
  namespace_transaction: {
21
23
  serialized: string;
22
- json: object;
24
+ transaction: {
25
+ operation: string;
26
+ serial: number;
27
+ mapping: Record<string, unknown>;
28
+ };
23
29
  hash: string;
24
30
  };
25
31
  party_to_key_transaction: {
26
32
  serialized: string;
27
- json: object;
33
+ transaction: {
34
+ operation: string;
35
+ serial: number;
36
+ mapping: Record<string, unknown>;
37
+ };
28
38
  hash: string;
29
39
  };
30
40
  party_to_participant_transaction: {
31
41
  serialized: string;
32
- json: object;
42
+ transaction: {
43
+ operation: string;
44
+ serial: number;
45
+ mapping: Record<string, unknown>;
46
+ };
33
47
  hash: string;
34
48
  };
35
49
  combined_hash: string;
@@ -314,23 +328,56 @@ export type OperationInfo =
314
328
  };
315
329
 
316
330
  const getGatewayUrl = (currency: CryptoCurrency) => coinConfig.getCoinConfig(currency).gatewayUrl;
317
- const getNodeId = (currency: CryptoCurrency) =>
318
- coinConfig.getCoinConfig(currency).nodeId || "ledger-live-devnet";
331
+ const getNodeId = (currency: CryptoCurrency) => {
332
+ const overrideNodeId = getEnv("CANTON_NODE_ID_OVERRIDE");
333
+ if (overrideNodeId) {
334
+ return overrideNodeId;
335
+ }
336
+ return coinConfig.getCoinConfig(currency).nodeId || "ledger-live-devnet";
337
+ };
319
338
  export const getNetworkType = (currency: CryptoCurrency) =>
320
339
  coinConfig.getCoinConfig(currency).networkType;
321
340
 
322
- const gatewayNetwork = <T, U = unknown>(req: LiveNetworkRequest<U>) => {
341
+ export const isPartyNotFound = (error: unknown): boolean => {
342
+ if (error instanceof Error) {
343
+ const errorMessage = error.message.toLowerCase().replace(/_/g, " ");
344
+ return errorMessage.includes("party") && errorMessage.includes("not found");
345
+ }
346
+ return false;
347
+ };
348
+
349
+ export const isPartyAlreadyExists = (error: unknown): boolean => {
350
+ if (error instanceof Error) {
351
+ const errorMessage = error.message.toLowerCase().replace(/_/g, " ");
352
+ return errorMessage.includes("party") && errorMessage.includes("already exists");
353
+ }
354
+ return false;
355
+ };
356
+
357
+ const gatewayNetwork = async <T, U = unknown>(
358
+ req: LiveNetworkRequest<U>,
359
+ ): Promise<LiveNetworkResponse<T>> => {
323
360
  const API_KEY = getEnv("CANTON_API_KEY");
324
- return network<T, U>({
325
- ...req,
326
- headers: {
327
- ...(req.headers || {}),
328
- ...(API_KEY && { "X-Ledger-Canton-Api-Key": API_KEY }),
329
- },
330
- });
361
+ try {
362
+ return await network<T, U>({
363
+ ...req,
364
+ headers: {
365
+ ...(req.headers || {}),
366
+ ...(API_KEY && { "X-Ledger-Canton-Api-Key": API_KEY }),
367
+ },
368
+ });
369
+ } catch (error) {
370
+ if (isPartyNotFound(error)) {
371
+ throw new TopologyChangeError("Topology change detected. Re-onboarding required.");
372
+ }
373
+ throw error;
374
+ }
331
375
  };
332
376
 
333
- export async function prepareOnboarding(currency: CryptoCurrency, pubKey: string) {
377
+ export async function prepareOnboarding(
378
+ currency: CryptoCurrency,
379
+ pubKey: string,
380
+ ): Promise<OnboardingPrepareResponse> {
334
381
  const gatewayUrl = getGatewayUrl(currency);
335
382
  const nodeId = getNodeId(currency);
336
383
  const fullUrl = `${gatewayUrl}/v1/node/${nodeId}/onboarding/prepare`;
@@ -347,13 +394,38 @@ export async function prepareOnboarding(currency: CryptoCurrency, pubKey: string
347
394
  return data;
348
395
  }
349
396
 
350
- type OnboardingSubmitError409 = {
351
- partyId: string;
352
- status: 409;
353
- type: "PARTY_ALREADY_EXISTS";
354
- message: string;
397
+ export async function isTopologyChangeRequired(currency: CryptoCurrency, pubKey: string) {
398
+ try {
399
+ const response = await prepareOnboarding(currency, pubKey);
400
+ // if response is not undefined (we have a transaction to sign) topology change is required
401
+ if (response) {
402
+ return true;
403
+ }
404
+ return false;
405
+ } catch (error) {
406
+ if (isPartyAlreadyExists(error)) {
407
+ return false;
408
+ }
409
+ throw error;
410
+ }
411
+ }
412
+
413
+ const getIsTopologyChangeRequiredCacheKey = (currency: CryptoCurrency, pubKey: string): string => {
414
+ const nodeId = getNodeId(currency);
415
+ return `${pubKey}_${nodeId}`;
355
416
  };
356
417
 
418
+ export const isTopologyChangeRequiredCached = makeLRUCache(
419
+ isTopologyChangeRequired,
420
+ getIsTopologyChangeRequiredCacheKey,
421
+ minutes(10),
422
+ );
423
+
424
+ export function clearIsTopologyChangeRequiredCache(currency: CryptoCurrency, pubKey: string): void {
425
+ const cacheKey = getIsTopologyChangeRequiredCacheKey(currency, pubKey);
426
+ isTopologyChangeRequiredCached.clear(cacheKey);
427
+ }
428
+
357
429
  export async function submitOnboarding(
358
430
  currency: CryptoCurrency,
359
431
  publicKey: string,
@@ -375,19 +447,19 @@ export async function submitOnboarding(
375
447
  },
376
448
  });
377
449
  return data;
378
- } catch (e) {
379
- if (e instanceof Error && "type" in e && e.type === "PARTY_ALREADY_EXISTS") {
380
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
381
- const { partyId } = e as unknown as OnboardingSubmitError409;
450
+ } catch (error) {
451
+ if (isPartyAlreadyExists(error)) {
452
+ // If party already exists, use party_id from prepare response
453
+ // The network layer strips custom properties from errors, so we can't extract partyId from error
382
454
  return {
383
455
  party: {
384
- party_id: partyId,
456
+ party_id: prepareResponse.party_id,
385
457
  public_key: publicKey,
386
458
  },
387
459
  };
388
460
  }
389
461
 
390
- throw e;
462
+ throw error;
391
463
  }
392
464
  }
393
465
 
@@ -225,7 +225,7 @@ export function createMockSigner(keyPair: CantonTestKeyPair) {
225
225
 
226
226
  const cleanHash = hashToSign.startsWith("0x") ? hashToSign.slice(2) : hashToSign;
227
227
  const signature = keyPair.sign(cleanHash);
228
- return signature;
228
+ return { signature };
229
229
  },
230
230
  };
231
231
  }
@@ -76,12 +76,18 @@ export type TransactionStatus = TransactionStatusCommon;
76
76
  export type TransactionStatusRaw = TransactionStatusCommonRaw;
77
77
 
78
78
  export type CantonResources = {
79
+ isOnboarded: boolean;
79
80
  instrumentUtxoCounts: Record<string, number>;
80
81
  pendingTransferProposals: TransferProposal[];
82
+ publicKey?: string;
83
+ xpub?: string;
81
84
  };
82
85
  export type CantonResourcesRaw = {
86
+ isOnboarded: boolean;
83
87
  instrumentUtxoCounts: Record<string, number>;
84
88
  pendingTransferProposals: TransferProposal[];
89
+ publicKey?: string;
90
+ xpub?: string;
85
91
  };
86
92
 
87
93
  export type CantonAccount = Account & {
@@ -4,3 +4,5 @@ export const SimulationError = createCustomErrorClass("SimulationError");
4
4
 
5
5
  export const TooManyUtxosCritical = createCustomErrorClass("TooManyUtxosCritical");
6
6
  export const TooManyUtxosWarning = createCustomErrorClass("TooManyUtxosWarning");
7
+
8
+ export const TopologyChangeError = createCustomErrorClass("TopologyChangeError");