UNPKG

@ledgerhq/hw-app-multiversx

Version:
170 lines 6.16 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const sdk_core_1 = require("@multiversx/sdk-core"); const bip32_path_1 = __importDefault(require("bip32-path")); const CHUNK_SIZE = 150; const CURVE_MASK = 0x80; const CLA = 0xed; const INS = { GET_VERSION: 0x02, GET_ADDRESS: 0x03, SET_ADDRESS: 0x05, PROVIDE_ESDT_INFO: 0x08, }; const SIGN_HASH_TX_INS = 0x07; const SW_OK = 0x9000; const SW_CANCEL = 0x6986; /** * MultiversX API * * @example * import MultiversX from "@ledgerhq/hw-app-multiversx"; * const multiversx = new MultiversX(transport) */ class MultiversX { transport; constructor(transport, scrambleKey = "eGLD") { this.transport = transport; transport.decorateAppAPIMethods(this, [ "getAddress", "setAddress", "signTransaction", "signMessage", "getAppConfiguration", "provideESDTInfo", ], scrambleKey); } /** * Get MultiversX app configuration. * * @return an object with a contractData, accountIndex, addressIndex, version * @example * const result = await multiversx.getAppConfiguration(); * const { contractData, accountIndex, addressIndex, version } = result; */ async getAppConfiguration() { const response = await this.transport.send(CLA, INS.GET_VERSION, 0x00, 0x00); return { contractData: response[0], accountIndex: response[1], addressIndex: response[2], version: `${response[3]}.${response[4]}.${response[5]}`, }; } serializePath(path) { const buf = Buffer.alloc(8); buf.writeUInt32BE(path[3], 0); buf.writeUInt32BE(path[2], 4); return buf; } /** * Get MultiversX address for a given BIP 32 path. * * @param path a path in BIP 32 format * @param boolDisplay optionally enable or not the display * @return an object with a address * @example * const result = await multiversx.getAddress("44'/508'/0'/0'/0'"); * const { publicKey, address } = result; */ async getAddress(path, boolDisplay) { const bipPath = bip32_path_1.default.fromString(path).toPathArray(); const data = this.serializePath(bipPath); const response = await this.transport.send(CLA, INS.GET_ADDRESS, boolDisplay ? 0x01 : 0x00, 0x00, data, [SW_OK, SW_CANCEL]); const addressLength = response[0]; const address = sdk_core_1.Address.newFromBech32(response.slice(1, 1 + addressLength).toString("ascii")); return { publicKey: address.toHex(), address: address.toBech32(), }; } /** * Set MultiversX address for a given BIP 32 path. * * @param path a path in BIP 32 format * @param display optionally enable or not the display * @return an object with a address * @example * const result = await multiversx.setAddress("44'/508'/0'/0/0"); * result : Buffer; */ async setAddress(path, display) { const bipPath = bip32_path_1.default.fromString(path).toPathArray(); const data = this.serializePath(bipPath); await this.transport.send(CLA, INS.SET_ADDRESS, display ? 0x01 : 0x00, 0x00, data, [ SW_OK, SW_CANCEL, ]); } async signTransaction(path, message) { const { signature } = await this.sign(path, message); if (signature === null) { throw new Error("null signature received"); } return signature.toString("hex"); } async sign(path, message) { const chunks = []; const buffer = Buffer.from(message); for (let i = 0; i < buffer.length; i += CHUNK_SIZE) { let end = i + CHUNK_SIZE; if (i > buffer.length) { end = buffer.length; } chunks.push(buffer.slice(i, end)); } const apdus = []; chunks.forEach((data, index) => { const apdu = { cla: CLA, ins: SIGN_HASH_TX_INS, p1: index === 0 ? 0x00 : CURVE_MASK, p2: CURVE_MASK, data, }; apdus.push(apdu); }); let response = {}; for (const apdu of apdus) { response = await this.transport.send(apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.data); } if (response.length !== 67 || response[0] !== 64) { throw new Error("invalid signature received from ledger device"); } const signature = response.slice(1, response.length - 2).toString("hex"); return { signature }; } serializeESDTInfo(ticker, id, decimals, chainId, signature) { const tickerLengthBuffer = Buffer.from([ticker.length]); const tickerBuffer = Buffer.from(ticker); const idLengthBuffer = Buffer.from([id.length]); const idBuffer = Buffer.from(id); const decimalsBuffer = Buffer.from([decimals]); const chainIdLengthBuffer = Buffer.from([chainId.length]); const chainIdBuffer = Buffer.from(chainId); const signatureBuffer = Buffer.from(signature, "hex"); const infoBuffer = [ tickerLengthBuffer, tickerBuffer, idLengthBuffer, idBuffer, decimalsBuffer, chainIdLengthBuffer, chainIdBuffer, signatureBuffer, ]; return Buffer.concat(infoBuffer); } async provideESDTInfo(ticker, id, decimals, chainId, signature) { if (!ticker || !id || !decimals || !chainId || !signature) { throw new Error("Invalid ESDT token credentials!"); } const data = this.serializeESDTInfo(ticker, id, decimals, chainId, signature); return await this.transport.send(CLA, INS.PROVIDE_ESDT_INFO, 0x00, 0x00, data); } } exports.default = MultiversX; //# sourceMappingURL=MultiversX.js.map