UNPKG

@terra-money/ledger-terra-js

Version:
216 lines 9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LedgerKey = exports.LedgerError = void 0; const terra_js_1 = require("@terra-money/terra.js"); const terra_js_2 = require("@terra-money/terra.js"); const app_1 = __importDefault(require("./app")); const secp256k1_1 = require("secp256k1"); const semver_1 = __importDefault(require("semver")); const LUNA_COIN_TYPE = 330; const INTERACTION_TIMEOUT = 120; const REQUIRED_APP_VERSION = "1.0.0"; class LedgerError extends Error { constructor(message) { super(message); this.name = "LedgerError"; } } exports.LedgerError = LedgerError; class LedgerKey extends terra_js_1.Key { constructor(transport) { super(); this.transport = transport; this.path = [44, LUNA_COIN_TYPE, 0, 0, 0]; this.app = new app_1.default(this.transport); } get accAddress() { if (!this.publicKey) { throw new Error("Ledger is unintialized. Initialize it first."); } return this.publicKey.address(); } static create(transport, index) { return __awaiter(this, void 0, void 0, function* () { if (!transport) { transport = yield createTransport(); } const key = new LedgerKey(transport); if (index != undefined) { key.path[4] = index; } if (transport && typeof transport.on === "function") { transport.on("disconnect", () => { key.transport = null; }); } yield key.initialize().catch(handleConnectError); return key; }); } initialize() { return __awaiter(this, void 0, void 0, function* () { const res = yield this.app.initialize(); const { app_name: appName } = this.app.getInfo(); if (appName !== "Terra") { throw new LedgerError("Open the Terra app in the Ledger"); } const { major, minor, patch } = this.app.getVersion(); const version = `${major}.${minor}.${patch}`; if (appName === "Terra" && semver_1.default.lt(version, REQUIRED_APP_VERSION)) { throw new LedgerError("Outdated version: Update Ledger Terra App to the latest version"); } checkLedgerErrors(res); yield this.loadAccountDetails(); }); } loadAccountDetails() { return __awaiter(this, void 0, void 0, function* () { const res = yield this.app.getAddressAndPubKey(this.path, "terra"); checkLedgerErrors(res); this._accAddress = res.bech32_address; this.publicKey = new terra_js_2.SimplePublicKey(Buffer.from(res.compressed_pk.data).toString("base64")); return this; }); } sign(message) { return __awaiter(this, void 0, void 0, function* () { if (!this.publicKey) { this.loadAccountDetails(); } const res = yield this.app.sign(this.path, message); checkLedgerErrors(res); return Buffer.from((0, secp256k1_1.signatureImport)(Buffer.from(res.signature))); }); } createSignature(_tx) { return __awaiter(this, void 0, void 0, function* () { throw new Error("direct sign mode is not supported"); }); } getAppAddressAndPubKey() { return __awaiter(this, void 0, void 0, function* () { return this.app.getAddressAndPubKey(this.path, 'terra'); }); } getAppInfo() { return this.app.getInfo(); } getAppDeviceInfo() { return __awaiter(this, void 0, void 0, function* () { return this.app.getDeviceInfo(); }); } getAppPublicKey() { return __awaiter(this, void 0, void 0, function* () { return this.app.getPublicKey(this.path); }); } getAppVersion() { return this.app.getVersion(); } showAddressAndPubKey() { return __awaiter(this, void 0, void 0, function* () { return this.app.showAddressAndPubKey(this.path, 'terra'); }); } } exports.LedgerKey = LedgerKey; const handleConnectError = (err) => { const message = err.message.trim(); if (message.startsWith("The device is already open")) { return; } if (err.name === "TransportOpenUserCancelled") { throw new LedgerError("Couldn't find the Ledger. Check the Ledger is plugged in and unlocked."); } if (message.startsWith("No WebUSB interface found for the Ledger device")) { throw new LedgerError(`Couldn't connect to a Ledger device. Use Ledger Live to upgrade the Ledger firmware to version ${REQUIRED_APP_VERSION} or later.`); } if (message.startsWith("Unable to claim interface")) { throw new LedgerError("Couldn't access Ledger device. Is it being used in another tab?"); } if (message.startsWith("Transport not defined")) { throw new LedgerError("Couldn't access Ledger device. Is it being used in another tab?"); } if (message.startsWith("Not supported")) { throw new LedgerError("This browser doesn't support WebUSB yet. Update it to the latest version."); } if (message.startsWith("No device selected")) { throw new LedgerError("Couldn't find the Ledger. Check the Ledger is plugged in and unlocked."); } throw err; }; const checkLedgerErrors = (response) => { if (!response) { return; } const { error_message, device_locked } = response; if (device_locked) { throw new LedgerError("Ledger's screensaver mode is on"); } if (error_message.startsWith("TransportRaceCondition")) { throw new LedgerError("Finish previous action in Ledger"); } else if (error_message.startsWith("DisconnectedDeviceDuringOperation")) { throw new LedgerError("Open the Terra app in the Ledger"); } switch (error_message) { case "U2F: Timeout": throw new LedgerError("Couldn't find a connected and unlocked Ledger device"); case "App does not seem to be open": throw new LedgerError("Open the Terra app in the Ledger"); case "Command not allowed": throw new LedgerError("Transaction rejected"); case "Transaction rejected": throw new LedgerError("User rejected the transaction"); case "Unknown Status Code: 26628": throw new LedgerError("Ledger's screensaver mode is on"); case "Instruction not supported": throw new LedgerError("Check the Ledger is running latest version of Terra"); case "No errors": break; default: throw new LedgerError(error_message); } }; const isWindows = (platform) => platform.indexOf("Win") > -1; const checkBrowser = (userAgent) => { const ua = userAgent.toLowerCase(); const isChrome = /chrome|crios/.test(ua) && !/edge|opr\//.test(ua); const isBrave = isChrome && !window.google; if (!isChrome && !isBrave) { throw new LedgerError("This browser doesn't support Ledger devices"); } return isChrome ? "chrome" : "brave"; }; function createTransport() { return __awaiter(this, void 0, void 0, function* () { let transport; checkBrowser(navigator.userAgent); if (isWindows(navigator.platform)) { if (!navigator.hid) { throw new LedgerError("This browser doesn't have HID enabled. Enable this feature by visiting: chrome://flags/#enable-experimental-web-platform-features"); } const TransportWebHid = require("@ledgerhq/hw-transport-webhid").default; transport = yield TransportWebHid.create(INTERACTION_TIMEOUT * 1000).catch(handleConnectError); } else { const TransportWebUsb = require("@ledgerhq/hw-transport-webusb").default; transport = yield TransportWebUsb.create(INTERACTION_TIMEOUT * 1000).catch(handleConnectError); } return transport; }); } //# sourceMappingURL=key.js.map