UNPKG

aion-gql-webcomponents

Version:
97 lines (96 loc) 3.85 kB
import Transport from "@ledgerhq/hw-transport-u2f"; import { Buffer } from "buffer"; import { Util } from "./Util"; import { CryptoUtil } from "../../util/CryptoUtil"; import { TransactionUtil } from "../../util/TransactionUtil"; export class LedgerProvider { constructor() { this.path = "44'/425'/0'/0'/0'"; this.connect(); } async connect() { return Transport.create().then(_transport => { _transport.decorateAppAPIMethods(this, [ "getAddress", "sign" ], "aion"); return _transport; }); } async unlock(progressCallback) { try { if (!this.transport) this.transport = await this.connect(); let result = await this.getAddress(this.path, true, false); if (progressCallback) progressCallback(100); this.address = result.address; this.publicKey = result.publicKey; return [result.address, result.publicKey]; } catch (e) { console.log("Error getting address", e); throw e; } } getAddress(path, boolDisplay, boolChaincode) { let paths = Util.splitPath(path); let buffer = new Buffer(1 + paths.length * 4); buffer[0] = paths.length; paths.forEach((element, index) => { buffer.writeUInt32BE(element, 1 + 4 * index); }); return this.transport.send(0xe0, 0x02, boolDisplay ? 0x01 : 0x00, boolChaincode ? 0x01 : 0x00, buffer) .then(response => { let result = { publicKey: '', address: '' }; if (response.length < 64) throw new Error("Invalid response for getAddress"); let publicKeyBuff = response.slice(0, 32); let addressBuff = response.slice(32, 64); result.publicKey = CryptoUtil.uia2hex(publicKeyBuff, true); result.address = CryptoUtil.uia2hex(addressBuff); return result; }); } async sign(transaction) { let rawTransaction = TransactionUtil.rlpEncode(transaction); let rawTxHash = CryptoUtil.uia2hex(rawTransaction, true); let paths = Util.splitPath(this.path); let offset = 0; let rawTx = new Buffer(rawTxHash, "hex"); let toSend = []; let response; while (offset !== rawTx.length) { let maxChunkSize = offset === 0 ? 150 - 1 - paths.length * 4 : 150; let chunkSize = offset + maxChunkSize > rawTx.length ? rawTx.length - offset : maxChunkSize; let buffer = new Buffer(offset === 0 ? 1 + paths.length * 4 + chunkSize : chunkSize); if (offset === 0) { buffer[0] = paths.length; paths.forEach((element, index) => { buffer.writeUInt32BE(element, 1 + 4 * index); }); rawTx.copy(buffer, 1 + 4 * paths.length, offset, offset + chunkSize); } else { rawTx.copy(buffer, 0, offset, offset + chunkSize); } toSend.push(buffer); offset += chunkSize; } return Util.foreach(toSend, (data, i) => { return this.transport .send(0xe0, 0x04, i === 0 ? 0x00 : 0x80, 0x00, data) .then(apduResponse => { response = apduResponse; }); }).then(() => { let signature = response.slice(0, 64); return TransactionUtil.verifyAndEncodedSignTransaction(transaction, rawTransaction, signature, CryptoUtil.hex2ua(this.publicKey)); }); } }