Files
grin-web-wallet/scripts/hardware_wallet_usb_transport.js
2024-12-20 18:08:44 -08:00

1164 lines
30 KiB
JavaScript
Executable File

// Use strict
"use strict";
// Classes
// HardwareWallet USB transport class
class HardwareWalletUsbTransport {
// Public
// Constructor
constructor(device, interfaceNumber) {
// Set device
this.device = device;
// Set interface number
this.interfaceNumber = interfaceNumber;
// Set allow disconnect event to true
this.allowDisconnectEvent = true;
// Set product name
var productName = device["manufacturerName"] + " " + device["productName"];
// Go through all devices
for(var i = 0; i < HardwareWalletUsbTransport.DEVICES["length"]; ++i) {
// Check if device's vendor ID matches the device's
if(device["vendorId"] === HardwareWalletUsbTransport.DEVICES[i]["Vendor ID"]) {
// Set type to device's type
this.type = HardwareWalletUsbTransport.DEVICES[i]["Type"];
// Check if device's product ID matches the device's
if("Product ID" in HardwareWalletUsbTransport.DEVICES[i] === false || device["productId"] === HardwareWalletUsbTransport.DEVICES[i]["Product ID"]) {
// Check if device has a product name
if("Product Name" in HardwareWalletUsbTransport.DEVICES[i] === true) {
// Set product name
productName = HardwareWalletUsbTransport.DEVICES[i]["Product Name"];
}
// Break
break;
}
}
}
// Set device model
this["deviceModel"] = {
// Product name
"productName": productName
};
}
// On
on(event, callback) {
// Check event
switch(event) {
// Disconnect
case "disconnect":
// Set self
var self = this;
// Create callback once
var callbackOnce = function(event) {
// Check if device was disconnected
if(event["device"] === self.device) {
// Remove USB disconnect event
navigator["usb"].removeEventListener("disconnect", callbackOnce);
// Check if disconnect event is allowed
if(self.allowDisconnectEvent === true) {
// Call callback
callback();
}
}
};
// USB disconnect event
navigator["usb"].addEventListener("disconnect", callbackOnce);
// Return callback once
return callbackOnce;
}
}
// Off
off(event, callback) {
// Check event
switch(event) {
// Disconnect
case "disconnect":
// Remove USB disconnect event
navigator["usb"].removeEventListener("disconnect", callback);
// Break
break;
}
}
// Close
close() {
// Clear allow disconnect event
this.allowDisconnectEvent = false;
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return releasing device interface and catch errors
return self.device.releaseInterface(self.interfaceNumber).catch(function(error) {
// Finally
}).finally(function() {
// Return resetting device and catch errors
return self.device.reset().catch(function(error) {
// Finally
}).finally(function() {
// Return closing device and catch errors
return self.device.close().then(function() {
// Resolve
resolve();
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
});
});
});
}
// Send
send(messageType, parameterOne, parameterTwo, data) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check type
switch(self.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Create header
var header = new Uint8Array([messageType >>> HardwareWalletUsbTransport.BITS_IN_A_BYTE, messageType, parameterOne, parameterTwo, data["length"]]);
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Create header
var header = new Uint8Array([messageType >>> HardwareWalletUsbTransport.BITS_IN_A_BYTE, messageType, data["length"] >>> (HardwareWalletUsbTransport.BITS_IN_A_BYTE * 3), data["length"] >>> (HardwareWalletUsbTransport.BITS_IN_A_BYTE * 2), data["length"] >>> HardwareWalletUsbTransport.BITS_IN_A_BYTE, data["length"]]);
// Break
break;
}
// Create message
var message = new Uint8Array(header["length"] + data["length"]);
message.set(header);
message.set(data, header["length"]);
// Return sending message to the device
return HardwareWalletUsbTransport.sendRequest(self.device, self.type, message).then(function(response) {
// Check if response contains a message type
if(response["length"] >= HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH) {
// Get message type
var messageType = (response[response["length"] - HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH] << HardwareWalletUsbTransport.BITS_IN_A_BYTE) | response[response["length"] - (HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH - 1)];
// Resolve
resolve({
// Message type
"Message Type": messageType,
// Data
"Data": response.subarray(0, response["length"] - HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH)
});
}
// Otherwise
else {
// Securely clear response
response.fill(0);
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check if error is that the device was disconnected
if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWalletUsbTransport.NOT_FOUND_ERROR_CODE) || ("name" in error === true && error["name"] === "NotFoundError"))) {
// Reject error
reject(new DOMException("", "NetworkError"));
}
// Otherwise
else {
// Reject error
reject(error);
}
});
});
}
// Request
static request(device = HardwareWalletUsbTransport.NO_DEVICE) {
// Return promise
return new Promise(function(resolve, reject) {
// Get device
var getDevice = function() {
// Return promise
return new Promise(function(resolve, reject) {
// Check if no device was provided
if(device === HardwareWalletUsbTransport.NO_DEVICE) {
// Return requesting USB device
return navigator["usb"].requestDevice({
// Filters
"filters": HardwareWalletUsbTransport.DEVICES.map(function(device) {
// Check if device has a product ID
if("Product ID" in device === true) {
// Return device's vendor ID and product ID
return {
// Vendor ID
"vendorId": device["Vendor ID"],
// Product ID
"productId": device["Product ID"]
};
}
// Otherwise
else {
// Return device's vendor ID
return {
// Vendor ID
"vendorId": device["Vendor ID"]
};
}
})
}).then(function(device) {
// Check if device isn't opened
if(device["opened"] === false) {
// Resolve device
resolve(device);
}
// Otherwise
else {
// Reject error
reject(new DOMException("", "InvalidStateError"));
}
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Initialize device applicable
var deviceApplicable = false;
// Go through all devices
for(var i = 0; i < HardwareWalletUsbTransport.DEVICES["length"]; ++i) {
// Check if device's vendor ID and product ID match the device's
if(device["vendorId"] === HardwareWalletUsbTransport.DEVICES[i]["Vendor ID"] && ("Product ID" in HardwareWalletUsbTransport.DEVICES[i] === false || device["productId"] === HardwareWalletUsbTransport.DEVICES[i]["Product ID"])) {
// Set device applicable
deviceApplicable = true;
// Break
break;
}
}
// Check if device is applicable
if(deviceApplicable === true) {
// Check if device isn't opened
if(device["opened"] === false) {
// Resolve device
resolve(device);
}
// Otherwise
else {
// Reject error
reject(new DOMException("", "InvalidStateError"));
}
}
// Otherwise
else {
// Reject
reject();
}
}
});
};
// Return getting device
return getDevice().then(function(device) {
// Return opening device
return device.open().then(function() {
// Return selecting device's configuration
return device.selectConfiguration(HardwareWalletUsbTransport.CONFIGURATION).then(function() {
// Return resetting device and catch errors
return device.reset().catch(function(error) {
// Finally
}).finally(function() {
// Initialize interface found
var interfaceFound = false;
// Go through all the configuration's interfaces
for(var i = 0; i < device["configurations"][0]["interfaces"]["length"] && interfaceFound === false; ++i) {
// Go through all of the interface's alternates
for(var j = 0; j < device["configurations"][0]["interfaces"][i]["alternates"]["length"]; ++j) {
// Check if alternates is for WebUSB
if(device["configurations"][0]["interfaces"][i]["alternates"][j]["interfaceClass"] === HardwareWalletUsbTransport.WEBUSB_INTERFACE_CLASS) {
// Set interface found
interfaceFound = true;
// Set interface number
var interfaceNumber = device["configurations"][0]["interfaces"][i]["interfaceNumber"];
// Break
break;
}
}
}
// Check if interface was found
if(interfaceFound === true) {
// Return claiming interface
return device.claimInterface(interfaceNumber).then(function() {
// Create transport for the device
var transport = new HardwareWalletUsbTransport(device, interfaceNumber);
// Resolve transport
resolve(transport);
// Catch errors
}).catch(function(error) {
// Return closing device and catch errors
return device.close().catch(function(error) {
// Finally
}).finally(function() {
// Reject error
reject(error);
});
});
}
// Otherwise
else {
// Return closing device and catch errors
return device.close().catch(function(error) {
// Finally
}).finally(function() {
// Reject
reject();
});
}
});
// Catch errors
}).catch(function(error) {
// Return closing device and catch errors
return device.close().catch(function(error) {
// Finally
}).finally(function() {
// Reject error
reject(error);
});
});
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
});
}
// List
static list() {
// Return promise
return new Promise(function(resolve, reject) {
// Return getting attached USB devices
return navigator["usb"].getDevices().then(function(devices) {
// Initialize applicable devices
var applicableDevices = [];
// Go through all devices
for(var i = 0; i < devices["length"]; ++i) {
// Check if device isn't opened
if(devices[i]["opened"] === false) {
// Initialize device applicable
var deviceApplicable = false;
// Go through all devices
for(var j = 0; j < HardwareWalletUsbTransport.DEVICES["length"]; ++j) {
// Check if device's vendor ID and product ID match the device's
if(devices[i]["vendorId"] === HardwareWalletUsbTransport.DEVICES[j]["Vendor ID"] && ("Product ID" in HardwareWalletUsbTransport.DEVICES[j] === false || devices[i]["productId"] === HardwareWalletUsbTransport.DEVICES[j]["Product ID"])) {
// Set device aapplicable
deviceApplicable = true;
// Break
break;
}
}
// Check if device is applicable
if(deviceApplicable === true) {
// Append device to list
applicableDevices.push(devices[i]);
}
}
}
// Resolve applicable devices
resolve(applicableDevices);
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
});
}
// Private
// Create packets
static createPackets(channel, type, payload = HardwareWalletUsbTransport.NO_PAYLOAD) {
// Initialize packets
var packets = [];
// Check if payload doesn't exist
if(payload === HardwareWalletUsbTransport.NO_PAYLOAD) {
// Set payload to an empty array
payload = new Uint8Array([]);
}
// Check type
switch(type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Create padded payload
var numberOfPackets = Math.ceil((HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH + payload["length"]) / (HardwareWalletUsbTransport.PACKET_SIZE - HardwareWalletUsbTransport.LEDGER_PACKET_HEADER_LENGTH));
var paddedPayload = (new Uint8Array(numberOfPackets * (HardwareWalletUsbTransport.PACKET_SIZE - HardwareWalletUsbTransport.LEDGER_PACKET_HEADER_LENGTH))).fill(0);
paddedPayload.set(new Uint8Array([payload["length"] >>> HardwareWalletUsbTransport.BITS_IN_A_BYTE, payload["length"]]));
paddedPayload.set(payload, Uint16Array["BYTES_PER_ELEMENT"]);
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if more than one packet will be used
if(payload["length"] > HardwareWalletUsbTransport.PACKET_SIZE - HardwareWalletUsbTransport.TREZOR_FIRST_PACKET_HEADER["length"]) {
// Create padded payload
var numberOfPackets = Math.ceil((payload["length"] - (HardwareWalletUsbTransport.PACKET_SIZE - HardwareWalletUsbTransport.TREZOR_FIRST_PACKET_HEADER["length"])) / (HardwareWalletUsbTransport.PACKET_SIZE - HardwareWalletUsbTransport.TREZOR_NEXT_PACKETS_HEADER["length"]));
var paddedPayload = (new Uint8Array(HardwareWalletUsbTransport.PACKET_SIZE - HardwareWalletUsbTransport.TREZOR_FIRST_PACKET_HEADER["length"] + numberOfPackets * (HardwareWalletUsbTransport.PACKET_SIZE - HardwareWalletUsbTransport.TREZOR_NEXT_PACKETS_HEADER["length"]))).fill(0);
paddedPayload.set(payload);
}
// Otherwise
else {
// Create padded payload
var paddedPayload = (new Uint8Array(HardwareWalletUsbTransport.PACKET_SIZE - HardwareWalletUsbTransport.TREZOR_FIRST_PACKET_HEADER["length"])).fill(0);
paddedPayload.set(payload);
}
// Break
break;
}
// Set payload to padded payload
payload = paddedPayload;
// Initialize payload offset
var payloadOffset = 0;
// Go through all packets required to send the payload
for(var i = 0; payloadOffset !== payload["length"]; ++i) {
// Check type
switch(type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Create header
var header = new Uint8Array([channel >>> HardwareWalletUsbTransport.BITS_IN_A_BYTE, channel, HardwareWalletUsbTransport.LEDGER_PACKET_HEADER_TAG, i >>> HardwareWalletUsbTransport.BITS_IN_A_BYTE, i]);
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if at the first packet
if(i === 0) {
// Create header
var header = HardwareWalletUsbTransport.TREZOR_FIRST_PACKET_HEADER;
}
// Otherwise
else {
// Create header
var header = HardwareWalletUsbTransport.TREZOR_NEXT_PACKETS_HEADER;
}
// Break
break;
}
// Get payload part length
var payloadPartLength = HardwareWalletUsbTransport.PACKET_SIZE - header["length"];
// Create packet
var packet = new Uint8Array(header["length"] + payloadPartLength);
packet.set(header);
packet.set(payload.subarray(payloadOffset, payloadOffset + payloadPartLength), header["length"]);
// Append packet to list
packets.push(packet);
// Update payload offset
payloadOffset += payloadPartLength;
}
// Return packets
return packets;
}
// Send request
static sendRequest(device, type, payload = HardwareWalletUsbTransport.NO_PAYLOAD) {
// Return promise
return new Promise(function(resolve, reject) {
// Create random channel
var channel = Math.floor(Math.random() * HardwareWalletUsbTransport.MAX_CHANNEL);
// Get packets
var packets = HardwareWalletUsbTransport.createPackets(channel, type, payload);
// Check type
switch(type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Set endpoint
var endpoint = HardwareWalletUsbTransport.LEDGER_ENDPOINT;
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Set endpoint
var endpoint = HardwareWalletUsbTransport.TREZOR_ENDPOINT;
// Break
break;
}
// Send packet
var sendPacket = new Promise(function(resolve, reject) {
// Resolve
resolve();
});
// Initialize sending packets
var sendingPackets = [sendPacket];
// Go through all packets
for(var i = 0; i < packets["length"]; ++i) {
// Get packet
let packet = packets[i];
// Send next pack after previous packet is send
sendPacket = sendPacket.then(function() {
// Return promise
return new Promise(function(resolve, reject) {
// Return transfering out packet
return device.transferOut(endpoint, packet).then(function() {
// Resolve
resolve();
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
});
// Catch errors
}).catch(function(error) {
// Return promise
return new Promise(function(resolve, reject) {
// Reject error
reject(error);
});
});
// Append sending packet to list
sendingPackets.push(sendPacket);
}
// Return sending all packets
return Promise.all(sendingPackets).then(function() {
// Receive packet
var receivePacket = function(expectedSequenceIndex) {
// Return promise
return new Promise(function(resolve, reject) {
// Return transfering in packet
return device.transferIn(endpoint, HardwareWalletUsbTransport.PACKET_SIZE).then(function(response) {
// Get packet from response
var packet = new Uint8Array(response["data"]["buffer"]);
// Check if packet's size is correct
if(packet["length"] === HardwareWalletUsbTransport.PACKET_SIZE) {
// Check type
switch(type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Get response channel
var responseChannel = (packet[0] << HardwareWalletUsbTransport.BITS_IN_A_BYTE) | packet[1];
// Check if response channel is correct
if(responseChannel === channel) {
// Check if tag is correct
if(packet[Uint16Array["BYTES_PER_ELEMENT"]] === HardwareWalletUsbTransport.LEDGER_PACKET_HEADER_TAG) {
// Get sequence index
var sequenceIndex = (packet[Uint16Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"]] << HardwareWalletUsbTransport.BITS_IN_A_BYTE) | packet[Uint16Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + 1];
// Check if sequence index is correct
if(sequenceIndex === expectedSequenceIndex) {
// Resolve packet's payload
resolve(packet.subarray(HardwareWalletUsbTransport.LEDGER_PACKET_HEADER_LENGTH));
}
// Otherwise
else {
// Securely clear packet
packet.fill(0);
// Reject
reject();
}
}
// Otherwise
else {
// Securely clear packet
packet.fill(0);
// Reject
reject();
}
}
// Otherwise
else {
// Securely clear packet
packet.fill(0);
// Reject
reject();
}
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if at the first packet
if(expectedSequenceIndex === 0) {
// Get magic numbers
var magicNumbers = packet.subarray(0, HardwareWalletUsbTransport.TREZOR_FIRST_PACKET_HEADER["length"]);
// Go through all magic numbers
for(var i = 0; i < magicNumbers["length"]; ++i) {
// Check if magic number isn't correct
if(magicNumbers[i] !== HardwareWalletUsbTransport.TREZOR_FIRST_PACKET_HEADER[i]) {
// Securely clear packet
packet.fill(0);
// Reject
reject();
// Return
return;
}
}
// Resolve packet's payload
resolve(packet.subarray(HardwareWalletUsbTransport.TREZOR_FIRST_PACKET_HEADER["length"]));
}
// Otherwise
else {
// Get magic numbers
var magicNumbers = packet.subarray(0, HardwareWalletUsbTransport.TREZOR_NEXT_PACKETS_HEADER["length"]);
// Go through all magic numbers
for(var i = 0; i < magicNumbers["length"]; ++i) {
// Check if magic number isn't correct
if(magicNumbers[i] !== HardwareWalletUsbTransport.TREZOR_NEXT_PACKETS_HEADER[i]) {
// Securely clear packet
packet.fill(0);
// Reject
reject();
// Return
return;
}
}
// Resolve packet's payload
resolve(packet.subarray(HardwareWalletUsbTransport.TREZOR_NEXT_PACKETS_HEADER["length"]));
}
// Break
break;
}
}
// Otherwise
else {
// Securely clear packet
packet.fill(0);
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
});
};
// Return receiving first packet
return receivePacket(0).then(function(responsePart) {
// Check type
switch(type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Get message type
var messageType = new Uint8Array([]);
// Get response size
var responseSize = (responsePart[0] << HardwareWalletUsbTransport.BITS_IN_A_BYTE) | responsePart[1];
// Set response
var response = responsePart.subarray(Uint16Array["BYTES_PER_ELEMENT"]);
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Get message type
var messageType = responsePart.subarray(0, HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH);
// Get response size
var responseSize = (responsePart[HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH] << (HardwareWalletUsbTransport.BITS_IN_A_BYTE * 3)) | (responsePart[HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH + 1] << (HardwareWalletUsbTransport.BITS_IN_A_BYTE * 2)) | (responsePart[HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH + 2] << HardwareWalletUsbTransport.BITS_IN_A_BYTE) | responsePart[HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH + 3];
// Set response
var response = responsePart.subarray(HardwareWalletUsbTransport.MESSAGE_TYPE_LENGTH + Uint32Array["BYTES_PER_ELEMENT"]);
// Break
break;
}
// Set next sequence index
var nextSequenceIndex = 1;
// Get next response part
var getNextResponsePart = function() {
// Return promise
return new Promise(function(resolve, reject) {
// Check if the entire response hasn't been received
if(response["length"] < responseSize) {
// Return receiving next packet
return receivePacket(nextSequenceIndex).then(function(responsePart) {
// Append response part to response
var currentResponse = new Uint8Array(response["length"] + responsePart["length"]);
currentResponse.set(response);
currentResponse.set(responsePart, response["length"]);
response.fill(0);
responsePart.fill(0);
response = currentResponse;
// Increment next sequence index
++nextSequenceIndex;
// Return getting next response part
return getNextResponsePart().then(function() {
// Resolve
resolve();
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve
resolve();
}
});
};
// Return getting next response part
return getNextResponsePart().then(function() {
// Append message type to response
var finalResponse = new Uint8Array(responseSize + messageType["length"]);
finalResponse.set(response.subarray(0, responseSize));
finalResponse.set(messageType, responseSize);
response.fill(0);
// Resolve final response
resolve(finalResponse);
// Catch errors
}).catch(function(error) {
// Securely clear response
response.fill(0);
// Reject error
reject(error);
});
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
});
}
// No payload
static get NO_PAYLOAD() {
// Return no payload
return null;
}
// No device
static get NO_DEVICE() {
// Return no device
return null;
}
// Devices
static get DEVICES() {
// Return devices
return [
// Ledger
{
// Type
"Type": HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE,
// Vendor ID
"Vendor ID": 0x2C97
},
// Trezor
{
// Type
"Type": HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE,
// Product name
"Product Name": "Trezor",
// Vendor ID
"Vendor ID": 0x1209,
// Product ID
"Product ID": 0x53C1
}
];
}
// WebUSB interface class
static get WEBUSB_INTERFACE_CLASS() {
// Return WebUSB interface class
return 0xFF;
}
// Configuration
static get CONFIGURATION() {
// Return configuration
return 0x01;
}
// Packet size
static get PACKET_SIZE() {
// Return packet size
return 64;
}
// Message type length
static get MESSAGE_TYPE_LENGTH() {
// Return message type length
return Uint16Array["BYTES_PER_ELEMENT"];
}
// Bits in a byte
static get BITS_IN_A_BYTE() {
// Rerurn bits in a byte
return 8;
}
// Ledger endpoint
static get LEDGER_ENDPOINT() {
// Return Ledger endpoint
return 0x03;
}
// Trezor endpoint
static get TREZOR_ENDPOINT() {
// Return Trezor endpoint
return 0x01;
}
// Not found error code
static get NOT_FOUND_ERROR_CODE() {
// Return not found error code
return 8;
}
// Ledger packet header length
static get LEDGER_PACKET_HEADER_LENGTH() {
// Return Ledger packet header length
return 5;
}
// Ledger packet header tag
static get LEDGER_PACKET_HEADER_TAG() {
// Return Ledger packet header tag
return 0x05;
}
// Trezor first packet header
static get TREZOR_FIRST_PACKET_HEADER() {
// Return Trezor packet header
return new Uint8Array([0x3F, 0x23, 0x23]);
}
// Trezor next packets header
static get TREZOR_NEXT_PACKETS_HEADER() {
// Return Trezor next packets header
return new Uint8Array([0x3F]);
}
// Max channel
static get MAX_CHANNEL() {
// Return max channel
return 0xFFFF;
}
}
// Main function
// Set global object's hardware wallet USB transport
globalThis["HardwareWalletUsbTransport"] = HardwareWalletUsbTransport;