UNPKG

@ledgerhq/hw-app-near

Version:
86 lines 3.25 kB
import { PublicKey } from "near-api-js/lib/utils"; import { KeyType } from "near-api-js/lib/utils/key_pair"; import { bip32PathToBytes } from "./utils"; // Based on https://github.com/LedgerHQ/ledger-secure-sdk/blob/master/include/os_io.h#L16 // 255B + CLA + INS + P1 + P2 + Lc const CHUNK_SIZE = 255; const CLA = 0x80; const INS_GET_PUBLIC_KEY = 4; const INS_GET_ADDRESS = 5; const INS_SIGN = 2; const P1_LAST_CHUNK = 0x80; const NETWORK_ID = "W".charCodeAt(0); /** * NEAR API * * @example * import Near from "@ledgerhq/hw-app-near"; * const near = new Near(transport) */ export default class Near { transport; constructor(transport) { this.transport = transport; transport.decorateAppAPIMethods(this, ["getPublicKey", "getAddress", "sign"], "NEAR"); } /** * @param path * @option verify - if true, user must verify if the address is correct on the device * @return an object with a publicKey and address * @example * near.getAddress("44'/397'/0'/0'/0'", true).then(o => o.address) */ async getAddress(path, verify) { const client = await createClient(this.transport); if (verify) { await client.getAddress(path); } const rawPublicKey = await client.getPublicKey(path, false); const publicKey = new PublicKey({ keyType: KeyType.ED25519, data: rawPublicKey, }); return { address: rawPublicKey.toString("hex"), publicKey: publicKey.toString(), }; } /** * @param transaction * @param path * @return a signature to be broadcasted to the chain */ async signTransaction(transaction, path) { const client = await createClient(this.transport); const signature = await client.sign(transaction, path); return signature; } } async function createClient(transport) { return { transport, async getPublicKey(path, verify) { const response = await this.transport.send(CLA, INS_GET_PUBLIC_KEY, verify ? 0 : 1, NETWORK_ID, bip32PathToBytes(path)); return Buffer.from(response.subarray(0, -2)); }, async getAddress(path) { const response = await this.transport.send(CLA, INS_GET_ADDRESS, 0, NETWORK_ID, bip32PathToBytes(path)); return Buffer.from(response.subarray(0, -2)); }, async sign(transactionData, path) { transactionData = Buffer.from(transactionData); const concatenatedData = Buffer.concat([bip32PathToBytes(path), transactionData]); const chunks = new Array(Math.ceil(concatenatedData.length / CHUNK_SIZE)) .fill("") .map((_, i) => concatenatedData.subarray(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE)); for (const chunk of chunks) { const isLastChunk = chunks.indexOf(chunk) === chunks.length - 1; const response = await this.transport.send(CLA, INS_SIGN, isLastChunk ? P1_LAST_CHUNK : 0, NETWORK_ID, chunk); if (isLastChunk) { return Buffer.from(response.subarray(0, -2)); } } }, }; } //# sourceMappingURL=Near.js.map