@ledgerhq/coin-canton 0.5.0-nightly.1 → 0.5.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 (166) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.unimportedrc.json +12 -4
  3. package/CHANGELOG.md +21 -0
  4. package/lib/api/getBalance.integ.test.js +1 -1
  5. package/lib/api/getBalance.integ.test.js.map +1 -1
  6. package/lib/api/index.d.ts.map +1 -1
  7. package/lib/api/index.js +11 -8
  8. package/lib/api/index.js.map +1 -1
  9. package/lib/bridge/createTransaction.test.js +1 -1
  10. package/lib/bridge/createTransaction.test.js.map +1 -1
  11. package/lib/bridge/index.d.ts +3 -3
  12. package/lib/bridge/index.d.ts.map +1 -1
  13. package/lib/bridge/index.js +9 -1
  14. package/lib/bridge/index.js.map +1 -1
  15. package/lib/bridge/onboard.d.ts +10 -0
  16. package/lib/bridge/onboard.d.ts.map +1 -0
  17. package/lib/bridge/onboard.integ.test.d.ts +2 -0
  18. package/lib/bridge/onboard.integ.test.d.ts.map +1 -0
  19. package/lib/bridge/onboard.integ.test.js +156 -0
  20. package/lib/bridge/onboard.integ.test.js.map +1 -0
  21. package/lib/bridge/onboard.js +139 -0
  22. package/lib/bridge/onboard.js.map +1 -0
  23. package/lib/bridge/prepareTransaction.d.ts.map +1 -1
  24. package/lib/bridge/prepareTransaction.js +5 -7
  25. package/lib/bridge/prepareTransaction.js.map +1 -1
  26. package/lib/bridge/signOperation.d.ts.map +1 -1
  27. package/lib/bridge/signOperation.js +2 -1
  28. package/lib/bridge/signOperation.js.map +1 -1
  29. package/lib/bridge/sync.d.ts.map +1 -1
  30. package/lib/bridge/sync.integ.test.d.ts +2 -0
  31. package/lib/bridge/sync.integ.test.d.ts.map +1 -0
  32. package/lib/bridge/sync.integ.test.js +175 -0
  33. package/lib/bridge/sync.integ.test.js.map +1 -0
  34. package/lib/bridge/sync.js +39 -36
  35. package/lib/bridge/sync.js.map +1 -1
  36. package/lib/bridge/updateTransaction.d.ts.map +1 -1
  37. package/lib/bridge/updateTransaction.js +0 -4
  38. package/lib/bridge/updateTransaction.js.map +1 -1
  39. package/lib/common-logic/history/listOperations.d.ts.map +1 -1
  40. package/lib/common-logic/history/listOperations.js +19 -31
  41. package/lib/common-logic/history/listOperations.js.map +1 -1
  42. package/lib/common-logic/transaction/craftTransaction.d.ts +4 -3
  43. package/lib/common-logic/transaction/craftTransaction.d.ts.map +1 -1
  44. package/lib/common-logic/transaction/craftTransaction.js +10 -12
  45. package/lib/common-logic/transaction/craftTransaction.js.map +1 -1
  46. package/lib/network/gateway.d.ts +194 -3
  47. package/lib/network/gateway.d.ts.map +1 -1
  48. package/lib/network/gateway.integ.test.js +121 -11
  49. package/lib/network/gateway.integ.test.js.map +1 -1
  50. package/lib/network/gateway.js +96 -18
  51. package/lib/network/gateway.js.map +1 -1
  52. package/lib/network/node.d.ts +2 -2
  53. package/lib/network/node.d.ts.map +1 -1
  54. package/lib/network/node.js.map +1 -1
  55. package/lib/network/types.d.ts +1 -1
  56. package/lib/network/types.d.ts.map +1 -1
  57. package/lib/signer/getAddress.d.ts.map +1 -1
  58. package/lib/signer/getAddress.js +2 -2
  59. package/lib/signer/getAddress.js.map +1 -1
  60. package/lib/test/cantonTestUtils.d.ts +33 -0
  61. package/lib/test/cantonTestUtils.d.ts.map +1 -0
  62. package/lib/test/cantonTestUtils.js +159 -0
  63. package/lib/test/cantonTestUtils.js.map +1 -0
  64. package/lib/types/bridge.d.ts +7 -1
  65. package/lib/types/bridge.d.ts.map +1 -1
  66. package/lib/types/index.d.ts +1 -10
  67. package/lib/types/index.d.ts.map +1 -1
  68. package/lib/types/index.js +1 -0
  69. package/lib/types/index.js.map +1 -1
  70. package/lib/types/onboard.d.ts +55 -0
  71. package/lib/types/onboard.d.ts.map +1 -0
  72. package/lib/types/onboard.js +22 -0
  73. package/lib/types/onboard.js.map +1 -0
  74. package/lib-es/api/getBalance.integ.test.js +1 -1
  75. package/lib-es/api/getBalance.integ.test.js.map +1 -1
  76. package/lib-es/api/index.d.ts.map +1 -1
  77. package/lib-es/api/index.js +12 -9
  78. package/lib-es/api/index.js.map +1 -1
  79. package/lib-es/bridge/createTransaction.test.js +1 -1
  80. package/lib-es/bridge/createTransaction.test.js.map +1 -1
  81. package/lib-es/bridge/index.d.ts +3 -3
  82. package/lib-es/bridge/index.d.ts.map +1 -1
  83. package/lib-es/bridge/index.js +9 -1
  84. package/lib-es/bridge/index.js.map +1 -1
  85. package/lib-es/bridge/onboard.d.ts +10 -0
  86. package/lib-es/bridge/onboard.d.ts.map +1 -0
  87. package/lib-es/bridge/onboard.integ.test.d.ts +2 -0
  88. package/lib-es/bridge/onboard.integ.test.d.ts.map +1 -0
  89. package/lib-es/bridge/onboard.integ.test.js +151 -0
  90. package/lib-es/bridge/onboard.integ.test.js.map +1 -0
  91. package/lib-es/bridge/onboard.js +133 -0
  92. package/lib-es/bridge/onboard.js.map +1 -0
  93. package/lib-es/bridge/prepareTransaction.d.ts.map +1 -1
  94. package/lib-es/bridge/prepareTransaction.js +6 -8
  95. package/lib-es/bridge/prepareTransaction.js.map +1 -1
  96. package/lib-es/bridge/signOperation.d.ts.map +1 -1
  97. package/lib-es/bridge/signOperation.js +2 -1
  98. package/lib-es/bridge/signOperation.js.map +1 -1
  99. package/lib-es/bridge/sync.d.ts.map +1 -1
  100. package/lib-es/bridge/sync.integ.test.d.ts +2 -0
  101. package/lib-es/bridge/sync.integ.test.d.ts.map +1 -0
  102. package/lib-es/bridge/sync.integ.test.js +137 -0
  103. package/lib-es/bridge/sync.integ.test.js.map +1 -0
  104. package/lib-es/bridge/sync.js +38 -35
  105. package/lib-es/bridge/sync.js.map +1 -1
  106. package/lib-es/bridge/updateTransaction.d.ts.map +1 -1
  107. package/lib-es/bridge/updateTransaction.js +0 -4
  108. package/lib-es/bridge/updateTransaction.js.map +1 -1
  109. package/lib-es/common-logic/history/listOperations.d.ts.map +1 -1
  110. package/lib-es/common-logic/history/listOperations.js +20 -29
  111. package/lib-es/common-logic/history/listOperations.js.map +1 -1
  112. package/lib-es/common-logic/transaction/craftTransaction.d.ts +4 -3
  113. package/lib-es/common-logic/transaction/craftTransaction.d.ts.map +1 -1
  114. package/lib-es/common-logic/transaction/craftTransaction.js +10 -12
  115. package/lib-es/common-logic/transaction/craftTransaction.js.map +1 -1
  116. package/lib-es/network/gateway.d.ts +194 -3
  117. package/lib-es/network/gateway.d.ts.map +1 -1
  118. package/lib-es/network/gateway.integ.test.js +122 -12
  119. package/lib-es/network/gateway.integ.test.js.map +1 -1
  120. package/lib-es/network/gateway.js +90 -17
  121. package/lib-es/network/gateway.js.map +1 -1
  122. package/lib-es/network/node.d.ts +2 -2
  123. package/lib-es/network/node.d.ts.map +1 -1
  124. package/lib-es/network/node.js.map +1 -1
  125. package/lib-es/network/types.d.ts +1 -1
  126. package/lib-es/network/types.d.ts.map +1 -1
  127. package/lib-es/signer/getAddress.d.ts.map +1 -1
  128. package/lib-es/signer/getAddress.js +2 -2
  129. package/lib-es/signer/getAddress.js.map +1 -1
  130. package/lib-es/test/cantonTestUtils.d.ts +33 -0
  131. package/lib-es/test/cantonTestUtils.d.ts.map +1 -0
  132. package/lib-es/test/cantonTestUtils.js +151 -0
  133. package/lib-es/test/cantonTestUtils.js.map +1 -0
  134. package/lib-es/types/bridge.d.ts +7 -1
  135. package/lib-es/types/bridge.d.ts.map +1 -1
  136. package/lib-es/types/index.d.ts +1 -10
  137. package/lib-es/types/index.d.ts.map +1 -1
  138. package/lib-es/types/index.js +1 -0
  139. package/lib-es/types/index.js.map +1 -1
  140. package/lib-es/types/onboard.d.ts +55 -0
  141. package/lib-es/types/onboard.d.ts.map +1 -0
  142. package/lib-es/types/onboard.js +19 -0
  143. package/lib-es/types/onboard.js.map +1 -0
  144. package/package.json +6 -6
  145. package/src/api/getBalance.integ.test.ts +1 -2
  146. package/src/api/index.ts +33 -26
  147. package/src/bridge/createTransaction.test.ts +1 -1
  148. package/src/bridge/index.ts +14 -4
  149. package/src/bridge/onboard.integ.test.ts +219 -0
  150. package/src/bridge/onboard.ts +220 -0
  151. package/src/bridge/prepareTransaction.ts +6 -15
  152. package/src/bridge/signOperation.ts +3 -2
  153. package/src/bridge/sync.integ.test.ts +180 -0
  154. package/src/bridge/sync.ts +57 -49
  155. package/src/bridge/updateTransaction.ts +0 -5
  156. package/src/common-logic/history/listOperations.ts +20 -31
  157. package/src/common-logic/transaction/craftTransaction.ts +13 -17
  158. package/src/network/gateway.integ.test.ts +156 -17
  159. package/src/network/gateway.ts +333 -26
  160. package/src/network/node.ts +3 -3
  161. package/src/network/types.ts +1 -1
  162. package/src/signer/getAddress.ts +3 -5
  163. package/src/test/cantonTestUtils.ts +181 -0
  164. package/src/types/bridge.ts +20 -0
  165. package/src/types/index.ts +1 -11
  166. package/src/types/onboard.ts +65 -0
