@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.
- package/.turbo/turbo-build.log +1 -1
- package/.unimportedrc.json +12 -4
- package/CHANGELOG.md +21 -0
- package/lib/api/getBalance.integ.test.js +1 -1
- package/lib/api/getBalance.integ.test.js.map +1 -1
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.js +11 -8
- package/lib/api/index.js.map +1 -1
- package/lib/bridge/createTransaction.test.js +1 -1
- package/lib/bridge/createTransaction.test.js.map +1 -1
- package/lib/bridge/index.d.ts +3 -3
- package/lib/bridge/index.d.ts.map +1 -1
- package/lib/bridge/index.js +9 -1
- package/lib/bridge/index.js.map +1 -1
- package/lib/bridge/onboard.d.ts +10 -0
- package/lib/bridge/onboard.d.ts.map +1 -0
- package/lib/bridge/onboard.integ.test.d.ts +2 -0
- package/lib/bridge/onboard.integ.test.d.ts.map +1 -0
- package/lib/bridge/onboard.integ.test.js +156 -0
- package/lib/bridge/onboard.integ.test.js.map +1 -0
- package/lib/bridge/onboard.js +139 -0
- package/lib/bridge/onboard.js.map +1 -0
- package/lib/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib/bridge/prepareTransaction.js +5 -7
- package/lib/bridge/prepareTransaction.js.map +1 -1
- package/lib/bridge/signOperation.d.ts.map +1 -1
- package/lib/bridge/signOperation.js +2 -1
- package/lib/bridge/signOperation.js.map +1 -1
- package/lib/bridge/sync.d.ts.map +1 -1
- package/lib/bridge/sync.integ.test.d.ts +2 -0
- package/lib/bridge/sync.integ.test.d.ts.map +1 -0
- package/lib/bridge/sync.integ.test.js +175 -0
- package/lib/bridge/sync.integ.test.js.map +1 -0
- package/lib/bridge/sync.js +39 -36
- package/lib/bridge/sync.js.map +1 -1
- package/lib/bridge/updateTransaction.d.ts.map +1 -1
- package/lib/bridge/updateTransaction.js +0 -4
- package/lib/bridge/updateTransaction.js.map +1 -1
- package/lib/common-logic/history/listOperations.d.ts.map +1 -1
- package/lib/common-logic/history/listOperations.js +19 -31
- package/lib/common-logic/history/listOperations.js.map +1 -1
- package/lib/common-logic/transaction/craftTransaction.d.ts +4 -3
- package/lib/common-logic/transaction/craftTransaction.d.ts.map +1 -1
- package/lib/common-logic/transaction/craftTransaction.js +10 -12
- package/lib/common-logic/transaction/craftTransaction.js.map +1 -1
- package/lib/network/gateway.d.ts +194 -3
- package/lib/network/gateway.d.ts.map +1 -1
- package/lib/network/gateway.integ.test.js +121 -11
- package/lib/network/gateway.integ.test.js.map +1 -1
- package/lib/network/gateway.js +96 -18
- package/lib/network/gateway.js.map +1 -1
- package/lib/network/node.d.ts +2 -2
- package/lib/network/node.d.ts.map +1 -1
- package/lib/network/node.js.map +1 -1
- package/lib/network/types.d.ts +1 -1
- package/lib/network/types.d.ts.map +1 -1
- package/lib/signer/getAddress.d.ts.map +1 -1
- package/lib/signer/getAddress.js +2 -2
- package/lib/signer/getAddress.js.map +1 -1
- package/lib/test/cantonTestUtils.d.ts +33 -0
- package/lib/test/cantonTestUtils.d.ts.map +1 -0
- package/lib/test/cantonTestUtils.js +159 -0
- package/lib/test/cantonTestUtils.js.map +1 -0
- package/lib/types/bridge.d.ts +7 -1
- package/lib/types/bridge.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -10
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +1 -0
- package/lib/types/index.js.map +1 -1
- package/lib/types/onboard.d.ts +55 -0
- package/lib/types/onboard.d.ts.map +1 -0
- package/lib/types/onboard.js +22 -0
- package/lib/types/onboard.js.map +1 -0
- package/lib-es/api/getBalance.integ.test.js +1 -1
- package/lib-es/api/getBalance.integ.test.js.map +1 -1
- package/lib-es/api/index.d.ts.map +1 -1
- package/lib-es/api/index.js +12 -9
- package/lib-es/api/index.js.map +1 -1
- package/lib-es/bridge/createTransaction.test.js +1 -1
- package/lib-es/bridge/createTransaction.test.js.map +1 -1
- package/lib-es/bridge/index.d.ts +3 -3
- package/lib-es/bridge/index.d.ts.map +1 -1
- package/lib-es/bridge/index.js +9 -1
- package/lib-es/bridge/index.js.map +1 -1
- package/lib-es/bridge/onboard.d.ts +10 -0
- package/lib-es/bridge/onboard.d.ts.map +1 -0
- package/lib-es/bridge/onboard.integ.test.d.ts +2 -0
- package/lib-es/bridge/onboard.integ.test.d.ts.map +1 -0
- package/lib-es/bridge/onboard.integ.test.js +151 -0
- package/lib-es/bridge/onboard.integ.test.js.map +1 -0
- package/lib-es/bridge/onboard.js +133 -0
- package/lib-es/bridge/onboard.js.map +1 -0
- package/lib-es/bridge/prepareTransaction.d.ts.map +1 -1
- package/lib-es/bridge/prepareTransaction.js +6 -8
- package/lib-es/bridge/prepareTransaction.js.map +1 -1
- package/lib-es/bridge/signOperation.d.ts.map +1 -1
- package/lib-es/bridge/signOperation.js +2 -1
- package/lib-es/bridge/signOperation.js.map +1 -1
- package/lib-es/bridge/sync.d.ts.map +1 -1
- package/lib-es/bridge/sync.integ.test.d.ts +2 -0
- package/lib-es/bridge/sync.integ.test.d.ts.map +1 -0
- package/lib-es/bridge/sync.integ.test.js +137 -0
- package/lib-es/bridge/sync.integ.test.js.map +1 -0
- package/lib-es/bridge/sync.js +38 -35
- package/lib-es/bridge/sync.js.map +1 -1
- package/lib-es/bridge/updateTransaction.d.ts.map +1 -1
- package/lib-es/bridge/updateTransaction.js +0 -4
- package/lib-es/bridge/updateTransaction.js.map +1 -1
- package/lib-es/common-logic/history/listOperations.d.ts.map +1 -1
- package/lib-es/common-logic/history/listOperations.js +20 -29
- package/lib-es/common-logic/history/listOperations.js.map +1 -1
- package/lib-es/common-logic/transaction/craftTransaction.d.ts +4 -3
- package/lib-es/common-logic/transaction/craftTransaction.d.ts.map +1 -1
- package/lib-es/common-logic/transaction/craftTransaction.js +10 -12
- package/lib-es/common-logic/transaction/craftTransaction.js.map +1 -1
- package/lib-es/network/gateway.d.ts +194 -3
- package/lib-es/network/gateway.d.ts.map +1 -1
- package/lib-es/network/gateway.integ.test.js +122 -12
- package/lib-es/network/gateway.integ.test.js.map +1 -1
- package/lib-es/network/gateway.js +90 -17
- package/lib-es/network/gateway.js.map +1 -1
- package/lib-es/network/node.d.ts +2 -2
- package/lib-es/network/node.d.ts.map +1 -1
- package/lib-es/network/node.js.map +1 -1
- package/lib-es/network/types.d.ts +1 -1
- package/lib-es/network/types.d.ts.map +1 -1
- package/lib-es/signer/getAddress.d.ts.map +1 -1
- package/lib-es/signer/getAddress.js +2 -2
- package/lib-es/signer/getAddress.js.map +1 -1
- package/lib-es/test/cantonTestUtils.d.ts +33 -0
- package/lib-es/test/cantonTestUtils.d.ts.map +1 -0
- package/lib-es/test/cantonTestUtils.js +151 -0
- package/lib-es/test/cantonTestUtils.js.map +1 -0
- package/lib-es/types/bridge.d.ts +7 -1
- package/lib-es/types/bridge.d.ts.map +1 -1
- package/lib-es/types/index.d.ts +1 -10
- package/lib-es/types/index.d.ts.map +1 -1
- package/lib-es/types/index.js +1 -0
- package/lib-es/types/index.js.map +1 -1
- package/lib-es/types/onboard.d.ts +55 -0
- package/lib-es/types/onboard.d.ts.map +1 -0
- package/lib-es/types/onboard.js +19 -0
- package/lib-es/types/onboard.js.map +1 -0
- package/package.json +6 -6
- package/src/api/getBalance.integ.test.ts +1 -2
- package/src/api/index.ts +33 -26
- package/src/bridge/createTransaction.test.ts +1 -1
- package/src/bridge/index.ts +14 -4
- package/src/bridge/onboard.integ.test.ts +219 -0
- package/src/bridge/onboard.ts +220 -0
- package/src/bridge/prepareTransaction.ts +6 -15
- package/src/bridge/signOperation.ts +3 -2
- package/src/bridge/sync.integ.test.ts +180 -0
- package/src/bridge/sync.ts +57 -49
- package/src/bridge/updateTransaction.ts +0 -5
- package/src/common-logic/history/listOperations.ts +20 -31
- package/src/common-logic/transaction/craftTransaction.ts +13 -17
- package/src/network/gateway.integ.test.ts +156 -17
- package/src/network/gateway.ts +333 -26
- package/src/network/node.ts +3 -3
- package/src/network/types.ts +1 -1
- package/src/signer/getAddress.ts +3 -5
- package/src/test/cantonTestUtils.ts +181 -0
- package/src/types/bridge.ts +20 -0
- package/src/types/index.ts +1 -11
- package/src/types/onboard.ts +65 -0
package/src/network/gateway.ts
CHANGED
|
@@ -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
|
-
|
|
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-
|
|
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
|
|
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:
|
|
299
|
+
url: fullUrl,
|
|
103
300
|
data: {
|
|
104
301
|
public_key: pubKey,
|
|
105
302
|
public_key_type: pubKeyType,
|
|
106
|
-
}
|
|
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
|
|
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
|
-
}
|
|
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
|
|
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
|
-
}
|
|
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
|
|
339
|
+
const { data } = await gatewayNetwork<InstrumentBalance[]>({
|
|
142
340
|
method: "GET",
|
|
143
|
-
|
|
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, "
|
|
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, "
|
|
352
|
+
return await getParty(pubKey, "public-key");
|
|
154
353
|
}
|
|
155
354
|
|
|
156
|
-
async function getParty(identifier: string, by: "
|
|
157
|
-
const { data } = await
|
|
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
|
|
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
|
-
|
|
373
|
+
operations: OperationInfo[];
|
|
178
374
|
}> {
|
|
179
|
-
const { data } = await
|
|
375
|
+
const { data } = await gatewayNetwork<{
|
|
180
376
|
next: number;
|
|
181
|
-
|
|
377
|
+
operations: OperationInfo[];
|
|
182
378
|
}>({
|
|
183
379
|
method: "GET",
|
|
184
|
-
url: `${getGatewayUrl()}/v1/node/${getNodeId()}/party/${partyId}/
|
|
185
|
-
|
|
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
|
|
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
|
+
}
|
package/src/network/node.ts
CHANGED
|
@@ -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,
|
|
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<
|
|
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<
|
|
92
|
+
const { data } = await network<SubmitResponse>({
|
|
93
93
|
url,
|
|
94
94
|
method: "GET",
|
|
95
95
|
});
|
package/src/network/types.ts
CHANGED
package/src/signer/getAddress.ts
CHANGED
|
@@ -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 {
|
|
4
|
+
import { CantonSigner } from "../types";
|
|
5
5
|
|
|
6
6
|
const getAddress = (signerContext: SignerContext<CantonSigner>): GetAddressFn => {
|
|
7
|
-
return async (deviceId: string, { path
|
|
8
|
-
const { address, publicKey } =
|
|
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
|
+
}
|