UNPKG

53.2 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 return new (P || (P = Promise))(function (resolve, reject) {
5 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 step((generator = generator.apply(thisArg, _arguments || [])).next());
9 });
10};
11var __generator = (this && this.__generator) || function (thisArg, body) {
12 var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13 return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14 function verb(n) { return function (v) { return step([n, v]); }; }
15 function step(op) {
16 if (f) throw new TypeError("Generator is already executing.");
17 while (_) try {
18 if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19 if (y = 0, t) op = [op[0] & 2, t.value];
20 switch (op[0]) {
21 case 0: case 1: t = op; break;
22 case 4: _.label++; return { value: op[1], done: false };
23 case 5: _.label++; y = op[1]; op = [0]; continue;
24 case 7: op = _.ops.pop(); _.trys.pop(); continue;
25 default:
26 if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27 if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28 if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29 if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30 if (t[2]) _.ops.pop();
31 _.trys.pop(); continue;
32 }
33 op = body.call(thisArg, _);
34 } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35 if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36 }
37};
38var __values = (this && this.__values) || function(o) {
39 var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
40 if (m) return m.call(o);
41 if (o && typeof o.length === "number") return {
42 next: function () {
43 if (o && i >= o.length) o = void 0;
44 return { value: o && o[i++], done: !o };
45 }
46 };
47 throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
48};
49var __importDefault = (this && this.__importDefault) || function (mod) {
50 return (mod && mod.__esModule) ? mod : { "default": mod };
51};
52exports.__esModule = true;
53exports.getFiltersForMessage = exports.isEIP712Message = exports.ledgerService = void 0;
54var utils_1 = require("./utils");
55var ledger_1 = __importDefault(require("./services/ledger"));
56exports.ledgerService = ledger_1["default"];
57var errors_1 = require("./errors");
58var EIP712_1 = require("./modules/EIP712");
59exports.isEIP712Message = EIP712_1.isEIP712Message;
60exports.getFiltersForMessage = EIP712_1.getFiltersForMessage;
61var starkQuantizationTypeMap = {
62 eth: 1,
63 erc20: 2,
64 erc721: 3,
65 erc20mintable: 4,
66 erc721mintable: 5
67};
68var remapTransactionRelatedErrors = function (e) {
69 if (e && e.statusCode === 0x6a80) {
70 return new errors_1.EthAppPleaseEnableContractData("Please enable Blind signing or Contract data in the Ethereum app Settings");
71 }
72 return e;
73};
74/**
75 * Ethereum API
76 *
77 * @example
78 * import Eth from "@ledgerhq/hw-app-eth";
79 * const eth = new Eth(transport)
80 */
81var Eth = /** @class */ (function () {
82 function Eth(transport, scrambleKey, loadConfig) {
83 if (scrambleKey === void 0) { scrambleKey = "w0w"; }
84 if (loadConfig === void 0) { loadConfig = {}; }
85 this.transport = transport;
86 this.loadConfig = loadConfig;
87 transport.decorateAppAPIMethods(this, [
88 "getAddress",
89 "provideERC20TokenInformation",
90 "signTransaction",
91 "signPersonalMessage",
92 "getAppConfiguration",
93 "signEIP712Message",
94 "signEIP712HashedMessage",
95 "starkGetPublicKey",
96 "starkSignOrder",
97 "starkSignOrder_v2",
98 "starkSignTransfer",
99 "starkSignTransfer_v2",
100 "starkProvideQuantum",
101 "starkProvideQuantum_v2",
102 "starkUnsafeSign",
103 "eth2GetPublicKey",
104 "eth2SetWithdrawalIndex",
105 "setExternalPlugin",
106 "setPlugin",
107 "getEIP1024PublicEncryptionKey",
108 "getEIP1024SharedSecret",
109 ], scrambleKey);
110 }
111 Eth.prototype.setLoadConfig = function (loadConfig) {
112 this.loadConfig = loadConfig;
113 };
114 /**
115 * get Ethereum address for a given BIP 32 path.
116 * @param path a path in BIP 32 format
117 * @option boolDisplay optionally enable or not the display
118 * @option boolChaincode optionally enable or not the chaincode request
119 * @return an object with a publicKey, address and (optionally) chainCode
120 * @example
121 * eth.getAddress("44'/60'/0'/0/0").then(o => o.address)
122 */
123 Eth.prototype.getAddress = function (path, boolDisplay, boolChaincode) {
124 var paths = (0, utils_1.splitPath)(path);
125 var buffer = Buffer.alloc(1 + paths.length * 4);
126 buffer[0] = paths.length;
127 paths.forEach(function (element, index) {
128 buffer.writeUInt32BE(element, 1 + 4 * index);
129 });
130 return this.transport
131 .send(0xe0, 0x02, boolDisplay ? 0x01 : 0x00, boolChaincode ? 0x01 : 0x00, buffer)
132 .then(function (response) {
133 var publicKeyLength = response[0];
134 var addressLength = response[1 + publicKeyLength];
135 return {
136 publicKey: response.slice(1, 1 + publicKeyLength).toString("hex"),
137 address: "0x" +
138 response
139 .slice(1 + publicKeyLength + 1, 1 + publicKeyLength + 1 + addressLength)
140 .toString("ascii"),
141 chainCode: boolChaincode
142 ? response
143 .slice(1 + publicKeyLength + 1 + addressLength, 1 + publicKeyLength + 1 + addressLength + 32)
144 .toString("hex")
145 : undefined
146 };
147 });
148 };
149 /**
150 * You can sign a transaction and retrieve v, r, s given the raw transaction and the BIP 32 path of the account to sign.
151 *
152 * @param path: the BIP32 path to sign the transaction on
153 * @param rawTxHex: the raw ethereum transaction in hexadecimal to sign
154 * @param resolution: resolution is an object with all "resolved" metadata necessary to allow the device to clear sign information. This includes: ERC20 token information, plugins, contracts, NFT signatures,... You must explicitly provide something to avoid having a warning. By default, you can use Ledger's service or your own resolution service. See services/types.js for the contract. Setting the value to "null" will fallback everything to blind signing but will still allow the device to sign the transaction.
155 * @example
156 import { ledgerService } from "@ledgerhq/hw-app-eth"
157 const tx = "e8018504e3b292008252089428ee52a8f3d6e5d15f8b131996950d7f296c7952872bd72a2487400080"; // raw tx to sign
158 const resolution = await ledgerService.resolveTransaction(tx);
159 const result = eth.signTransaction("44'/60'/0'/0/0", tx, resolution);
160 console.log(result);
161 */
162 Eth.prototype.signTransaction = function (path, rawTxHex, resolution) {
163 return __awaiter(this, void 0, void 0, function () {
164 var _a, _b, plugin, e_1_1, _c, _d, _e, payload, signature, e_2_1, _f, _g, nft, e_3_1, _h, _j, data, e_4_1, rawTx, _k, vrsOffset, txType, chainId, chainIdTruncated, paths, response, offset, _loop_1, this_1, response_byte, v, oneByteChainId, ecc_parity, r, s;
165 var e_1, _l, e_2, _m, e_3, _o, e_4, _p;
166 return __generator(this, function (_q) {
167 switch (_q.label) {
168 case 0:
169 if (!(resolution === undefined)) return [3 /*break*/, 2];
170 console.warn("hw-app-eth: signTransaction(path, rawTxHex, resolution): " +
171 "please provide the 'resolution' parameter. " +
172 "See https://github.com/LedgerHQ/ledgerjs/blob/master/packages/hw-app-eth/README.md " +
173 "– the previous signature is deprecated and providing the 3rd 'resolution' parameter explicitly will become mandatory so you have the control on the resolution and the fallback mecanism (e.g. fallback to blind signing or not)." +
174 "// Possible solution:\n" +
175 " + import { ledgerService } from '@ledgerhq/hw-app-eth';\n" +
176 " + const resolution = await ledgerService.resolveTransaction(rawTxHex);");
177 return [4 /*yield*/, ledger_1["default"]
178 .resolveTransaction(rawTxHex, this.loadConfig, {
179 externalPlugins: true,
180 erc20: true
181 })["catch"](function (e) {
182 console.warn("an error occurred in resolveTransaction => fallback to blind signing: " +
183 String(e));
184 return null;
185 })];
186 case 1:
187 resolution = _q.sent();
188 _q.label = 2;
189 case 2:
190 if (!resolution) return [3 /*break*/, 31];
191 _q.label = 3;
192 case 3:
193 _q.trys.push([3, 8, 9, 10]);
194 _a = __values(resolution.plugin), _b = _a.next();
195 _q.label = 4;
196 case 4:
197 if (!!_b.done) return [3 /*break*/, 7];
198 plugin = _b.value;
199 return [4 /*yield*/, setPlugin(this.transport, plugin)];
200 case 5:
201 _q.sent();
202 _q.label = 6;
203 case 6:
204 _b = _a.next();
205 return [3 /*break*/, 4];
206 case 7: return [3 /*break*/, 10];
207 case 8:
208 e_1_1 = _q.sent();
209 e_1 = { error: e_1_1 };
210 return [3 /*break*/, 10];
211 case 9:
212 try {
213 if (_b && !_b.done && (_l = _a["return"])) _l.call(_a);
214 }
215 finally { if (e_1) throw e_1.error; }
216 return [7 /*endfinally*/];
217 case 10:
218 _q.trys.push([10, 15, 16, 17]);
219 _c = __values(resolution.externalPlugin), _d = _c.next();
220 _q.label = 11;
221 case 11:
222 if (!!_d.done) return [3 /*break*/, 14];
223 _e = _d.value, payload = _e.payload, signature = _e.signature;
224 return [4 /*yield*/, setExternalPlugin(this.transport, payload, signature)];
225 case 12:
226 _q.sent();
227 _q.label = 13;
228 case 13:
229 _d = _c.next();
230 return [3 /*break*/, 11];
231 case 14: return [3 /*break*/, 17];
232 case 15:
233 e_2_1 = _q.sent();
234 e_2 = { error: e_2_1 };
235 return [3 /*break*/, 17];
236 case 16:
237 try {
238 if (_d && !_d.done && (_m = _c["return"])) _m.call(_c);
239 }
240 finally { if (e_2) throw e_2.error; }
241 return [7 /*endfinally*/];
242 case 17:
243 _q.trys.push([17, 22, 23, 24]);
244 _f = __values(resolution.nfts), _g = _f.next();
245 _q.label = 18;
246 case 18:
247 if (!!_g.done) return [3 /*break*/, 21];
248 nft = _g.value;
249 return [4 /*yield*/, provideNFTInformation(this.transport, Buffer.from(nft, "hex"))];
250 case 19:
251 _q.sent();
252 _q.label = 20;
253 case 20:
254 _g = _f.next();
255 return [3 /*break*/, 18];
256 case 21: return [3 /*break*/, 24];
257 case 22:
258 e_3_1 = _q.sent();
259 e_3 = { error: e_3_1 };
260 return [3 /*break*/, 24];
261 case 23:
262 try {
263 if (_g && !_g.done && (_o = _f["return"])) _o.call(_f);
264 }
265 finally { if (e_3) throw e_3.error; }
266 return [7 /*endfinally*/];
267 case 24:
268 _q.trys.push([24, 29, 30, 31]);
269 _h = __values(resolution.erc20Tokens), _j = _h.next();
270 _q.label = 25;
271 case 25:
272 if (!!_j.done) return [3 /*break*/, 28];
273 data = _j.value;
274 return [4 /*yield*/, provideERC20TokenInformation(this.transport, Buffer.from(data, "hex"))];
275 case 26:
276 _q.sent();
277 _q.label = 27;
278 case 27:
279 _j = _h.next();
280 return [3 /*break*/, 25];
281 case 28: return [3 /*break*/, 31];
282 case 29:
283 e_4_1 = _q.sent();
284 e_4 = { error: e_4_1 };
285 return [3 /*break*/, 31];
286 case 30:
287 try {
288 if (_j && !_j.done && (_p = _h["return"])) _p.call(_h);
289 }
290 finally { if (e_4) throw e_4.error; }
291 return [7 /*endfinally*/];
292 case 31:
293 rawTx = Buffer.from(rawTxHex, "hex");
294 _k = (0, utils_1.decodeTxInfo)(rawTx), vrsOffset = _k.vrsOffset, txType = _k.txType, chainId = _k.chainId, chainIdTruncated = _k.chainIdTruncated;
295 paths = (0, utils_1.splitPath)(path);
296 offset = 0;
297 _loop_1 = function () {
298 var first, maxChunkSize, chunkSize, buffer;
299 return __generator(this, function (_r) {
300 switch (_r.label) {
301 case 0:
302 first = offset === 0;
303 maxChunkSize = first ? 150 - 1 - paths.length * 4 : 150;
304 chunkSize = offset + maxChunkSize > rawTx.length
305 ? rawTx.length - offset
306 : maxChunkSize;
307 if (vrsOffset != 0 && offset + chunkSize >= vrsOffset) {
308 // Make sure that the chunk doesn't end right on the EIP 155 marker if set
309 chunkSize = rawTx.length - offset;
310 }
311 buffer = Buffer.alloc(first ? 1 + paths.length * 4 + chunkSize : chunkSize);
312 if (first) {
313 buffer[0] = paths.length;
314 paths.forEach(function (element, index) {
315 buffer.writeUInt32BE(element, 1 + 4 * index);
316 });
317 rawTx.copy(buffer, 1 + 4 * paths.length, offset, offset + chunkSize);
318 }
319 else {
320 rawTx.copy(buffer, 0, offset, offset + chunkSize);
321 }
322 return [4 /*yield*/, this_1.transport
323 .send(0xe0, 0x04, first ? 0x00 : 0x80, 0x00, buffer)["catch"](function (e) {
324 throw remapTransactionRelatedErrors(e);
325 })];
326 case 1:
327 response = _r.sent();
328 offset += chunkSize;
329 return [2 /*return*/];
330 }
331 });
332 };
333 this_1 = this;
334 _q.label = 32;
335 case 32:
336 if (!(offset !== rawTx.length)) return [3 /*break*/, 34];
337 return [5 /*yield**/, _loop_1()];
338 case 33:
339 _q.sent();
340 return [3 /*break*/, 32];
341 case 34:
342 response_byte = response[0];
343 v = "";
344 if (chainId.times(2).plus(35).plus(1).isGreaterThan(255)) {
345 oneByteChainId = (chainIdTruncated * 2 + 35) % 256;
346 ecc_parity = Math.abs(response_byte - oneByteChainId);
347 if (txType != null) {
348 // For EIP2930 and EIP1559 tx, v is simply the parity.
349 v = ecc_parity % 2 == 1 ? "00" : "01";
350 }
351 else {
352 // Legacy type transaction with a big chain ID
353 v = chainId.times(2).plus(35).plus(ecc_parity).toString(16);
354 }
355 }
356 else {
357 v = response_byte.toString(16);
358 }
359 // Make sure v has is prefixed with a 0 if its length is odd ("1" -> "01").
360 if (v.length % 2 == 1) {
361 v = "0" + v;
362 }
363 r = response.slice(1, 1 + 32).toString("hex");
364 s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
365 return [2 /*return*/, { v: v, r: r, s: s }];
366 }
367 });
368 });
369 };
370 /**
371 */
372 Eth.prototype.getAppConfiguration = function () {
373 return this.transport.send(0xe0, 0x06, 0x00, 0x00).then(function (response) {
374 return {
375 arbitraryDataEnabled: response[0] & 0x01,
376 erc20ProvisioningNecessary: response[0] & 0x02,
377 starkEnabled: response[0] & 0x04,
378 starkv2Supported: response[0] & 0x08,
379 version: "" + response[1] + "." + response[2] + "." + response[3]
380 };
381 });
382 };
383 /**
384 * You can sign a message according to eth_sign RPC call and retrieve v, r, s given the message and the BIP 32 path of the account to sign.
385 * @example
386 eth.signPersonalMessage("44'/60'/0'/0/0", Buffer.from("test").toString("hex")).then(result => {
387 var v = result['v'] - 27;
388 v = v.toString(16);
389 if (v.length < 2) {
390 v = "0" + v;
391 }
392 console.log("Signature 0x" + result['r'] + result['s'] + v);
393 })
394 */
395 Eth.prototype.signPersonalMessage = function (path, messageHex) {
396 return __awaiter(this, void 0, void 0, function () {
397 var paths, offset, message, response, _loop_2, this_2, v, r, s;
398 return __generator(this, function (_a) {
399 switch (_a.label) {
400 case 0:
401 paths = (0, utils_1.splitPath)(path);
402 offset = 0;
403 message = Buffer.from(messageHex, "hex");
404 _loop_2 = function () {
405 var maxChunkSize, chunkSize, buffer;
406 return __generator(this, function (_b) {
407 switch (_b.label) {
408 case 0:
409 maxChunkSize = offset === 0 ? 150 - 1 - paths.length * 4 - 4 : 150;
410 chunkSize = offset + maxChunkSize > message.length
411 ? message.length - offset
412 : maxChunkSize;
413 buffer = Buffer.alloc(offset === 0 ? 1 + paths.length * 4 + 4 + chunkSize : chunkSize);
414 if (offset === 0) {
415 buffer[0] = paths.length;
416 paths.forEach(function (element, index) {
417 buffer.writeUInt32BE(element, 1 + 4 * index);
418 });
419 buffer.writeUInt32BE(message.length, 1 + 4 * paths.length);
420 message.copy(buffer, 1 + 4 * paths.length + 4, offset, offset + chunkSize);
421 }
422 else {
423 message.copy(buffer, 0, offset, offset + chunkSize);
424 }
425 return [4 /*yield*/, this_2.transport.send(0xe0, 0x08, offset === 0 ? 0x00 : 0x80, 0x00, buffer)];
426 case 1:
427 response = _b.sent();
428 offset += chunkSize;
429 return [2 /*return*/];
430 }
431 });
432 };
433 this_2 = this;
434 _a.label = 1;
435 case 1:
436 if (!(offset !== message.length)) return [3 /*break*/, 3];
437 return [5 /*yield**/, _loop_2()];
438 case 2:
439 _a.sent();
440 return [3 /*break*/, 1];
441 case 3:
442 v = response[0];
443 r = response.slice(1, 1 + 32).toString("hex");
444 s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
445 return [2 /*return*/, { v: v, r: r, s: s }];
446 }
447 });
448 });
449 };
450 /**
451 * Sign a prepared message following web3.eth.signTypedData specification. The host computes the domain separator and hashStruct(message)
452 * @example
453 eth.signEIP712HashedMessage("44'/60'/0'/0/0", Buffer.from("0101010101010101010101010101010101010101010101010101010101010101").toString("hex"), Buffer.from("0202020202020202020202020202020202020202020202020202020202020202").toString("hex")).then(result => {
454 var v = result['v'] - 27;
455 v = v.toString(16);
456 if (v.length < 2) {
457 v = "0" + v;
458 }
459 console.log("Signature 0x" + result['r'] + result['s'] + v);
460 })
461 */
462 Eth.prototype.signEIP712HashedMessage = function (path, domainSeparatorHex, hashStructMessageHex) {
463 return (0, EIP712_1.signEIP712HashedMessage)(this.transport, path, domainSeparatorHex, hashStructMessageHex);
464 };
465 /**
466 * Sign an EIP-721 formatted message following the specification here:
467 * https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/ethapp.asc#sign-eth-eip-712
468 * ⚠️ This method is not compatible with nano S (LNS). Make sure to use a try/catch to fallback on the signEIP712HashedMessage method ⚠️
469 @example
470 eth.signEIP721Message("44'/60'/0'/0/0", {
471 domain: {
472 chainId: 69,
473 name: "Da Domain",
474 verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
475 version: "1"
476 },
477 types: {
478 "EIP712Domain": [
479 { name: "name", type: "string" },
480 { name: "version", type: "string" },
481 { name: "chainId", type: "uint256" },
482 { name: "verifyingContract", type: "address" }
483 ],
484 "Test": [
485 { name: "contents", type: "string" }
486 ]
487 },
488 primaryType: "Test",
489 message: {contents: "Hello, Bob!"},
490 })
491 *
492 * @param {String} path derivationPath
493 * @param {Object} jsonMessage message to sign
494 * @param {Boolean} fullImplem use the legacy implementation
495 * @returns {Promise}
496 */
497 Eth.prototype.signEIP712Message = function (path, jsonMessage, fullImplem) {
498 if (fullImplem === void 0) { fullImplem = false; }
499 return __awaiter(this, void 0, void 0, function () {
500 return __generator(this, function (_a) {
501 return [2 /*return*/, (0, EIP712_1.signEIP712Message)(this.transport, path, jsonMessage, fullImplem, this.loadConfig)];
502 });
503 });
504 };
505 /**
506 * get Stark public key for a given BIP 32 path.
507 * @param path a path in BIP 32 format
508 * @option boolDisplay optionally enable or not the display
509 * @return the Stark public key
510 */
511 Eth.prototype.starkGetPublicKey = function (path, boolDisplay) {
512 var paths = (0, utils_1.splitPath)(path);
513 var buffer = Buffer.alloc(1 + paths.length * 4);
514 buffer[0] = paths.length;
515 paths.forEach(function (element, index) {
516 buffer.writeUInt32BE(element, 1 + 4 * index);
517 });
518 return this.transport
519 .send(0xf0, 0x02, boolDisplay ? 0x01 : 0x00, 0x00, buffer)
520 .then(function (response) {
521 return response.slice(0, response.length - 2);
522 });
523 };
524 /**
525 * sign a Stark order
526 * @param path a path in BIP 32 format
527 * @option sourceTokenAddress contract address of the source token (not present for ETH)
528 * @param sourceQuantization quantization used for the source token
529 * @option destinationTokenAddress contract address of the destination token (not present for ETH)
530 * @param destinationQuantization quantization used for the destination token
531 * @param sourceVault ID of the source vault
532 * @param destinationVault ID of the destination vault
533 * @param amountSell amount to sell
534 * @param amountBuy amount to buy
535 * @param nonce transaction nonce
536 * @param timestamp transaction validity timestamp
537 * @return the signature
538 */
539 Eth.prototype.starkSignOrder = function (path, sourceTokenAddress, sourceQuantization, destinationTokenAddress, destinationQuantization, sourceVault, destinationVault, amountSell, amountBuy, nonce, timestamp) {
540 var sourceTokenAddressHex = (0, utils_1.maybeHexBuffer)(sourceTokenAddress);
541 var destinationTokenAddressHex = (0, utils_1.maybeHexBuffer)(destinationTokenAddress);
542 var paths = (0, utils_1.splitPath)(path);
543 var buffer = Buffer.alloc(1 + paths.length * 4 + 20 + 32 + 20 + 32 + 4 + 4 + 8 + 8 + 4 + 4, 0);
544 var offset = 0;
545 buffer[0] = paths.length;
546 paths.forEach(function (element, index) {
547 buffer.writeUInt32BE(element, 1 + 4 * index);
548 });
549 offset = 1 + 4 * paths.length;
550 if (sourceTokenAddressHex) {
551 sourceTokenAddressHex.copy(buffer, offset);
552 }
553 offset += 20;
554 Buffer.from(sourceQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
555 offset += 32;
556 if (destinationTokenAddressHex) {
557 destinationTokenAddressHex.copy(buffer, offset);
558 }
559 offset += 20;
560 Buffer.from(destinationQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
561 offset += 32;
562 buffer.writeUInt32BE(sourceVault, offset);
563 offset += 4;
564 buffer.writeUInt32BE(destinationVault, offset);
565 offset += 4;
566 Buffer.from(amountSell.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
567 offset += 8;
568 Buffer.from(amountBuy.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
569 offset += 8;
570 buffer.writeUInt32BE(nonce, offset);
571 offset += 4;
572 buffer.writeUInt32BE(timestamp, offset);
573 return this.transport
574 .send(0xf0, 0x04, 0x01, 0x00, buffer)
575 .then(function (response) {
576 var r = response.slice(1, 1 + 32).toString("hex");
577 var s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
578 return {
579 r: r,
580 s: s
581 };
582 });
583 };
584 /**
585 * sign a Stark order using the Starkex V2 protocol
586 * @param path a path in BIP 32 format
587 * @option sourceTokenAddress contract address of the source token (not present for ETH)
588 * @param sourceQuantizationType quantization type used for the source token
589 * @option sourceQuantization quantization used for the source token (not present for erc 721 or mintable erc 721)
590 * @option sourceMintableBlobOrTokenId mintable blob (mintable erc 20 / mintable erc 721) or token id (erc 721) associated to the source token
591 * @option destinationTokenAddress contract address of the destination token (not present for ETH)
592 * @param destinationQuantizationType quantization type used for the destination token
593 * @option destinationQuantization quantization used for the destination token (not present for erc 721 or mintable erc 721)
594 * @option destinationMintableBlobOrTokenId mintable blob (mintable erc 20 / mintable erc 721) or token id (erc 721) associated to the destination token
595 * @param sourceVault ID of the source vault
596 * @param destinationVault ID of the destination vault
597 * @param amountSell amount to sell
598 * @param amountBuy amount to buy
599 * @param nonce transaction nonce
600 * @param timestamp transaction validity timestamp
601 * @return the signature
602 */
603 Eth.prototype.starkSignOrder_v2 = function (path, sourceTokenAddress, sourceQuantizationType, sourceQuantization, sourceMintableBlobOrTokenId, destinationTokenAddress, destinationQuantizationType, destinationQuantization, destinationMintableBlobOrTokenId, sourceVault, destinationVault, amountSell, amountBuy, nonce, timestamp) {
604 var sourceTokenAddressHex = (0, utils_1.maybeHexBuffer)(sourceTokenAddress);
605 var destinationTokenAddressHex = (0, utils_1.maybeHexBuffer)(destinationTokenAddress);
606 if (!(sourceQuantizationType in starkQuantizationTypeMap)) {
607 throw new Error("eth.starkSignOrderv2 invalid source quantization type=" +
608 sourceQuantizationType);
609 }
610 if (!(destinationQuantizationType in starkQuantizationTypeMap)) {
611 throw new Error("eth.starkSignOrderv2 invalid destination quantization type=" +
612 destinationQuantizationType);
613 }
614 var paths = (0, utils_1.splitPath)(path);
615 var buffer = Buffer.alloc(1 +
616 paths.length * 4 +
617 1 +
618 20 +
619 32 +
620 32 +
621 1 +
622 20 +
623 32 +
624 32 +
625 4 +
626 4 +
627 8 +
628 8 +
629 4 +
630 4, 0);
631 var offset = 0;
632 buffer[0] = paths.length;
633 paths.forEach(function (element, index) {
634 buffer.writeUInt32BE(element, 1 + 4 * index);
635 });
636 offset = 1 + 4 * paths.length;
637 buffer[offset] = starkQuantizationTypeMap[sourceQuantizationType];
638 offset++;
639 if (sourceTokenAddressHex) {
640 sourceTokenAddressHex.copy(buffer, offset);
641 }
642 offset += 20;
643 if (sourceQuantization) {
644 Buffer.from(sourceQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
645 }
646 offset += 32;
647 if (sourceMintableBlobOrTokenId) {
648 Buffer.from(sourceMintableBlobOrTokenId.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
649 }
650 offset += 32;
651 buffer[offset] = starkQuantizationTypeMap[destinationQuantizationType];
652 offset++;
653 if (destinationTokenAddressHex) {
654 destinationTokenAddressHex.copy(buffer, offset);
655 }
656 offset += 20;
657 if (destinationQuantization) {
658 Buffer.from(destinationQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
659 }
660 offset += 32;
661 if (destinationMintableBlobOrTokenId) {
662 Buffer.from(destinationMintableBlobOrTokenId.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
663 }
664 offset += 32;
665 buffer.writeUInt32BE(sourceVault, offset);
666 offset += 4;
667 buffer.writeUInt32BE(destinationVault, offset);
668 offset += 4;
669 Buffer.from(amountSell.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
670 offset += 8;
671 Buffer.from(amountBuy.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
672 offset += 8;
673 buffer.writeUInt32BE(nonce, offset);
674 offset += 4;
675 buffer.writeUInt32BE(timestamp, offset);
676 return this.transport
677 .send(0xf0, 0x04, 0x03, 0x00, buffer)
678 .then(function (response) {
679 var r = response.slice(1, 1 + 32).toString("hex");
680 var s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
681 return {
682 r: r,
683 s: s
684 };
685 });
686 };
687 /**
688 * sign a Stark transfer
689 * @param path a path in BIP 32 format
690 * @option transferTokenAddress contract address of the token to be transferred (not present for ETH)
691 * @param transferQuantization quantization used for the token to be transferred
692 * @param targetPublicKey target Stark public key
693 * @param sourceVault ID of the source vault
694 * @param destinationVault ID of the destination vault
695 * @param amountTransfer amount to transfer
696 * @param nonce transaction nonce
697 * @param timestamp transaction validity timestamp
698 * @return the signature
699 */
700 Eth.prototype.starkSignTransfer = function (path, transferTokenAddress, transferQuantization, targetPublicKey, sourceVault, destinationVault, amountTransfer, nonce, timestamp) {
701 var transferTokenAddressHex = (0, utils_1.maybeHexBuffer)(transferTokenAddress);
702 var targetPublicKeyHex = (0, utils_1.hexBuffer)(targetPublicKey);
703 var paths = (0, utils_1.splitPath)(path);
704 var buffer = Buffer.alloc(1 + paths.length * 4 + 20 + 32 + 32 + 4 + 4 + 8 + 4 + 4, 0);
705 var offset = 0;
706 buffer[0] = paths.length;
707 paths.forEach(function (element, index) {
708 buffer.writeUInt32BE(element, 1 + 4 * index);
709 });
710 offset = 1 + 4 * paths.length;
711 if (transferTokenAddressHex) {
712 transferTokenAddressHex.copy(buffer, offset);
713 }
714 offset += 20;
715 Buffer.from(transferQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
716 offset += 32;
717 targetPublicKeyHex.copy(buffer, offset);
718 offset += 32;
719 buffer.writeUInt32BE(sourceVault, offset);
720 offset += 4;
721 buffer.writeUInt32BE(destinationVault, offset);
722 offset += 4;
723 Buffer.from(amountTransfer.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
724 offset += 8;
725 buffer.writeUInt32BE(nonce, offset);
726 offset += 4;
727 buffer.writeUInt32BE(timestamp, offset);
728 return this.transport
729 .send(0xf0, 0x04, 0x02, 0x00, buffer)
730 .then(function (response) {
731 var r = response.slice(1, 1 + 32).toString("hex");
732 var s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
733 return {
734 r: r,
735 s: s
736 };
737 });
738 };
739 /**
740 * sign a Stark transfer or conditional transfer using the Starkex V2 protocol
741 * @param path a path in BIP 32 format
742 * @option transferTokenAddress contract address of the token to be transferred (not present for ETH)
743 * @param transferQuantizationType quantization type used for the token to be transferred
744 * @option transferQuantization quantization used for the token to be transferred (not present for erc 721 or mintable erc 721)
745 * @option transferMintableBlobOrTokenId mintable blob (mintable erc 20 / mintable erc 721) or token id (erc 721) associated to the token to be transferred
746 * @param targetPublicKey target Stark public key
747 * @param sourceVault ID of the source vault
748 * @param destinationVault ID of the destination vault
749 * @param amountTransfer amount to transfer
750 * @param nonce transaction nonce
751 * @param timestamp transaction validity timestamp
752 * @option conditionalTransferAddress onchain address of the condition for a conditional transfer
753 * @option conditionalTransferFact fact associated to the condition for a conditional transfer
754 * @return the signature
755 */
756 Eth.prototype.starkSignTransfer_v2 = function (path, transferTokenAddress, transferQuantizationType, transferQuantization, transferMintableBlobOrTokenId, targetPublicKey, sourceVault, destinationVault, amountTransfer, nonce, timestamp, conditionalTransferAddress, conditionalTransferFact) {
757 var transferTokenAddressHex = (0, utils_1.maybeHexBuffer)(transferTokenAddress);
758 var targetPublicKeyHex = (0, utils_1.hexBuffer)(targetPublicKey);
759 var conditionalTransferAddressHex = (0, utils_1.maybeHexBuffer)(conditionalTransferAddress);
760 if (!(transferQuantizationType in starkQuantizationTypeMap)) {
761 throw new Error("eth.starkSignTransferv2 invalid quantization type=" +
762 transferQuantizationType);
763 }
764 var paths = (0, utils_1.splitPath)(path);
765 var buffer = Buffer.alloc(1 +
766 paths.length * 4 +
767 1 +
768 20 +
769 32 +
770 32 +
771 32 +
772 4 +
773 4 +
774 8 +
775 4 +
776 4 +
777 (conditionalTransferAddressHex ? 32 + 20 : 0), 0);
778 var offset = 0;
779 buffer[0] = paths.length;
780 paths.forEach(function (element, index) {
781 buffer.writeUInt32BE(element, 1 + 4 * index);
782 });
783 offset = 1 + 4 * paths.length;
784 buffer[offset] = starkQuantizationTypeMap[transferQuantizationType];
785 offset++;
786 if (transferTokenAddressHex) {
787 transferTokenAddressHex.copy(buffer, offset);
788 }
789 offset += 20;
790 if (transferQuantization) {
791 Buffer.from(transferQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
792 }
793 offset += 32;
794 if (transferMintableBlobOrTokenId) {
795 Buffer.from(transferMintableBlobOrTokenId.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
796 }
797 offset += 32;
798 targetPublicKeyHex.copy(buffer, offset);
799 offset += 32;
800 buffer.writeUInt32BE(sourceVault, offset);
801 offset += 4;
802 buffer.writeUInt32BE(destinationVault, offset);
803 offset += 4;
804 Buffer.from(amountTransfer.toString(16).padStart(16, "0"), "hex").copy(buffer, offset);
805 offset += 8;
806 buffer.writeUInt32BE(nonce, offset);
807 offset += 4;
808 buffer.writeUInt32BE(timestamp, offset);
809 if (conditionalTransferAddressHex && conditionalTransferFact) {
810 offset += 4;
811 Buffer.from(conditionalTransferFact.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
812 offset += 32;
813 conditionalTransferAddressHex.copy(buffer, offset);
814 }
815 return this.transport
816 .send(0xf0, 0x04, conditionalTransferAddressHex ? 0x05 : 0x04, 0x00, buffer)
817 .then(function (response) {
818 var r = response.slice(1, 1 + 32).toString("hex");
819 var s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
820 return {
821 r: r,
822 s: s
823 };
824 });
825 };
826 /**
827 * provide quantization information before singing a deposit or withdrawal Stark powered contract call
828 *
829 * It shall be run following a provideERC20TokenInformation call for the given contract
830 *
831 * @param operationContract contract address of the token to be transferred (not present for ETH)
832 * @param operationQuantization quantization used for the token to be transferred
833 */
834 Eth.prototype.starkProvideQuantum = function (operationContract, operationQuantization) {
835 var operationContractHex = (0, utils_1.maybeHexBuffer)(operationContract);
836 var buffer = Buffer.alloc(20 + 32, 0);
837 if (operationContractHex) {
838 operationContractHex.copy(buffer, 0);
839 }
840 Buffer.from(operationQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, 20);
841 return this.transport.send(0xf0, 0x08, 0x00, 0x00, buffer).then(function () { return true; }, function (e) {
842 if (e && e.statusCode === 0x6d00) {
843 // this case happen for ETH application versions not supporting Stark extensions
844 return false;
845 }
846 throw e;
847 });
848 };
849 /**
850 * provide quantization information before singing a deposit or withdrawal Stark powered contract call using the Starkex V2 protocol
851 *
852 * It shall be run following a provideERC20TokenInformation call for the given contract
853 *
854 * @param operationContract contract address of the token to be transferred (not present for ETH)
855 * @param operationQuantizationType quantization type of the token to be transferred
856 * @option operationQuantization quantization used for the token to be transferred (not present for erc 721 or mintable erc 721)
857 * @option operationMintableBlobOrTokenId mintable blob (mintable erc 20 / mintable erc 721) or token id (erc 721) of the token to be transferred
858 */
859 Eth.prototype.starkProvideQuantum_v2 = function (operationContract, operationQuantizationType, operationQuantization, operationMintableBlobOrTokenId) {
860 var operationContractHex = (0, utils_1.maybeHexBuffer)(operationContract);
861 if (!(operationQuantizationType in starkQuantizationTypeMap)) {
862 throw new Error("eth.starkProvideQuantumV2 invalid quantization type=" +
863 operationQuantizationType);
864 }
865 var buffer = Buffer.alloc(20 + 32 + 32, 0);
866 var offset = 0;
867 if (operationContractHex) {
868 operationContractHex.copy(buffer, offset);
869 }
870 offset += 20;
871 if (operationQuantization) {
872 Buffer.from(operationQuantization.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
873 }
874 offset += 32;
875 if (operationMintableBlobOrTokenId) {
876 Buffer.from(operationMintableBlobOrTokenId.toString(16).padStart(64, "0"), "hex").copy(buffer, offset);
877 }
878 return this.transport
879 .send(0xf0, 0x08, starkQuantizationTypeMap[operationQuantizationType], 0x00, buffer)
880 .then(function () { return true; }, function (e) {
881 if (e && e.statusCode === 0x6d00) {
882 // this case happen for ETH application versions not supporting Stark extensions
883 return false;
884 }
885 throw e;
886 });
887 };
888 /**
889 * sign the given hash over the Stark curve
890 * It is intended for speed of execution in case an unknown Stark model is pushed and should be avoided as much as possible.
891 * @param path a path in BIP 32 format
892 * @param hash hexadecimal hash to sign
893 * @return the signature
894 */
895 Eth.prototype.starkUnsafeSign = function (path, hash) {
896 var hashHex = (0, utils_1.hexBuffer)(hash);
897 var paths = (0, utils_1.splitPath)(path);
898 var buffer = Buffer.alloc(1 + paths.length * 4 + 32);
899 var offset = 0;
900 buffer[0] = paths.length;
901 paths.forEach(function (element, index) {
902 buffer.writeUInt32BE(element, 1 + 4 * index);
903 });
904 offset = 1 + 4 * paths.length;
905 hashHex.copy(buffer, offset);
906 return this.transport
907 .send(0xf0, 0x0a, 0x00, 0x00, buffer)
908 .then(function (response) {
909 var r = response.slice(1, 1 + 32).toString("hex");
910 var s = response.slice(1 + 32, 1 + 32 + 32).toString("hex");
911 return {
912 r: r,
913 s: s
914 };
915 });
916 };
917 /**
918 * get an Ethereum 2 BLS-12 381 public key for a given BIP 32 path.
919 * @param path a path in BIP 32 format
920 * @option boolDisplay optionally enable or not the display
921 * @return an object with a publicKey
922 * @example
923 * eth.eth2GetPublicKey("12381/3600/0/0").then(o => o.publicKey)
924 */
925 Eth.prototype.eth2GetPublicKey = function (path, boolDisplay) {
926 var paths = (0, utils_1.splitPath)(path);
927 var buffer = Buffer.alloc(1 + paths.length * 4);
928 buffer[0] = paths.length;
929 paths.forEach(function (element, index) {
930 buffer.writeUInt32BE(element, 1 + 4 * index);
931 });
932 return this.transport
933 .send(0xe0, 0x0e, boolDisplay ? 0x01 : 0x00, 0x00, buffer)
934 .then(function (response) {
935 return {
936 publicKey: response.slice(0, -2).toString("hex")
937 };
938 });
939 };
940 /**
941 * Set the index of a Withdrawal key used as withdrawal credentials in an ETH 2 deposit contract call signature
942 *
943 * It shall be run before the ETH 2 deposit transaction is signed. If not called, the index is set to 0
944 *
945 * @param withdrawalIndex index path in the EIP 2334 path m/12381/3600/withdrawalIndex/0
946 * @return True if the method was executed successfully
947 */
948 Eth.prototype.eth2SetWithdrawalIndex = function (withdrawalIndex) {
949 var buffer = Buffer.alloc(4, 0);
950 buffer.writeUInt32BE(withdrawalIndex, 0);
951 return this.transport.send(0xe0, 0x10, 0x00, 0x00, buffer).then(function () { return true; }, function (e) {
952 if (e && e.statusCode === 0x6d00) {
953 // this case happen for ETH application versions not supporting ETH 2
954 return false;
955 }
956 throw e;
957 });
958 };
959 /**
960 * get a public encryption key on Curve25519 according to EIP 1024
961 * @param path a path in BIP 32 format
962 * @option boolDisplay optionally enable or not the display
963 * @return an object with a publicKey
964 * @example
965 * eth.getEIP1024PublicEncryptionKey("44'/60'/0'/0/0").then(o => o.publicKey)
966 */
967 Eth.prototype.getEIP1024PublicEncryptionKey = function (path, boolDisplay) {
968 var paths = (0, utils_1.splitPath)(path);
969 var buffer = Buffer.alloc(1 + paths.length * 4);
970 buffer[0] = paths.length;
971 paths.forEach(function (element, index) {
972 buffer.writeUInt32BE(element, 1 + 4 * index);
973 });
974 return this.transport
975 .send(0xe0, 0x18, boolDisplay ? 0x01 : 0x00, 0x00, buffer)
976 .then(function (response) {
977 return {
978 publicKey: response.slice(0, -2).toString("hex")
979 };
980 });
981 };
982 /**
983 * get a shared secret on Curve25519 according to EIP 1024
984 * @param path a path in BIP 32 format
985 * @param remotePublicKeyHex remote Curve25519 public key
986 * @option boolDisplay optionally enable or not the display
987 * @return an object with a shared secret
988 * @example
989 * eth.getEIP1024SharedSecret("44'/60'/0'/0/0", "87020e80af6e07a6e4697f091eacadb9e7e6629cb7e5a8a371689a3ed53b3d64").then(o => o.sharedSecret)
990 */
991 Eth.prototype.getEIP1024SharedSecret = function (path, remotePublicKeyHex, boolDisplay) {
992 var paths = (0, utils_1.splitPath)(path);
993 var remotePublicKey = (0, utils_1.hexBuffer)(remotePublicKeyHex);
994 var buffer = Buffer.alloc(1 + paths.length * 4 + 32);
995 var offset = 0;
996 buffer[0] = paths.length;
997 paths.forEach(function (element, index) {
998 buffer.writeUInt32BE(element, 1 + 4 * index);
999 });
1000 offset = 1 + 4 * paths.length;
1001 remotePublicKey.copy(buffer, offset);
1002 return this.transport
1003 .send(0xe0, 0x18, boolDisplay ? 0x01 : 0x00, 0x01, buffer)
1004 .then(function (response) {
1005 return {
1006 sharedSecret: response.slice(0, -2).toString("hex")
1007 };
1008 });
1009 };
1010 Eth.prototype.provideERC20TokenInformation = function (_a) {
1011 var data = _a.data;
1012 return provideERC20TokenInformation(this.transport, data);
1013 };
1014 Eth.prototype.setExternalPlugin = function (pluginName, contractAddress, selector) {
1015 console.warn("hw-app-eth: eth.setExternalPlugin is deprecated. signTransaction solves this for you when providing it in `resolution`.");
1016 return setExternalPlugin(this.transport, pluginName, selector);
1017 };
1018 Eth.prototype.setPlugin = function (data) {
1019 console.warn("hw-app-eth: eth.setPlugin is deprecated. signTransaction solves this for you when providing it in `resolution`.");
1020 return setPlugin(this.transport, data);
1021 };
1022 return Eth;
1023}());
1024exports["default"] = Eth;
1025// internal helpers
1026function provideERC20TokenInformation(transport, data) {
1027 return transport.send(0xe0, 0x0a, 0x00, 0x00, data).then(function () { return true; }, function (e) {
1028 if (e && e.statusCode === 0x6d00) {
1029 // this case happen for older version of ETH app, since older app version had the ERC20 data hardcoded, it's fine to assume it worked.
1030 // we return a flag to know if the call was effective or not
1031 return false;
1032 }
1033 throw e;
1034 });
1035}
1036function provideNFTInformation(transport, data) {
1037 return transport.send(0xe0, 0x14, 0x00, 0x00, data).then(function () { return true; }, function (e) {
1038 if (e && e.statusCode === 0x6d00) {
1039 // older version of ETH app => error because we don't allow blind sign when NFT is explicitly requested to be resolved.
1040 throw new errors_1.EthAppNftNotSupported();
1041 }
1042 throw e;
1043 });
1044}
1045function setExternalPlugin(transport, payload, signature) {
1046 var payloadBuffer = Buffer.from(payload, "hex");
1047 var signatureBuffer = Buffer.from(signature, "hex");
1048 var buffer = Buffer.concat([payloadBuffer, signatureBuffer]);
1049 return transport.send(0xe0, 0x12, 0x00, 0x00, buffer).then(function () { return true; }, function (e) {
1050 if (e && e.statusCode === 0x6a80) {
1051 // this case happen when the plugin name is too short or too long
1052 return false;
1053 }
1054 else if (e && e.statusCode === 0x6984) {
1055 // this case happen when the plugin requested is not installed on the device
1056 return false;
1057 }
1058 else if (e && e.statusCode === 0x6d00) {
1059 // this case happen for older version of ETH app
1060 return false;
1061 }
1062 throw e;
1063 });
1064}
1065function setPlugin(transport, data) {
1066 var buffer = Buffer.from(data, "hex");
1067 return transport.send(0xe0, 0x16, 0x00, 0x00, buffer).then(function () { return true; }, function (e) {
1068 if (e && e.statusCode === 0x6a80) {
1069 // this case happen when the plugin name is too short or too long
1070 return false;
1071 }
1072 else if (e && e.statusCode === 0x6984) {
1073 // this case happen when the plugin requested is not installed on the device
1074 return false;
1075 }
1076 else if (e && e.statusCode === 0x6d00) {
1077 // this case happen for older version of ETH app
1078 return false;
1079 }
1080 throw e;
1081 });
1082}
1083//# sourceMappingURL=Eth.js.map
\No newline at end of file