@@ -1,11 +1,37 @@
1
1
  import network from "@ledgerhq/live-network";
2
+ import type { LiveNetworkRequest } from "@ledgerhq/live-network/network";
3
+ import { getEnv } from "@ledgerhq/live-env";
2
4
  import coinConfig from "../config";
5
+ import {
6
+ PrepareTransactionRequest,
7
+ PrepareTransactionResponse,
8
+ SubmitTransactionRequest,
9
+ SubmitTransactionResponse,
10
+ PreApprovalResult,
11
+ } from "../types/onboard";
3
12
 
4
13
  type OnboardingPrepareResponse = {
5
14
  party_id: string;
6
15
  party_name: string;
7
16
  public_key_fingerprint: string;
8
- topology_transactions_hash: string;
17
+ transactions: {
18
+ namespace_transaction: {
19
+ serialized: string;
20
+ json: object;
21
+ hash: string;
22
+ };
23
+ party_to_key_transaction: {
24
+ serialized: string;
25
+ json: object;
26
+ hash: string;
27
+ };
28
+ party_to_participant_transaction: {
29
+ serialized: string;
30
+ json: object;
31
+ hash: string;
32
+ };
33
+ combined_hash: string;
34
+ };
9
35
  };
10
36
 
11
37
  type OnboardingPrepareRequest = {
@@ -13,6 +39,31 @@ type OnboardingPrepareRequest = {
13
39
  public_key_type: string;
14
40
  };
15
41
 
42
+ export type PrepareTransferResponse = {
43
+ hash: string;
44
+ json: any; // The actual structure is complex, using any for now
45
+ serialized: string;
46
+ };
47
+
48
+ export type PrepareTransferRequest = {
49
+ type: "token-transfer-request";
50
+ amount: number;
51
+ recipient: string;
52
+ execute_before_secs: number;
53
+ instrument_id: string;
54
+ reason?: string;
55
+ };
56
+
57
+ export type PrepareTapRequest = {
58
+ type: "tap-request";
59
+ amount: number;
60
+ };
61
+
62
+ export type PreparePreapprovalRequest = {
63
+ type: "transfer-pre-approval-proposal";
64
+ receiver: string;
65
+ };
66
+
16
67
  type OnboardingSubmitRequest = {
17
68
  prepare_request: OnboardingPrepareRequest;
18
69
  prepare_response: OnboardingPrepareResponse;
@@ -63,6 +114,9 @@ export type CreatedEvent = BaseEvent & {
63
114
  };
64
115
  signatories: string[];
65
116
  observers: string[];
117
+ details: {
118
+ createArguments: { fields: unknown[] };
119
+ };
66
120
  };
67
121
 
68
122
  type ExercisedEvent = BaseEvent & {
@@ -90,21 +144,165 @@ export type TxInfo = {
90
144
  trace_context: string;
91
145
  };
92
146
 
147
+ export type OperationInfo =
148
+ | {
149
+ uid: string;
150
+ transaction_hash: string;
151
+ transaction_timestamp: string;
152
+ status: "Success";
153
+ type: "Initialize";
154
+ senders: string[];
155
+ recipients: string[];
156
+ transfers: [
157
+ {
158
+ address: string;
159
+ type: "Initialize";
160
+ value: string;
161
+ asset: string;
162
+ details: {
163
+ type: "pre-approval";
164
+ };
165
+ },
166
+ ];
167
+ block: {
168
+ height: number;
169
+ time: string;
170
+ hash: string;
171
+ };
172
+ fee: {
173
+ value: string;
174
+ asset: {
175
+ type: "native";
176
+ issuer: null;
177
+ };
178
+ details: {
179
+ type: string;
180
+ };
181
+ };
182
+ asset: {
183
+ type: "token";
184
+ issuer: string;
185
+ };
186
+ details: {
187
+ type: "pre-approval";
188
+ };
189
+ }
190
+ | {
191
+ uid: string;
192
+ transaction_hash: string;
193
+ transaction_timestamp: string;
194
+ status: "Success";
195
+ type: "Receive";
196
+ senders: string[];
197
+ recipients: string[];
198
+ transfers: [
199
+ {
200
+ address: string;
201
+ type: "Receive";
202
+ value: string;
203
+ asset: string;
204
+ details: {
205
+ type: "tap";
206
+ };
207
+ },
208
+ ];
209
+ block: {
210
+ height: number;
211
+ time: string;
212
+ hash: string;
213
+ };
214
+ fee: {
215
+ value: string;
216
+ asset: {
217
+ type: "native";
218
+ issuer: null;
219
+ };
220
+ details: {
221
+ type: string;
222
+ };
223
+ };
224
+ asset: {
225
+ type: "native";
226
+ issuer: null;
227
+ };
228
+ details: {
229
+ type: "tap";
230
+ };
231
+ }
232
+ | {
233
+ uid: string;
234
+ transaction_hash: string;
235
+ transaction_timestamp: string;
236
+ status: "Success";
237
+ type: "Send";
238
+ senders: string[];
239
+ recipients: string[];
240
+ transfers: [
241
+ {
242
+ address: string;
243
+ type: "Send";
244
+ value: string;
245
+ asset: string;
246
+ details: {
247
+ type: "transfer";
248
+ };
249
+ },
250
+ ];
251
+ block: {
252
+ height: number;
253
+ time: string;
254
+ hash: string;
255
+ };
256
+ fee: {
257
+ value: string;
258
+ asset: {
259
+ type: "native";
260
+ issuer: null;
261
+ };
262
+ details: {
263
+ type: string;
264
+ };
265
+ };
266
+ asset: {
267
+ type: "native";
268
+ issuer: null;
269
+ };
270
+ details: {
271
+ type: "transfer";
272
+ };
273
+ };
274
+
93
275
  const getGatewayUrl = () => coinConfig.getCoinConfig().gatewayUrl;
94
- const getNodeId = () => coinConfig.getCoinConfig().nodeId || "ledger-live-devnet-prd";
276
+ const getNodeId = () => coinConfig.getCoinConfig().nodeId || "ledger-devnet-stg";
277
+
278
+ const gatewayNetwork = <T, U = unknown>(req: LiveNetworkRequest<U>) => {
279
+ const API_KEY = getEnv("CANTON_API_KEY");
280
+ return network<T, U>({
281
+ ...req,
282
+ headers: {
283
+ ...(req.headers || {}),
284
+ ...(API_KEY && { "X-Ledger-Canton-Api-Key": API_KEY }),
285
+ },
286
+ });
287
+ };
95
288
 
96
289
  export async function prepareOnboarding(
97
290
  pubKey: string,
98
291
  pubKeyType: string,
99
292
  ): Promise<OnboardingPrepareResponse> {
100
- const { data } = await network<OnboardingPrepareResponse>({
293
+ const gatewayUrl = getGatewayUrl();
294
+ const nodeId = getNodeId();
295
+ const fullUrl = `${gatewayUrl}/v1/node/${nodeId}/onboarding/prepare`;
296
+
297
+ const { data } = await gatewayNetwork<OnboardingPrepareResponse, OnboardingPrepareRequest>({
101
298
  method: "POST",
102
- url: `${getGatewayUrl()}/v1/node/${getNodeId()}/onboarding/prepare`,
299
+ url: fullUrl,
103
300
  data: {
104
301
  public_key: pubKey,
105
302
  public_key_type: pubKeyType,
106
- } satisfies OnboardingPrepareRequest,
303
+ },
107
304
  });
305
+
108
306
  return data;
109
307
  }
110
308
 
@@ -113,58 +311,56 @@ export async function submitOnboarding(
113
311
  prepareResponse: OnboardingPrepareResponse,
114
312
  signature: string,
115
313
  ) {
116
- const { data } = await network<OnboardingSubmitResponse>({
314
+ const { data } = await gatewayNetwork<OnboardingSubmitResponse, OnboardingSubmitRequest>({
117
315
  method: "POST",
118
316
  url: `${getGatewayUrl()}/v1/node/${getNodeId()}/onboarding/submit`,
119
317
  data: {
120
318
  prepare_request: prepareRequest,
121
319
  prepare_response: prepareResponse,
122
320
  signature,
123
- } satisfies OnboardingSubmitRequest,
321
+ },
124
322
  });
125
323
  return data;
126
324
  }
127
325
 
128
326
  export async function submit(serializedTx: string, signature: string) {
129
- const { data } = await network<TransactionSubmitResponse>({
327
+ const { data } = await gatewayNetwork<TransactionSubmitResponse, TransactionSubmitRequest>({
130
328
  method: "POST",
131
329
  url: `${getGatewayUrl()}/v1/node/${getNodeId()}/transaction/submit`,
132
330
  data: {
133
331
  serialized: serializedTx,
134
332
  signature,
135
- } satisfies TransactionSubmitRequest,
333
+ },
136
334
  });
137
335
  return data;
138
336
  }
139
337
 
140
338
  export async function getBalance(partyId: string): Promise<InstrumentBalance[]> {
141
- const { data } = await network<InstrumentBalance[]>({
339
+ const { data } = await gatewayNetwork<InstrumentBalance[]>({
142
340
  method: "GET",
143
- url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/balance`,
341
+ // TODO: we need better solution ?
342
+ url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId.replace(/_/g, ":")}/balance`,
144
343
  });
145
344
  return data;
146
345
  }
147
346
 
148
347
  export async function getPartyById(partyId: string): Promise<PartyInfo> {
149
- return await getParty(partyId, "ID");
348
+ return await getParty(partyId, "party-id");
150
349
  }
151
350
 
152
351
  export async function getPartyByPubKey(pubKey: string): Promise<PartyInfo> {
153
- return await getParty(pubKey, "PK");
352
+ return await getParty(pubKey, "public-key");
154
353
  }
155
354
 
156
- async function getParty(identifier: string, by: "ID" | "PK"): Promise<PartyInfo> {
157
- const { data } = await network<PartyInfo>({
355
+ async function getParty(identifier: string, by: "party-id" | "public-key"): Promise<PartyInfo> {
356
+ const { data } = await gatewayNetwork<PartyInfo>({
158
357
  method: "GET",
159
- url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${identifier}`,
160
- data: {
161
- by,
162
- },
358
+ url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${identifier}?by=${by}`,
163
359
  });
164
360
  return data;
165
361
  }
166
362
 
167
- export async function getTransactions(
363
+ export async function getOperations(
168
364
  partyId: string,
169
365
  options?: {
170
366
  cursor?: number | undefined;
@@ -174,23 +370,134 @@ export async function getTransactions(
174
370
  },
175
371
  ): Promise<{
176
372
  next: number;
177
- transactions: TxInfo[];
373
+ operations: OperationInfo[];
178
374
  }> {
179
- const { data } = await network<{
375
+ const { data } = await gatewayNetwork<{
180
376
  next: number;
181
- transactions: TxInfo[];
377
+ operations: OperationInfo[];
182
378
  }>({
183
379
  method: "GET",
184
- url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/transactions`,
185
- data: options,
380
+ url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId.replace(/_/g, ":")}/operations`,
381
+ params: options,
382
+ });
383
+ return data;
384
+ }
385
+
386
+ type PrepareTapRequestRequest = {
387
+ partyId: string;
388
+ amount?: number;
389
+ };
390
+
391
+ type PrepareTapRequestResponse = {
392
+ serialized: "string";
393
+ json: null;
394
+ hash: "string";
395
+ };
396
+
397
+ enum TransactionType {
398
+ TAP_REQUEST = "tap-request",
399
+ TRANSFER_PRE_APPROVAL_PROPOSAL = "transfer-pre-approval-proposal",
400
+ }
401
+
402
+ export async function prepareTapRequest({
403
+ partyId,
404
+ amount = 1000000,
405
+ }: PrepareTapRequestRequest): Promise<PrepareTapRequestResponse> {
406
+ const { data } = await gatewayNetwork<
407
+ PrepareTapRequestResponse,
408
+ { amount: number; type: string }
409
+ >({
410
+ method: "POST",
411
+ url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/transaction/prepare`,
412
+ data: {
413
+ amount: parseInt(amount.toString(), 10), // Convert to integer to avoid scientific notation
414
+ type: TransactionType.TAP_REQUEST,
415
+ },
416
+ });
417
+ return data;
418
+ }
419
+
420
+ type SubmitTapRequestRequest = {
421
+ partyId: string;
422
+ serialized: string;
423
+ signature: string;
424
+ };
425
+
426
+ type SubmitTapRequestResponse = {
427
+ submission_id: string;
428
+ update_id: string;
429
+ };
430
+
431
+ export async function submitTapRequest({
432
+ partyId,
433
+ serialized,
434
+ signature,
435
+ }: SubmitTapRequestRequest): Promise<SubmitTapRequestResponse> {
436
+ const { data } = await gatewayNetwork<
437
+ SubmitTapRequestResponse,
438
+ Omit<SubmitTapRequestRequest, "partyId">
439
+ >({
440
+ method: "POST",
441
+ url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/transaction/submit`,
442
+ data: {
443
+ serialized,
444
+ signature,
445
+ },
446
+ });
447
+ return data;
448
+ }
449
+
450
+ export async function prepareTransferRequest(
451
+ partyId: string,
452
+ params: PrepareTransferRequest,
453
+ ): Promise<PrepareTransferResponse> {
454
+ const { data } = await network<PrepareTransferResponse>({
455
+ method: "POST",
456
+ url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/transaction/prepare`,
457
+ data: params,
186
458
  });
187
459
  return data;
188
460
  }
189
461
 
190
462
  export async function getLedgerEnd(): Promise<number> {
191
- const { data } = await network<number>({
463
+ const { data } = await gatewayNetwork<number>({
192
464
  method: "GET",
193
465
  url: `${getGatewayUrl()}/v1/node/${getNodeId()}/ledger-end`,
194
466
  });
195
467
  return data;
196
468
  }
469
+
470
+ export async function preparePreApprovalTransaction(
471
+ partyId: string,
472
+ ): Promise<PrepareTransactionResponse> {
473
+ const { data } = await gatewayNetwork<PrepareTransactionResponse, PrepareTransactionRequest>({
474
+ method: "POST",
475
+ url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/transaction/prepare`,
476
+ data: {
477
+ type: TransactionType.TRANSFER_PRE_APPROVAL_PROPOSAL,
478
+ receiver: partyId,
479
+ },
480
+ });
481
+ return data;
482
+ }
483
+
484
+ export async function submitPreApprovalTransaction(
485
+ partyId: string,
486
+ { serialized }: PrepareTransactionResponse,
487
+ signature: string,
488
+ ): Promise<PreApprovalResult> {
489
+ const { data } = await gatewayNetwork<SubmitTransactionResponse, SubmitTransactionRequest>({
490
+ method: "POST",
491
+ url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/transaction/submit`,
492
+ data: {
493
+ serialized,
494
+ signature,
495
+ },
496
+ });
497
+
498
+ return {
499
+ isApproved: true,
500
+ submissionId: data.submission_id,
501
+ updateId: data.update_id,
502
+ };
503
+ }
@@ -3,7 +3,7 @@ import network from "@ledgerhq/live-network";
3
3
  import type { LiveNetworkRequest } from "@ledgerhq/live-network/network";
4
4
  import { getEnv } from "@ledgerhq/live-env";
5
5
  import coinConfig from "../config";
6
- import { AccountInfoResponse, SubmitReponse } from "./types";
6
+ import { AccountInfoResponse, SubmitResponse } from "./types";
7
7
  import crypto from "crypto";
8
8
 
9
9
  const getNodeUrl = () => coinConfig.getCoinConfig().nodeUrl || "";
@@ -86,10 +86,10 @@ export const getLedgerEnd = async (): Promise<number> => {
86
86
  return data.offset;
87
87
  };
88
88
 
89
- export const submit = async (signedTx: string): Promise<SubmitReponse> => {
89
+ export const submit = async (signedTx: string): Promise<SubmitResponse> => {
90
90
  // @ts-expect-error: add NODE_BOILERPLATE to libs/env/src/env.ts
91
91
  const url = `${getEnv("NODE_BOILERPLATE")}/submit`;
92
- const { data } = await network<SubmitReponse>({
92
+ const { data } = await network<SubmitResponse>({
93
93
  url,
94
94
  method: "GET",
95
95
  });
@@ -40,7 +40,7 @@ export type AccountInfoResponse = {
40
40
  validated: boolean;
41
41
  } & ResponseStatus;
42
42
 
43
- export type SubmitReponse = {
43
+ export type SubmitResponse = {
44
44
  accepted: boolean;
45
45
  tx_hash: string;
46
46
  };
@@ -1,13 +1,11 @@
1
1
  import { GetAddressOptions } from "@ledgerhq/coin-framework/derivation";
2
2
  import { GetAddressFn } from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
3
3
  import { SignerContext } from "@ledgerhq/coin-framework/signer";
4
- import { CantonAddress, CantonSigner } from "../types";
4
+ import { CantonSigner } from "../types";
5
5
 
6
6
  const getAddress = (signerContext: SignerContext<CantonSigner>): GetAddressFn => {
7
- return async (deviceId: string, { path, verify }: GetAddressOptions) => {
8
- const { address, publicKey } = (await signerContext(deviceId, signer =>
9
- signer.getAddress(path),
10
- )) as CantonAddress;
7
+ return async (deviceId: string, { path }: GetAddressOptions) => {
8
+ const { address, publicKey } = await signerContext(deviceId, signer => signer.getAddress(path));
11
9
 
12
10
  return {
13
11
  path,
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Canton Testing Utilities for Ed25519 Key Generation
3
+ *
4
+ * Provides utilities to generate proper Ed25519 keypairs for testing Canton
5
+ * onboarding without requiring physical Ledger devices.
6
+ */
7
+
8
+ import crypto from "crypto";
9
+
10
+ export interface CantonTestKeyPair {
11
+ publicKeyHex: string; // Ready for Canton Gateway API
12
+ privateKeyHex: string; // ASN.1 DER encoded private key in hex format
13
+ privateKeyPem: string; // PEM format for signing operations
14
+ fingerprint: string; // Canton public key fingerprint (multihash: 1220 + SHA256(publicKey))
15
+ sign: (hashHex: string) => string; // Sign transaction hash
16
+ }
17
+
18
+ /**
19
+ * Generate fresh Ed25519 keypair
20
+ */
21
+ export function generateMockKeyPair(): CantonTestKeyPair {
22
+ const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");
23
+
24
+ const publicKeyBuffer = publicKey.export({ type: "spki", format: "der" });
25
+ const rawPublicKey = publicKeyBuffer.slice(-32);
26
+ const publicKeyHex = rawPublicKey.toString("hex");
27
+
28
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
29
+ const privateKeyPem = privateKey.export({ type: "pkcs8", format: "pem" }) as string;
30
+ const privateKeyDer = privateKey.export({ type: "pkcs8", format: "der" });
31
+ const privateKeyHex = privateKeyDer.toString("hex");
32
+
33
+ // Generate fingerprint: Canton computes SHA256(purpose_bytes + public_key_bytes)
34
+ // where purpose_bytes is 4-byte big-endian representation of PURPOSE_PUBLIC_KEY_FINGERPRINT (12)
35
+ const PURPOSE_PUBLIC_KEY_FINGERPRINT = 12;
36
+ const purposeBytes = Buffer.allocUnsafe(4);
37
+ purposeBytes.writeInt32BE(PURPOSE_PUBLIC_KEY_FINGERPRINT, 0);
38
+
39
+ const hash = crypto.createHash("sha256");
40
+ hash.update(purposeBytes);
41
+ hash.update(rawPublicKey);
42
+ const hashedContent = hash.digest();
43
+
44
+ // Multihash encoding: 0x12 (SHA256) + 0x20 (32 bytes) + hash
45
+ const multihashPrefix = Buffer.from([0x12, 0x20]);
46
+ const fingerprintBuffer = Buffer.concat([multihashPrefix, hashedContent]);
47
+ const fingerprint = fingerprintBuffer.toString("hex");
48
+
49
+ return {
50
+ publicKeyHex, // 64-char hex string (no 0x prefix)
51
+ privateKeyHex, // ASN.1 DER encoded private key in hex format
52
+ privateKeyPem, // PEM format string
53
+ fingerprint, // Canton format: multihash prefix + SHA256(public key)
54
+
55
+ /**
56
+ * Sign a transaction hash using proper Ed25519 signature
57
+ */
58
+ sign: (hashHex: string): string => {
59
+ const hashBuffer = Buffer.from(hashHex, "hex");
60
+ const privateKeyObj = crypto.createPrivateKey({
61
+ key: privateKeyPem,
62
+ format: "pem",
63
+ type: "pkcs8",
64
+ });
65
+
66
+ const signature = crypto.sign(null, hashBuffer, privateKeyObj);
67
+ return signature.toString("hex");
68
+ },
69
+ };
70
+ }
71
+
72
+ /**
73
+ * Verify Ed25519 signature against public key and message hash
74
+ */
75
+ export function verifySignature(
76
+ publicKeyHex: string,
77
+ signatureHex: string,
78
+ messageHashHex: string,
79
+ ): { isValid: boolean; error?: string; details: any } {
80
+ try {
81
+ // Clean inputs - remove 0x prefixes if present
82
+ const cleanPublicKey = publicKeyHex.startsWith("0x") ? publicKeyHex.slice(2) : publicKeyHex;
83
+ const cleanSignature = signatureHex.startsWith("0x") ? signatureHex.slice(2) : signatureHex;
84
+ const cleanMessageHash = messageHashHex.startsWith("0x")
85
+ ? messageHashHex.slice(2)
86
+ : messageHashHex;
87
+
88
+ const details: any = {
89
+ publicKeyLength: cleanPublicKey.length,
90
+ signatureLength: cleanSignature.length,
91
+ messageHashLength: cleanMessageHash.length,
92
+ publicKeyBytes: cleanPublicKey.length / 2,
93
+ signatureBytes: cleanSignature.length / 2,
94
+ messageHashBytes: cleanMessageHash.length / 2,
95
+ };
96
+
97
+ // Validate input lengths
98
+ if (cleanPublicKey.length !== 64) {
99
+ return {
100
+ isValid: false,
101
+ error: `Invalid public key length: expected 64 hex chars (32 bytes), got ${cleanPublicKey.length}`,
102
+ details,
103
+ };
104
+ }
105
+
106
+ // Ed25519 signatures should be 64 bytes, but we might receive 65 bytes with recovery ID
107
+ let processedSignature = cleanSignature;
108
+ if (cleanSignature.length === 130) {
109
+ processedSignature = cleanSignature.slice(2, -2);
110
+ details.originalSignatureLength = cleanSignature.length;
111
+ details.processedSignatureLength = processedSignature.length;
112
+ } else if (cleanSignature.length !== 128) {
113
+ return {
114
+ isValid: false,
115
+ error: `Invalid signature length: expected 128 hex chars (64 bytes) or 130 hex chars (65 bytes), got ${cleanSignature.length}`,
116
+ details,
117
+ };
118
+ }
119
+
120
+ // Convert hex to buffers
121
+ const publicKeyBuffer = Buffer.from(cleanPublicKey, "hex");
122
+ const signatureBuffer = Buffer.from(processedSignature, "hex");
123
+ const messageBuffer = Buffer.from(cleanMessageHash, "hex");
124
+
125
+ // Create public key object for verification
126
+ // Ed25519 public keys need to be wrapped in SPKI format for Node.js crypto
127
+ const spkiHeader = Buffer.from([
128
+ 0x30,
129
+ 0x2a, // SEQUENCE, length 42
130
+ 0x30,
131
+ 0x05, // SEQUENCE, length 5
132
+ 0x06,
133
+ 0x03,
134
+ 0x2b,
135
+ 0x65,
136
+ 0x70, // OID for Ed25519
137
+ 0x03,
138
+ 0x21,
139
+ 0x00, // BIT STRING, length 33, no unused bits
140
+ ]);
141
+ const spkiPublicKey = Buffer.concat([spkiHeader, publicKeyBuffer]);
142
+
143
+ const publicKeyObj = crypto.createPublicKey({
144
+ key: spkiPublicKey,
145
+ format: "der",
146
+ type: "spki",
147
+ });
148
+
149
+ // Verify signature
150
+ const isValid = crypto.verify(null, messageBuffer, publicKeyObj, signatureBuffer);
151
+
152
+ return {
153
+ isValid,
154
+ details: {
155
+ ...details,
156
+ processedSignatureLength: processedSignature.length,
157
+ verificationMethod: "Node.js crypto.verify with Ed25519",
158
+ },
159
+ };
160
+ } catch (error) {
161
+ return {
162
+ isValid: false,
163
+ error: `Verification failed: ${error instanceof Error ? error.message : String(error)}`,
164
+ details: { error: String(error) },
165
+ };
166
+ }
167
+ }
168
+
169
+ export function createMockSigner(keyPair: CantonTestKeyPair) {
170
+ return {
171
+ getAddress: async (derivationPath: string) => ({
172
+ address: `canton_test_${keyPair.fingerprint.slice(-8)}`,
173
+ publicKey: keyPair.publicKeyHex,
174
+ }),
175
+
176
+ signTransaction: async (derivationPath: string, hashToSign: string) => {
177
+ const cleanHash = hashToSign.startsWith("0x") ? hashToSign.slice(2) : hashToSign;
178
+ return keyPair.sign(cleanHash);
179
+ },
180
+ };
181
+ }