mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-06 15:52:47 +00:00
7063 lines
230 KiB
JavaScript
Executable File
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;
|