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

7063 lines
230 KiB
JavaScript
Executable File

// Use strict
"use strict";
// Classes
// HardwareWallet class
class HardwareWallet {
// Public
// Constructor
constructor(application) {
// Set application
this.application = application;
// Set transport to no transport
this.transport = HardwareWallet.NO_TRANSPORT;
// Set root public key to no root public key
this.rootPublicKey = HardwareWallet.NO_ROOT_PUBLIC_KEY;
// Set seed cookie to no seed cookie
this.seedCookie = HardwareWallet.NO_SEED_COOKIE;
// Set connected to false
this.connected = false;
// Set in use to false
this.inUse = false;
// Set exclusive lock obtained to false
this.exclusiveLockObtained = false;
// Set exclusive lock release event index
this.exclusiveLockReleaseEventIndex = 0;
// Set locked to false
this.locked = false;
// Set connection type to USB connection type
this.connectionType = HardwareWallet.USB_CONNECTION_TYPE;
// Set wallet key path
this.walletKeyPath = Wallet.NO_KEY_PATH;
// Set hardware type
this.hardwareType = HardwareWallet.LEDGER_HARDWARE_TYPE;
}
// Get root public key
getRootPublicKey() {
// Return copy of root public key
return new Uint8Array(this.rootPublicKey);
}
// Get seed cookie
getSeedCookie() {
// Return seed cookie
return this.seedCookie;
}
// Get connection type
getConnectionType() {
// Return connection type
return this.connectionType;
}
// Get hardware type
getHardwareType() {
// Return hardware type
return this.hardwareType;
}
// Is connected
isConnected() {
// Return if connected
return this.connected === true;
}
// Set in use
setInUse(inUse) {
// Set is in use
this.inUse = inUse;
}
// Get in use
getInUse() {
// Return in use
return this.inUse;
}
// Is locked
isLocked() {
// Return if locked
return this.locked === true;
}
// Close
close() {
// Check if root public key exists
if(this.rootPublicKey !== HardwareWallet.NO_ROOT_PUBLIC_KEY) {
// Securely clear the root public key
this.rootPublicKey.fill(0);
// Set root public key to no root public key
this.rootPublicKey = HardwareWallet.NO_ROOT_PUBLIC_KEY;
}
// Set seed cookie to no seed cookie
this.seedCookie = HardwareWallet.NO_SEED_COOKIE;
// Clear in use
this.inUse = false;
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Resolve
resolve();
});
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Resolve
resolve();
}
});
});
}
// Connect
connect(hardwareWalletDescriptor, failOnLock = false, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if not connected
if(self.isConnected() === false) {
// Function get hardware wallet transport
var getHardwareWalletTransport = function() {
// Return promise
return new Promise(function(resolve, reject) {
// Check if connecting to any hardware wallet descriptor
if(hardwareWalletDescriptor === HardwareWallet.ANY_HARDWARE_WALLET_DESCRIPTOR) {
// Check if USB is supported
if("usb" in navigator === true) {
// Return connecting to any USB hardware wallet
return HardwareWalletUsbTransport.request().then(function(transport) {
// Set connection type to USB connection type
self.connectionType = HardwareWallet.USB_CONNECTION_TYPE;
// Resolve transport
resolve(transport);
// Catch errors
}).catch(function(error) {
// Check if error is that user canceled action
if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.NOT_FOUND_ERROR_CODE) || ("name" in error === true && error["name"] === "NotFoundError"))) {
// Check if Bluetooth is supported
if("bluetooth" in navigator === true) {
// Return connecting to any Bluetooth hardware wallet
return HardwareWalletBluetoothTransport.request().then(function(transport) {
// Set connection type to Bluetooth connection type
self.connectionType = HardwareWallet.BLUETOOTH_CONNECTION_TYPE;
// Resolve transport
resolve(transport);
// Catch errors
}).catch(function(error) {
// Check if error is that user canceled action
if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.NOT_FOUND_ERROR_CODE) || ("name" in error === true && error["name"] === "NotFoundError"))) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('No hardware wallet was selected.')) + ((Common.isPopup() === true) ? Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to open this extension in a tab or window if it\'s not able to connect to a hardware wallet.')) : ""));
}
// Otherwise check if error was a connection error
else if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.NETWORK_ERROR_CODE) || ("name" in error === true && error["name"] === "NetworkError"))) {
// Check if is an extension
if(Common.isExtension() === true) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to be already paired with the device before this extension can connect to it.')));
}
// Otherwise check if is an app
else if(Common.isApp() === true) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to be already paired with the device before this app can connect to it.')));
}
// Otherwise
else {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to be already paired with the device before this site can connect to it.')));
}
}
// Otherwise check if error was an invalid state error
else if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.INVALID_STATE_ERROR_CODE) || ("name" in error === true && error["name"] === "InvalidStateError"))) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That hardware wallet is currently in use.')));
}
// Otherwise
else {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')));
}
});
}
// Otherwise
else {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('No hardware wallet was selected.')) + ((Common.isPopup() === true) ? Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to open this extension in a tab or window if it\'s not able to connect to a hardware wallet.')) : ""));
}
}
// Otherwise check if error was an invalid state error
else if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.INVALID_STATE_ERROR_CODE) || ("name" in error === true && error["name"] === "InvalidStateError"))) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That hardware wallet is currently in use.')));
}
// Otherwise
else {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')));
}
});
}
// Otherwise check if Bluetooth is supported
else if("bluetooth" in navigator === true) {
// Return connecting to any Bluetooth hardware wallet
return HardwareWalletBluetoothTransport.request().then(function(transport) {
// Set connection type to Bluetooth connection type
self.connectionType = HardwareWallet.BLUETOOTH_CONNECTION_TYPE;
// Resolve transport
resolve(transport);
// Catch errors
}).catch(function(error) {
// Check if error is that user canceled action
if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.NOT_FOUND_ERROR_CODE) || ("name" in error === true && error["name"] === "NotFoundError"))) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('No hardware wallet was selected.')) + ((Common.isPopup() === true) ? Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to open this extension in a tab or window if it\'s not able to connect to a hardware wallet.')) : ""));
}
// Otherwise check if error was a connection error
else if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.NETWORK_ERROR_CODE) || ("name" in error === true && error["name"] === "NetworkError"))) {
// Check if is an extension
if(Common.isExtension() === true) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to be already paired with the device before this extension can connect to it.')));
}
// Otherwise check if is an app
else if(Common.isApp() === true) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to be already paired with the device before this app can connect to it.')));
}
// Otherwise
else {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to be already paired with the device before this site can connect to it.')));
}
}
// Otherwise check if error was an invalid state error
else if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.INVALID_STATE_ERROR_CODE) || ("name" in error === true && error["name"] === "InvalidStateError"))) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That hardware wallet is currently in use.')));
}
// Otherwise
else {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')));
}
});
}
}
// Otherwise
else {
// Return connecting to provided hardware wallet descriptor
return HardwareWalletUsbTransport.request(hardwareWalletDescriptor).then(function(transport) {
// Set connection type to USB connection type
self.connectionType = HardwareWallet.USB_CONNECTION_TYPE;
// Resolve transport
resolve(transport);
// Catch errors
}).catch(function(error) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Connecting to that hardware wallet failed.')));
});
}
});
};
// Return gwetting hardware wallet transport
return getHardwareWalletTransport().then(function(transport) {
// Set transport
self.transport = transport;
// Get product name
var productName = self.transport["deviceModel"]["productName"];
// Get minimum compatible version
var minimumCompatibleVersion = self.getMinimumCompatibleVersion();
// Check transport's type
switch(self.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Set hardware type to Ledger hardware type
self.hardwareType = HardwareWallet.LEDGER_HARDWARE_TYPE;
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Set hardware type to Trezor hardware type
self.hardwareType = HardwareWallet.TREZOR_HARDWARE_TYPE;
// Break
break;
}
// Set connected
self.connected = true;
// Transport on disconnect
self.transport.on("disconnect", function() {
// Obtain exclusive lock
self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
}
// Release exclusive lock
self.releaseExclusiveLock();
});
});
// Check transport's type
switch(self.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Return requesting getting the application information from the hardware wallet
return self.send(HardwareWalletDefinitions.LEDGER_GET_APPLICATION_INFORMATION_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_DATA, HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, text, textArguments, allowUnlock, failOnLock, preventMessages, cancelOccurred).then(function(response) {
// Check if response contains an application name length
if(response["length"] >= Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"]) {
// Get application name length
var applicationNameLength = response[Uint8Array["BYTES_PER_ELEMENT"]];
// Check if response contains an application name
if(response["length"] >= Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + applicationNameLength) {
// Set error occured to false
var errorOccurred = false;
// Try
try {
// Get application name from the response
var applicationName = (new TextDecoder("utf-8", {"fatal": true})).decode(response.subarray(Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"], Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + applicationNameLength));
}
// Catch error
catch(error) {
// Set error occurred
errorOccurred = true;
}
// Check if error didn't occur and application name is valid
if(errorOccurred === false && applicationName === HardwareWallet.APPLICATION_NAME) {
// Check if response contains an application version length
if(response["length"] >= Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + applicationNameLength + Uint8Array["BYTES_PER_ELEMENT"]) {
// Get application version length
var applicationVersionLength = response[Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + applicationNameLength];
// Check if response contains an application version
if(response["length"] >= Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + applicationNameLength + Uint8Array["BYTES_PER_ELEMENT"] + applicationVersionLength) {
// Try
try {
// Get application version from the response
var applicationVersion = (new TextDecoder("utf-8", {"fatal": true})).decode(response.subarray(Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + applicationNameLength + Uint8Array["BYTES_PER_ELEMENT"], Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + applicationNameLength + Uint8Array["BYTES_PER_ELEMENT"] + applicationVersionLength));
}
// Catch error
catch(error) {
// Set error occurred
errorOccurred = true;
}
// Check if error didn't occur and application version is compatible
if(errorOccurred === false && HardwareWallet.isCompatibleVersion(applicationVersion, minimumCompatibleVersion) === true) {
// Return requesting getting the seed cookie from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_GET_SEED_COOKIE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT)
}, HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, text, textArguments, allowUnlock, failOnLock, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === HardwareWallet.SEED_COOKIE_LENGTH) {
// Get seed cookie from response
self.seedCookie = response;
// Release exclusive lock
self.releaseExclusiveLock();
// Resolve
resolve();
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the seed cookie from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText((failOnLock === false) ? Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet.') : Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
});
}
// Catch errors
}).catch(function(error) {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Check if error is canceled
if(error === Common.CANCELED_ERROR) {
// Reject error
reject(error);
}
// Otherwise check if error is disconnected error
else if(error === HardwareWallet.DISCONNECTED_ERROR) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That hardware wallet was disconnected.')));
}
// Otherwise
else {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the seed cookie from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText((failOnLock === false) ? Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet.') : Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
}
});
});
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('The app on that %1$x hardware wallet isn\'t compatible. Update the app on the hardware wallet to version %2$v or newer to continue.'), [productName, minimumCompatibleVersion]));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the app information from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText((failOnLock === false) ? Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet.') : Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the app information from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText((failOnLock === false) ? Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet.') : Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the app information from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText((failOnLock === false) ? Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet.') : Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the app information from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText((failOnLock === false) ? Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet.') : Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the app information from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText((failOnLock === false) ? Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet.') : Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
});
}
// Catch errors
}).catch(function(error) {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Check if error is canceled
if(error === Common.CANCELED_ERROR) {
// Reject error
reject(error);
}
// Otherwise check if error is disconnected error
else if(error === HardwareWallet.DISCONNECTED_ERROR) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That hardware wallet was disconnected.')));
}
// Otherwise
else {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the app information from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText((failOnLock === false) ? Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet.') : Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
}
});
});
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Return requesting initializing on the hardware wallet
return self.send(HardwareWalletDefinitions.TREZOR_INITIALIZE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_DATA, HardwareWalletDefinitions.TREZOR_FEATURES_MESSAGE_TYPE, text, textArguments, allowUnlock, failOnLock, preventMessages, cancelOccurred).then(function(response) {
// Check if response contains a major version, minor version, patch version, pin protection, passphrase protection, initialized, unlocked, and model
if(response["length"] >= Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"]) {
// Get major version
var majorVersion = parseInt(Common.toHexString(response.subarray(0, Uint32Array["BYTES_PER_ELEMENT"])), Common.HEX_NUMBER_BASE);
// Get minor version
var minorVersion = parseInt(Common.toHexString(response.subarray(Uint32Array["BYTES_PER_ELEMENT"], Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"])), Common.HEX_NUMBER_BASE);
// Get patch version
var patchVersion = parseInt(Common.toHexString(response.subarray(Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"], Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"])), Common.HEX_NUMBER_BASE);
// Get firmware version
var firmwareVersion = majorVersion.toFixed() + "." + minorVersion.toFixed() + "." + patchVersion.toFixed();
// Get model length
var modelLength = response[Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"]];
// Check if response contains a model and capabilities
if(response["length"] >= Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + modelLength + Uint8Array["BYTES_PER_ELEMENT"]) {
// Set error occured to false
var errorOccurred = false;
// Try
try {
// Get model
var model = (new TextDecoder("utf-8", {"fatal": true})).decode(response.subarray(Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"], Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + modelLength));
}
// Catch error
catch(error) {
// Set error occurred
errorOccurred = true;
}
// Check if error didn't occur
if(errorOccurred === false) {
// Check model
switch(model) {
// One
case "1":
// Update transport's product name to include model
self.transport["deviceModel"]["productName"] += " Model One";
// Break
break;
// T
case "T":
// Update transport's product name to include model
self.transport["deviceModel"]["productName"] += " Model T";
// Break
break;
// Safe 3, Safe 5, or default
case "Safe 3":
case "Safe 5":
default:
// Update transport's product name to include model
self.transport["deviceModel"]["productName"] += " " + model;
// Break
break;
}
// Update product name
productName = self.transport["deviceModel"]["productName"];
// Update minimum compatible version
minimumCompatibleVersion = self.getMinimumCompatibleVersion();
// Check if firmware version is compatible
if(HardwareWallet.isCompatibleVersion(firmwareVersion, minimumCompatibleVersion) === true) {
// Get capabilities length
var capabilitiesLength = response[Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + modelLength];
// Check if response contains capabilities and passphrase always on device
if(response["length"] >= Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + modelLength + Uint8Array["BYTES_PER_ELEMENT"] + capabilitiesLength + Uint8Array["BYTES_PER_ELEMENT"]) {
// Get capabilities
var capabilities = response.subarray(Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + modelLength + Uint8Array["BYTES_PER_ELEMENT"], Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + modelLength + Uint8Array["BYTES_PER_ELEMENT"] + capabilitiesLength);
// Check if device is MimbleWimble Coin capable
if(capabilities.indexOf(HardwareWallet.MIMBLEWIMBLE_COIN_CAPABLE) !== Common.INDEX_NOT_FOUND) {
// Get initialized
var initialized = response[Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"]] !== 0;
// Check if device is initialized
if(initialized === true) {
// Get pin enabled
var pinEnabled = response[Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"]] !== 0;
// Get unlocked
var unlocked = response[Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"]] !== 0;
// Get passphrase enabled
var passphraseEnabled = response[Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"]] !== 0;
// Get passphrase always on device
var passphraseAlwaysOnDevice = response[Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint32Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + Uint8Array["BYTES_PER_ELEMENT"] + modelLength + Uint8Array["BYTES_PER_ELEMENT"] + capabilitiesLength] !== 0;
// Check if not set to fail on lock, pin isn't enabled, or device is unlocked
if(failOnLock === false || pinEnabled === false || unlocked === true) {
// Check if not set to fail on lock, passphrase isn't enabled, or passphrase always on device isn't enabled
if(failOnLock === false || passphraseEnabled === false || passphraseAlwaysOnDevice === false) {
// Return requesting getting the seed cookie from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_GET_SEED_COOKIE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT)
}, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_SEED_COOKIE_MESSAGE_TYPE, text, textArguments, allowUnlock, failOnLock, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === HardwareWallet.SEED_COOKIE_LENGTH) {
// Get seed cookie from response
self.seedCookie = response;
// Release exclusive lock
self.releaseExclusiveLock();
// Resolve
resolve();
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the seed cookie from that %1$x hardware wallet failed.'), [productName]));
});
}
// Catch errors
}).catch(function(error) {
// Return closing transport and catch errors
return self.transport.close().catch(function() {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Check if error is canceled
if(error === Common.CANCELED_ERROR) {
// Reject error
reject(error);
}
// Otherwise check if error is disconnected error
else if(error === HardwareWallet.DISCONNECTED_ERROR) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That hardware wallet was disconnected.')));
}
// Otherwise
else {
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"], HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the seed cookie from that %1$x hardware wallet failed.'), [productName]));
}
});
});
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That %1$x hardware wallet is locked. Unlock the hardware wallet to continue.'), [productName]));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That %1$x hardware wallet is locked. Unlock the hardware wallet to continue.'), [productName]));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That %1$x hardware wallet isn\'t initialized. Initialize the hardware wallet to continue.'), [productName]));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('The firmware on that %1$x hardware wallet isn\'t compatible. Install a compatible firmware on the hardware wallet to continue.'), [productName]));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the features from that %1$x hardware wallet failed.'), [productName]));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('The firmware on that %1$x hardware wallet isn\'t compatible. Update the firmware on the hardware wallet to version %2$v or newer to continue.'), [productName, minimumCompatibleVersion]));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the features from that %1$x hardware wallet failed.'), [productName]));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the features from that %1$x hardware wallet failed.'), [productName]));
});
}
}
// Otherwise
else {
// Return closing transport and catch errors
return self.transport.close().catch(function(error) {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the features from that %1$x hardware wallet failed.'), [productName]));
});
}
// Catch errors
}).catch(function(error) {
// Return closing transport and catch errors
return self.transport.close().catch(function() {
// Finally
}).finally(function() {
// Clear connected
self.connected = false;
// Set transport to no transport
self.transport = HardwareWallet.NO_TRANSPORT;
// Trigger disconnect event
$(self).trigger(HardwareWallet.DISCONNECT_EVENT);
// Release exclusive lock
self.releaseExclusiveLock();
// Check if error is canceled
if(error === Common.CANCELED_ERROR) {
// Reject error
reject(error);
}
// Otherwise check if error is disconnected error
else if(error === HardwareWallet.DISCONNECTED_ERROR) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That hardware wallet was disconnected.')));
}
// Otherwise
else {
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"], HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the features from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('You may need to disconnect and reconnect the hardware wallet to connect to it.')));
}
});
});
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
});
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('The hardware wallet is already connected.')));
}
});
});
}
// Get public key
getPublicKey() {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Get product name
var productName = self.transport["deviceModel"]["productName"];
// Return requesting getting the root public key from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_GET_ROOT_PUBLIC_KEY_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT)
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_ROOT_PUBLIC_KEY_MESSAGE_TYPE], HardwareWallet.NO_TEXT, [], false, true, true, Common.NO_CANCEL_OCCURRED).then(function(response) {
// Check if response is valid
if(response["length"] === Crypto.SECP256K1_PUBLIC_KEY_LENGTH && Secp256k1Zkp.isValidPublicKey(response) === true) {
// Get root public key from response
self.rootPublicKey = response;
// Release exclusive lock
self.releaseExclusiveLock();
// Resolve root public key
resolve(self.getRootPublicKey());
}
// Otherwise
else {
// Securely clear response
response.fill(0);
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the root public key from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the root public key from that %1$x hardware wallet failed.'), [productName]));
// Break
break;
}
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if error is disconnected error
if(error === HardwareWallet.DISCONNECTED_ERROR) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That hardware wallet was disconnected.')));
}
// Otherwise
else {
// Check transport's type
switch(self.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Check if user rejected the request
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.LEDGER_USER_REJECTED_MESSAGE_TYPE) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Exporting the root public key on that %1$x hardware wallet was denied.'), [productName]));
}
// Otherwise
else {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the root public key from that %1$x hardware wallet failed.'), [productName]) + Message.createText(Language.getDefaultTranslation('(?<=.) ')) + Message.createText(Language.getDefaultTranslation('Make sure that the correct app is open on the hardware wallet and that the hardware wallet isn\'t locked.')));
}
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Exporting the root public key on that %1$x hardware wallet was denied.'), [productName]));
// Return
return;
}
}
}
// Reject error
reject(Message.createText(Language.getDefaultTranslation('Getting the root public key from that %1$x hardware wallet failed.'), [productName]));
// Break
break;
}
}
});
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(Message.createText(Language.getDefaultTranslation('That hardware wallet was disconnected.')));
}
});
});
}
// Get commit
getCommit(value, identifier, switchType, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting getting the commit from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_GET_COMMITMENT_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Identifier
"Identifier": identifier.getValue(),
// Value
"Value": value,
// Switch type
"Switch Type": switchType
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_COMMITMENT_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] === Crypto.COMMIT_LENGTH && Secp256k1Zkp.isValidCommit(response) === true) {
// Get commit from response
var commit = response;
// Resolve commit
resolve(commit);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Get proof
getProof(value, identifier, switchType, message, proofBuilder, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting getting the commit from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_GET_COMMITMENT_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Identifier
"Identifier": identifier.getValue(),
// Value
"Value": value,
// Switch type
"Switch Type": switchType
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_COMMITMENT_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === Crypto.COMMIT_LENGTH && Secp256k1Zkp.isValidCommit(response) === true) {
// Get commit from response
var commit = response;
// Return getting rewind nonce from the proof builder
return proofBuilder.rewindNonce(commit).then(function(rewindNonce) {
// Try
try {
// Return requesting getting the proof components from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_GET_BULLETPROOF_COMPONENTS_MESSAGE_TYPE, message, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Message type
"Parameter One": message,
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Identifier
"Identifier": identifier.getValue(),
// Value
"Value": value,
// Switch type
"Switch Type": switchType
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_BULLETPROOF_COMPONENTS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] === Crypto.TAU_X_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH && (Secp256k1Zkp.isValidSecretKey(response.subarray(0, Crypto.TAU_X_LENGTH)) === true || Common.arraysAreEqual(response.subarray(0, Crypto.TAU_X_LENGTH), Crypto.ZERO_SECRET_KEY) === true) && Secp256k1Zkp.isValidPublicKey(response.subarray(Crypto.TAU_X_LENGTH, Crypto.TAU_X_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH)) === true && Secp256k1Zkp.isValidPublicKey(response.subarray(Crypto.TAU_X_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH, Crypto.TAU_X_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH)) === true) {
// Get tau x from response
var tauX = response.subarray(0, Crypto.TAU_X_LENGTH);
// Get t one from response
var tOne = response.subarray(Crypto.TAU_X_LENGTH, Crypto.TAU_X_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH);
// Get t two from response
var tTwo = response.subarray(Crypto.TAU_X_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH, Crypto.TAU_X_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH + Crypto.SECP256K1_PUBLIC_KEY_LENGTH);
// Try
try {
// Get proof message from identifier and switch type
var proofMessage = proofBuilder.proofMessage(identifier, switchType);
}
// Catch errors
catch(error) {
// Securely clear rewind nonce
rewindNonce.fill(0);
// Reject error
reject(error);
// Return
return;
}
// Check if creating proof with the tau x, t one, t two, commit, value, rewind nonce, and proof message was successful
var proof = Secp256k1Zkp.createBulletproofBlindless(tauX, tOne, tTwo, commit, value.toFixed(), rewindNonce, new Uint8Array([]), proofMessage);
if(proof !== Secp256k1Zkp.OPERATION_FAILED && Secp256k1Zkp.verifyBulletproof(proof, commit, new Uint8Array([])) === true) {
// Securely clear rewind nonce
rewindNonce.fill(0);
// Resolve proof
resolve(proof);
}
// Otherwise
else {
// Securely clear rewind nonce
rewindNonce.fill(0);
// Reject
reject();
}
}
// Otherwise
else {
// Securely clear rewind nonce
rewindNonce.fill(0);
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Securely clear rewind nonce
rewindNonce.fill(0);
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Securely clear rewind nonce
rewindNonce.fill(0);
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
});
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Get Tor address
getTorAddress(index, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting getting the Tor address from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_GET_ADDRESS_MESSAGE_TYPE, HardwareWallet.TOR_ADDRESS_TYPE, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Address type
"Parameter One": HardwareWallet.TOR_ADDRESS_TYPE,
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Index
"Index": new BigNumber(index)
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_ADDRESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] === ((self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE) ? Uint8Array["BYTES_PER_ELEMENT"] : 0) + Tor.ADDRESS_LENGTH) {
// Try
try {
// Get Tor address from response
var torAddress = (new TextDecoder("utf-8", {"fatal": true})).decode((self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE) ? response.subarray(Uint8Array["BYTES_PER_ELEMENT"]) : response);
// Get public key from Tor address
Tor.torAddressToPublicKey(torAddress);
}
// Catch errors
catch(error) {
// Reject error
reject(error);
// Return
return;
}
// Resolve Tor address
resolve(torAddress);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Verify Tor address
verifyTorAddress(index, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting verifying the Tor address on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_VERIFY_ADDRESS_MESSAGE_TYPE, HardwareWallet.TOR_ADDRESS_TYPE, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Address type
"Parameter One": HardwareWallet.TOR_ADDRESS_TYPE,
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Index
"Index": new BigNumber(index)
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.TREZOR_SUCCESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] === 0) {
// Resolve
resolve();
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Check if user rejected the request
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.LEDGER_USER_REJECTED_MESSAGE_TYPE) {
// Reject user rejected error
reject(HardwareWallet.USER_REJECTED_ERROR);
}
// Otherwise
else {
// Reject error
reject(error);
}
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject user rejected error
reject(HardwareWallet.USER_REJECTED_ERROR);
// Return
return;
}
}
}
// Reject error
reject(error);
// Break
break;
}
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Get MQS address
getMqsAddress(index, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting getting the MQS address from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_GET_ADDRESS_MESSAGE_TYPE, HardwareWallet.MQS_ADDRESS_TYPE, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Address type
"Parameter One": HardwareWallet.MQS_ADDRESS_TYPE,
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Index
"Index": new BigNumber(index)
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_ADDRESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] === ((self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE) ? Uint8Array["BYTES_PER_ELEMENT"] : 0) + Mqs.ADDRESS_LENGTH) {
// Try
try {
// Get MQS address from response
var mqsAddress = (new TextDecoder("utf-8", {"fatal": true})).decode((self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE) ? response.subarray(Uint8Array["BYTES_PER_ELEMENT"]) : response);
// Get public key from MQS address
Mqs.mqsAddressToPublicKey(mqsAddress, Consensus.getNetworkType() === Consensus.MAINNET_NETWORK_TYPE);
}
// Catch errors
catch(error) {
// Reject error
reject(error);
// Return
return;
}
// Resolve MQS address
resolve(mqsAddress);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Verify MQS address
verifyMqsAddress(index, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting verifying the MQS address on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_VERIFY_ADDRESS_MESSAGE_TYPE, HardwareWallet.MQS_ADDRESS_TYPE, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Address type
"Parameter One": HardwareWallet.MQS_ADDRESS_TYPE,
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Index
"Index": new BigNumber(index)
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.TREZOR_SUCCESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] === 0) {
// Resolve
resolve();
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Check if user rejected the request
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.LEDGER_USER_REJECTED_MESSAGE_TYPE) {
// Reject user rejected error
reject(HardwareWallet.USER_REJECTED_ERROR);
}
// Otherwise
else {
// Reject error
reject(error);
}
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject user rejected error
reject(HardwareWallet.USER_REJECTED_ERROR);
// Return
return;
}
}
}
// Reject error
reject(error);
// Break
break;
}
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Get Slatepack address
getSlatepackAddress(index, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting getting the Slatepack address from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_GET_ADDRESS_MESSAGE_TYPE, HardwareWallet.SLATEPACK_ADDRESS_TYPE, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Address type
"Parameter One": HardwareWallet.SLATEPACK_ADDRESS_TYPE,
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Index
"Index": new BigNumber(index)
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_ADDRESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] === ((self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE) ? Uint8Array["BYTES_PER_ELEMENT"] : 0) + Slatepack.ADDRESS_LENGTH) {
// Try
try {
// Get Slatepack address from response
var slatepackAddress = (new TextDecoder("utf-8", {"fatal": true})).decode((self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE) ? response.subarray(Uint8Array["BYTES_PER_ELEMENT"]) : response);
// Get public key from Slatepack address
Slatepack.slatepackAddressToPublicKey(slatepackAddress);
}
// Catch errors
catch(error) {
// Reject error
reject(error);
// Return
return;
}
// Resolve Slatepack address
resolve(slatepackAddress);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Verify Slatepack address
verifySlatepackAddress(index, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting verifying the Slatepack address on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_VERIFY_ADDRESS_MESSAGE_TYPE, HardwareWallet.SLATEPACK_ADDRESS_TYPE, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Address type
"Parameter One": HardwareWallet.SLATEPACK_ADDRESS_TYPE,
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Index
"Index": new BigNumber(index)
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.TREZOR_SUCCESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] === 0) {
// Resolve
resolve();
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Check if user rejected the request
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.LEDGER_USER_REJECTED_MESSAGE_TYPE) {
// Reject user rejected error
reject(HardwareWallet.USER_REJECTED_ERROR);
}
// Otherwise
else {
// Reject error
reject(error);
}
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject user rejected error
reject(HardwareWallet.USER_REJECTED_ERROR);
// Return
return;
}
}
}
// Reject error
reject(error);
// Break
break;
}
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Decrypt slate
decryptSlate(index, slate, address, nonce, salt = HardwareWallet.NO_SALT, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Check if slate is valid
if(slate["length"] > Slatepack.TAG_LENGTH) {
// Try
try {
// Return requesting start decrypting on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_START_DECRYPTING_SLATE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Index
"Index": new BigNumber(index),
// Nonce
"Nonce": nonce,
// Sender address or ephemeral X25519 public key
"Sender Address Or Ephemeral X25519 Public Key": (new TextEncoder()).encode(address),
// Salt or encrypted file key
"Salt Or Encrypted File Key": (salt !== HardwareWallet.NO_SALT) ? salt : new Uint8Array([]),
// Payload nonce
"Payload Nonce": new Uint8Array([])
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.TREZOR_SUCCESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === 0) {
// Get encrypted data from slate
var encryptedData = slate.subarray(0, slate["length"] - Slatepack.TAG_LENGTH);
// Set decrypt chunk
var decryptChunk = new Promise(function(resolve, reject) {
// Resolve
resolve();
});
// Initialize decrypting chunks
var decryptingChunks = [decryptChunk];
// Go through all of the encrypted data chunks
for(let i = 0; i < Math.ceil(encryptedData["length"] / HardwareWallet.ENCRYPTION_AND_DECRYPTION_MAXIMUM_CHUNK_SIZE); ++i) {
// Decrypt chunk after the previous chunk is decrypted
decryptChunk = decryptChunk.then(function() {
// Return promise
return new Promise(function(resolve, reject) {
// Return decrypting chunk on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_CONTINUE_DECRYPTING_SLATE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Data
"Encrypted Data": encryptedData.subarray(i * HardwareWallet.ENCRYPTION_AND_DECRYPTION_MAXIMUM_CHUNK_SIZE, Math.min(encryptedData["length"], i * HardwareWallet.ENCRYPTION_AND_DECRYPTION_MAXIMUM_CHUNK_SIZE + HardwareWallet.ENCRYPTION_AND_DECRYPTION_MAXIMUM_CHUNK_SIZE))
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_DECRYPTED_SLATE_DATA_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] > 0) {
// Get decrypted data chunk from response
var decryptedDataChunk = response;
// Resolve decrypted data chunk
resolve(decryptedDataChunk);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
});
// Catch errors
}).catch(function(error) {
// Return Promise
return new Promise(function(resolve, reject) {
// Reject error
reject(error);
});
});
// Append decrypting chunk to list
decryptingChunks.push(decryptChunk);
}
// Return decrypting all chunks
return Promise.all(decryptingChunks).then(function(decryptedDataChunks) {
// Get tag from slate
var tag = slate.subarray(slate["length"] - Slatepack.TAG_LENGTH);
// Return requesting finish decrypting on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_FINISH_DECRYPTING_SLATE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Tag
"Tag": tag
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_DECRYPTED_SLATE_AES_KEY_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] === Crypto.AES_KEY_LENGTH) {
// Get AES key from response
var aesKey = response;
// Initialize AES decrypt chunks
var aesDecryptChunks = [];
// Go through all decrypted chunks
for(var i = 1; i < decryptedDataChunks["length"]; ++i) {
// Get decrypted data chunk
let decryptedDataChunk = decryptedDataChunks[i];
// Append decrypting AES chunk to list
aesDecryptChunks.push(new Promise(function(resolve, reject) {
// Return performing AES decryption on decrypted data chunk using the AES key
return Crypto.aesDecrypt(decryptedDataChunk, aesKey).then(function(dataChunk) {
// Resolve data chunk
resolve(dataChunk);
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
}));
}
// Return waiting for all data chunks to be AES decrypted
return Promise.all(aesDecryptChunks).then(function(dataChunks) {
// Securely clear AES key
aesKey.fill(0);
// Resolve combined data chunks
resolve(Common.mergeArrays(dataChunks));
// Catch errors
}).catch(function(error) {
// Securely clear AES key
aesKey.fill(0);
// Reject error
reject(error);
});
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
});
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject
reject();
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Encrypt slate
encryptSlate(index, slate, address, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Check if slate is valid
if(slate["length"] !== 0) {
// Try
try {
// Return requesting start encrypting on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_START_ENCRYPTING_SLATE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Index
"Index": new BigNumber(index),
// Recipient address
"Recipient Address": (new TextEncoder()).encode(address)
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_ENCRYPTED_SLATE_NONCE_AND_SALT_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] >= Slatepack.NONCE_LENGTH) {
// Get nonce from response
var nonce = response.subarray(0, Slatepack.NONCE_LENGTH);
// Get decrypted data from slate
var decryptedData = slate;
// Set encrypt chunk
var encryptChunk = new Promise(function(resolve, reject) {
// Resolve
resolve(new Uint8Array([]));
});
// Initialize encrypting chunks
var encryptingChunks = [encryptChunk];
// Go through all of the decrypted data chunks
for(let i = 0; i < Math.ceil(decryptedData["length"] / HardwareWallet.ENCRYPTION_AND_DECRYPTION_MAXIMUM_CHUNK_SIZE); ++i) {
// Encrypt chunk after the previous chunk is encrypted
encryptChunk = encryptChunk.then(function() {
// Return promise
return new Promise(function(resolve, reject) {
// Return encrypting chunk on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_CONTINUE_ENCRYPTING_SLATE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Data
"Data": decryptedData.subarray(i * HardwareWallet.ENCRYPTION_AND_DECRYPTION_MAXIMUM_CHUNK_SIZE, Math.min(decryptedData["length"], i * HardwareWallet.ENCRYPTION_AND_DECRYPTION_MAXIMUM_CHUNK_SIZE + HardwareWallet.ENCRYPTION_AND_DECRYPTION_MAXIMUM_CHUNK_SIZE))
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_ENCRYPTED_SLATE_DATA_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] > 0) {
// Get encrypted data chunk from response
var encryptedDataChunk = response;
// Resolve encrypted data chunk
resolve(encryptedDataChunk);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
});
// Catch errors
}).catch(function(error) {
// Return Promise
return new Promise(function(resolve, reject) {
// Reject error
reject(error);
});
});
// Append encrypting chunk to list
encryptingChunks.push(encryptChunk);
}
// Return encrypting all chunks
return Promise.all(encryptingChunks).then(function(encryptedDataChunks) {
// Return requesting finish encrypting on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_FINISH_ENCRYPTING_SLATE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_DATA, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_ENCRYPTED_SLATE_TAG_AND_SIGNATURE_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check if response is valid
if(response["length"] >= Slatepack.TAG_LENGTH) {
// Get tag from response
var tag = response.subarray(0, Slatepack.TAG_LENGTH);
// Append the tag to the encrypted data chunks
var encryptedData = Common.mergeArrays([
// Encrypted data chunks
Common.mergeArrays(encryptedDataChunks),
// tag
tag
]);
// Resolve nonce and encrypted data
resolve([
// Nonce
nonce,
// Encrypted data
encryptedData
]);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
});
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject
reject();
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Start transaction
startTransaction(index, output, input, fee, secretNonceIndex = HardwareWallet.NO_SECRET_NONCE_INDEX, address = HardwareWallet.NO_ADDRESS, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Return obtainined exclusive lock
return self.obtainExclusiveLock().then(function() {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting starting transaction on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_START_TRANSACTION_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Coin type
"Coin Type": Consensus.getWalletType(),
// Network type
"Network Type": Consensus.getNetworkType(),
// Account
"Account": new BigNumber(HardwareWallet.ACCOUNT),
// Index
"Index": new BigNumber(index),
// Output
"Output": output,
// Input
"Input": input,
// Fee
"Fee": fee,
// Secret nonce index
"Secret Nonce Index": secretNonceIndex,
// Address
"Address": (address !== HardwareWallet.NO_ADDRESS) ? (new TextEncoder()).encode(address) : new Uint8Array([])
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.TREZOR_SUCCESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === 0) {
// Resolve
resolve();
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch error
catch(error) {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject error
reject(error);
}
}
// Otherwise
else {
// Release exclusive lock
self.releaseExclusiveLock();
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
});
});
}
// Include output in transaction
includeOutputInTransaction(value, identifier, switchType, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting including output in transaction on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_CONTINUE_TRANSACTION_INCLUDE_OUTPUT_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Identifier
"Identifier": identifier.getValue(),
// Value
"Value": value,
// Switch type
"Switch Type": switchType
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.TREZOR_SUCCESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === 0) {
// Resolve
resolve();
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Reject error
reject(error);
}
}
// Otherwise
else {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
}
// Otherwise
else {
// Reject
reject();
}
});
}
// Include input in transaction
includeInputInTransaction(value, identifier, switchType, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Return requesting including input in transaction on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_CONTINUE_TRANSACTION_INCLUDE_INPUT_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Identifier
"Identifier": identifier.getValue(),
// Value
"Value": value,
// Switch type
"Switch Type": switchType
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.TREZOR_SUCCESS_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === 0) {
// Resolve
resolve();
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Catch errors
catch(error) {
// Reject error
reject(error);
}
}
// Otherwise
else {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
}
// Otherwise
else {
// Reject
reject();
}
});
}
// Apply offset to transaction
applyOffsetToTransaction(offset, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Check if connected
if(self.isConnected() === true) {
// Return requesting applying an offset to the transaction on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_CONTINUE_TRANSACTION_APPLY_OFFSET_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Offset
"Offset": offset
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_TRANSACTION_SECRET_NONCE_INDEX_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === 0 || response["length"] === 1) {
// Get secret nonce index from response
var secretNonceIndex = (response["length"] === 1) ? response[0] : HardwareWallet.NO_SECRET_NONCE_INDEX;
// Resolve secret nonce index
resolve(secretNonceIndex);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Otherwise
else {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
}
// Otherwise
else {
// Reject
reject();
}
});
}
// Get transaction public key
getTransactionPublicKey(text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Check if connected
if(self.isConnected() === true) {
// Return requesting getting the transaction public key from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_CONTINUE_TRANSACTION_GET_PUBLIC_KEY_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_DATA, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_TRANSACTION_PUBLIC_KEY_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === Crypto.SECP256K1_PUBLIC_KEY_LENGTH && Secp256k1Zkp.isValidPublicKey(response) === true) {
// Get public key from response
var publicKey = response;
// Resolve public key
resolve(publicKey);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Otherwise
else {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
}
// Otherwise
else {
// Reject
reject();
}
});
}
// Get transaction public nonce
getTransactionPublicNonce(text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Check if connected
if(self.isConnected() === true) {
// Return requesting getting the transaction public nonce from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_CONTINUE_TRANSACTION_GET_PUBLIC_NONCE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_DATA, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_TRANSACTION_PUBLIC_NONCE_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === Crypto.SECP256K1_PUBLIC_KEY_LENGTH && Secp256k1Zkp.isValidPublicKey(response) === true) {
// Get public nonce from response
var publicNonce = response;
// Resolve public nonce
resolve(publicNonce);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Otherwise
else {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
}
// Otherwise
else {
// Reject
reject();
}
});
}
// Get transaction message signature
getTransactionMessageSignature(message, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Check if connected
if(self.isConnected() === true) {
// Return requesting getting the transaction message signature from the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_CONTINUE_TRANSACTION_GET_MESSAGE_SIGNATURE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Message
"Message": (new TextEncoder()).encode(message)
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_TRANSACTION_MESSAGE_SIGNATURE_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] === Crypto.SINGLE_SIGNER_SIGNATURE_LENGTH && Secp256k1Zkp.isValidSingleSignerSignature(response) === true) {
// Get message signature from response
var messageSignature = response;
// Resolve signature
resolve(messageSignature);
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check transport's type
switch(self.transport.type) {
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject canceled error
reject(Common.CANCELED_ERROR);
// Return
return;
}
}
}
// Break
break;
}
// Reject error
reject(error);
});
}
// Otherwise
else {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
}
// Otherwise
else {
// Reject
reject();
}
});
}
// Get transaction information
getTransactionInformation(publicNonce, publicKey, features, lockHeight = Slate.NO_LOCK_HEIGHT, relativeHeight = Slate.NO_RELATIVE_HEIGHT, kernelCommit = HardwareWallet.NO_KERNEL_COMMIT, address = HardwareWallet.NO_ADDRESS, receiverSignature = Slate.NO_RECEIVER_SIGNATURE, text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Check if connected
if(self.isConnected() === true) {
// Try
try {
// Check features
switch(features) {
// Coinbase or plain features
case SlateKernel.COINBASE_FEATURES:
case SlateKernel.PLAIN_FEATURES:
// Set kernel information to features
var kernelInformation = new Uint8Array([features]);
// Break
break;
// Height locked features
case SlateKernel.HEIGHT_LOCKED_FEATURES:
// Set kernel information to features followed by the lock height
var kernelInformation = Common.mergeArrays([
// Features
new Uint8Array([features]),
// Lock height
lockHeight.toBytes(BigNumber.LITTLE_ENDIAN, Common.BYTES_IN_A_UINT64)
]);
// Break
break;
// No recent duplicate features
case SlateKernel.NO_RECENT_DUPLICATE_FEATURES:
// Set kernel features to features followed by the relative height
var kernelInformation = Common.mergeArrays([
// Features
new Uint8Array([features]),
// Relative height
relativeHeight.toBytes(BigNumber.LITTLE_ENDIAN, Common.BYTES_IN_A_UINT16)
]);
// Break
break;
}
}
// Catch errors
catch(error) {
// Reject error
reject(error);
// Return
return;
}
// Check wallet type
switch(Consensus.getWalletType()) {
// MWC wallet
case Consensus.MWC_WALLET_TYPE:
// Check if address exists
if(address !== HardwareWallet.NO_ADDRESS) {
// Check address length
switch(address["length"]) {
// Tor address length
case Tor.ADDRESS_LENGTH:
// Set address type
var addressType = HardwareWallet.TOR_ADDRESS_TYPE;
// Break
break;
// MQS address length
case Mqs.ADDRESS_LENGTH:
// Set address type
var addressType = HardwareWallet.MQS_ADDRESS_TYPE;
// Break
break;
}
}
// Otherwise
else {
// Set address type
var addressType = HardwareWallet.MQS_ADDRESS_TYPE;
}
// Break
break;
// GRIN wallet
case Consensus.GRIN_WALLET_TYPE:
// Set address type
var addressType = HardwareWallet.SLATEPACK_ADDRESS_TYPE;
// Break
break;
// EPIC wallet
case Consensus.EPIC_WALLET_TYPE:
// Set address type
var addressType = HardwareWallet.TOR_ADDRESS_TYPE;
// Break
break;
}
// Return requesting finishing the transaction on the hardware wallet
return self.send(HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_FINISH_TRANSACTION_MESSAGE_TYPE, addressType, HardwareWallet.NO_PARAMETER, {
// Address type
"Parameter One": addressType,
// Public nonce
"Public Nonce": publicNonce,
// Public key
"Public Key": publicKey,
// Kernel information
"Kernel Information": kernelInformation,
// Kernel commitment
"Kernel Commitment": (kernelCommit !== HardwareWallet.NO_KERNEL_COMMIT) ? kernelCommit : new Uint8Array([]),
// Payment proof
"Payment Proof": (receiverSignature !== Slate.NO_RECEIVER_SIGNATURE) ? receiverSignature : new Uint8Array([])
}, [HardwareWalletDefinitions.LEDGER_SUCCESS_MESSAGE_TYPE, HardwareWalletDefinitions.MIMBLEWIMBLE_COIN_TRANSACTION_SIGNATURE_AND_PAYMENT_PROOF_MESSAGE_TYPE], text, textArguments, allowUnlock, false, preventMessages, cancelOccurred).then(function(response) {
// Check if response is valid
if(response["length"] >= Crypto.SINGLE_SIGNER_SIGNATURE_LENGTH && Secp256k1Zkp.isValidSingleSignerSignature(response.subarray(0, Crypto.SINGLE_SIGNER_SIGNATURE_LENGTH)) === true) {
// Get signature from response
var signature = response.subarray(0, Crypto.SINGLE_SIGNER_SIGNATURE_LENGTH);
// Get payment proof from response
var paymentProof = (response["length"] > Crypto.SINGLE_SIGNER_SIGNATURE_LENGTH) ? response.subarray(Crypto.SINGLE_SIGNER_SIGNATURE_LENGTH) : HardwareWallet.NO_PAYMENT_PROOF;
// Check if payment proof is valid
if(paymentProof === HardwareWallet.NO_PAYMENT_PROOF || paymentProof["length"] <= Crypto.MAXIMUM_MESSAGE_HASH_SIGNATURE_LENGTH || paymentProof["length"] === Crypto.ED25519_SIGNATURE_LENGTH) {
// Resolve transaction information
resolve([
// Signature
signature,
// Payment proof
paymentProof
]);
}
// Otherwise
else {
// Reject
reject();
}
}
// Otherwise
else {
// Reject
reject();
}
// Catch errors
}).catch(function(error) {
// Check transport's type
switch(self.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Check if user rejected the request
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.LEDGER_USER_REJECTED_MESSAGE_TYPE) {
// Reject user rejected error
reject(HardwareWallet.USER_REJECTED_ERROR);
}
// Otherwise
else {
// Reject error
reject(error);
}
// Break
break;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Reject user rejected error
reject(HardwareWallet.USER_REJECTED_ERROR);
// Return
return;
}
}
}
// Reject error
reject(error);
// Break
break;
}
});
}
// Otherwise
else {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
}
// Otherwise
else {
// Reject
reject();
}
});
}
// Cancel transaction
cancelTransaction() {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Release exclusive lock
self.releaseExclusiveLock();
// Resolve
resolve();
}
// Otherwise
else {
// Reject
reject();
}
});
}
// Complete transaction
completeTransaction() {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Release exclusive lock
self.releaseExclusiveLock();
// Resolve
resolve();
}
// Otherwise
else {
// Reject
reject();
}
});
}
// Set wallet key path
setWalletKeyPath(walletKeyPath) {
// Set wallet key path
this.walletKeyPath = walletKeyPath;
}
// Get wallet key path
getWalletKeyPath() {
// Return wallet key path
return this.walletKeyPath;
}
// Get available hardware wallet descriptors
static getAvailableHardwareWalletDescriptors() {
// Return promise
return new Promise(function(resolve, reject) {
// Return getting available hardware wallet descriptors
return HardwareWalletUsbTransport.list().then(function(availableHardwareWalletDescriptors) {
// Resolve available hardware wallet descriptors
resolve(availableHardwareWalletDescriptors);
// Catch errors
}).catch(function(error) {
// Reject error
reject(error);
});
});
}
// Is supported
static isSupported() {
// Return if USB or Bluetooth are supported
return "usb" in navigator === true || "bluetooth" in navigator === true;
}
// Any hardware wallet descriptor
static get ANY_HARDWARE_WALLET_DESCRIPTOR() {
// Return any hardware wallet descriptor
return null;
}
// Ledger hardware type
static get LEDGER_HARDWARE_TYPE() {
// Return Ledger hardware type
return 0;
}
// Trezor hardware type
static get TREZOR_HARDWARE_TYPE() {
// Return Trezor hardware type
return HardwareWallet.LEDGER_HARDWARE_TYPE + 1;
}
// Disconnect event
static get DISCONNECT_EVENT() {
// Return disconnect event
return "HardwareWalletDisconnectEvent";
}
// Before disconnect event
static get BEFORE_DISCONNECT_EVENT() {
// Return before disconnect event
return "HardwareWalletBeforeDisconnectEvent";
}
// Unlock event
static get UNLOCK_EVENT() {
// Return unlock event
return "HardwareWalletUnlockEvent";
}
// Device cancel event
static get DEVICE_CANCEL_EVENT() {
// Return device cancel event
return "HardwareWalletDeviceCancelEvent";
}
// Transaction information signature index
static get TRANSACTION_INFORMATION_SIGNATURE_INDEX() {
// Return transaction information signature index
return 0;
}
// Transaction information payment proof index
static get TRANSACTION_INFORMATION_PAYMENT_PROOF_INDEX() {
// Return transaction information payment proof index
return HardwareWallet.TRANSACTION_INFORMATION_SIGNATURE_INDEX + 1;
}
// No text
static get NO_TEXT() {
// Return no text
return null;
}
// Disconnected error
static get DISCONNECTED_ERROR() {
// Return disconnected error
return "HardwareWalletDisconnectedError";
}
// User rejected error
static get USER_REJECTED_ERROR() {
// Return user rejected error
return "HardwareWalletUserRejectedError";
}
// Encrypted slate nonce index
static get ENCRYPTED_SLATE_NONCE_INDEX() {
// Return encrypted slate nonce index
return 0;
}
// Encrypted slate data index
static get ENCRYPTED_SLATE_DATA_INDEX() {
// Return encrypted slate data index
return HardwareWallet.ENCRYPTED_SLATE_NONCE_INDEX + 1;
}
// Sending transaction message
static get SENDING_TRANSACTION_MESSAGE() {
// Return sending transaction message
return 0;
}
// Receiving transaction message
static get RECEIVING_TRANSACTION_MESSAGE() {
// Return receiving transaction message
return HardwareWallet.SENDING_TRANSACTION_MESSAGE + 1;
}
// Creating coinbase message
static get CREATING_COINBASE_MESSAGE() {
// Return creating coinbase message
return HardwareWallet.RECEIVING_TRANSACTION_MESSAGE + 1;
}
// USB connection type
static get USB_CONNECTION_TYPE() {
// Return USB connection type
return 0;
}
// Bluetooth connection type
static get BLUETOOTH_CONNECTION_TYPE() {
// Return Bluetooth connection type
return HardwareWallet.USB_CONNECTION_TYPE + 1;
}
// No secret nonce index
static get NO_SECRET_NONCE_INDEX() {
// Return no secret nonce index
return 0;
}
// Private
// Obtain exclusive lock
obtainExclusiveLock() {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if exclusive lock is locked
if(self.exclusiveLockObtained === true) {
// Get current exclusive lock release event index
var index = self.exclusiveLockReleaseEventIndex++;
// Check if current current exclusive lock release event index is at the max safe integer
if(index === Number.MAX_SAFE_INTEGER)
// Reset current exclusive lock release event index
self.exclusiveLockReleaseEventIndex = 0;
// Exclusive lock release index event
$(self).on(HardwareWallet.EXCLUSIVE_LOCK_RELEASE_EVENT + "." + index.toFixed(), function() {
// Check if exclusive lock isn't locked
if(self.exclusiveLockObtained === false) {
// Turn off exclusive lock release index event
$(self).off(HardwareWallet.EXCLUSIVE_LOCK_RELEASE_EVENT + "." + index.toFixed());
// Lock exclusive lock
self.exclusiveLockObtained = true;
// Resolve
resolve();
}
});
}
// Otherwise
else {
// Lock exclusive lock
self.exclusiveLockObtained = true;
// Resolve
resolve();
}
});
}
// Release exclusive lock
releaseExclusiveLock() {
// Check if exclusive lock is locked
if(this.exclusiveLockObtained === true) {
// Set self
var self = this;
// Set timeout
setTimeout(function() {
// Unlock exclusive lock
self.exclusiveLockObtained = false;
// Trigger exclusive lock release event
$(self).trigger(HardwareWallet.EXCLUSIVE_LOCK_RELEASE_EVENT);
}, 0);
}
}
// Send
send(messageType, parameterOne, parameterTwo, data = HardwareWallet.NO_DATA, allowedResponseTypes = [], text = HardwareWallet.NO_TEXT, textArguments = [], allowUnlock = false, failOnLock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED, forceSend = false, preventUnlockMessageDone = false, unlockMessageShown = false) {
// Set self
var self = this;
// Return promise
return new Promise(function(resolve, reject) {
// Check if cancel didn't occur or force sending
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false || forceSend === true) {
// Return performing the instruction on the hardware wallet
return self.transport.send(messageType, parameterOne, parameterTwo, self.encode(messageType, data)).then(function(response) {
// Check if cancel didn't occur or force sending and unlock message isn't shown
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false || (forceSend === true && unlockMessageShown === false)) {
// Check if the hardware wallet is locked and not set to fail on lock
if((self.transport.type === HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE && (response["Message Type"] === HardwareWalletDefinitions.LEDGER_APP_LOCKED_MESSAGE_TYPE || response["Message Type"] === HardwareWalletDefinitions.LEDGER_DEVICE_LOCKED_MESSAGE_TYPE)) && failOnLock === false) {
// Set locked
self.locked = true;
// Initialize canceled
var canceled = false;
// Check if showing message
if(text !== HardwareWallet.NO_TEXT) {
// Show hardware wallet unlock message
var showMessage = self.application.showHardwareWalletUnlockMessage(self, text, textArguments, allowUnlock, preventMessages, cancelOccurred);
// Catch errors while showing the message
showMessage.catch(function(error) {
// Set canceled
canceled = true;
});
}
// Resend
var resend = function() {
// Return promise
return new Promise(function(resolve, reject) {
// Set timeout
setTimeout(function() {
// Check if canceled
if(canceled === true) {
// Clear locked
self.locked = false;
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
// Otherwise
else {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Return performing the instruction on the hardware wallet
return self.transport.send(messageType, parameterOne, parameterTwo, self.encode(messageType, data)).then(function(response) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if the hardware wallet is locked and not set to fail on lock
if((self.transport.type === HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE && (response["Message Type"] === HardwareWalletDefinitions.LEDGER_APP_LOCKED_MESSAGE_TYPE || response["Message Type"] === HardwareWalletDefinitions.LEDGER_DEVICE_LOCKED_MESSAGE_TYPE)) && failOnLock === false) {
// Return resend
return resend().then(function(response) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Resolve response
resolve(response);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
// Catch error
}).catch(function(error) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Reject error
reject(error);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
});
}
// Otherwise check if response type isn't allowed
else if(response["Message Type"] !== ((Array.isArray(allowedResponseTypes) === true) ? allowedResponseTypes[self.transport.type] : allowedResponseTypes)) {
// Clear locked
self.locked = false;
// Check if response data isn't used
if(response["Message Type"] !== HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Securely clear response data
response["Data"].fill(0);
}
// Reject response
reject(response);
}
// Otherwise
else {
// Clear locked
self.locked = false;
// Try
try {
// Decode response
var decodedResponse = self.decode(response["Message Type"], response["Data"]);
}
// Catch errors
catch(error) {
// Securely clear response data
response["Data"].fill(0);
// Reject error
reject(error);
// Return
return;
}
// Securely clear response data
response["Data"].fill(0);
// Trigger unlock event
$(self).trigger(HardwareWallet.UNLOCK_EVENT);
// Check if showing message and not canceled
if(text !== HardwareWallet.NO_TEXT && canceled === false) {
// Return waiting until showing message has finished
return showMessage.then(function() {
// Resolve decoded response
resolve(decodedResponse);
// Catch errors
}).catch(function() {
// Resolve decoded response
resolve(decodedResponse);
});
}
// Otherwise
else {
// Resolve decoded response
resolve(decodedResponse);
}
}
}
// Otherwise
else {
// Securely clear response data
response["Data"].fill(0);
// Clear locked
self.locked = false;
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
// Catch errors
}).catch(function(error) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if error is that the device was disconnected
if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.NETWORK_ERROR_CODE) || ("name" in error === true && error["name"] === "NetworkError"))) {
// Clear locked
self.locked = false;
// Trigger before disconnect event
$(self).trigger(HardwareWallet.BEFORE_DISCONNECT_EVENT);
// Check if showing message and not canceled
if(text !== HardwareWallet.NO_TEXT && canceled === false) {
// Return waiting until showing message has finished
return showMessage.then(function() {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
// Catch errors
}).catch(function() {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
});
}
// Otherwise
else {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
}
// Otherwise
else {
// Clear locked
self.locked = false;
// Reject error
reject(error);
}
}
// Otherwise
else {
// Clear locked
self.locked = false;
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
});
}
// Otherwise
else {
// Clear locked
self.locked = false;
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
}
}, HardwareWallet.RESEND_REQUEST_DELAY_MILLISECONDS);
});
};
// Return resend
return resend().then(function(response) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Resolve response
resolve(response);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
// Catch error
}).catch(function(error) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Reject error
reject(error);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
});
}
// Otherwise check if hardware wallet requires button acknowledgment
else if(self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE && response["Message Type"] === HardwareWalletDefinitions.TREZOR_BUTTON_REQUEST_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode response
var decodedResponse = self.decode(response["Message Type"], response["Data"]);
}
// Catch errors
catch(error) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if device is locked or needs a passphrase and not set to fail on lock
if(decodedResponse["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedResponse[0] === HardwareWalletDefinitions.TREZOR_PIN_ENTRY_BUTTON_REQUEST_TYPE || decodedResponse[0] === HardwareWalletDefinitions.TREZOR_PASSPHRASE_ENTRY_BUTTON_REQUEST_TYPE) && failOnLock === false) {
// Check if unlock message isn't shown
if(unlockMessageShown === false) {
// Set locked
self.locked = true;
}
// Initialize canceled
var canceled = false;
// Initialize prevent cancel
var preventCancel = false;
// Check if showing message and unlock message isn't shown
if(text !== HardwareWallet.NO_TEXT && unlockMessageShown === false) {
// Show hardware wallet unlock message
var showMessage = self.application.showHardwareWalletUnlockMessage(self, text, textArguments, allowUnlock, preventMessages, cancelOccurred);
// Catch errors while showing the message
showMessage.catch(function(error) {
// Check if not preventing cancel
if(preventCancel === false) {
// Set canceled
canceled = true;
// Clear locked
self.locked = false;
// Reset transport device and catch errors
self.transport.device.reset().catch(function(error) {
// Finally
}).finally(function() {
// Reject canceled error
reject(Common.CANCELED_ERROR);
});
}
});
}
// Return sending button acknowledge response
return self.send(HardwareWalletDefinitions.TREZOR_BUTTON_ACKNOWLEDGE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_DATA, allowedResponseTypes, text, textArguments, allowUnlock, failOnLock, preventMessages, function() {
// Return if cancel occurred or canceled
return (cancelOccurred !== Common.NO_CANCEL_OCCURRED && cancelOccurred() === true) || canceled === true;
}, true, preventUnlockMessageDone, true).then(function(response) {
// Check if not canceled
if(canceled === false) {
// Set prevent cancel
preventCancel = true;
// Check if unlock message isn't shown
if(unlockMessageShown === false) {
// Clear locked
self.locked = false;
}
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if unlock message isn't shown
if(unlockMessageShown === false) {
// Trigger unlock event
$(self).trigger(HardwareWallet.UNLOCK_EVENT);
}
// Check if showing message and unlock message isn't shown
if(text !== HardwareWallet.NO_TEXT && unlockMessageShown === false) {
// Return waiting until showing message has finished
return showMessage.then(function() {
// Resolve response
resolve(response);
// Catch errors
}).catch(function() {
// Resolve response
resolve(response);
});
}
// Otherwise
else {
// Resolve response
resolve(response);
}
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
}
// Catch errors
}).catch(function(error) {
// Check if not canceled
if(canceled === false) {
// Set prevent cancel
preventCancel = true;
// Check if unlock message isn't shown
if(unlockMessageShown === false) {
// Clear locked
self.locked = false;
}
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if unlock message isn't shown
if(unlockMessageShown === false) {
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if user rejected the request
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_ACTION_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE)) {
// Trigger device cancel event
$(self).trigger(HardwareWallet.DEVICE_CANCEL_EVENT);
}
}
}
}
// Reject error
reject(error);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
}
});
}
}
// Return sending button acknowledge response
return self.send(HardwareWalletDefinitions.TREZOR_BUTTON_ACKNOWLEDGE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_DATA, allowedResponseTypes, text, textArguments, allowUnlock, failOnLock, preventMessages, cancelOccurred, true).then(function(response) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Resolve response
resolve(response);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
// Catch errors
}).catch(function(error) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Reject error
reject(error);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
});
}
// Otherwise check if hardware wallet requires passphrase acknowledgment
else if(self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE && response["Message Type"] === HardwareWalletDefinitions.TREZOR_PASSPHRASE_REQUEST_MESSAGE_TYPE) {
// Return sending passphrase acknowledge response
return self.send(HardwareWalletDefinitions.TREZOR_PASSPHRASE_ACKNOWLEDGE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Passphrase
"Passphrase": ""
}, allowedResponseTypes, text, textArguments, allowUnlock, failOnLock, preventMessages, cancelOccurred, true).then(function(response) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Resolve response
resolve(response);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
// Catch errors
}).catch(function(error) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Reject error
reject(error);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
});
}
// Otherwise check if hardware wallet requires pin matrix acknowledgment
else if(self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE && response["Message Type"] === HardwareWalletDefinitions.TREZOR_PIN_MATRIX_REQUEST_MESSAGE_TYPE) {
// Check if not set to fail on lock and text exists
if(failOnLock === false && text !== HardwareWallet.NO_TEXT) {
// Set locked
self.locked = true;
// Initialize disconnected
var disconnected = false;
// Transport on disconnect
var disconnectCallback = self.transport.on("disconnect", function() {
// Set disconnected
disconnected = true;
// Clear locked
self.locked = false;
// Trigger before disconnect event
$(self).trigger(HardwareWallet.BEFORE_DISCONNECT_EVENT);
});
// Return showing hardware wallet unlock message
return self.application.showHardwareWalletUnlockMessage(self, text, textArguments, allowUnlock, preventMessages, cancelOccurred).then(function(alphabeticPin) {
// Check if disconnected
if(disconnected === true) {
// Check if not preventing unlock message done and not preventing messages
if(preventUnlockMessageDone === false && preventMessages === false) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred).then(function() {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
});
}
// Otherwise
else {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
}
// Otherwise
else {
// Turn off transport on disconnect
self.transport.off("disconnect", disconnectCallback);
// Clear locked
self.locked = false;
// Return sending pin matrix acknowledge response
return self.send(HardwareWalletDefinitions.TREZOR_PIN_MATRIX_ACKNOWLEDGE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Pin
"Pin": HardwareWallet.alphabeticPinToPin(Common.removeWhitespace(alphabeticPin))
}, allowedResponseTypes, text, textArguments, allowUnlock, failOnLock, preventMessages, cancelOccurred, true, true).then(function(response) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if not preventing unlock message done
if(preventUnlockMessageDone === false) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred).then(function() {
// Resolve response
resolve(response);
});
}
// Otherwise
else {
// Resolve response
resolve(response);
}
}
// Otherwise
else {
// Check if not preventing unlock message done
if(preventUnlockMessageDone === false) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred).then(function() {
// Reject canceled error
reject(Common.CANCELED_ERROR);
});
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
}
// Catch errors
}).catch(function(error) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if failure occurred
if(Object.isObject(error) === true && "Message Type" in error === true && error["Message Type"] === HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Initialize error occurred
var errorOccurred = false;
// Try
try {
// Decode error
var decodedError = self.decode(error["Message Type"], error["Data"]);
}
// Catch errors
catch(decodeError) {
// Set error occurred
errorOccurred = true;
}
// Check if an error didn't occur
if(errorOccurred === false) {
// Check if pin was incorrect
if(decodedError["length"] >= Uint8Array["BYTES_PER_ELEMENT"] && (decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE || decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_INVALID_FAILURE_TYPE)) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred, false).then(function() {
// Check if not preventing messages
if(preventMessages === false) {
// Message before replace hardware wallet event
$(self.application.message).on(Message.BEFORE_REPLACE_EVENT + ".hardwareWallet", function(event, messageType, messageData) {
// Check if message type is hardware wallet disconnect message
if(messageType === Application.HARDWARE_WALLET_DISCONNECT_MESSAGE) {
// Cancel replacing message
self.application.message.cancelReplace();
// Return false to stop other replace message
return false;
}
});
}
// Return resending message
return self.send(messageType, parameterOne, parameterTwo, data, allowedResponseTypes, (decodedError[0] === HardwareWalletDefinitions.TREZOR_PIN_CANCELED_FAILURE_TYPE) ? Language.getDefaultTranslation('Invalid pin.') : Language.getDefaultTranslation('Incorrect pin.'), [], allowUnlock, failOnLock, true, cancelOccurred, true, true).then(function(response) {
// Turn off message before replace hardware wallet event
$(self.application.message).off(Message.BEFORE_REPLACE_EVENT + ".hardwareWallet");
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if not preventing unlock message done
if(preventUnlockMessageDone === false) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred).then(function() {
// Resolve response
resolve(response);
});
}
// Otherwise
else {
// Resolve response
resolve(response);
}
}
// Otherwise
else {
// Check if not preventing unlock message done
if(preventUnlockMessageDone === false) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred).then(function() {
// Reject canceled error
reject(Common.CANCELED_ERROR);
});
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
}
// Catch errors
}).catch(function(error) {
// Turn off message before replace hardware wallet event
$(self.application.message).off(Message.BEFORE_REPLACE_EVENT + ".hardwareWallet");
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if not preventing unlock message done and not preventing messages
if(preventUnlockMessageDone === false && preventMessages === false) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred).then(function() {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Reject error
reject(error);
}
}
// Otherwise
else {
// Check if not preventing unlock message done
if(preventUnlockMessageDone === false) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred).then(function() {
// Reject canceled error
reject(Common.CANCELED_ERROR);
});
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
}
});
});
}
}
}
// Check if not preventing unlock message done
if(preventUnlockMessageDone === false) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred).then(function() {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Reject error
reject(error);
}
}
// Otherwise
else {
// Check if not preventing unlock message done
if(preventUnlockMessageDone === false) {
// Return hiding application hardware unlock message
return self.application.hardwareWalletUnlockMessageDone(preventMessages, cancelOccurred).then(function() {
// Reject canceled error
reject(Common.CANCELED_ERROR);
});
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
}
});
}
// Catch errors
}).catch(function(error) {
// Check if disconnected
if(disconnected === true) {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
// Otherwise
else {
// Turn off transport on disconnect
self.transport.off("disconnect", disconnectCallback);
// Clear locked
self.locked = false;
// Return sending pin matrix acknowledge response
return self.send(HardwareWalletDefinitions.TREZOR_PIN_MATRIX_ACKNOWLEDGE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Pin
"Pin": HardwareWallet.INVALID_PIN
}, allowedResponseTypes, text, textArguments, allowUnlock, failOnLock, preventMessages, cancelOccurred, true).then(function(response) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Reject error
reject(error);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
// Catch errors
}).catch(function() {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Reject error
reject(error);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
});
}
});
}
// Otherwise
else {
// Return sending pin matrix acknowledge response
return self.send(HardwareWalletDefinitions.TREZOR_PIN_MATRIX_ACKNOWLEDGE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Pin
"Pin": HardwareWallet.INVALID_PIN
}, allowedResponseTypes, text, textArguments, allowUnlock, failOnLock, preventMessages, cancelOccurred, true).then(function(response) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Resolve response
resolve(response);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
// Catch errors
}).catch(function(error) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Reject error
reject(error);
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
});
}
}
// Otherwise check if response type isn't allowed
else if(response["Message Type"] !== ((Array.isArray(allowedResponseTypes) === true) ? allowedResponseTypes[self.transport.type] : allowedResponseTypes)) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if response data isn't used
if(response["Message Type"] !== HardwareWalletDefinitions.TREZOR_FAILURE_MESSAGE_TYPE) {
// Securely clear response data
response["Data"].fill(0);
}
// Reject response
reject(response);
}
// Otherwise
else {
// Securely clear response data
response["Data"].fill(0);
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
}
// Otherwise
else {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Try
try {
// Decode response
var decodedResponse = self.decode(response["Message Type"], response["Data"]);
}
// Catch errors
catch(error) {
// Securely clear response data
response["Data"].fill(0);
// Reject error
reject(error);
// Return
return;
}
// Securely clear response data
response["Data"].fill(0);
// Resolve decoded response
resolve(decodedResponse);
}
// Otherwise
else {
// Securely clear response data
response["Data"].fill(0);
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
}
}
// Otherwise
else {
// Securely clear response data
response["Data"].fill(0);
// Check if unlock message isn't shown
if(unlockMessageShown === false) {
// Check if hardware wallet requires button acknowledgment
if(self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE && response["Message Type"] === HardwareWalletDefinitions.TREZOR_BUTTON_REQUEST_MESSAGE_TYPE) {
// Return sending button acknowledge response and catch errors
return self.send(HardwareWalletDefinitions.TREZOR_BUTTON_ACKNOWLEDGE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_DATA, [], HardwareWallet.NO_TEXT, [], false, true).catch(function(error) {
// Finally
}).finally(function() {
// Reject canceled error
reject(Common.CANCELED_ERROR);
});
}
// Otherwise check if hardware wallet requires passphrase acknowledgment
else if(self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE && response["Message Type"] === HardwareWalletDefinitions.TREZOR_PASSPHRASE_REQUEST_MESSAGE_TYPE) {
// Return sending passphrase acknowledge response
return self.send(HardwareWalletDefinitions.TREZOR_PASSPHRASE_ACKNOWLEDGE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Passphrase
"Passphrase": ""
}, [], HardwareWallet.NO_TEXT, [], false, true).catch(function(error) {
// Finally
}).finally(function() {
// Reject canceled error
reject(Common.CANCELED_ERROR);
});
}
// Otherwise check if hardware wallet requires pin matrix acknowledgment
else if(self.transport.type === HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE && response["Message Type"] === HardwareWalletDefinitions.TREZOR_PIN_MATRIX_REQUEST_MESSAGE_TYPE) {
// Return sending pin matrix acknowledge response
return self.send(HardwareWalletDefinitions.TREZOR_PIN_MATRIX_ACKNOWLEDGE_MESSAGE_TYPE, HardwareWallet.NO_PARAMETER, HardwareWallet.NO_PARAMETER, {
// Pin
"Pin": HardwareWallet.INVALID_PIN
}, [], HardwareWallet.NO_TEXT, [], false, true).catch(function(error) {
// Finally
}).finally(function() {
// Reject canceled error
reject(Common.CANCELED_ERROR);
});
}
}
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
// Catch errors
}).catch(function(error) {
// Check if cancel didn't occur
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
// Check if error is that the device was disconnected
if(typeof error === "object" && error !== null && (("code" in error === true && error["code"] === HardwareWallet.NETWORK_ERROR_CODE) || ("name" in error === true && error["name"] === "NetworkError"))) {
// Reject disconnected error
reject(HardwareWallet.DISCONNECTED_ERROR);
}
// Otherwise
else {
// Reject error
reject(error);
}
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
});
}
// Otherwise
else {
// Reject canceled error
reject(Common.CANCELED_ERROR);
}
});
}
// Encode
encode(messageType, data) {
// Check if data is no data
if(data === HardwareWallet.NO_DATA) {
// Return nothing
return new Uint8Array([]);
}
// Check transport's type
switch(this.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Get message schema
var messageSchema = HardwareWalletDefinitions.SCHEMA[messageType.toFixed()];
// Initialize result
var result = new Uint8Array([]);
// Go through all fields in the message schema
for(var fieldNumber in messageSchema) {
if(messageSchema.hasOwnProperty(fieldNumber) === true) {
// Check if field isn't ignored
if(HardwareWalletDefinitions.LEDGER_IGNORE_FIELD_NAMES.indexOf(messageSchema[fieldNumber]["Name"]) === Common.INDEX_NOT_FOUND) {
// Go through all values in the data
for(var name in data) {
if(data.hasOwnProperty(name) === true) {
// Check if data is for the field
if(name === messageSchema[fieldNumber]["Name"]) {
// Check if data is a big number
if(data[name] instanceof BigNumber === true) {
// Set field payload
var fieldPayload = data[name].toBytes(BigNumber.LITTLE_ENDIAN, messageSchema[fieldNumber]["Size"]);
}
// Otherwise check if data is bytes
else if(data[name] instanceof Uint8Array === true) {
// Set field payload
var fieldPayload = data[name];
}
// Otherwise check if data is a string
else if(typeof data[name] === "string") {
// Set field payload
var fieldPayload = (new TextEncoder()).encode(data[name]);
}
// Otherwise check if data is a number
else if(typeof data[name] === "number") {
// Set field payload
var fieldPayload = new Uint8Array([data[name]]);
}
// Append field payload to the result
result = Common.mergeArrays([
// Result
result,
// Field payload
fieldPayload
]);
// Break
break;
}
}
}
}
}
}
// Return result
return result;
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Return data encoded as Protocol Buffers
return ProtocolBuffers.encode(messageType, data, HardwareWalletDefinitions.SCHEMA);
}
}
// Decode
decode(messageType, data, transportType = HardwareWallet.NO_TRANSPORT_TYPE) {
// Check transport's type
switch((transportType !== HardwareWallet.NO_TRANSPORT_TYPE) ? transportType : this.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Return data
return new Uint8Array(data);
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Decode data as Protocol Buffers
var protocolBuffers = ProtocolBuffers.decode(messageType, data, HardwareWalletDefinitions.SCHEMA);
// Get message schema
var messageSchema = HardwareWalletDefinitions.SCHEMA[messageType.toFixed()];
// Initialize result
var result = new Uint8Array([]);
// Go through all fields in the message schema
for(var fieldNumber in messageSchema) {
if(messageSchema.hasOwnProperty(fieldNumber) === true) {
// Check if field doesn't exist in the Protocol Buffers
if(messageSchema[fieldNumber]["Name"] in protocolBuffers === false) {
// Check if field is optional
if("Optional" in messageSchema[fieldNumber] === true && messageSchema[fieldNumber]["Optional"] === true) {
// Go to next field
continue;
}
// Check if field's type is bool
if(messageSchema[fieldNumber]["Type"] === ProtocolBuffers.BOOL_SCHEMA_DATA_TYPE) {
// Set field payload to false
protocolBuffers[messageSchema[fieldNumber]["Name"]] = [false];
}
// Otherwise
else {
// Securely clear result
result.fill(0);
// Throw error
throw "Field doesn't exist in the Protocol Buffers.";
}
}
// Get field payload
var fieldPayload = protocolBuffers[messageSchema[fieldNumber]["Name"]];
// Set include length
var includeLength = false;
// Check field's expected type
switch(messageSchema[fieldNumber]["Type"]) {
// Uint
case ProtocolBuffers.UINT_SCHEMA_DATA_TYPE:
// Set field data
var fieldData = fieldPayload[fieldPayload["length"] - 1].toBytes(BigNumber.BIG_ENDIAN, messageSchema[fieldNumber]["Size"]);
// Break
break;
// Bool
case ProtocolBuffers.BOOL_SCHEMA_DATA_TYPE:
// Set field data
var fieldData = new Uint8Array([(fieldPayload[fieldPayload["length"] - 1] === true) ? 1 : 0]);
// Break
break;
// Enum
case ProtocolBuffers.ENUM_SCHEMA_DATA_TYPE:
// Set field data
var fieldData = new Uint8Array(fieldPayload);
// Check if more than one value exists in the field payload
if(fieldPayload["length"] > 1) {
// Check if field length is too big
if(fieldPayload["length"] > Common.BYTE_MAX_VALUE) {
// Throw error
throw "Field length is too big.";
}
// Set field data to include field length
fieldData = Common.mergeArrays([new Uint8Array([fieldPayload["length"]]), fieldData]);
}
// Break
break;
// String
case ProtocolBuffers.STRING_SCHEMA_DATA_TYPE:
// Set field data
var fieldData = (new TextEncoder()).encode(fieldPayload[fieldPayload["length"] - 1]);
// Set include length
includeLength = true;
// Check if field length is too big
if(fieldData["length"] > Common.BYTE_MAX_VALUE) {
// Throw error
throw "Field length is too big.";
}
// Break
break;
// Bytes
case ProtocolBuffers.BYTES_SCHEMA_DATA_TYPE:
// Set field data
var fieldData = fieldPayload[fieldPayload["length"] - 1];
// Break
break;
// Sint
case ProtocolBuffers.SINT_SCHEMA_DATA_TYPE:
// Throw error
throw "Field type not supported.";
}
// Append field data to the result
var currentResult = new Uint8Array(result["length"] + ((includeLength === true) ? Uint8Array["BYTES_PER_ELEMENT"] : 0) + fieldData["length"]);
currentResult.set(result);
if(includeLength === true) {
currentResult[result["length"]] = fieldData["length"];
}
currentResult.set(fieldData, result["length"] + ((includeLength === true) ? Uint8Array["BYTES_PER_ELEMENT"] : 0));
result.fill(0);
result = currentResult;
}
}
// Return result
return result;
}
}
// Get minimum compatible version
getMinimumCompatibleVersion() {
// Check transport's type
switch(this.transport.type) {
// Ledger type
case HardwareWalletDefinitions.LEDGER_TRANSPORT_TYPE:
// Return minimum compatible version
return "7.4.1";
// Trezor type
case HardwareWalletDefinitions.TREZOR_TRANSPORT_TYPE:
// Check transport's product name
switch(this.transport["deviceModel"]["productName"]) {
// Trezor Model One
case "Trezor Model One":
// Return minimum compatible version
return "1.12.2";
// Trezor Model T, Trezor Safe 3, Safe 5, or default
case "Trezor Model T":
case "Trezor Safe 3":
case "Trezor Safe 5":
default:
// Return minimum compatible version
return "2.6.4";
}
}
}
// Alphabetic pin to pin
static alphabeticPinToPin(alphabeticPin) {
// Check if alphabetic pin is empty
if(alphabeticPin["length"] === 0) {
// Return invalid pin
return HardwareWallet.INVALID_PIN;
}
// Initialize result
var result = "";
// Go through all characters in the alphabetic pin
for(var i = 0; i < alphabeticPin["length"]; ++i) {
// Check if character is valid
if(alphabeticPin[i] in HardwareWallet.ALPHABETIC_PIN_CHARACTERS === true) {
// Append pin character to result
result += HardwareWallet.ALPHABETIC_PIN_CHARACTERS[alphabeticPin[i]];
}
// Otherwise
else {
// Return invalid pin
return HardwareWallet.INVALID_PIN;
}
}
// Return result
return result;
}
// Alphabetic pin characters
static get ALPHABETIC_PIN_CHARACTERS() {
// Return alphabetic pin characters
return {
// Upper case a
"A": "7",
// Upper case b
"B": "8",
// Upper case c
"C": "9",
// Upper case d
"D": "4",
// Upper case e
"E": "5",
// Upper case f
"F": "6",
// Upper case g
"G": "1",
// Upper case h
"H": "2",
// Upper case i
"I": "3",
// Lower case a
"a": "7",
// Lower case b
"b": "8",
// Lower case c
"c": "9",
// Lower case d
"d": "4",
// Lower case e
"e": "5",
// Lower case f
"f": "6",
// Lower case g
"g": "1",
// Lower case h
"h": "2",
// Lower case i
"i": "3"
};
}
// Invalid pin
static get INVALID_PIN() {
// Return invalid pin
return "A";
}
// Is compatible version
static isCompatibleVersion(version, minimumCompatibleVersion) {
// Get version parts from the version
var versionParts = version.match(HardwareWallet.VERSION_STRING_PATTERN);
// Check if getting version parts was successful
if(versionParts !== Common.NO_MATCH_FOUND) {
// Get minimum compatible version parts
var minimumCompatibleVersionParts = minimumCompatibleVersion.match(HardwareWallet.VERSION_STRING_PATTERN);
// Go through all version parts
for(var i = 0; i < versionParts["length"]; ++i) {
// Check if version part is greater than the minimum compatible version part
if((new BigNumber(versionParts[i])).isGreaterThan(minimumCompatibleVersionParts[i]) === true) {
// Return true
return true;
}
// Otherwise check if version part is less than the minimum compatible version part
else if((new BigNumber(versionParts[i])).isLessThan(minimumCompatibleVersionParts[i]) === true) {
// Return false
return false;
}
}
// Return true
return true;
}
// Return false
return false;
}
// Exclusive lock release event
static get EXCLUSIVE_LOCK_RELEASE_EVENT() {
// Return exclusive lock release event
return "HardwareWalletExclusiveLockReleaseEvent";
}
// No transport
static get NO_TRANSPORT() {
// Return no transport
return null;
}
// No root public key
static get NO_ROOT_PUBLIC_KEY() {
// Return no root public key
return null;
}
// No seed cookie
static get NO_SEED_COOKIE() {
// Return no seed cookie
return null;
}
// No address
static get NO_ADDRESS() {
// Return no address
return null;
}
// No kernel commit
static get NO_KERNEL_COMMIT() {
// Return no kernel commit
return null;
}
// No payment proof
static get NO_PAYMENT_PROOF() {
// Return no payment proof
return null;
}
// Application name
static get APPLICATION_NAME() {
// Check wallet type
switch(Consensus.getWalletType()) {
// MWC wallet
case Consensus.MWC_WALLET_TYPE:
// Check network type
switch(Consensus.getNetworkType()) {
// Mainnet network type
case Consensus.MAINNET_NETWORK_TYPE:
// Return application name
return "MimbleWimble Coin";
// Testnet network type
case Consensus.TESTNET_NETWORK_TYPE:
// Return application name
return "MimbleWimble Coin Floonet";
}
// Break
break;
// GRIN wallet
case Consensus.GRIN_WALLET_TYPE:
// Check network type
switch(Consensus.getNetworkType()) {
// Mainnet network type
case Consensus.MAINNET_NETWORK_TYPE:
// Return application name
return "Grin";
// Testnet network type
case Consensus.TESTNET_NETWORK_TYPE:
// Return application name
return "Grin Testnet";
}
// Break
break;
// EPIC wallet
case Consensus.EPIC_WALLET_TYPE:
// Check network type
switch(Consensus.getNetworkType()) {
// Mainnet network type
case Consensus.MAINNET_NETWORK_TYPE:
// Return application name
return "Epic Cash";
// Testnet network type
case Consensus.TESTNET_NETWORK_TYPE:
// Return application name
return "Epic Cash Floonet";
}
// Break
break;
}
}
// MimbleWimble Coin capable
static get MIMBLEWIMBLE_COIN_CAPABLE() {
// Return MimbleWimble Coin capable
return 0xC7;
}
// Version string pattern
static get VERSION_STRING_PATTERN() {
// Return hex string pattern
return /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u;
}
// Seed cookie length
static get SEED_COOKIE_LENGTH() {
// Return seed cookie length
return 64;
}
// No parameter
static get NO_PARAMETER() {
// Return no parameter
return 0;
}
// Account
static get ACCOUNT() {
// Return account
return 0;
}
// MQS address type
static get MQS_ADDRESS_TYPE() {
// Return MQS address type
return 0;
}
// Tor address type
static get TOR_ADDRESS_TYPE() {
// Return Tor address type
return HardwareWallet.MQS_ADDRESS_TYPE + 1;
}
// Slatepack address type
static get SLATEPACK_ADDRESS_TYPE() {
// Return Slatepack address type
return HardwareWallet.TOR_ADDRESS_TYPE + 1;
}
// No data
static get NO_DATA() {
// Return no data
return null;
}
// Resend request delay milliseconds
static get RESEND_REQUEST_DELAY_MILLISECONDS() {
// Return resend request delay milliseconds
return 50;
}
// Not found error code
static get NOT_FOUND_ERROR_CODE() {
// Return not found error code
return 8;
}
// Invalid state error code
static get INVALID_STATE_ERROR_CODE() {
// Return invalid state error code
return 11;
}
// Network error code
static get NETWORK_ERROR_CODE() {
// Return network error code
return 19;
}
// No salt
static get NO_SALT() {
// Return no salt
return null;
}
// Encryption and decryption maximum chunk size
static get ENCRYPTION_AND_DECRYPTION_MAXIMUM_CHUNK_SIZE() {
// Return encryption and decryption maximum chunk size
return 64;
}
// No transport type
static get NO_TRANSPORT_TYPE() {
// Return no transport type
return null;
}
}
// Main function
// Set global object's hardware wallet
globalThis["HardwareWallet"] = HardwareWallet;