@ledgerhq/hw-app-canton 0.6.0 → 0.7.0-nightly.0
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/CHANGELOG.md +6 -0
- package/README.md +3 -2
- package/lib/Canton.d.ts +51 -5
- package/lib/Canton.d.ts.map +1 -1
- package/lib/Canton.js +217 -38
- package/lib/Canton.js.map +1 -1
- package/lib-es/Canton.d.ts +51 -5
- package/lib-es/Canton.d.ts.map +1 -1
- package/lib-es/Canton.js +218 -39
- package/lib-es/Canton.js.map +1 -1
- package/package.json +5 -5
- package/src/Canton.test.ts +118 -39
- package/src/Canton.ts +306 -47
- package/lib/Canton.integ.test.d.ts +0 -2
- package/lib/Canton.integ.test.d.ts.map +0 -1
- package/lib/Canton.integ.test.js +0 -88
- package/lib/Canton.integ.test.js.map +0 -1
- package/lib/Canton.test.d.ts +0 -2
- package/lib/Canton.test.d.ts.map +0 -1
- package/lib/Canton.test.js +0 -127
- package/lib/Canton.test.js.map +0 -1
- package/lib-es/Canton.integ.test.d.ts +0 -2
- package/lib-es/Canton.integ.test.d.ts.map +0 -1
- package/lib-es/Canton.integ.test.js +0 -60
- package/lib-es/Canton.integ.test.js.map +0 -1
- package/lib-es/Canton.test.d.ts +0 -2
- package/lib-es/Canton.test.d.ts.map +0 -1
- package/lib-es/Canton.test.js +0 -122
- package/lib-es/Canton.test.js.map +0 -1
package/lib-es/Canton.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TransportStatusError } from "@ledgerhq/errors";
|
|
2
2
|
import BIPPath from "bip32-path";
|
|
3
3
|
const CLA = 0xe0;
|
|
4
4
|
const P1_NON_CONFIRM = 0x00;
|
|
5
5
|
const P1_CONFIRM = 0x01;
|
|
6
|
-
|
|
6
|
+
const P1_SIGN_UNTYPED_VERSIONED_MESSAGE = 0x01;
|
|
7
|
+
const P1_SIGN_PREPARED_TRANSACTION = 0x02;
|
|
7
8
|
const P2_NONE = 0x00;
|
|
8
|
-
// P2 indicating first APDU in a large request.
|
|
9
9
|
const P2_FIRST = 0x01;
|
|
10
|
-
// P2 indicating that this is not the last APDU in a large request.
|
|
11
10
|
const P2_MORE = 0x02;
|
|
12
|
-
// P2 indicating that this is the last APDU of a message in a multi message request.
|
|
13
11
|
const P2_MSG_END = 0x04;
|
|
14
12
|
const INS = {
|
|
15
13
|
GET_VERSION: 0x03,
|
|
@@ -23,6 +21,7 @@ const STATUS = {
|
|
|
23
21
|
};
|
|
24
22
|
const ED25519_SIGNATURE_HEX_LENGTH = 128; // hex characters (64 bytes)
|
|
25
23
|
const CANTON_SIGNATURE_HEX_LENGTH = 132; // hex characters (66 bytes with framing)
|
|
24
|
+
const MAX_APDU_DATA_LENGTH = 255;
|
|
26
25
|
/**
|
|
27
26
|
* Canton BOLOS API
|
|
28
27
|
*/
|
|
@@ -44,7 +43,8 @@ export default class Canton {
|
|
|
44
43
|
const serializedPath = this.serializePath(bipPath);
|
|
45
44
|
const p1 = display ? P1_CONFIRM : P1_NON_CONFIRM;
|
|
46
45
|
const response = await this.transport.send(CLA, INS.GET_ADDR, p1, P2_NONE, serializedPath);
|
|
47
|
-
|
|
46
|
+
this.checkTransportResponse(response);
|
|
47
|
+
const responseData = this.extractResponseData(response);
|
|
48
48
|
const { publicKey } = this.extractPublicKeyAndChainCode(responseData);
|
|
49
49
|
const address = "canton_" + this.publicKeyToAddress(publicKey);
|
|
50
50
|
return {
|
|
@@ -54,23 +54,148 @@ export default class Canton {
|
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
/**
|
|
57
|
-
* Sign a Canton transaction
|
|
57
|
+
* Sign a Canton transaction
|
|
58
|
+
* using the appropriate signing method based on transaction type.
|
|
58
59
|
*
|
|
59
60
|
* @param path a path in BIP-32 format
|
|
60
|
-
* @param
|
|
61
|
+
* @param data either prepared transaction components, untyped versioned message, or txHash string (backwards compatibility)
|
|
61
62
|
* @return the signature
|
|
62
63
|
*/
|
|
63
|
-
async signTransaction(path,
|
|
64
|
+
async signTransaction(path, data) {
|
|
65
|
+
// Backwards compatibility: handle txHash string format
|
|
66
|
+
if (typeof data === "string") {
|
|
67
|
+
return this.signTxHash(path, data);
|
|
68
|
+
}
|
|
69
|
+
if ("damlTransaction" in data) {
|
|
70
|
+
return this.signPreparedTransaction(path, data);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
return this.signUntypedVersionedMessage(path, data);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Sign a transaction hash (backwards compatibility)
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
async signTxHash(path, txHash) {
|
|
64
81
|
// 1. Send the derivation path
|
|
65
82
|
const bipPath = BIPPath.fromString(path).toPathArray();
|
|
66
83
|
const serializedPath = this.serializePath(bipPath);
|
|
67
|
-
const pathResponse = await this.transport.send(CLA, INS.SIGN,
|
|
68
|
-
this.
|
|
69
|
-
// 2. Send the transaction hash
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
const pathResponse = await this.transport.send(CLA, INS.SIGN, P1_SIGN_UNTYPED_VERSIONED_MESSAGE, P2_FIRST | P2_MORE, serializedPath);
|
|
85
|
+
this.checkTransportResponse(pathResponse);
|
|
86
|
+
// 2. Send the transaction hash as a single transaction
|
|
87
|
+
const transactionBuffer = Buffer.from(txHash, "hex");
|
|
88
|
+
const response = await this.transport.send(CLA, INS.SIGN, P1_SIGN_UNTYPED_VERSIONED_MESSAGE, P2_MSG_END, transactionBuffer);
|
|
89
|
+
this.checkTransportResponse(response);
|
|
90
|
+
const responseData = this.extractResponseData(response);
|
|
91
|
+
return this.cleanSignatureFormat(responseData);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Sign a prepared Canton transaction
|
|
95
|
+
* @private
|
|
96
|
+
*/
|
|
97
|
+
async signPreparedTransaction(path, components) {
|
|
98
|
+
let responseData = null;
|
|
99
|
+
// 1. Send the derivation path
|
|
100
|
+
const bipPath = BIPPath.fromString(path).toPathArray();
|
|
101
|
+
const serializedPath = this.serializePath(bipPath);
|
|
102
|
+
const pathResponse = await this.transport.send(CLA, INS.SIGN, P1_SIGN_PREPARED_TRANSACTION, P2_FIRST | P2_MORE, serializedPath);
|
|
103
|
+
this.checkTransportResponse(pathResponse);
|
|
104
|
+
// 2. Send the DAML transaction
|
|
105
|
+
await this.sendChunkedData({
|
|
106
|
+
ins: INS.SIGN,
|
|
107
|
+
p1: P1_SIGN_PREPARED_TRANSACTION,
|
|
108
|
+
payload: Buffer.from(components.damlTransaction),
|
|
109
|
+
isFinal: false,
|
|
110
|
+
});
|
|
111
|
+
// 3. Send each node
|
|
112
|
+
for (const [i, node] of components.nodes.entries()) {
|
|
113
|
+
this.validateUint8Array(node, `Node at index ${i}`);
|
|
114
|
+
await this.sendChunkedData({
|
|
115
|
+
ins: INS.SIGN,
|
|
116
|
+
p1: P1_SIGN_PREPARED_TRANSACTION,
|
|
117
|
+
payload: Buffer.from(node),
|
|
118
|
+
isFinal: false,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
// 4. Send the metadata
|
|
122
|
+
const isFinal = components.inputContracts.length === 0;
|
|
123
|
+
const result = await this.sendChunkedData({
|
|
124
|
+
ins: INS.SIGN,
|
|
125
|
+
p1: P1_SIGN_PREPARED_TRANSACTION,
|
|
126
|
+
payload: Buffer.from(components.metadata),
|
|
127
|
+
isFinal,
|
|
128
|
+
});
|
|
129
|
+
if (isFinal) {
|
|
130
|
+
responseData = result;
|
|
131
|
+
}
|
|
132
|
+
// 5. Send each input contract - last one should return data
|
|
133
|
+
for (const [i, inputContract] of components.inputContracts.entries()) {
|
|
134
|
+
this.validateUint8Array(inputContract, `Input contract at index ${i}`);
|
|
135
|
+
const isFinal = i === components.inputContracts.length - 1;
|
|
136
|
+
const result = await this.sendChunkedData({
|
|
137
|
+
ins: INS.SIGN,
|
|
138
|
+
p1: P1_SIGN_PREPARED_TRANSACTION,
|
|
139
|
+
payload: Buffer.from(inputContract),
|
|
140
|
+
isFinal,
|
|
141
|
+
});
|
|
142
|
+
if (isFinal) {
|
|
143
|
+
responseData = result;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (!responseData) {
|
|
147
|
+
throw new Error("No response data received from device");
|
|
148
|
+
}
|
|
149
|
+
return this.cleanSignatureFormat(responseData);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Sign topology transactions for Canton onboarding
|
|
153
|
+
* @private
|
|
154
|
+
*/
|
|
155
|
+
async signUntypedVersionedMessage(path, data) {
|
|
156
|
+
const { transactions } = data;
|
|
157
|
+
if (!transactions || transactions.length === 0) {
|
|
158
|
+
throw new TypeError("At least one transaction is required");
|
|
159
|
+
}
|
|
160
|
+
// 1. Send the derivation path
|
|
161
|
+
const bipPath = BIPPath.fromString(path).toPathArray();
|
|
162
|
+
const serializedPath = this.serializePath(bipPath);
|
|
163
|
+
const pathResponse = await this.transport.send(CLA, INS.SIGN, P1_SIGN_UNTYPED_VERSIONED_MESSAGE, P2_FIRST | P2_MORE, serializedPath);
|
|
164
|
+
this.checkTransportResponse(pathResponse);
|
|
165
|
+
// 2. Send each transaction using chunking for large data
|
|
166
|
+
for (const [i, transaction] of transactions.entries()) {
|
|
167
|
+
if (!transaction) {
|
|
168
|
+
throw new TypeError(`Transaction at index ${i} is undefined or null`);
|
|
169
|
+
}
|
|
170
|
+
const transactionBuffer = Buffer.from(transaction, "hex");
|
|
171
|
+
const isLastTransaction = i === transactions.length - 1;
|
|
172
|
+
if (transactionBuffer.length <= MAX_APDU_DATA_LENGTH) {
|
|
173
|
+
// Small transaction - send directly
|
|
174
|
+
const p2 = isLastTransaction ? P2_MSG_END : P2_MORE | P2_MSG_END;
|
|
175
|
+
const response = await this.transport.send(CLA, INS.SIGN, P1_SIGN_UNTYPED_VERSIONED_MESSAGE, p2, transactionBuffer);
|
|
176
|
+
if (isLastTransaction) {
|
|
177
|
+
this.checkTransportResponse(response);
|
|
178
|
+
const responseData = this.extractResponseData(response);
|
|
179
|
+
return this.cleanSignatureFormat(responseData);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
this.checkTransportResponse(response);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
// Large transaction - use chunking
|
|
187
|
+
const responseData = await this.sendChunkedData({
|
|
188
|
+
ins: INS.SIGN,
|
|
189
|
+
p1: P1_SIGN_UNTYPED_VERSIONED_MESSAGE,
|
|
190
|
+
payload: transactionBuffer,
|
|
191
|
+
isFinal: isLastTransaction,
|
|
192
|
+
});
|
|
193
|
+
if (isLastTransaction && responseData) {
|
|
194
|
+
return this.cleanSignatureFormat(responseData);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
throw new TypeError("No transactions provided");
|
|
74
199
|
}
|
|
75
200
|
/**
|
|
76
201
|
* Get the app configuration.
|
|
@@ -78,46 +203,100 @@ export default class Canton {
|
|
|
78
203
|
*/
|
|
79
204
|
async getAppConfiguration() {
|
|
80
205
|
const response = await this.transport.send(CLA, INS.GET_VERSION, P1_NON_CONFIRM, P2_NONE, Buffer.alloc(0));
|
|
81
|
-
|
|
206
|
+
this.checkTransportResponse(response);
|
|
207
|
+
const responseData = this.extractResponseData(response);
|
|
82
208
|
const { major, minor, patch } = this.extractVersion(responseData);
|
|
83
209
|
return {
|
|
84
210
|
version: `${major}.${minor}.${patch}`,
|
|
85
211
|
};
|
|
86
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Validate Uint8Array with descriptive error message
|
|
215
|
+
* @private
|
|
216
|
+
*/
|
|
217
|
+
validateUint8Array(value, context) {
|
|
218
|
+
if (!value) {
|
|
219
|
+
throw new TypeError(`${context} is undefined or null`);
|
|
220
|
+
}
|
|
221
|
+
if (!(value instanceof Uint8Array)) {
|
|
222
|
+
throw new TypeError(`${context} is not a Uint8Array: ${typeof value}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Unified chunking strategy for sending data to device
|
|
227
|
+
* @private
|
|
228
|
+
*/
|
|
229
|
+
async sendChunkedData({ ins, p1, payload, isFinal = false, }) {
|
|
230
|
+
const chunks = this.createChunks(payload);
|
|
231
|
+
let responseData = null;
|
|
232
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
233
|
+
const isLastChunk = i === chunks.length - 1;
|
|
234
|
+
let p2 = P2_MORE;
|
|
235
|
+
if (isLastChunk) {
|
|
236
|
+
p2 = isFinal ? P2_MSG_END : P2_MORE | P2_MSG_END;
|
|
237
|
+
}
|
|
238
|
+
const response = await this.transport.send(CLA, ins, p1, p2, chunks[i]);
|
|
239
|
+
if (isFinal && isLastChunk) {
|
|
240
|
+
this.checkTransportResponse(response);
|
|
241
|
+
responseData = this.extractResponseData(response);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
this.checkTransportResponse(response);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return responseData;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Create optimized chunks from payload
|
|
251
|
+
* @private
|
|
252
|
+
*/
|
|
253
|
+
createChunks(payload) {
|
|
254
|
+
if (payload.length <= MAX_APDU_DATA_LENGTH) {
|
|
255
|
+
return [payload];
|
|
256
|
+
}
|
|
257
|
+
const totalChunks = Math.ceil(payload.length / MAX_APDU_DATA_LENGTH);
|
|
258
|
+
const chunks = new Array(totalChunks);
|
|
259
|
+
let offset = 0;
|
|
260
|
+
for (let i = 0; i < totalChunks; i++) {
|
|
261
|
+
const chunkSize = Math.min(MAX_APDU_DATA_LENGTH, payload.length - offset);
|
|
262
|
+
chunks[i] = payload.slice(offset, offset + chunkSize);
|
|
263
|
+
offset += chunkSize;
|
|
264
|
+
}
|
|
265
|
+
return chunks;
|
|
266
|
+
}
|
|
87
267
|
/**
|
|
88
268
|
* Converts 65-byte Canton format to 64-byte Ed25519:
|
|
89
269
|
* [40][64_bytes_signature][00] (132 hex chars)
|
|
90
270
|
* @private
|
|
91
271
|
*/
|
|
92
272
|
cleanSignatureFormat(signature) {
|
|
93
|
-
|
|
94
|
-
|
|
273
|
+
const signatureHex = signature.toString("hex");
|
|
274
|
+
if (signatureHex.length === ED25519_SIGNATURE_HEX_LENGTH) {
|
|
275
|
+
return signatureHex;
|
|
95
276
|
}
|
|
96
|
-
if (
|
|
97
|
-
const cleanedSignature =
|
|
277
|
+
if (signatureHex.length === CANTON_SIGNATURE_HEX_LENGTH) {
|
|
278
|
+
const cleanedSignature = signatureHex.slice(2, -2);
|
|
98
279
|
return cleanedSignature;
|
|
99
280
|
}
|
|
100
|
-
|
|
101
|
-
return signature;
|
|
281
|
+
return signatureHex;
|
|
102
282
|
}
|
|
103
283
|
/**
|
|
104
|
-
*
|
|
284
|
+
* Check transport response for errors and throw appropriate exceptions
|
|
105
285
|
* @private
|
|
106
286
|
*/
|
|
107
|
-
|
|
287
|
+
checkTransportResponse(response) {
|
|
108
288
|
const statusCode = response.readUInt16BE(response.length - 2);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
switch (errorType) {
|
|
112
|
-
case "address":
|
|
113
|
-
throw new UserRefusedAddress();
|
|
114
|
-
case "transaction":
|
|
115
|
-
throw new UserRefusedOnDevice();
|
|
116
|
-
default:
|
|
117
|
-
throw new Error();
|
|
118
|
-
}
|
|
289
|
+
if (statusCode !== STATUS.OK) {
|
|
290
|
+
throw new TransportStatusError(statusCode);
|
|
119
291
|
}
|
|
120
|
-
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Extract response data from transport response
|
|
295
|
+
* APDU responses have format: [data][status_code(2_bytes)]
|
|
296
|
+
* @private
|
|
297
|
+
*/
|
|
298
|
+
extractResponseData(response) {
|
|
299
|
+
return response.slice(0, -2);
|
|
121
300
|
}
|
|
122
301
|
/**
|
|
123
302
|
* Serialize a BIP path to a data buffer for Canton BOLOS
|
|
@@ -172,9 +351,9 @@ export default class Canton {
|
|
|
172
351
|
*/
|
|
173
352
|
extractVersion(data) {
|
|
174
353
|
return {
|
|
175
|
-
major: parseInt(data.subarray(0, 1).toString("hex"), 16),
|
|
176
|
-
minor: parseInt(data.subarray(1, 2).toString("hex"), 16),
|
|
177
|
-
patch: parseInt(data.subarray(2, 3).toString("hex"), 16),
|
|
354
|
+
major: Number.parseInt(data.subarray(0, 1).toString("hex"), 16),
|
|
355
|
+
minor: Number.parseInt(data.subarray(1, 2).toString("hex"), 16),
|
|
356
|
+
patch: Number.parseInt(data.subarray(2, 3).toString("hex"), 16),
|
|
178
357
|
};
|
|
179
358
|
}
|
|
180
359
|
}
|
package/lib-es/Canton.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Canton.js","sourceRoot":"","sources":["../src/Canton.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Canton.js","sourceRoot":"","sources":["../src/Canton.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/hw-app-canton",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0-nightly.0",
|
|
4
4
|
"description": "Ledger Hardware Wallet Canton Application API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Ledger",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"license": "Apache-2.0",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"bip32-path": "^0.4.2",
|
|
29
|
-
"@ledgerhq/errors": "^6.
|
|
30
|
-
"@ledgerhq/hw-transport": "6.31.
|
|
29
|
+
"@ledgerhq/errors": "^6.27.0-nightly.0",
|
|
30
|
+
"@ledgerhq/hw-transport": "6.31.13-nightly.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/jest": "^29.5.10",
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"source-map-support": "^0.5.21",
|
|
39
39
|
"ts-jest": "^29.1.1",
|
|
40
40
|
"ts-node": "^10.4.0",
|
|
41
|
-
"@ledgerhq/hw-transport-mocker": "^6.29.
|
|
42
|
-
"@ledgerhq/hw-transport-node-speculos-http": "^6.
|
|
41
|
+
"@ledgerhq/hw-transport-mocker": "^6.29.13-nightly.0",
|
|
42
|
+
"@ledgerhq/hw-transport-node-speculos-http": "^6.31.0-nightly.1"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"clean": "rimraf lib lib-es",
|
package/src/Canton.test.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { openTransportReplayer, RecordStore } from "@ledgerhq/hw-transport-mocker";
|
|
2
|
+
import { TransportStatusError } from "@ledgerhq/errors";
|
|
2
3
|
import Canton from "./Canton";
|
|
3
4
|
|
|
5
|
+
const PATH = "44'/6767'/0'/0'/0'";
|
|
6
|
+
|
|
4
7
|
describe("Canton", () => {
|
|
5
8
|
describe("decorateAppAPIMethods", () => {
|
|
6
9
|
it("should properly decorate transport methods", async () => {
|
|
@@ -30,12 +33,12 @@ describe("Canton", () => {
|
|
|
30
33
|
const canton = new Canton(transport);
|
|
31
34
|
|
|
32
35
|
// WHEN
|
|
33
|
-
const result = await canton.getAddress(
|
|
36
|
+
const result = await canton.getAddress(PATH);
|
|
34
37
|
|
|
35
38
|
// THEN
|
|
36
39
|
expect(result).toEqual({
|
|
37
40
|
address: "canton_402f2e68",
|
|
38
|
-
path:
|
|
41
|
+
path: PATH,
|
|
39
42
|
publicKey: "c59f7f29374d24506dd6490a5db472cf00958e195e146f3dc9c97f96d5c51097",
|
|
40
43
|
});
|
|
41
44
|
});
|
|
@@ -51,12 +54,12 @@ describe("Canton", () => {
|
|
|
51
54
|
const canton = new Canton(transport);
|
|
52
55
|
|
|
53
56
|
// WHEN
|
|
54
|
-
const result = await canton.getAddress(
|
|
57
|
+
const result = await canton.getAddress(PATH, true);
|
|
55
58
|
|
|
56
59
|
// THEN
|
|
57
60
|
expect(result).toEqual({
|
|
58
61
|
address: "canton_402f2e68",
|
|
59
|
-
path:
|
|
62
|
+
path: PATH,
|
|
60
63
|
publicKey: "c59f7f29374d24506dd6490a5db472cf00958e195e146f3dc9c97f96d5c51097",
|
|
61
64
|
});
|
|
62
65
|
});
|
|
@@ -67,55 +70,74 @@ describe("Canton", () => {
|
|
|
67
70
|
const canton = new Canton(transport);
|
|
68
71
|
|
|
69
72
|
// WHEN & THEN
|
|
70
|
-
|
|
73
|
+
await expect(canton.getAddress("invalid-path")).rejects.toThrow();
|
|
71
74
|
});
|
|
72
75
|
|
|
73
|
-
it("should handle
|
|
76
|
+
it("should handle user refused address", async () => {
|
|
74
77
|
// GIVEN
|
|
75
78
|
const transport = await openTransportReplayer(
|
|
76
79
|
RecordStore.fromString(`
|
|
77
|
-
=>
|
|
78
|
-
<=
|
|
80
|
+
=> e005010015058000002c80001a6f800000008000000080000000
|
|
81
|
+
<= 6985
|
|
79
82
|
`),
|
|
80
83
|
);
|
|
81
84
|
const canton = new Canton(transport);
|
|
82
85
|
|
|
83
|
-
// WHEN
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
// THEN
|
|
87
|
-
expect(result).toBeDefined();
|
|
88
|
-
expect(result.address).toBeDefined();
|
|
89
|
-
expect(result.publicKey).toBeDefined();
|
|
86
|
+
// WHEN & THEN
|
|
87
|
+
await expect(canton.getAddress(PATH, true)).rejects.toThrow(new TransportStatusError(0x6985));
|
|
90
88
|
});
|
|
91
|
-
|
|
92
|
-
// should handle user refused address
|
|
93
89
|
});
|
|
94
90
|
|
|
95
91
|
describe("signTransaction", () => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
it("should sign untyped versioned message", async () => {
|
|
93
|
+
// GIVEN
|
|
94
|
+
const transport = await openTransportReplayer(
|
|
95
|
+
RecordStore.fromString(`
|
|
96
|
+
=> e006010315058000002c80001a6f800000008000000080000000
|
|
97
|
+
<= 9000
|
|
98
|
+
=> e006010420d1e98829444207b0e170346b2e80b58a2ffc602b01e190fb742016d407c84efd
|
|
99
|
+
<= 40a65f53c3657bc04efefb67a425ba093a5cb5391d18142f148bb2c48daacf316114cff920a58d5996ca828c7ce265f537f1d7fca8fa82c3c73bd944a96e701a00009000
|
|
100
|
+
`),
|
|
101
|
+
);
|
|
102
|
+
const canton = new Canton(transport);
|
|
103
|
+
const data = {
|
|
104
|
+
transactions: ["d1e98829444207b0e170346b2e80b58a2ffc602b01e190fb742016d407c84efd"],
|
|
105
|
+
};
|
|
99
106
|
|
|
100
|
-
|
|
107
|
+
// WHEN
|
|
108
|
+
const result = await canton.signTransaction(PATH, data);
|
|
101
109
|
|
|
102
|
-
|
|
110
|
+
// THEN
|
|
111
|
+
expect(result).toEqual(
|
|
112
|
+
"a65f53c3657bc04efefb67a425ba093a5cb5391d18142f148bb2c48daacf316114cff920a58d5996ca828c7ce265f537f1d7fca8fa82c3c73bd944a96e701a00",
|
|
113
|
+
);
|
|
114
|
+
});
|
|
103
115
|
|
|
104
|
-
it("should sign
|
|
116
|
+
it("should sign large untyped versioned message with chunking", async () => {
|
|
105
117
|
// GIVEN
|
|
118
|
+
const largeTransaction =
|
|
119
|
+
"d1e98829444207b0e170346b2e80b58a2ffc602b01e190fb742016d407c84efd".repeat(10);
|
|
120
|
+
|
|
121
|
+
const firstChunk = largeTransaction.substring(0, 510);
|
|
122
|
+
const secondChunk = largeTransaction.substring(510, 640);
|
|
123
|
+
|
|
106
124
|
const transport = await openTransportReplayer(
|
|
107
125
|
RecordStore.fromString(`
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
126
|
+
=> e006010315058000002c80001a6f800000008000000080000000
|
|
127
|
+
<= 9000
|
|
128
|
+
=> e0060102ff${firstChunk}
|
|
129
|
+
<= 9000
|
|
130
|
+
=> e006010441${secondChunk}
|
|
131
|
+
<= 40a65f53c3657bc04efefb67a425ba093a5cb5391d18142f148bb2c48daacf316114cff920a58d5996ca828c7ce265f537f1d7fca8fa82c3c73bd944a96e701a00009000
|
|
132
|
+
`),
|
|
113
133
|
);
|
|
114
134
|
const canton = new Canton(transport);
|
|
115
|
-
const
|
|
135
|
+
const data = {
|
|
136
|
+
transactions: [largeTransaction],
|
|
137
|
+
};
|
|
116
138
|
|
|
117
139
|
// WHEN
|
|
118
|
-
const result = await canton.signTransaction(
|
|
140
|
+
const result = await canton.signTransaction(PATH, data);
|
|
119
141
|
|
|
120
142
|
// THEN
|
|
121
143
|
expect(result).toEqual(
|
|
@@ -123,18 +145,77 @@ describe("Canton", () => {
|
|
|
123
145
|
);
|
|
124
146
|
});
|
|
125
147
|
|
|
126
|
-
it("should
|
|
148
|
+
it("should sign prepared transaction", async () => {
|
|
127
149
|
// GIVEN
|
|
128
150
|
const transport = await openTransportReplayer(
|
|
129
151
|
RecordStore.fromString(`
|
|
130
|
-
=>
|
|
131
|
-
<=
|
|
152
|
+
=> e006020315058000002c80001a6f800000008000000080000000
|
|
153
|
+
<= 9000
|
|
154
|
+
=> e0060202ff${"1234567890abcdef".repeat(31)}1234567890abcd
|
|
155
|
+
<= 9000
|
|
156
|
+
=> e006020608ef1234567890abcd
|
|
157
|
+
<= 9000
|
|
158
|
+
=> e0060202ff${"1234567890abcdef".repeat(31)}1234567890abcd
|
|
159
|
+
<= 9000
|
|
160
|
+
=> e006020608ef1234567890abcd
|
|
161
|
+
<= 9000
|
|
162
|
+
=> e0060202ff${"1234567890abcdef".repeat(31)}1234567890abcd
|
|
163
|
+
<= 9000
|
|
164
|
+
=> e006020608ef1234567890abcd
|
|
165
|
+
<= 9000
|
|
166
|
+
=> e0060202ff${"1234567890abcdef".repeat(31)}1234567890abcd
|
|
167
|
+
<= 9000
|
|
168
|
+
=> e006020408ef1234567890abcd
|
|
169
|
+
<= 40a65f53c3657bc04efefb67a425ba093a5cb5391d18142f148bb2c48daacf316114cff920a58d5996ca828c7ce265f537f1d7fca8fa82c3c73bd944a96e701a009000
|
|
132
170
|
`),
|
|
133
171
|
);
|
|
134
172
|
const canton = new Canton(transport);
|
|
135
173
|
|
|
136
|
-
|
|
137
|
-
|
|
174
|
+
const testData = "1234567890abcdef".repeat(31) + "1234567890abcdef1234567890abcd";
|
|
175
|
+
const components = {
|
|
176
|
+
damlTransaction: Buffer.from(testData, "hex"),
|
|
177
|
+
nodes: [Buffer.from(testData, "hex")],
|
|
178
|
+
metadata: Buffer.from(testData, "hex"),
|
|
179
|
+
inputContracts: [Buffer.from(testData, "hex")],
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// WHEN
|
|
183
|
+
const result = await canton.signTransaction(PATH, components);
|
|
184
|
+
|
|
185
|
+
// THEN
|
|
186
|
+
expect(result).toEqual(
|
|
187
|
+
"40a65f53c3657bc04efefb67a425ba093a5cb5391d18142f148bb2c48daacf316114cff920a58d5996ca828c7ce265f537f1d7fca8fa82c3c73bd944a96e701a00",
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe("error handling", () => {
|
|
192
|
+
it("should handle user refused transaction", async () => {
|
|
193
|
+
// GIVEN
|
|
194
|
+
const transport = await openTransportReplayer(
|
|
195
|
+
RecordStore.fromString(`
|
|
196
|
+
=> e006010315058000002c80001a6f800000008000000080000000
|
|
197
|
+
<= 6985
|
|
198
|
+
`),
|
|
199
|
+
);
|
|
200
|
+
const canton = new Canton(transport);
|
|
201
|
+
const data = {
|
|
202
|
+
transactions: ["test"],
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// WHEN & THEN
|
|
206
|
+
await expect(canton.signTransaction(PATH, data)).rejects.toThrow(
|
|
207
|
+
new TransportStatusError(0x6985),
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("should handle invalid transaction data", async () => {
|
|
212
|
+
// GIVEN
|
|
213
|
+
const transport = await openTransportReplayer(new RecordStore());
|
|
214
|
+
const canton = new Canton(transport);
|
|
215
|
+
|
|
216
|
+
// WHEN & THEN
|
|
217
|
+
await expect(canton.signTransaction(PATH, null as any)).rejects.toThrow();
|
|
218
|
+
});
|
|
138
219
|
});
|
|
139
220
|
});
|
|
140
221
|
|
|
@@ -144,7 +225,7 @@ describe("Canton", () => {
|
|
|
144
225
|
const transport = await openTransportReplayer(
|
|
145
226
|
RecordStore.fromString(`
|
|
146
227
|
=> e003000000
|
|
147
|
-
<=
|
|
228
|
+
<= 0101009000
|
|
148
229
|
`),
|
|
149
230
|
);
|
|
150
231
|
const canton = new Canton(transport);
|
|
@@ -154,10 +235,8 @@ describe("Canton", () => {
|
|
|
154
235
|
|
|
155
236
|
// THEN
|
|
156
237
|
expect(result).toEqual({
|
|
157
|
-
version: "
|
|
238
|
+
version: "1.1.0",
|
|
158
239
|
});
|
|
159
240
|
});
|
|
160
|
-
|
|
161
|
-
// should handle configuration error
|
|
162
241
|
});
|
|
163
242
|
});
|