1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | import { splitPath, foreach } from "./utils";
|
19 | import { EthAppPleaseEnableContractData } from "@ledgerhq/errors";
|
20 | import { BigNumber } from "bignumber.js";
|
21 | import { encode, decode } from "rlp";
|
22 | const starkQuantizationTypeMap = {
|
23 | eth: 1,
|
24 | erc20: 2,
|
25 | erc721: 3,
|
26 | erc20mintable: 4,
|
27 | erc721mintable: 5
|
28 | };
|
29 |
|
30 | function hexBuffer(str) {
|
31 | return Buffer.from(str.startsWith("0x") ? str.slice(2) : str, "hex");
|
32 | }
|
33 |
|
34 | function maybeHexBuffer(str) {
|
35 | if (!str) return null;
|
36 | return hexBuffer(str);
|
37 | }
|
38 |
|
39 | const remapTransactionRelatedErrors = e => {
|
40 | if (e && e.statusCode === 0x6a80) {
|
41 | return new EthAppPleaseEnableContractData("Please enable Contract data on the Ethereum app Settings");
|
42 | }
|
43 |
|
44 | return e;
|
45 | };
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | export default class Eth {
|
56 | constructor(transport, scrambleKey = "w0w") {
|
57 | this.transport = void 0;
|
58 | this.transport = transport;
|
59 | transport.decorateAppAPIMethods(this, ["getAddress", "provideERC20TokenInformation", "signTransaction", "signPersonalMessage", "getAppConfiguration", "signEIP712HashedMessage", "starkGetPublicKey", "starkSignOrder", "starkSignOrder_v2", "starkSignTransfer", "starkSignTransfer_v2", "starkProvideQuantum", "starkProvideQuantum_v2", "starkUnsafeSign", "eth2GetPublicKey", "eth2SetWithdrawalIndex"], scrambleKey);
|
60 | }
|
61 | |
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 | getAddress(path, boolDisplay, boolChaincode) {
|
73 | let paths = splitPath(path);
|
74 | let buffer = Buffer.alloc(1 + paths.length * 4);
|
75 | buffer[0] = paths.length;
|
76 | paths.forEach((element, index) => {
|
77 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
78 | });
|
79 | return this.transport.send(0xe0, 0x02, boolDisplay ? 0x01 : 0x00, boolChaincode ? 0x01 : 0x00, buffer).then(response => {
|
80 | let result = {};
|
81 | let publicKeyLength = response[0];
|
82 | let addressLength = response[1 + publicKeyLength];
|
83 | result.publicKey = response.slice(1, 1 + publicKeyLength).toString("hex");
|
84 | result.address = "0x" + response.slice(1 + publicKeyLength + 1, 1 + publicKeyLength + 1 + addressLength).toString("ascii");
|
85 |
|
86 | if (boolChaincode) {
|
87 | result.chainCode = response.slice(1 + publicKeyLength + 1 + addressLength, 1 + publicKeyLength + 1 + addressLength + 32).toString("hex");
|
88 | }
|
89 |
|
90 | return result;
|
91 | });
|
92 | }
|
93 | |
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 | provideERC20TokenInformation({
|
111 | data
|
112 | }) {
|
113 | return this.transport.send(0xe0, 0x0a, 0x00, 0x00, data).then(() => true, e => {
|
114 | if (e && e.statusCode === 0x6d00) {
|
115 |
|
116 |
|
117 | return false;
|
118 | }
|
119 |
|
120 | throw e;
|
121 | });
|
122 | }
|
123 | |
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 | signTransaction(path, rawTxHex) {
|
131 | let paths = splitPath(path);
|
132 | let offset = 0;
|
133 | let rawTx = Buffer.from(rawTxHex, "hex");
|
134 | let toSend = [];
|
135 | let response;
|
136 |
|
137 | let rlpTx = decode(rawTx);
|
138 | let rlpOffset = 0;
|
139 | let chainIdPrefix = "";
|
140 |
|
141 | if (rlpTx.length > 6) {
|
142 | let rlpVrs = encode(rlpTx.slice(-3));
|
143 | rlpOffset = rawTx.length - (rlpVrs.length - 1);
|
144 | const chainIdSrc = rlpTx[6];
|
145 | const chainIdBuf = Buffer.alloc(4);
|
146 | chainIdSrc.copy(chainIdBuf, 4 - chainIdSrc.length);
|
147 | chainIdPrefix = (chainIdBuf.readUInt32BE(0) * 2).toString(16).slice(0, -2);
|
148 | }
|
149 |
|
150 | while (offset !== rawTx.length) {
|
151 | let maxChunkSize = offset === 0 ? 150 - 1 - paths.length * 4 : 150;
|
152 | let chunkSize = offset + maxChunkSize > rawTx.length ? rawTx.length - offset : maxChunkSize;
|
153 |
|
154 | if (rlpOffset != 0 && offset + chunkSize == rlpOffset) {
|
155 |
|
156 | chunkSize--;
|
157 | }
|
158 |
|
159 | let buffer = Buffer.alloc(offset === 0 ? 1 + paths.length * 4 + chunkSize : chunkSize);
|
160 |
|
161 | if (offset === 0) {
|
162 | buffer[0] = paths.length;
|
163 | paths.forEach((element, index) => {
|
164 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
165 | });
|
166 | rawTx.copy(buffer, 1 + 4 * paths.length, offset, offset + chunkSize);
|
167 | } else {
|
168 | rawTx.copy(buffer, 0, offset, offset + chunkSize);
|
169 | }
|
170 |
|
171 | toSend.push(buffer);
|
172 | offset += chunkSize;
|
173 | }
|
174 |
|
175 | return foreach(toSend, (data, i) => this.transport.send(0xe0, 0x04, i === 0 ? 0x00 : 0x80, 0x00, data).then(apduResponse => {
|
176 | response = apduResponse;
|
177 | })).then(() => {
|
178 | const v = chainIdPrefix + response.slice(0, 1).toString("hex");
|
179 | const r = response.slice(1, 1 + 32).toString("hex");
|
180 | const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
|
181 | return {
|
182 | v,
|
183 | r,
|
184 | s
|
185 | };
|
186 | }, e => {
|
187 | throw remapTransactionRelatedErrors(e);
|
188 | });
|
189 | }
|
190 | |
191 |
|
192 |
|
193 |
|
194 | getAppConfiguration() {
|
195 | return this.transport.send(0xe0, 0x06, 0x00, 0x00).then(response => {
|
196 | let result = {};
|
197 | result.arbitraryDataEnabled = response[0] & 0x01;
|
198 | result.erc20ProvisioningNecessary = response[0] & 0x02;
|
199 | result.starkEnabled = response[0] & 0x04;
|
200 | result.starkv2Supported = response[0] & 0x08;
|
201 | result.version = "" + response[1] + "." + response[2] + "." + response[3];
|
202 | return result;
|
203 | });
|
204 | }
|
205 | |
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 | signPersonalMessage(path, messageHex) {
|
220 | let paths = splitPath(path);
|
221 | let offset = 0;
|
222 | let message = Buffer.from(messageHex, "hex");
|
223 | let toSend = [];
|
224 | let response;
|
225 |
|
226 | while (offset !== message.length) {
|
227 | let maxChunkSize = offset === 0 ? 150 - 1 - paths.length * 4 - 4 : 150;
|
228 | let chunkSize = offset + maxChunkSize > message.length ? message.length - offset : maxChunkSize;
|
229 | let buffer = Buffer.alloc(offset === 0 ? 1 + paths.length * 4 + 4 + chunkSize : chunkSize);
|
230 |
|
231 | if (offset === 0) {
|
232 | buffer[0] = paths.length;
|
233 | paths.forEach((element, index) => {
|
234 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
235 | });
|
236 | buffer.writeUInt32BE(message.length, 1 + 4 * paths.length);
|
237 | message.copy(buffer, 1 + 4 * paths.length + 4, offset, offset + chunkSize);
|
238 | } else {
|
239 | message.copy(buffer, 0, offset, offset + chunkSize);
|
240 | }
|
241 |
|
242 | toSend.push(buffer);
|
243 | offset += chunkSize;
|
244 | }
|
245 |
|
246 | return foreach(toSend, (data, i) => this.transport.send(0xe0, 0x08, i === 0 ? 0x00 : 0x80, 0x00, data).then(apduResponse => {
|
247 | response = apduResponse;
|
248 | })).then(() => {
|
249 | const v = response[0];
|
250 | const r = response.slice(1, 1 + 32).toString("hex");
|
251 | const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
|
252 | return {
|
253 | v,
|
254 | r,
|
255 | s
|
256 | };
|
257 | });
|
258 | }
|
259 | |
260 |
|
261 |
|
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 | signEIP712HashedMessage(path, domainSeparatorHex, hashStructMessageHex) {
|
274 | const domainSeparator = hexBuffer(domainSeparatorHex);
|
275 | const hashStruct = hexBuffer(hashStructMessageHex);
|
276 | let paths = splitPath(path);
|
277 | let buffer = Buffer.alloc(1 + paths.length * 4 + 32 + 32, 0);
|
278 | let offset = 0;
|
279 | buffer[0] = paths.length;
|
280 | paths.forEach((element, index) => {
|
281 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
282 | });
|
283 | offset = 1 + 4 * paths.length;
|
284 | domainSeparator.copy(buffer, offset);
|
285 | offset += 32;
|
286 | hashStruct.copy(buffer, offset);
|
287 | return this.transport.send(0xe0, 0x0c, 0x00, 0x00, buffer).then(response => {
|
288 | const v = response[0];
|
289 | const r = response.slice(1, 1 + 32).toString("hex");
|
290 | const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
|
291 | return {
|
292 | v,
|
293 | r,
|
294 | s
|
295 | };
|
296 | });
|
297 | }
|
298 | |
299 |
|
300 |
|
301 |
|
302 |
|
303 |
|
304 |
|
305 |
|
306 | starkGetPublicKey(path, boolDisplay) {
|
307 | let paths = splitPath(path);
|
308 | let buffer = Buffer.alloc(1 + paths.length * 4);
|
309 | buffer[0] = paths.length;
|
310 | paths.forEach((element, index) => {
|
311 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
312 | });
|
313 | return this.transport.send(0xf0, 0x02, boolDisplay ? 0x01 : 0x00, 0x00, buffer).then(response => {
|
314 | return response.slice(0, response.length - 2);
|
315 | });
|
316 | }
|
317 | |
318 |
|
319 |
|
320 |
|
321 |
|
322 |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 |
|
328 |
|
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 | starkSignOrder(path, sourceTokenAddress, sourceQuantization, destinationTokenAddress, destinationQuantization, sourceVault, destinationVault, amountSell, amountBuy, nonce, timestamp) {
|
335 | const sourceTokenAddressHex = maybeHexBuffer(sourceTokenAddress);
|
336 | const destinationTokenAddressHex = maybeHexBuffer(destinationTokenAddress);
|
337 | let paths = splitPath(path);
|
338 | let buffer = Buffer.alloc(1 + paths.length * 4 + 20 + 32 + 20 + 32 + 4 + 4 + 8 + 8 + 4 + 4, 0);
|
339 | let offset = 0;
|
340 | buffer[0] = paths.length;
|
341 | paths.forEach((element, index) => {
|
342 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
343 | });
|
344 | offset = 1 + 4 * paths.length;
|
345 |
|
346 | if (sourceTokenAddressHex) {
|
347 | sourceTokenAddressHex.copy(buffer, offset);
|
348 | }
|
349 |
|
350 | offset += 20;
|
351 | Buffer.from(sourceQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
352 | offset += 32;
|
353 |
|
354 | if (destinationTokenAddressHex) {
|
355 | destinationTokenAddressHex.copy(buffer, offset);
|
356 | }
|
357 |
|
358 | offset += 20;
|
359 | Buffer.from(destinationQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
360 | offset += 32;
|
361 | buffer.writeUInt32BE(sourceVault, offset);
|
362 | offset += 4;
|
363 | buffer.writeUInt32BE(destinationVault, offset);
|
364 | offset += 4;
|
365 | Buffer.from(amountSell.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
|
366 | offset += 8;
|
367 | Buffer.from(amountBuy.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
|
368 | offset += 8;
|
369 | buffer.writeUInt32BE(nonce, offset);
|
370 | offset += 4;
|
371 | buffer.writeUInt32BE(timestamp, offset);
|
372 | return this.transport.send(0xf0, 0x04, 0x01, 0x00, buffer).then(response => {
|
373 | const r = response.slice(1, 1 + 32).toString("hex");
|
374 | const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
|
375 | return {
|
376 | r,
|
377 | s
|
378 | };
|
379 | });
|
380 | }
|
381 | |
382 |
|
383 |
|
384 |
|
385 |
|
386 |
|
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 |
|
396 |
|
397 |
|
398 |
|
399 |
|
400 |
|
401 |
|
402 | starkSignOrder_v2(path, sourceTokenAddress, sourceQuantizationType, sourceQuantization, sourceMintableBlobOrTokenId, destinationTokenAddress, destinationQuantizationType, destinationQuantization, destinationMintableBlobOrTokenId, sourceVault, destinationVault, amountSell, amountBuy, nonce, timestamp) {
|
403 | const sourceTokenAddressHex = maybeHexBuffer(sourceTokenAddress);
|
404 | const destinationTokenAddressHex = maybeHexBuffer(destinationTokenAddress);
|
405 |
|
406 | if (!(sourceQuantizationType in starkQuantizationTypeMap)) {
|
407 | throw new Error("eth.starkSignOrderv2 invalid source quantization type=" + sourceQuantizationType);
|
408 | }
|
409 |
|
410 | if (!(destinationQuantizationType in starkQuantizationTypeMap)) {
|
411 | throw new Error("eth.starkSignOrderv2 invalid destination quantization type=" + destinationQuantizationType);
|
412 | }
|
413 |
|
414 | let paths = splitPath(path);
|
415 | let buffer = Buffer.alloc(1 + paths.length * 4 + 1 + 20 + 32 + 32 + 1 + 20 + 32 + 32 + 4 + 4 + 8 + 8 + 4 + 4, 0);
|
416 | let offset = 0;
|
417 | buffer[0] = paths.length;
|
418 | paths.forEach((element, index) => {
|
419 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
420 | });
|
421 | offset = 1 + 4 * paths.length;
|
422 | buffer[offset] = starkQuantizationTypeMap[sourceQuantizationType];
|
423 | offset++;
|
424 |
|
425 | if (sourceTokenAddressHex) {
|
426 | sourceTokenAddressHex.copy(buffer, offset);
|
427 | }
|
428 |
|
429 | offset += 20;
|
430 |
|
431 | if (sourceQuantization) {
|
432 | Buffer.from(sourceQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
433 | }
|
434 |
|
435 | offset += 32;
|
436 |
|
437 | if (sourceMintableBlobOrTokenId) {
|
438 | Buffer.from(sourceMintableBlobOrTokenId.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
439 | }
|
440 |
|
441 | offset += 32;
|
442 | buffer[offset] = starkQuantizationTypeMap[destinationQuantizationType];
|
443 | offset++;
|
444 |
|
445 | if (destinationTokenAddressHex) {
|
446 | destinationTokenAddressHex.copy(buffer, offset);
|
447 | }
|
448 |
|
449 | offset += 20;
|
450 |
|
451 | if (destinationQuantization) {
|
452 | Buffer.from(destinationQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
453 | }
|
454 |
|
455 | offset += 32;
|
456 |
|
457 | if (destinationMintableBlobOrTokenId) {
|
458 | Buffer.from(destinationMintableBlobOrTokenId.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
459 | }
|
460 |
|
461 | offset += 32;
|
462 | buffer.writeUInt32BE(sourceVault, offset);
|
463 | offset += 4;
|
464 | buffer.writeUInt32BE(destinationVault, offset);
|
465 | offset += 4;
|
466 | Buffer.from(amountSell.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
|
467 | offset += 8;
|
468 | Buffer.from(amountBuy.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
|
469 | offset += 8;
|
470 | buffer.writeUInt32BE(nonce, offset);
|
471 | offset += 4;
|
472 | buffer.writeUInt32BE(timestamp, offset);
|
473 | return this.transport.send(0xf0, 0x04, 0x03, 0x00, buffer).then(response => {
|
474 | const r = response.slice(1, 1 + 32).toString("hex");
|
475 | const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
|
476 | return {
|
477 | r,
|
478 | s
|
479 | };
|
480 | });
|
481 | }
|
482 | |
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 |
|
493 |
|
494 |
|
495 |
|
496 |
|
497 | starkSignTransfer(path, transferTokenAddress, transferQuantization, targetPublicKey, sourceVault, destinationVault, amountTransfer, nonce, timestamp) {
|
498 | const transferTokenAddressHex = maybeHexBuffer(transferTokenAddress);
|
499 | const targetPublicKeyHex = hexBuffer(targetPublicKey);
|
500 | let paths = splitPath(path);
|
501 | let buffer = Buffer.alloc(1 + paths.length * 4 + 20 + 32 + 32 + 4 + 4 + 8 + 4 + 4, 0);
|
502 | let offset = 0;
|
503 | buffer[0] = paths.length;
|
504 | paths.forEach((element, index) => {
|
505 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
506 | });
|
507 | offset = 1 + 4 * paths.length;
|
508 |
|
509 | if (transferTokenAddressHex) {
|
510 | transferTokenAddressHex.copy(buffer, offset);
|
511 | }
|
512 |
|
513 | offset += 20;
|
514 | Buffer.from(transferQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
515 | offset += 32;
|
516 | targetPublicKeyHex.copy(buffer, offset);
|
517 | offset += 32;
|
518 | buffer.writeUInt32BE(sourceVault, offset);
|
519 | offset += 4;
|
520 | buffer.writeUInt32BE(destinationVault, offset);
|
521 | offset += 4;
|
522 | Buffer.from(amountTransfer.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
|
523 | offset += 8;
|
524 | buffer.writeUInt32BE(nonce, offset);
|
525 | offset += 4;
|
526 | buffer.writeUInt32BE(timestamp, offset);
|
527 | return this.transport.send(0xf0, 0x04, 0x02, 0x00, buffer).then(response => {
|
528 | const r = response.slice(1, 1 + 32).toString("hex");
|
529 | const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
|
530 | return {
|
531 | r,
|
532 | s
|
533 | };
|
534 | });
|
535 | }
|
536 | |
537 |
|
538 |
|
539 |
|
540 |
|
541 |
|
542 |
|
543 |
|
544 |
|
545 |
|
546 |
|
547 |
|
548 |
|
549 |
|
550 |
|
551 |
|
552 |
|
553 |
|
554 |
|
555 | starkSignTransfer_v2(path, transferTokenAddress, transferQuantizationType, transferQuantization, transferMintableBlobOrTokenId, targetPublicKey, sourceVault, destinationVault, amountTransfer, nonce, timestamp, conditionalTransferAddress, conditionalTransferFact) {
|
556 | const transferTokenAddressHex = maybeHexBuffer(transferTokenAddress);
|
557 | const targetPublicKeyHex = hexBuffer(targetPublicKey);
|
558 | const conditionalTransferAddressHex = maybeHexBuffer(conditionalTransferAddress);
|
559 |
|
560 | if (!(transferQuantizationType in starkQuantizationTypeMap)) {
|
561 | throw new Error("eth.starkSignTransferv2 invalid quantization type=" + transferQuantizationType);
|
562 | }
|
563 |
|
564 | let paths = splitPath(path);
|
565 | let buffer = Buffer.alloc(1 + paths.length * 4 + 1 + 20 + 32 + 32 + 32 + 4 + 4 + 8 + 4 + 4 + (conditionalTransferAddressHex ? 32 + 20 : 0), 0);
|
566 | let offset = 0;
|
567 | buffer[0] = paths.length;
|
568 | paths.forEach((element, index) => {
|
569 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
570 | });
|
571 | offset = 1 + 4 * paths.length;
|
572 | buffer[offset] = starkQuantizationTypeMap[transferQuantizationType];
|
573 | offset++;
|
574 |
|
575 | if (transferTokenAddressHex) {
|
576 | transferTokenAddressHex.copy(buffer, offset);
|
577 | }
|
578 |
|
579 | offset += 20;
|
580 |
|
581 | if (transferQuantization) {
|
582 | Buffer.from(transferQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
583 | }
|
584 |
|
585 | offset += 32;
|
586 |
|
587 | if (transferMintableBlobOrTokenId) {
|
588 | Buffer.from(transferMintableBlobOrTokenId.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
589 | }
|
590 |
|
591 | offset += 32;
|
592 | targetPublicKeyHex.copy(buffer, offset);
|
593 | offset += 32;
|
594 | buffer.writeUInt32BE(sourceVault, offset);
|
595 | offset += 4;
|
596 | buffer.writeUInt32BE(destinationVault, offset);
|
597 | offset += 4;
|
598 | Buffer.from(amountTransfer.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
|
599 | offset += 8;
|
600 | buffer.writeUInt32BE(nonce, offset);
|
601 | offset += 4;
|
602 | buffer.writeUInt32BE(timestamp, offset);
|
603 |
|
604 | if (conditionalTransferAddressHex && conditionalTransferFact) {
|
605 | offset += 4;
|
606 | Buffer.from(conditionalTransferFact.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
607 | offset += 32;
|
608 | conditionalTransferAddressHex.copy(buffer, offset);
|
609 | }
|
610 |
|
611 | return this.transport.send(0xf0, 0x04, conditionalTransferAddressHex ? 0x05 : 0x04, 0x00, buffer).then(response => {
|
612 | const r = response.slice(1, 1 + 32).toString("hex");
|
613 | const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
|
614 | return {
|
615 | r,
|
616 | s
|
617 | };
|
618 | });
|
619 | }
|
620 | |
621 |
|
622 |
|
623 |
|
624 |
|
625 |
|
626 |
|
627 |
|
628 |
|
629 |
|
630 | starkProvideQuantum(operationContract, operationQuantization) {
|
631 | const operationContractHex = maybeHexBuffer(operationContract);
|
632 | let buffer = Buffer.alloc(20 + 32, 0);
|
633 |
|
634 | if (operationContractHex) {
|
635 | operationContractHex.copy(buffer, 0);
|
636 | }
|
637 |
|
638 | Buffer.from(operationQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, 20);
|
639 | return this.transport.send(0xf0, 0x08, 0x00, 0x00, buffer).then(() => true, e => {
|
640 | if (e && e.statusCode === 0x6d00) {
|
641 |
|
642 | return false;
|
643 | }
|
644 |
|
645 | throw e;
|
646 | });
|
647 | }
|
648 | |
649 |
|
650 |
|
651 |
|
652 |
|
653 |
|
654 |
|
655 |
|
656 |
|
657 |
|
658 |
|
659 |
|
660 | starkProvideQuantum_v2(operationContract, operationQuantizationType, operationQuantization, operationMintableBlobOrTokenId) {
|
661 | const operationContractHex = maybeHexBuffer(operationContract);
|
662 |
|
663 | if (!(operationQuantizationType in starkQuantizationTypeMap)) {
|
664 | throw new Error("eth.starkProvideQuantumV2 invalid quantization type=" + operationQuantizationType);
|
665 | }
|
666 |
|
667 | let buffer = Buffer.alloc(20 + 32 + 32, 0);
|
668 | let offset = 0;
|
669 |
|
670 | if (operationContractHex) {
|
671 | operationContractHex.copy(buffer, offset);
|
672 | }
|
673 |
|
674 | offset += 20;
|
675 |
|
676 | if (operationQuantization) {
|
677 | Buffer.from(operationQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
678 | }
|
679 |
|
680 | offset += 32;
|
681 |
|
682 | if (operationMintableBlobOrTokenId) {
|
683 | Buffer.from(operationMintableBlobOrTokenId.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
|
684 | }
|
685 |
|
686 | return this.transport.send(0xf0, 0x08, starkQuantizationTypeMap[operationQuantizationType], 0x00, buffer).then(() => true, e => {
|
687 | if (e && e.statusCode === 0x6d00) {
|
688 |
|
689 | return false;
|
690 | }
|
691 |
|
692 | throw e;
|
693 | });
|
694 | }
|
695 | |
696 |
|
697 |
|
698 |
|
699 |
|
700 |
|
701 |
|
702 |
|
703 |
|
704 | starkUnsafeSign(path, hash) {
|
705 | const hashHex = hexBuffer(hash);
|
706 | let paths = splitPath(path);
|
707 | let buffer = Buffer.alloc(1 + paths.length * 4 + 32);
|
708 | let offset = 0;
|
709 | buffer[0] = paths.length;
|
710 | paths.forEach((element, index) => {
|
711 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
712 | });
|
713 | offset = 1 + 4 * paths.length;
|
714 | hashHex.copy(buffer, offset);
|
715 | return this.transport.send(0xf0, 0x0a, 0x00, 0x00, buffer).then(response => {
|
716 | const r = response.slice(1, 1 + 32).toString("hex");
|
717 | const s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
|
718 | return {
|
719 | r,
|
720 | s
|
721 | };
|
722 | });
|
723 | }
|
724 | |
725 |
|
726 |
|
727 |
|
728 |
|
729 |
|
730 |
|
731 |
|
732 |
|
733 |
|
734 | eth2GetPublicKey(path, boolDisplay) {
|
735 | let paths = splitPath(path);
|
736 | let buffer = Buffer.alloc(1 + paths.length * 4);
|
737 | buffer[0] = paths.length;
|
738 | paths.forEach((element, index) => {
|
739 | buffer.writeUInt32BE(element, 1 + 4 * index);
|
740 | });
|
741 | return this.transport.send(0xe0, 0x0e, boolDisplay ? 0x01 : 0x00, 0x00, buffer).then(response => {
|
742 | let result = {};
|
743 | result.publicKey = response.slice(0, -2).toString("hex");
|
744 | return result;
|
745 | });
|
746 | }
|
747 | |
748 |
|
749 |
|
750 |
|
751 |
|
752 |
|
753 |
|
754 |
|
755 |
|
756 |
|
757 | eth2SetWithdrawalIndex(withdrawalIndex) {
|
758 | let buffer = Buffer.alloc(4, 0);
|
759 | buffer.writeUInt32BE(withdrawalIndex, 0);
|
760 | return this.transport.send(0xe0, 0x10, 0x00, 0x00, buffer).then(() => true, e => {
|
761 | if (e && e.statusCode === 0x6d00) {
|
762 |
|
763 | return false;
|
764 | }
|
765 |
|
766 | throw e;
|
767 | });
|
768 | }
|
769 |
|
770 | }
|
771 |
|
\ | No newline at end of file |