mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-06 15:52:47 +00:00
4227 lines
108 KiB
JavaScript
Executable File
4227 lines
108 KiB
JavaScript
Executable File
// Use strict
|
|
"use strict";
|
|
|
|
|
|
// Classes
|
|
|
|
// Wallet class
|
|
class Wallet {
|
|
|
|
// Public
|
|
|
|
// Initialize
|
|
static initialize() {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Get the saved password pepper
|
|
var currentPasswordPepper = localStorage.getItem(Wallet.PASSWORD_PEPPER_LOCAL_STORAGE_NAME);
|
|
|
|
// Check if password pepper doesn't exist or isn't valid
|
|
if(currentPasswordPepper === Common.INVALID_LOCAL_STORAGE_ITEM || Common.isHexString(currentPasswordPepper) === false) {
|
|
|
|
// Create password pepper
|
|
var passwordPepper = new Uint8Array(Wallet.PASSWORD_PEPPER_LENGTH);
|
|
|
|
// Fill password pepper with random values
|
|
crypto.getRandomValues(passwordPepper);
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Save password pepper
|
|
localStorage.setItem(Wallet.PASSWORD_PEPPER_LOCAL_STORAGE_NAME, Common.toHexString(passwordPepper));
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Reject
|
|
reject();
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Resolve
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
// Constructor
|
|
constructor(name, color, salt, initializationVector, numberOfIterations, encryptedSeed, addressSuffix, order, syncedHeight, spentAmount, unspentAmount, unconfirmedAmount, lockedAmount, pendingAmount, expiredAmount, walletType, networkType, lastIdentifier, hardwareType, encryptedRootPublicKey, useBip39, encryptedBip39Salt, accountNumber, paymentProofIndex, keyPath) {
|
|
|
|
// Set performing address suffix operation
|
|
this.setPerformingAddressSuffixOperation(false);
|
|
|
|
// Set address suffix verified
|
|
this.setAddressSuffixVerified(false);
|
|
|
|
// Set syncing status to syncing
|
|
this.setSyncingStatus(Wallet.STATUS_SYNCING);
|
|
|
|
// Set last sync index
|
|
this.setLastSyncIndex(Wallet.NO_SYNC_INDEX);
|
|
|
|
// Set starting sync height
|
|
this.setStartingSyncHeight(Wallet.CURRENT_HEIGHT);
|
|
|
|
// Set seed to no seed
|
|
this.seed = Wallet.NO_SEED;
|
|
|
|
// Set root public key to no root public key
|
|
this.rootPublicKey = Wallet.NO_ROOT_PUBLIC_KEY;
|
|
|
|
// Set extended private key to no extended private key
|
|
this.extendedPrivateKey = Wallet.NO_EXTENDED_PRIVATE_KEY;
|
|
|
|
// Set hardware wallet to no hardware wallet
|
|
this.hardwareWallet = Wallet.NO_HARDWARE_WALLET;
|
|
|
|
// Set BIP39 salt to no BIP39 salt
|
|
this.bip39Salt = Wallet.NO_BIP39_SALT;
|
|
|
|
// Set percent synced
|
|
this.setPercentSynced(new BigNumber(Wallets.MINIMUM_PERCENT));
|
|
|
|
// Check if parameters are provided
|
|
if(typeof name !== "undefined") {
|
|
|
|
// Set name
|
|
this.setName(name);
|
|
|
|
// Set color
|
|
this.setColor(color);
|
|
|
|
// Set salt
|
|
this.setSalt(salt);
|
|
|
|
// Set initialization vector
|
|
this.setInitializationVector(initializationVector);
|
|
|
|
// Set number of iterations
|
|
this.setNumberOfIterations(numberOfIterations);
|
|
|
|
// Set encrypted seed
|
|
this.setEncryptedSeed(encryptedSeed);
|
|
|
|
// Set address sv
|
|
this.setAddressSuffix(addressSuffix);
|
|
|
|
// Set order
|
|
this.setOrder(order);
|
|
|
|
// Set synced height
|
|
this.setSyncedHeight(syncedHeight);
|
|
|
|
// Set spent amount
|
|
this.setSpentAmount(spentAmount);
|
|
|
|
// Set unspent amount
|
|
this.setUnspentAmount(unspentAmount);
|
|
|
|
// Set unconfirmed amount
|
|
this.setUnconfirmedAmount(unconfirmedAmount);
|
|
|
|
// Set locked amount
|
|
this.setLockedAmount(lockedAmount);
|
|
|
|
// Set pending amount
|
|
this.setPendingAmount(pendingAmount);
|
|
|
|
// Set expired amount
|
|
this.setExpiredAmount(expiredAmount);
|
|
|
|
// Set wallet type
|
|
this.setWalletType(walletType);
|
|
|
|
// Set network type
|
|
this.setNetworkType(networkType);
|
|
|
|
// Set last identifier
|
|
this.setLastIdentifier(lastIdentifier);
|
|
|
|
// Set hardware type
|
|
this.setHardwareType(hardwareType);
|
|
|
|
// Set encrypted root public key
|
|
this.setEncryptedRootPublicKey(encryptedRootPublicKey);
|
|
|
|
// Set use BIP39
|
|
this.setUseBip39(useBip39);
|
|
|
|
// Set encrypted BIP39 salt
|
|
this.setEncryptedBip39Salt(encryptedBip39Salt);
|
|
|
|
// Set account number
|
|
this.setAccountNumber(accountNumber);
|
|
|
|
// Set payment proof index
|
|
this.setPaymentProofIndex(paymentProofIndex);
|
|
|
|
// Set key path
|
|
this.setKeyPath(keyPath);
|
|
|
|
// Set starting sync height
|
|
this.setStartingSyncHeight(syncedHeight);
|
|
}
|
|
}
|
|
|
|
// Initialize
|
|
initialize(name, password, walletType, networkType, syncedHeight, syncingStatus, hardwareWallet, passphrase, useBip39, bip39Salt, existingWallets = []) {
|
|
|
|
// Set name
|
|
this.setName(name);
|
|
|
|
// Set color to random color
|
|
this.setColor(Wallet.getRandomColor());
|
|
|
|
// Set salt to a random salt
|
|
this.setSalt(crypto.getRandomValues(new Uint8Array(Wallet.SALT_LENGTH)));
|
|
|
|
// Set initialization vector to a random initialization vector
|
|
this.setInitializationVector(crypto.getRandomValues(new Uint8Array(Wallet.INITIALIZATION_VECTOR_LENGTH)));
|
|
|
|
// Set number of iterations
|
|
this.setNumberOfIterations(Wallet.DEFAULT_NUMBER_OF_ITERATIONS);
|
|
|
|
// Set address suffix
|
|
this.setAddressSuffix(Wallet.NO_ADDRESS_SUFFIX);
|
|
|
|
// Set order
|
|
this.setOrder(Wallet.NO_ORDER);
|
|
|
|
// Set synced height
|
|
this.setSyncedHeight(syncedHeight);
|
|
|
|
// Set spent amount
|
|
this.setSpentAmount(new BigNumber(0));
|
|
|
|
// Set unspent amount
|
|
this.setUnspentAmount(new BigNumber(0));
|
|
|
|
// Set unconfirmed amount
|
|
this.setUnconfirmedAmount(new BigNumber(0));
|
|
|
|
// Set locked amount
|
|
this.setLockedAmount(new BigNumber(0));
|
|
|
|
// Set pending amount
|
|
this.setPendingAmount(new BigNumber(0));
|
|
|
|
// Set expired amount
|
|
this.setExpiredAmount(new BigNumber(0));
|
|
|
|
// Set wallet type
|
|
this.setWalletType(walletType);
|
|
|
|
// Set network type
|
|
this.setNetworkType(networkType);
|
|
|
|
// Set last identifier
|
|
this.setLastIdentifier(Wallet.NO_LAST_IDENTIFIER);
|
|
|
|
// Set hardware type
|
|
this.setHardwareType((hardwareWallet !== Wallet.NO_HARDWARE_WALLET) ? hardwareWallet.getHardwareType() : Wallet.NO_HARDWARE_TYPE);
|
|
|
|
// Set account number
|
|
this.setAccountNumber(0);
|
|
|
|
// Set payment proof index
|
|
this.setPaymentProofIndex(0);
|
|
|
|
// Set key path to no key path
|
|
this.setKeyPath(Wallet.NO_KEY_PATH);
|
|
|
|
// Set starting sync height
|
|
this.setStartingSyncHeight(syncedHeight);
|
|
|
|
// Set syncing status
|
|
this.setSyncingStatus(syncingStatus);
|
|
|
|
// Set hardware wallet
|
|
this.hardwareWallet = hardwareWallet;
|
|
|
|
// Set use BIP39
|
|
this.setUseBip39(useBip39);
|
|
|
|
// Check if hardware wallet exists
|
|
if(hardwareWallet !== Wallet.NO_HARDWARE_WALLET) {
|
|
|
|
// Set hardware wallet's wallet key path
|
|
hardwareWallet.setWalletKeyPath(Wallet.NO_KEY_PATH);
|
|
}
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Set seed to a new seed
|
|
self.seed = new Seed();
|
|
|
|
// Return initializing seed
|
|
return self.seed.initialize((passphrase !== Wallet.NO_PASSPHRASE) ? passphrase : Seed.DEFAULT_SEED_LENGTH, (passphrase !== Wallet.NO_PASSPHRASE) ? [] : existingWallets.map(function(existingWallet) {
|
|
|
|
// Check if existing wallet isn't a hardware wallet and doesn't use BIP39
|
|
if(existingWallet.getHardwareType() === Wallet.NO_HARDWARE_TYPE && existingWallet.getUseBip39() === false) {
|
|
|
|
// Return existing wallet's seed
|
|
return existingWallet.seed;
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return new seed
|
|
return new Seed();
|
|
}
|
|
|
|
})).then(function() {
|
|
|
|
// Set BIP39 salt
|
|
self.bip39Salt = bip39Salt;
|
|
|
|
// Return encrypting seed and BIP39 salt
|
|
return self.encryptSeedAndBip39Salt(password, self.getSalt(), self.getNumberOfIterations(), self.getInitializationVector()).then(function(encryptedSeedAndBip39Salt) {
|
|
|
|
// Set encrypted seed to the encrypted seed
|
|
self.setEncryptedSeed(encryptedSeedAndBip39Salt[Wallet.ENCRYPT_SEED_AND_BIP39_SALT_ENCRYPTED_SEED_INDEX]);
|
|
|
|
// Set encrypted root public key to no encrypted root public key
|
|
self.setEncryptedRootPublicKey(Wallet.NO_ENCRYPTED_ROOT_PUBLIC_KEY);
|
|
|
|
// Set encrypted BIP39 salt to the encrypted BIP39 salt
|
|
self.setEncryptedBip39Salt(encryptedSeedAndBip39Salt[Wallet.ENCRYPT_SEED_AND_BIP39_SALT_ENCRYPTED_BIP39_SALT_INDEX]);
|
|
|
|
// Return getting extended private key from seed
|
|
return self.seed.getExtendedPrivateKey(Wallet.SEED_KEY, self.getUseBip39(), self.bip39Salt).then(function(extendedPrivateKey) {
|
|
|
|
// Set extended private key
|
|
self.extendedPrivateKey = extendedPrivateKey;
|
|
|
|
// Return getting root public key
|
|
return self.getRootPublicKey().then(function(rootPublicKey) {
|
|
|
|
// Initialize get existing root public keys
|
|
var getExistingRootPublicKeys = [];
|
|
|
|
// Initialize existing root public key
|
|
var existingRootPublicKeys = [];
|
|
|
|
// Go through all existing wallets
|
|
for(var i = 0; i < existingWallets["length"]; ++i) {
|
|
|
|
// Get existing wallet
|
|
let existingWallet = existingWallets[i];
|
|
|
|
// Append getting existing wallet's root public key to list
|
|
getExistingRootPublicKeys.push(new Promise(function(resolve, reject) {
|
|
|
|
// Return getting existing wallet's root public key
|
|
return existingWallet.getRootPublicKey().then(function(existingRootPublicKey) {
|
|
|
|
// Append existing root public key to list
|
|
existingRootPublicKeys.push(existingRootPublicKey);
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}));
|
|
}
|
|
|
|
// Return getting all existing root public keys
|
|
return Promise.all(getExistingRootPublicKeys).then(function() {
|
|
|
|
// Go through all existing root public keys
|
|
for(var i = 0; i < existingRootPublicKeys["length"]; ++i) {
|
|
|
|
// Check if root public key already exists
|
|
if(Common.arraysAreEqualTimingSafe(rootPublicKey, existingRootPublicKeys[i]) === true) {
|
|
|
|
// Go through all remaining existing root public keys
|
|
for(var j = i; j < existingRootPublicKeys["length"]; ++j) {
|
|
|
|
// Securely clear existing root public key
|
|
existingRootPublicKeys[j].fill(0);
|
|
}
|
|
|
|
// Securely clear the root public key
|
|
rootPublicKey.fill(0);
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('A wallet with the same passphrase already exists in your list of wallets.'));
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Securely clear existing root public key
|
|
existingRootPublicKeys[i].fill(0);
|
|
}
|
|
|
|
// Securely clear the root public key
|
|
rootPublicKey.fill(0);
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Go through all existing root public keys
|
|
for(var i = 0; i < existingRootPublicKeys["length"]; ++i) {
|
|
|
|
// Securely clear existing root public key
|
|
existingRootPublicKeys[i].fill(0);
|
|
}
|
|
|
|
// Securely clear the root public key
|
|
rootPublicKey.fill(0);
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Creating wallet failed.'));
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Creating wallet failed.'));
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Creating wallet failed.'));
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Creating wallet failed.'));
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Check if a passphrase was used
|
|
if(passphrase !== Wallet.NO_PASSPHRASE) {
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Invalid passphrase.'));
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Creating wallet failed.'));
|
|
}
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if hardware is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Set that hardware wallet is in use
|
|
self.getHardwareWallet().setInUse(true);
|
|
|
|
// Hardware wallet on hardware disconnect event
|
|
$(self.getHardwareWallet()).one(HardwareWallet.DISCONNECT_EVENT, function() {
|
|
|
|
// Check if hardware wallet exists
|
|
if(self.getHardwareWallet() !== Wallet.NO_HARDWARE_WALLET) {
|
|
|
|
// Close hardware wallet
|
|
self.getHardwareWallet().close();
|
|
|
|
// Set hardware wallet to no hardware wallet
|
|
self.hardwareWallet = Wallet.NO_HARDWARE_WALLET;
|
|
}
|
|
|
|
// Check if key path exists
|
|
if(self.getKeyPath() !== Wallet.NO_KEY_PATH) {
|
|
|
|
// Trigger wallet disconnect event
|
|
$(document).trigger(Wallet.DISCONNECT_EVENT, [
|
|
|
|
// Key path
|
|
self.getKeyPath()
|
|
]);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if hardware wallet exists
|
|
if(self.getHardwareWallet() !== Wallet.NO_HARDWARE_WALLET) {
|
|
|
|
// Close hardware wallet
|
|
self.getHardwareWallet().close();
|
|
|
|
// Set hardware wallet to no hardware wallet
|
|
self.hardwareWallet = Wallet.NO_HARDWARE_WALLET;
|
|
}
|
|
}
|
|
|
|
// Initialize root public key candidate
|
|
var rootPublicKeyCandidate = hardwareWallet.getRootPublicKey();
|
|
|
|
// Initialize get existing root public keys
|
|
var getExistingRootPublicKeys = [];
|
|
|
|
// Initialize existing root public key
|
|
var existingRootPublicKeys = [];
|
|
|
|
// Go through all existing wallets
|
|
for(var i = 0; i < existingWallets["length"]; ++i) {
|
|
|
|
// Get existing wallet
|
|
let existingWallet = existingWallets[i];
|
|
|
|
// Append getting existing wallet's root public key to list
|
|
getExistingRootPublicKeys.push(new Promise(function(resolve, reject) {
|
|
|
|
// Return getting existing wallet's root public key
|
|
return existingWallet.getRootPublicKey().then(function(existingRootPublicKey) {
|
|
|
|
// Append existing root public key to list
|
|
existingRootPublicKeys.push(existingRootPublicKey);
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}));
|
|
}
|
|
|
|
// Return getting all existing root public keys
|
|
return Promise.all(getExistingRootPublicKeys).then(function() {
|
|
|
|
// Go through all existing root public keys
|
|
for(var i = 0; i < existingRootPublicKeys["length"]; ++i) {
|
|
|
|
// Check if root public key already exists
|
|
if(Common.arraysAreEqualTimingSafe(rootPublicKeyCandidate, existingRootPublicKeys[i]) === true) {
|
|
|
|
// Go through all remaining existing root public keys
|
|
for(var j = i; j < existingRootPublicKeys["length"]; ++j) {
|
|
|
|
// Securely clear existing root public key
|
|
existingRootPublicKeys[j].fill(0);
|
|
}
|
|
|
|
// Securely clear the root public key candidate
|
|
rootPublicKeyCandidate.fill(0);
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('A wallet with the same root public key already exists in your list of wallets.'));
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Securely clear existing root public key
|
|
existingRootPublicKeys[i].fill(0);
|
|
}
|
|
|
|
// Set root public key
|
|
self.rootPublicKey = rootPublicKeyCandidate;
|
|
|
|
// Return encrypting root public key
|
|
return self.encryptRootPublicKey(password, self.getSalt(), self.getNumberOfIterations(), self.getInitializationVector()).then(function(encryptedRootPublicKey) {
|
|
|
|
// Set encrypted seed to no encrypted seed
|
|
self.setEncryptedSeed(Wallet.NO_ENCRYPTED_SEED);
|
|
|
|
// Set encrypted root public key to encrypted root public key
|
|
self.setEncryptedRootPublicKey(encryptedRootPublicKey);
|
|
|
|
// Set encrypted BIP39 salt to no encrypted BIP39 salt
|
|
self.setEncryptedBip39Salt(Wallet.NO_ENCRYPTED_BIP39_SALT);
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Creating wallet failed.'));
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Go through all existing root public keys
|
|
for(var i = 0; i < existingRootPublicKeys["length"]; ++i) {
|
|
|
|
// Securely clear existing root public key
|
|
existingRootPublicKeys[i].fill(0);
|
|
}
|
|
|
|
// Securely clear the root public key candidate
|
|
rootPublicKeyCandidate.fill(0);
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Creating wallet failed.'));
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Open
|
|
open(password) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return decrypting seed and BIP39 salt
|
|
return self.decryptSeedAndBip39Salt(password, self.getSalt(), self.getNumberOfIterations(), self.getInitializationVector()).then(function(decryptedSeedAndBip39Salt) {
|
|
|
|
// Check if seed exists
|
|
if(self.seed !== Wallet.NO_SEED) {
|
|
|
|
// Uninitialize seed
|
|
self.seed.uninitialize();
|
|
}
|
|
|
|
// Create seed
|
|
self.seed = new Seed();
|
|
|
|
// Check if BIP39 salt exists
|
|
if(self.bip39Salt !== Wallet.NO_BIP39_SALT) {
|
|
|
|
// Securely clear the BIP39 salt
|
|
self.bip39Salt.fill(0);
|
|
}
|
|
|
|
// Set BIP39 salt
|
|
self.bip39Salt = decryptedSeedAndBip39Salt[Wallet.DECRYPT_SEED_AND_BIP39_SALT_DECRYPTED_BIP39_SALT_INDEX];
|
|
|
|
// Return initializing seed
|
|
return self.seed.initialize(decryptedSeedAndBip39Salt[Wallet.DECRYPT_SEED_AND_BIP39_SALT_DECRYPTED_SEED_INDEX]).then(function() {
|
|
|
|
// Return getting extended private key from seed
|
|
return self.seed.getExtendedPrivateKey(Wallet.SEED_KEY, self.getUseBip39(), self.bip39Salt).then(function(extendedPrivateKey) {
|
|
|
|
// Check if extended private key exists
|
|
if(self.extendedPrivateKey !== Wallet.NO_EXTENDED_PRIVATE_KEY) {
|
|
|
|
// Securely clear the extended private key
|
|
self.extendedPrivateKey.fill(0);
|
|
}
|
|
|
|
// Set extended private key
|
|
self.extendedPrivateKey = extendedPrivateKey;
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Invalid wallet.'));
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Securely clear decrypted seed
|
|
decryptedSeedAndBip39Salt[Wallet.DECRYPT_SEED_AND_BIP39_SALT_DECRYPTED_SEED_INDEX].fill(0);
|
|
|
|
// Securely clear decrypted BIP39 salt
|
|
decryptedSeedAndBip39Salt[Wallet.DECRYPT_SEED_AND_BIP39_SALT_DECRYPTED_BIP39_SALT_INDEX].fill(0);
|
|
|
|
// Close
|
|
self.close();
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Invalid wallet.'));
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Incorrect password.'));
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return decrypting root public key
|
|
return self.decryptRootPublicKey(password, self.getSalt(), self.getNumberOfIterations(), self.getInitializationVector()).then(function(decryptedRootPublicKey) {
|
|
|
|
// Check if root public key exists
|
|
if(self.rootPublicKey !== Wallet.NO_ROOT_PUBLIC_KEY) {
|
|
|
|
// Securely clear the root public key
|
|
self.rootPublicKey.fill(0);
|
|
}
|
|
|
|
// Set root public key to decrypted root public key
|
|
self.rootPublicKey = decryptedRootPublicKey;
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Incorrect password.'));
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Is open
|
|
isOpen() {
|
|
|
|
// Return if seed or root public key exist
|
|
return this.seed !== Wallet.NO_SEED || this.rootPublicKey !== Wallet.NO_ROOT_PUBLIC_KEY;
|
|
}
|
|
|
|
// Close
|
|
close() {
|
|
|
|
// Check if seed exists
|
|
if(this.seed !== Wallet.NO_SEED) {
|
|
|
|
// Uninitialize seed
|
|
this.seed.uninitialize();
|
|
|
|
// Set seed to no seed
|
|
this.seed = Wallet.NO_SEED;
|
|
}
|
|
|
|
// Check if root public key exists
|
|
if(this.rootPublicKey !== Wallet.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 = Wallet.NO_ROOT_PUBLIC_KEY;
|
|
}
|
|
|
|
// Check if extended private key exists
|
|
if(this.extendedPrivateKey !== Wallet.NO_EXTENDED_PRIVATE_KEY) {
|
|
|
|
// Securely clear the extended private key
|
|
this.extendedPrivateKey.fill(0);
|
|
|
|
// Set extended private key to no extended private key
|
|
this.extendedPrivateKey = Wallet.NO_EXTENDED_PRIVATE_KEY;
|
|
}
|
|
|
|
// Check if hardware wallet exists
|
|
if(this.getHardwareWallet() !== Wallet.NO_HARDWARE_WALLET) {
|
|
|
|
// Close the hardware wallet
|
|
this.getHardwareWallet().close();
|
|
|
|
// Set hardware wallet to no hardware wallet
|
|
this.hardwareWallet = Wallet.NO_HARDWARE_WALLET;
|
|
}
|
|
|
|
// Check if BIP39 salt exists
|
|
if(this.bip39Salt !== Wallet.NO_BIP39_SALT) {
|
|
|
|
// Securely clear the BIP39 salt
|
|
this.bip39Salt.fill(0);
|
|
|
|
// Set BIP39 salt to no BIP39 salt
|
|
this.bip39Salt = Wallet.NO_BIP39_SALT;
|
|
}
|
|
}
|
|
|
|
// Get passphrase
|
|
getPassphrase() {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('The wallet is closed.'));
|
|
}
|
|
|
|
// Otherwise check if wallet is a hardware wallet
|
|
else if(self.getHardwareType() !== Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Passphrases can\'t be retrieved from hardware wallets.'));
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return getting seed's mnemonic
|
|
return self.seed.getMnemonic().then(function(mnemonic) {
|
|
|
|
// Check if BIP39 salt exists
|
|
if(self.bip39Salt !== Wallet.NO_BIP39_SALT) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Resolve mnemonic with BIP39 salt
|
|
resolve(mnemonic + " " + (new TextDecoder("utf-8", {"fatal": true})).decode(self.bip39Salt));
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Invalid wallet.'));
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Resolve mnemonic
|
|
resolve(mnemonic);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(Language.getDefaultTranslation('Invalid wallet.'));
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Get root public key
|
|
getRootPublicKey() {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise check if wallet isn't a hardware wallet
|
|
else if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return getting root public key
|
|
return Crypto.rootPublicKey(self.extendedPrivateKey).then(function(rootPublicKey) {
|
|
|
|
// Resolve root public key
|
|
resolve(rootPublicKey);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject("Invalid wallet.");
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Resolve copy of root public key
|
|
resolve(new Uint8Array(self.rootPublicKey));
|
|
}
|
|
});
|
|
}
|
|
|
|
// Get address key
|
|
getAddressKey(index) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise check if wallet is a hardware wallet
|
|
else if(self.getHardwareType() !== Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Reject error
|
|
reject("Address key can't be retrieved from a hardware wallet.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return getting address key
|
|
return Crypto.addressKey(self.extendedPrivateKey, index).then(function(addressKey) {
|
|
|
|
// Resolve address key
|
|
resolve(addressKey);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject("Invalid wallet.");
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Get Tor proof address
|
|
getTorProofAddress(hardwareWalletLockedText = HardwareWallet.NO_TEXT, hardwareWalletLockedTextArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return getting address private key at payment proof Tor address index
|
|
return self.getAddressKey(Wallet.PAYMENT_PROOF_TOR_ADDRESS_KEY_INDEX).then(function(addressSecretKey) {
|
|
|
|
// Check if getting address public key from the address private key failed
|
|
var addressPublicKey = Ed25519.publicKeyFromSecretKey(addressSecretKey);
|
|
|
|
if(addressPublicKey === Ed25519.OPERATION_FAILED) {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Reject error
|
|
reject("Getting address public key from the address private key failed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Set Tor proof address to the Tor address of the addres public key
|
|
var torProofAddress = Tor.publicKeyToTorAddress(addressPublicKey);
|
|
|
|
// Resolve Tor proof address
|
|
resolve(torProofAddress);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting Tor address with the hardware wallet
|
|
return self.getHardwareWallet().getTorAddress(Wallet.PAYMENT_PROOF_TOR_ADDRESS_KEY_INDEX, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(torProofAddress) {
|
|
|
|
// Resolve Tor proof address
|
|
resolve(torProofAddress);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Get MQS proof address
|
|
getMqsProofAddress(hardwareWalletLockedText = HardwareWallet.NO_TEXT, hardwareWalletLockedTextArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return getting address private key at payment proof MQS address index
|
|
return self.getAddressKey(Wallet.PAYMENT_PROOF_MQS_ADDRESS_KEY_INDEX).then(function(addressSecretKey) {
|
|
|
|
// Check if getting address public key from the address private key failed
|
|
var addressPublicKey = Secp256k1Zkp.publicKeyFromSecretKey(addressSecretKey);
|
|
|
|
if(addressPublicKey === Secp256k1Zkp.OPERATION_FAILED) {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Reject error
|
|
reject("Getting address public key from the address private key failed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Set MQS proof address to the MQS address of the address public key
|
|
var mqsProofAddress = Mqs.publicKeyToMqsAddress(addressPublicKey, self.getNetworkType() === Consensus.MAINNET_NETWORK_TYPE);
|
|
|
|
// Resolve MQS proof address
|
|
resolve(mqsProofAddress);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting MQS address with the hardware wallet
|
|
return self.getHardwareWallet().getMqsAddress(Wallet.PAYMENT_PROOF_MQS_ADDRESS_KEY_INDEX, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(mqsProofAddress) {
|
|
|
|
// Resolve MQS proof address
|
|
resolve(mqsProofAddress);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Get Slatepack proof address
|
|
getSlatepackProofAddress(hardwareWalletLockedText = HardwareWallet.NO_TEXT, hardwareWalletLockedTextArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return getting address private key at payment proof Slatepack address index
|
|
return self.getAddressKey(Wallet.PAYMENT_PROOF_SLATEPACK_ADDRESS_KEY_INDEX).then(function(addressSecretKey) {
|
|
|
|
// Check if getting address public key from the address private key failed
|
|
var addressPublicKey = Ed25519.publicKeyFromSecretKey(addressSecretKey);
|
|
|
|
if(addressPublicKey === Ed25519.OPERATION_FAILED) {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Reject error
|
|
reject("Getting address public key from the address private key failed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Set Slatepack proof address to the Slatepack address of the addres public key
|
|
var slatepackProofAddress = Slatepack.publicKeyToSlatepackAddress(addressPublicKey);
|
|
|
|
// Resolve Slatepack proof address
|
|
resolve(slatepackProofAddress);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting Slatepack address with the hardware wallet
|
|
return self.getHardwareWallet().getSlatepackAddress(Wallet.PAYMENT_PROOF_SLATEPACK_ADDRESS_KEY_INDEX, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(slatepackProofAddress) {
|
|
|
|
// Resolve Slatepack proof address
|
|
resolve(slatepackProofAddress);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Get coinbase proof
|
|
getCoinbaseProof(fees, height, identifier, hardwareWalletLockedText = HardwareWallet.NO_TEXT, hardwareWalletLockedTextArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false)
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if no last identifier exists
|
|
if(self.getLastIdentifier() === Wallet.NO_LAST_IDENTIFIER) {
|
|
|
|
// Get default identifier
|
|
var defaultIdentifier = new Identifier();
|
|
|
|
// Set the current identifier to the default identifier's child identifier
|
|
var currentIdentifier = defaultIdentifier.getChild();
|
|
}
|
|
|
|
// Otherwise check if an identifier is provided and it was previously used
|
|
else if(identifier !== Identifier.NO_IDENTIFIER && self.getLastIdentifier().includesValue(identifier) === true)
|
|
|
|
// Set current identifier to the identifier
|
|
var currentIdentifier = identifier;
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Set the current identifier to the last identifier's next identifier
|
|
var currentIdentifier = self.getLastIdentifier().getNext();
|
|
}
|
|
|
|
// Get reward from fees and height
|
|
var reward = Consensus.getReward(self.getNetworkType() === Consensus.MAINNET_NETWORK_TYPE, fees, height);
|
|
|
|
// Set switch type
|
|
var switchType = Crypto.SWITCH_TYPE_REGULAR;
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return initializing new proof builder
|
|
var proofBuilder = new NewProofBuilder();
|
|
|
|
return proofBuilder.initialize(self.extendedPrivateKey).then(function() {
|
|
|
|
// Return creating proof from extended private key, reward, current identifier, switch type, and proof builder
|
|
return Crypto.proof(self.extendedPrivateKey, reward, currentIdentifier, switchType, proofBuilder).then(function(proof) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Resolve proof
|
|
resolve(proof);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return initializing view proof builder
|
|
var proofBuilder = new ViewProofBuilder();
|
|
|
|
return proofBuilder.initialize(self.rootPublicKey).then(function() {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting proof from reward, current identifier, switch type, and proof builder with the hardware wallet
|
|
return self.getHardwareWallet().getProof(reward, currentIdentifier, switchType, HardwareWallet.CREATING_COINBASE_MESSAGE, proofBuilder, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(proof) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Resolve proof
|
|
resolve(proof);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Build coinbase
|
|
buildCoinbase(fees, height, identifier, proof = Wallet.NO_PROOF, hardwareWalletLockedText = HardwareWallet.NO_TEXT, hardwareWalletLockedTextArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false)
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if no last identifier exists
|
|
if(self.getLastIdentifier() === Wallet.NO_LAST_IDENTIFIER) {
|
|
|
|
// Get default identifier
|
|
var defaultIdentifier = new Identifier();
|
|
|
|
// Set the current identifier to the default identifier's child identifier
|
|
var currentIdentifier = defaultIdentifier.getChild();
|
|
|
|
// Set last identifier to the current identifier without the extras
|
|
self.setLastIdentifier(currentIdentifier);
|
|
}
|
|
|
|
// Otherwise check if an identifier is provided and it was previously used
|
|
else if(identifier !== Identifier.NO_IDENTIFIER && self.getLastIdentifier().includesValue(identifier) === true)
|
|
|
|
// Set current identifier to the identifier
|
|
var currentIdentifier = identifier;
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Set the current identifier to the last identifier's next identifier
|
|
var currentIdentifier = self.getLastIdentifier().getNext();
|
|
|
|
// Set last identifier to the current identifier without the extras
|
|
self.setLastIdentifier(currentIdentifier);
|
|
}
|
|
|
|
// Get reward from fees and height
|
|
var reward = Consensus.getReward(self.getNetworkType() === Consensus.MAINNET_NETWORK_TYPE, fees, height);
|
|
|
|
// Set switch type
|
|
var switchType = Crypto.SWITCH_TYPE_REGULAR;
|
|
|
|
// Get commit
|
|
var getCommit = function() {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return creating commit from extended private key, reward, current identifier, and switch type
|
|
return Crypto.commit(self.extendedPrivateKey, reward, currentIdentifier, switchType).then(function(commit) {
|
|
|
|
// Resolve commit
|
|
resolve(commit);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting commit from reward, current identifier, and switch type with the hardware wallet
|
|
return self.getHardwareWallet().getCommit(reward, currentIdentifier, switchType, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(commit) {
|
|
|
|
// Resolve commit
|
|
resolve(commit);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
// Return getting commit
|
|
return getCommit().then(function(commit) {
|
|
|
|
// Get proof
|
|
var getProof = function() {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if a proof is provided
|
|
if(proof !== Wallet.NO_PROOF) {
|
|
|
|
// Resolve proof
|
|
resolve(proof);
|
|
}
|
|
|
|
// Otherwise check if wallet isn't a hardware wallet
|
|
else if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return initializing new proof builder
|
|
var proofBuilder = new NewProofBuilder();
|
|
|
|
return proofBuilder.initialize(self.extendedPrivateKey).then(function() {
|
|
|
|
// Return creating proof from extended private key, reward, current identifier, switch type, and proof builder
|
|
return Crypto.proof(self.extendedPrivateKey, reward, currentIdentifier, switchType, proofBuilder).then(function(proof) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Resolve proof
|
|
resolve(proof);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return initializing view proof builder
|
|
var proofBuilder = new ViewProofBuilder();
|
|
|
|
return proofBuilder.initialize(self.rootPublicKey).then(function() {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting proof from reward, current identifier, switch type, and proof builder with the hardware wallet
|
|
return self.getHardwareWallet().getProof(reward, currentIdentifier, switchType, HardwareWallet.CREATING_COINBASE_MESSAGE, proofBuilder, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(proof) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Resolve proof
|
|
resolve(proof);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
// Return getting proof
|
|
return getProof().then(function(proof) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Get over commit from reward
|
|
var overCommit = Crypto.commitAmount(reward);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Check if getting excess from commit and over commit was successful
|
|
var excess = Secp256k1Zkp.pedersenCommitSum([
|
|
|
|
// Commit
|
|
commit
|
|
], [
|
|
|
|
// Over commit
|
|
overCommit
|
|
]);
|
|
|
|
if(excess !== Secp256k1Zkp.OPERATION_FAILED) {
|
|
|
|
// Check if creating public key from excess was successful
|
|
var publicKey = Secp256k1Zkp.pedersenCommitToPublicKey(excess);
|
|
|
|
if(publicKey !== Secp256k1Zkp.OPERATION_FAILED) {
|
|
|
|
// Get excess signature
|
|
var getExcessSignature = function() {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Create kernel coinbase signature message
|
|
var message = SlateKernel.signatureMessage(SlateKernel.COINBASE_FEATURES);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Return getting secret key from coinbase output
|
|
return self.getSum([
|
|
|
|
// Output
|
|
[
|
|
|
|
// Amount
|
|
reward,
|
|
|
|
// Identifier
|
|
currentIdentifier,
|
|
|
|
// Switch type
|
|
switchType
|
|
]
|
|
|
|
], []).then(function(secretKey) {
|
|
|
|
// Check if creating single-signer signature from the message, secret key, and public key was successful
|
|
var excessSignature = Secp256k1Zkp.createSingleSignerSignature(message, secretKey, Secp256k1Zkp.NO_SECRET_NONCE, publicKey, Secp256k1Zkp.NO_PUBLIC_NONCE, Secp256k1Zkp.NO_PUBLIC_NONCE_TOTAL);
|
|
|
|
if(excessSignature !== Secp256k1Zkp.OPERATION_FAILED) {
|
|
|
|
// Securely clear secret key
|
|
secretKey.fill(0);
|
|
|
|
// Resolve excess signature
|
|
resolve(excessSignature);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Securely clear secret key
|
|
secretKey.fill(0);
|
|
|
|
// Reject error
|
|
reject("Creating single-signer signature failed.");
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return starting transaction for the reward amount with the hardware wallet
|
|
return self.getHardwareWallet().startTransaction(Wallet.PAYMENT_PROOF_TOR_ADDRESS_KEY_INDEX, reward, new BigNumber(0), new BigNumber(0), HardwareWallet.NO_SECRET_NONCE_INDEX, HardwareWallet.NO_ADDRESS, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function() {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return including output in the transaction with the hardware wallet
|
|
return self.getHardwareWallet().includeOutputInTransaction(reward, currentIdentifier, switchType, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function() {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting transaction public nonce with the hardware wallet
|
|
return self.getHardwareWallet().getTransactionPublicNonce(hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(publicNonce) {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting transaction information with the public nonce, public key, and kernel features with the hardware wallet
|
|
return self.getHardwareWallet().getTransactionInformation(publicNonce, publicKey, SlateKernel.COINBASE_FEATURES, Slate.NO_LOCK_HEIGHT, Slate.NO_RELATIVE_HEIGHT, HardwareWallet.NO_KERNEL_COMMIT, HardwareWallet.NO_ADDRESS, Slate.NO_RECEIVER_SIGNATURE, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(transactionInformation) {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return completing transaction with the hardware wallet
|
|
return self.getHardwareWallet().completeTransaction().then(function() {
|
|
|
|
// Resolve excess signature
|
|
resolve(transactionInformation[HardwareWallet.TRANSACTION_INFORMATION_SIGNATURE_INDEX]);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return canceling transaction with the hardware wallet and catch errors
|
|
return self.getHardwareWallet().cancelTransaction().catch(function(error) {
|
|
|
|
// Finally
|
|
}).finally(function() {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return canceling transaction with the hardware wallet and catch errors
|
|
return self.getHardwareWallet().cancelTransaction().catch(function(error) {
|
|
|
|
// Finally
|
|
}).finally(function() {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return canceling transaction with the hardware wallet and catch errors
|
|
return self.getHardwareWallet().cancelTransaction().catch(function(error) {
|
|
|
|
// Finally
|
|
}).finally(function() {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
// Return getting excess signature
|
|
return getExcessSignature().then(function(excessSignature) {
|
|
|
|
// Resolve
|
|
resolve([
|
|
|
|
// Identifier
|
|
currentIdentifier,
|
|
|
|
// Commit
|
|
commit,
|
|
|
|
// Proof
|
|
proof,
|
|
|
|
// Excess
|
|
excess,
|
|
|
|
// Excess signature
|
|
excessSignature
|
|
]);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject error
|
|
reject("Getting public key from Pedersen commit failed.");
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject error
|
|
reject("Performing Pedersen commit sum failed.");
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Get sum
|
|
getSum(outputs, inputs) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise check if wallet is a hardware wallet
|
|
else if(self.getHardwareType() !== Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Reject error
|
|
reject("Sum can't be retrieved from a hardware wallet.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Go through all outputs
|
|
var deriveOutputKeys = [];
|
|
var outputKeys = [];
|
|
for(var i = 0; i < outputs["length"]; ++i) {
|
|
|
|
// Get output
|
|
let output = outputs[i];
|
|
|
|
// Append to derive output keys
|
|
deriveOutputKeys.push(new Promise(function(resolve, reject) {
|
|
|
|
// Return deriving output key from extended private key and output
|
|
return Crypto.deriveSecretKey(self.extendedPrivateKey, output[Wallet.OUTPUT_AMOUNT_INDEX], output[Wallet.OUTPUT_IDENTIFIER_INDEX], output[Wallet.OUTPUT_SWITCH_TYPE_INDEX]).then(function(outputKey) {
|
|
|
|
// Append output key to list
|
|
outputKeys.push(outputKey);
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}));
|
|
}
|
|
|
|
// Go through all inputs
|
|
var deriveInputKeys = [];
|
|
var inputKeys = [];
|
|
for(var i = 0; i < inputs["length"]; ++i) {
|
|
|
|
// Get input
|
|
let input = inputs[i];
|
|
|
|
// Append to derive input keys
|
|
deriveInputKeys.push(new Promise(function(resolve, reject) {
|
|
|
|
// Return deriving input key from extended private key and input
|
|
return Crypto.deriveSecretKey(self.extendedPrivateKey, input[Wallet.INPUT_AMOUNT_INDEX], input[Wallet.INPUT_IDENTIFIER_INDEX], input[Wallet.INPUT_SWITCH_TYPE_INDEX]).then(function(inputKey) {
|
|
|
|
// Append input key to list
|
|
inputKeys.push(inputKey);
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}));
|
|
}
|
|
|
|
// Wait for all output keys to be derived
|
|
Promise.all(deriveOutputKeys).then(function() {
|
|
|
|
// Wait for all input keys to be derived
|
|
Promise.all(deriveInputKeys).then(function() {
|
|
|
|
// Check if getting sum from derived keys failed
|
|
var sum = Secp256k1Zkp.blindSum(outputKeys, inputKeys);
|
|
|
|
if(sum === Secp256k1Zkp.OPERATION_FAILED) {
|
|
|
|
// Go through all output keys
|
|
for(var i = 0; i < outputKeys["length"]; ++i) {
|
|
|
|
// Securely clear output key
|
|
outputKeys[i].fill(0);
|
|
}
|
|
|
|
// Go through all input keys
|
|
for(var i = 0; i < inputKeys["length"]; ++i) {
|
|
|
|
// Securely clear input key
|
|
inputKeys[i].fill(0);
|
|
}
|
|
|
|
// Reject error
|
|
reject("Getting sum from derived keys failed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Go through all output keys
|
|
for(var i = 0; i < outputKeys["length"]; ++i) {
|
|
|
|
// Securely clear output key
|
|
outputKeys[i].fill(0);
|
|
}
|
|
|
|
// Go through all input keys
|
|
for(var i = 0; i < inputKeys["length"]; ++i) {
|
|
|
|
// Securely clear input key
|
|
inputKeys[i].fill(0);
|
|
}
|
|
|
|
// Check if sum isn't a valid secret key
|
|
if(Secp256k1Zkp.isValidSecretKey(sum) !== true) {
|
|
|
|
// Securely clear sum
|
|
sum.fill(0);
|
|
|
|
// Reject error
|
|
reject("Sum isn't a valid secret key.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Resolve sum
|
|
resolve(sum);
|
|
}
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Go through all output keys
|
|
for(var i = 0; i < outputKeys["length"]; ++i) {
|
|
|
|
// Securely clear output key
|
|
outputKeys[i].fill(0);
|
|
}
|
|
|
|
// Go through all input keys
|
|
for(var i = 0; i < inputKeys["length"]; ++i) {
|
|
|
|
// Securely clear input key
|
|
inputKeys[i].fill(0);
|
|
}
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Go through all output keys
|
|
for(var i = 0; i < outputKeys["length"]; ++i) {
|
|
|
|
// Securely clear output key
|
|
outputKeys[i].fill(0);
|
|
}
|
|
|
|
// Go through all input keys
|
|
for(var i = 0; i < inputKeys["length"]; ++i) {
|
|
|
|
// Securely clear input key
|
|
inputKeys[i].fill(0);
|
|
}
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Build output
|
|
buildOutput(amount, height = Identifier.NO_HEIGHT, message = HardwareWallet.SENDING_TRANSACTION_MESSAGE, hardwareWalletLockedText = HardwareWallet.NO_TEXT, hardwareWalletLockedTextArguments = [], allowUnlock = false, preventMessages = false, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false)
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if no last identifier exists
|
|
if(self.getLastIdentifier() === Wallet.NO_LAST_IDENTIFIER) {
|
|
|
|
// Get default identifier
|
|
var defaultIdentifier = new Identifier();
|
|
|
|
// Set the current identifier to the default identifier's child identifier
|
|
var currentIdentifier = defaultIdentifier.getChild(height);
|
|
|
|
// Set last identifier to the current identifier without the extras
|
|
self.setLastIdentifier(currentIdentifier.removeExtras());
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Set the current identifier to the last identifier's next identifier
|
|
var currentIdentifier = self.getLastIdentifier().getNext(height);
|
|
|
|
// Set last identifier to the current identifier without the extras
|
|
self.setLastIdentifier(currentIdentifier.removeExtras());
|
|
}
|
|
|
|
// Set switch type
|
|
var switchType = Crypto.SWITCH_TYPE_REGULAR;
|
|
|
|
// Get commit
|
|
var getCommit = function() {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return creating commit from extended private key, amount, current identifier, and switch type
|
|
return Crypto.commit(self.extendedPrivateKey, amount, currentIdentifier, switchType).then(function(commit) {
|
|
|
|
// Resolve commit
|
|
resolve(commit);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting commit from amount, current identifier, and switch type with the hardware wallet
|
|
return self.getHardwareWallet().getCommit(amount, currentIdentifier, switchType, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(commit) {
|
|
|
|
// Resolve commit
|
|
resolve(commit);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
// Return getting commit
|
|
return getCommit().then(function(commit) {
|
|
|
|
// Get proof
|
|
var getProof = function() {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't a hardware wallet
|
|
if(self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Return initializing new proof builder
|
|
var proofBuilder = new NewProofBuilder();
|
|
|
|
return proofBuilder.initialize(self.extendedPrivateKey).then(function() {
|
|
|
|
// Return creating proof from extended private key, amount, current identifier, switch type, and proof builder
|
|
return Crypto.proof(self.extendedPrivateKey, amount, currentIdentifier, switchType, proofBuilder).then(function(proof) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Resolve proof
|
|
resolve(proof);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return initializing view proof builder
|
|
var proofBuilder = new ViewProofBuilder();
|
|
|
|
return proofBuilder.initialize(self.rootPublicKey).then(function() {
|
|
|
|
// Check if hardware wallet is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Return getting proof from amount, current identifier, switch type, and proof builder with the hardware wallet
|
|
return self.getHardwareWallet().getProof(amount, currentIdentifier, switchType, message, proofBuilder, hardwareWalletLockedText, hardwareWalletLockedTextArguments, allowUnlock, preventMessages, cancelOccurred).then(function(proof) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Resolve proof
|
|
resolve(proof);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Uninitialize proof builder
|
|
proofBuilder.uninitialize();
|
|
|
|
// Reject hardware disconnected error
|
|
reject(HardwareWallet.DISCONNECTED_ERROR);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
// Return getting proof
|
|
return getProof().then(function(proof) {
|
|
|
|
// Resolve
|
|
resolve([
|
|
|
|
// Amount
|
|
amount,
|
|
|
|
// Identifier
|
|
currentIdentifier,
|
|
|
|
// Switch type
|
|
switchType,
|
|
|
|
// Features
|
|
SlateOutput.PLAIN_FEATURES,
|
|
|
|
// Commit
|
|
commit,
|
|
|
|
// Proof
|
|
proof
|
|
]);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Build Tor payment proof
|
|
buildTorPaymentProof(amount, commit, senderAddress) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise check if wallet is a hardware wallet
|
|
else if(self.getHardwareType() !== Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Reject error
|
|
reject("Payment proof can't be retrieved from a hardware wallet.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Get message from amount, commit, and sender address
|
|
var message = Slate.getPaymentProofMessage(amount, commit, senderAddress);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Return getting address private key at payment proof Tor address index
|
|
return self.getAddressKey(Wallet.PAYMENT_PROOF_TOR_ADDRESS_KEY_INDEX).then(function(addressSecretKey) {
|
|
|
|
// Check if signing message with address private key failed
|
|
var torPaymentProof = Ed25519.sign(message, addressSecretKey);
|
|
|
|
if(torPaymentProof === Ed25519.OPERATION_FAILED) {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Reject error
|
|
reject("Signing message with address key failed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Resolve Tor payment proof
|
|
resolve(torPaymentProof);
|
|
}
|
|
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Build MQS payment proof
|
|
buildMqsPaymentProof(amount, commit, senderAddress) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise check if wallet is a hardware wallet
|
|
else if(self.getHardwareType() !== Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Reject error
|
|
reject("Payment proof can't be retrieved from a hardware wallet.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Get message from amount, commit, and sender address
|
|
var message = Slate.getPaymentProofMessage(amount, commit, senderAddress);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Return getting address private key at payment proof MQS address index
|
|
return self.getAddressKey(Wallet.PAYMENT_PROOF_MQS_ADDRESS_KEY_INDEX).then(function(addressSecretKey) {
|
|
|
|
// Get message hash
|
|
var messageHash = new Uint8Array(sha256.arrayBuffer(message));
|
|
|
|
// Check if signing message with address private key failed
|
|
var mqsPaymentProof = Secp256k1Zkp.createMessageHashSignature(messageHash, addressSecretKey);
|
|
|
|
if(mqsPaymentProof === Secp256k1Zkp.OPERATION_FAILED) {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Reject error
|
|
reject("Signing message with address key failed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Resolve MQS payment proof
|
|
resolve(mqsPaymentProof);
|
|
}
|
|
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Build Slatepack payment proof
|
|
buildSlatepackPaymentProof(amount, commit, senderAddress) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise check if wallet is a hardware wallet
|
|
else if(self.getHardwareType() !== Wallet.NO_HARDWARE_TYPE) {
|
|
|
|
// Reject error
|
|
reject("Payment proof can't be retrieved from a hardware wallet.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Get message from amount, commit, and sender address
|
|
var message = Slate.getPaymentProofMessage(amount, commit, senderAddress);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Return getting address private key at payment proof Slatepack address index
|
|
return self.getAddressKey(Wallet.PAYMENT_PROOF_SLATEPACK_ADDRESS_KEY_INDEX).then(function(addressSecretKey) {
|
|
|
|
// Check if signing message with address private key failed
|
|
var slatepackPaymentProof = Ed25519.sign(message, addressSecretKey);
|
|
|
|
if(slatepackPaymentProof === Ed25519.OPERATION_FAILED) {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Reject error
|
|
reject("Signing message with address key failed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Securely clear address private key
|
|
addressSecretKey.fill(0);
|
|
|
|
// Resolve Slatepack payment proof
|
|
resolve(slatepackPaymentProof);
|
|
}
|
|
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Get name
|
|
getName() {
|
|
|
|
// Return name
|
|
return this.name;
|
|
}
|
|
|
|
// Set name
|
|
setName(name) {
|
|
|
|
// Set name
|
|
this.name = name;
|
|
}
|
|
|
|
// Get color
|
|
getColor() {
|
|
|
|
// Return color
|
|
return this.color;
|
|
}
|
|
|
|
// Set color
|
|
setColor(color) {
|
|
|
|
// Check if color is valid
|
|
if(Wallet.COLOR_PATTERN.test(color) === true)
|
|
|
|
// Set color
|
|
this.color = color;
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Set color to random color
|
|
this.color = Wallet.getRandomColor();
|
|
}
|
|
|
|
// Get salt
|
|
getSalt() {
|
|
|
|
// Return salt
|
|
return this.salt;
|
|
}
|
|
|
|
// Set salt
|
|
setSalt(salt) {
|
|
|
|
// Set salt
|
|
this.salt = salt;
|
|
}
|
|
|
|
// Get initialization vector
|
|
getInitializationVector() {
|
|
|
|
// Return initialization vector
|
|
return this.initializationVector;
|
|
}
|
|
|
|
// Set initialization vector
|
|
setInitializationVector(initializationVector) {
|
|
|
|
// Set initialization vector
|
|
this.initializationVector = initializationVector;
|
|
}
|
|
|
|
// Get number of iterations
|
|
getNumberOfIterations() {
|
|
|
|
// Return number of iterations
|
|
return this.numberOfIterations;
|
|
}
|
|
|
|
// Set number of iterations
|
|
setNumberOfIterations(numberOfIterations) {
|
|
|
|
// Set number of iterations
|
|
this.numberOfIterations = numberOfIterations;
|
|
}
|
|
|
|
// Get encrypted seed
|
|
getEncryptedSeed() {
|
|
|
|
// Return encrypted seed
|
|
return this.encryptedSeed;
|
|
}
|
|
|
|
// Set encrypted seed
|
|
setEncryptedSeed(encryptedSeed) {
|
|
|
|
// Set encrypted seed
|
|
this.encryptedSeed = encryptedSeed;
|
|
}
|
|
|
|
// Get address suffix
|
|
getAddressSuffix() {
|
|
|
|
// Return address suffix
|
|
return this.addressSuffix;
|
|
}
|
|
|
|
// Set address suffix
|
|
setAddressSuffix(addressSuffix) {
|
|
|
|
// Set address suffix
|
|
this.addressSuffix = addressSuffix;
|
|
}
|
|
|
|
// Get order
|
|
getOrder() {
|
|
|
|
// Return order
|
|
return this.order;
|
|
}
|
|
|
|
// Set order
|
|
setOrder(order) {
|
|
|
|
// Set order
|
|
this.order = order;
|
|
}
|
|
|
|
// Get synced height
|
|
getSyncedHeight() {
|
|
|
|
// Return synced height
|
|
return this.syncedHeight;
|
|
}
|
|
|
|
// Set synced height
|
|
setSyncedHeight(syncedHeight) {
|
|
|
|
// Set synced height
|
|
this.syncedHeight = syncedHeight;
|
|
}
|
|
|
|
// Get spent amount
|
|
getSpentAmount() {
|
|
|
|
// Return spent amount
|
|
return this.spentAmount;
|
|
}
|
|
|
|
// Set spent amount
|
|
setSpentAmount(spentAmount) {
|
|
|
|
// Set spent amount
|
|
this.spentAmount = spentAmount;
|
|
}
|
|
|
|
// Get unspent amount
|
|
getUnspentAmount() {
|
|
|
|
// Return unspent amount
|
|
return this.unspentAmount;
|
|
}
|
|
|
|
// Set unspent amount
|
|
setUnspentAmount(unspentAmount) {
|
|
|
|
// Set unspent amount
|
|
this.unspentAmount = unspentAmount;
|
|
}
|
|
|
|
// Get unconfirmed amount
|
|
getUnconfirmedAmount() {
|
|
|
|
// Return unconfirmed amount
|
|
return this.unconfirmedAmount;
|
|
}
|
|
|
|
// Set unconfirmed amount
|
|
setUnconfirmedAmount(unconfirmedAmount) {
|
|
|
|
// Set unconfirmed amount
|
|
this.unconfirmedAmount = unconfirmedAmount;
|
|
}
|
|
|
|
// Get locked amount
|
|
getLockedAmount() {
|
|
|
|
// Return locked amount
|
|
return this.lockedAmount;
|
|
}
|
|
|
|
// Set locked amount
|
|
setLockedAmount(lockedAmount) {
|
|
|
|
// Set locked amount
|
|
this.lockedAmount = lockedAmount;
|
|
}
|
|
|
|
// Get pending amount
|
|
getPendingAmount() {
|
|
|
|
// Return pending amount
|
|
return this.pendingAmount;
|
|
}
|
|
|
|
// Set pending amount
|
|
setPendingAmount(pendingAmount) {
|
|
|
|
// Set pending amount
|
|
this.pendingAmount = pendingAmount;
|
|
}
|
|
|
|
// Get expired amount
|
|
getExpiredAmount() {
|
|
|
|
// Return expired amount
|
|
return this.expiredAmount;
|
|
}
|
|
|
|
// Set expired amount
|
|
setExpiredAmount(expiredAmount) {
|
|
|
|
// Set expired amount
|
|
this.expiredAmount = expiredAmount;
|
|
}
|
|
|
|
// Get wallet type
|
|
getWalletType() {
|
|
|
|
// Return wallet type
|
|
return this.walletType;
|
|
}
|
|
|
|
// Set wallet type
|
|
setWalletType(walletType) {
|
|
|
|
// Set wallet type
|
|
this.walletType = walletType;
|
|
}
|
|
|
|
// Get network type
|
|
getNetworkType() {
|
|
|
|
// Return network type
|
|
return this.networkType;
|
|
}
|
|
|
|
// Set network type
|
|
setNetworkType(networkType) {
|
|
|
|
// Check if network type is valid
|
|
if(networkType === Consensus.MAINNET_NETWORK_TYPE || networkType === Consensus.TESTNET_NETWORK_TYPE)
|
|
|
|
// Set network type
|
|
this.networkType = networkType;
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Set network type
|
|
this.networkType = Consensus.getNetworkType();
|
|
}
|
|
|
|
// Get last identifier
|
|
getLastIdentifier() {
|
|
|
|
// Return last identifier
|
|
return this.lastIdentifier;
|
|
}
|
|
|
|
// Set last identifier
|
|
setLastIdentifier(lastIdentifier) {
|
|
|
|
// Set last identifier
|
|
this.lastIdentifier = lastIdentifier;
|
|
}
|
|
|
|
// Get hardware type
|
|
getHardwareType() {
|
|
|
|
// Return hardware type
|
|
return this.hardwareType;
|
|
}
|
|
|
|
// Set hardware type
|
|
setHardwareType(hardwareType) {
|
|
|
|
// Set hardware type
|
|
this.hardwareType = hardwareType;
|
|
}
|
|
|
|
// Get encrypted root public key
|
|
getEncryptedRootPublicKey() {
|
|
|
|
// Return encrypted root public key
|
|
return this.encryptedRootPublicKey;
|
|
}
|
|
|
|
// Set encrypted root public key
|
|
setEncryptedRootPublicKey(encryptedRootPublicKey) {
|
|
|
|
// Set encrypted root public key
|
|
this.encryptedRootPublicKey = encryptedRootPublicKey;
|
|
}
|
|
|
|
// Get use BIP39
|
|
getUseBip39() {
|
|
|
|
// Return use BIP39
|
|
return this.useBip39;
|
|
}
|
|
|
|
// Set use BIP39
|
|
setUseBip39(useBip39) {
|
|
|
|
// Set use BIP39
|
|
this.useBip39 = useBip39;
|
|
}
|
|
|
|
// Get encrypted BIP39 salt
|
|
getEncryptedBip39Salt() {
|
|
|
|
// Return encrypted BIP39 salt
|
|
return this.encryptedBip39Salt;
|
|
}
|
|
|
|
// Set encrypted BIP39 salt
|
|
setEncryptedBip39Salt(encryptedBip39Salt) {
|
|
|
|
// Set encrypted BIP39 salt
|
|
this.encryptedBip39Salt = encryptedBip39Salt;
|
|
}
|
|
|
|
// Get account number
|
|
getAccountNumber() {
|
|
|
|
// Return account number
|
|
return this.accountNumber;
|
|
}
|
|
|
|
// Set account number
|
|
setAccountNumber(accountNumber) {
|
|
|
|
// Set account number
|
|
this.accountNumber = accountNumber;
|
|
}
|
|
|
|
// Get payment proof index
|
|
getPaymentProofIndex() {
|
|
|
|
// Return payment proof index
|
|
return this.paymentProofIndex;
|
|
}
|
|
|
|
// Set payment proof index
|
|
setPaymentProofIndex(paymentProofIndex) {
|
|
|
|
// Set payment proof index
|
|
this.paymentProofIndex = paymentProofIndex;
|
|
}
|
|
|
|
// Get key path
|
|
getKeyPath() {
|
|
|
|
// Return key path
|
|
return this.keyPath;
|
|
}
|
|
|
|
// Set key path
|
|
setKeyPath(keyPath) {
|
|
|
|
// Set keyPath
|
|
this.keyPath = keyPath;
|
|
|
|
// Check if hardware wallet exists
|
|
if(this.getHardwareWallet() !== Wallet.NO_HARDWARE_WALLET) {
|
|
|
|
// Set hardware wallet's wallet key path
|
|
this.getHardwareWallet().setWalletKeyPath(keyPath);
|
|
}
|
|
}
|
|
|
|
// Get starting sync height
|
|
getStartingSyncHeight() {
|
|
|
|
// Return starting sync height
|
|
return this.startingSyncHeight;
|
|
}
|
|
|
|
// Set starting sync height
|
|
setStartingSyncHeight(startingSyncHeight) {
|
|
|
|
// Set starting sync height
|
|
this.startingSyncHeight = startingSyncHeight;
|
|
}
|
|
|
|
// Get sync complete value
|
|
getSyncCompleteValue(syncCompleteValue) {
|
|
|
|
// Return sync complete value
|
|
return this.syncCompleteValue;
|
|
}
|
|
|
|
// Set sync complete value
|
|
setSyncCompleteValue(syncCompleteValue) {
|
|
|
|
// Set sync complete value
|
|
this.syncCompleteValue = syncCompleteValue;
|
|
}
|
|
|
|
// Get performing address suffix operation
|
|
getPerformingAddressSuffixOperation() {
|
|
|
|
// Return performing address suffix operation
|
|
return this.performingAddressSuffixOperation;
|
|
}
|
|
|
|
// Set performing address suffix operation
|
|
setPerformingAddressSuffixOperation(performingAddressSuffixOperation) {
|
|
|
|
// Set performing address suffix operation
|
|
this.performingAddressSuffixOperation = performingAddressSuffixOperation;
|
|
}
|
|
|
|
// Get address suffix verified
|
|
getAddressSuffixVerified() {
|
|
|
|
// Return address suffix verified
|
|
return this.addressSuffixVerified;
|
|
}
|
|
|
|
// Set address suffix verified
|
|
setAddressSuffixVerified(addressSuffixVerified) {
|
|
|
|
// Set address suffix verified
|
|
this.addressSuffixVerified = addressSuffixVerified;
|
|
}
|
|
|
|
// Get syncing status
|
|
getSyncingStatus() {
|
|
|
|
// Return syncing status
|
|
return this.syncingStatus;
|
|
}
|
|
|
|
// Set syncing status
|
|
setSyncingStatus(syncingStatus) {
|
|
|
|
// Set syncing status
|
|
this.syncingStatus = syncingStatus;
|
|
}
|
|
|
|
// Get last sync index
|
|
getLastSyncIndex() {
|
|
|
|
// Return last sync index
|
|
return this.lastSyncIndex;
|
|
}
|
|
|
|
// Set last sync index
|
|
setLastSyncIndex(lastSyncIndex) {
|
|
|
|
// Set last sync index
|
|
this.lastSyncIndex = lastSyncIndex;
|
|
}
|
|
|
|
// Get percent synced
|
|
getPercentSynced() {
|
|
|
|
// Return percent synced
|
|
return this.percentSynced;
|
|
}
|
|
|
|
// Set percent synced
|
|
setPercentSynced(percentSynced) {
|
|
|
|
// Set percent synced
|
|
this.percentSynced = percentSynced;
|
|
}
|
|
|
|
// Get address
|
|
getAddress(type) {
|
|
|
|
// Check if doesn't have an address suffix
|
|
if(this.getAddressSuffix() === Wallet.NO_ADDRESS_SUFFIX)
|
|
|
|
// Return empty string
|
|
return "";
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Parse address suffix as a URL
|
|
new URL(this.getAddressSuffix());
|
|
|
|
// Return address suffix
|
|
return this.getAddressSuffix();
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Check type
|
|
switch(type) {
|
|
|
|
// HTTP address type
|
|
case Wallet.HTTP_ADDRESS_TYPE:
|
|
|
|
// Return HTTP address
|
|
return this.getHttpAddress();
|
|
|
|
// Tor address type
|
|
case Wallet.TOR_ADDRESS_TYPE:
|
|
|
|
// Return Tor address
|
|
return this.getTorAddress();
|
|
|
|
// Match connection address type
|
|
case Wallet.MATCH_CONNECTION_ADDRESS_TYPE:
|
|
|
|
// Return address that matches connection
|
|
return (Tor.isOnionService() === true) ? this.getTorAddress() : this.getHttpAddress();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Owns output
|
|
ownsOutput(output) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return getting output's information
|
|
return output.getInformation((self.getHardwareType() === Wallet.NO_HARDWARE_TYPE) ? self.extendedPrivateKey : self.rootPublicKey, self.getNetworkType() === Consensus.MAINNET_NETWORK_TYPE).then(function(outputInformation) {
|
|
|
|
// Resolve output information
|
|
resolve(outputInformation);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Is syncing
|
|
isSyncing() {
|
|
|
|
// Return is syncing status is syncing or resyning
|
|
return this.getSyncingStatus() === Wallet.STATUS_SYNCING || this.getSyncingStatus() === Wallet.STATUS_RESYNCING;
|
|
}
|
|
|
|
// Is synced
|
|
isSynced() {
|
|
|
|
// Return if syncing status is synced
|
|
return this.getSyncingStatus() === Wallet.STATUS_SYNCED;
|
|
}
|
|
|
|
// Connect to applicable hardware
|
|
connectToApplicableHardware(hardwareWallets) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if open, is a hardware wallet, and hardware isn't connected
|
|
if(self.isOpen() === true && self.getHardwareType() !== Wallet.NO_HARDWARE_TYPE && self.isHardwareConnected() === false) {
|
|
|
|
// Return getting the seed cookie from the root public key
|
|
return crypto["subtle"].digest(Wallet.SEED_COOKIE_DIGEST_ALGORITHM, self.rootPublicKey).then(function(seedCookie) {
|
|
|
|
// Get seed cookie in the correct format
|
|
seedCookie = new Uint8Array(seedCookie);
|
|
|
|
// Check if open, is a hardware wallet, and hardware isn't connected
|
|
if(self.isOpen() === true && self.getHardwareType() !== Wallet.NO_HARDWARE_TYPE && self.isHardwareConnected() === false) {
|
|
|
|
// Go through all hardware wallets
|
|
for(var i = 0; i < hardwareWallets["length"]; ++i) {
|
|
|
|
// Get hardware wallet
|
|
var hardwareWallet = hardwareWallets[i];
|
|
|
|
// Check if hardware wallet isn't in use
|
|
if(hardwareWallet.getInUse() === false) {
|
|
|
|
// Check if the hardware wallet's seed cookie matches the wallet's
|
|
if(Common.arraysAreEqual(seedCookie, hardwareWallet.getSeedCookie()) === true) {
|
|
|
|
// Set hardware wallet to the hardware wallet
|
|
self.hardwareWallet = hardwareWallet;
|
|
|
|
// Check if hardware types differ
|
|
if(self.getHardwareType() !== self.hardwareWallet.getHardwareType()) {
|
|
|
|
// Trigger wallet hardware type change event
|
|
$(document).trigger(Wallet.HARDWARE_TYPE_CHANGE_EVENT, [
|
|
|
|
// Key path
|
|
self.getKeyPath(),
|
|
|
|
// New hardware type
|
|
self.hardwareWallet.getHardwareType()
|
|
]);
|
|
}
|
|
|
|
// Set hardware wallet's wallet key path
|
|
hardwareWallet.setWalletKeyPath(self.getKeyPath());
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if hardware is connected
|
|
if(self.isHardwareConnected() === true) {
|
|
|
|
// Set that hardware wallet is in use
|
|
self.getHardwareWallet().setInUse(true);
|
|
|
|
// Trigger wallet connect event
|
|
$(document).trigger(Wallet.CONNECT_EVENT, [
|
|
|
|
// Key path
|
|
self.getKeyPath(),
|
|
|
|
// Connection type
|
|
self.getHardwareWallet().getConnectionType()
|
|
]);
|
|
|
|
// Hardware wallet on hardware disconnect event
|
|
$(self.getHardwareWallet()).one(HardwareWallet.DISCONNECT_EVENT, function() {
|
|
|
|
// Check if hardware wallet exists
|
|
if(self.getHardwareWallet() !== Wallet.NO_HARDWARE_WALLET) {
|
|
|
|
// Close hardware wallet
|
|
self.getHardwareWallet().close();
|
|
|
|
// Set hardware wallet to no hardware wallet
|
|
self.hardwareWallet = Wallet.NO_HARDWARE_WALLET;
|
|
}
|
|
|
|
// Check if key path exists
|
|
if(self.getKeyPath() !== Wallet.NO_KEY_PATH) {
|
|
|
|
// Trigger wallet disconnect event
|
|
$(document).trigger(Wallet.DISCONNECT_EVENT, [
|
|
|
|
// Key path
|
|
self.getKeyPath()
|
|
]);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if hardware wallet exists
|
|
if(self.getHardwareWallet() !== Wallet.NO_HARDWARE_WALLET) {
|
|
|
|
// Close hardware wallet
|
|
self.getHardwareWallet().close();
|
|
|
|
// Set hardware wallet to no hardware wallet
|
|
self.hardwareWallet = Wallet.NO_HARDWARE_WALLET;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Resolve
|
|
resolve();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Is hardware connected
|
|
isHardwareConnected() {
|
|
|
|
// Return is hardware wallet is connected
|
|
return this.getHardwareWallet() !== Wallet.NO_HARDWARE_WALLET && this.getHardwareWallet().isConnected() === true;
|
|
}
|
|
|
|
// Get hardware wallet
|
|
getHardwareWallet() {
|
|
|
|
// Return hardware wallet
|
|
return this.hardwareWallet;
|
|
}
|
|
|
|
// No key path
|
|
static get NO_KEY_PATH() {
|
|
|
|
// Return no key path
|
|
return null;
|
|
}
|
|
|
|
// No name
|
|
static get NO_NAME() {
|
|
|
|
// Return no name
|
|
return null;
|
|
}
|
|
|
|
// No encrypted seed
|
|
static get NO_ENCRYPTED_SEED() {
|
|
|
|
// Return no encrypted seed
|
|
return null;
|
|
}
|
|
|
|
// No address suffix
|
|
static get NO_ADDRESS_SUFFIX() {
|
|
|
|
// Return no address suffix
|
|
return null;
|
|
}
|
|
|
|
// No order
|
|
static get NO_ORDER() {
|
|
|
|
// Return no order
|
|
return null;
|
|
}
|
|
|
|
// Unknown order
|
|
static get UNKNOWN_ORDER() {
|
|
|
|
// Return unknown order
|
|
return undefined;
|
|
}
|
|
|
|
// No last identifier
|
|
static get NO_LAST_IDENTIFIER() {
|
|
|
|
// Return no last identifier
|
|
return null;
|
|
}
|
|
|
|
// No hardware type
|
|
static get NO_HARDWARE_TYPE() {
|
|
|
|
// Return no hardware type
|
|
return null;
|
|
}
|
|
|
|
// No encrypted root public key
|
|
static get NO_ENCRYPTED_ROOT_PUBLIC_KEY() {
|
|
|
|
// Return no encrypted seed
|
|
return null;
|
|
}
|
|
|
|
// No encrypted BIP39 salt
|
|
static get NO_ENCRYPTED_BIP39_SALT() {
|
|
|
|
// Return no encrypted seed
|
|
return null;
|
|
}
|
|
|
|
// Current height
|
|
static get CURRENT_HEIGHT() {
|
|
|
|
// Return current height
|
|
return null;
|
|
}
|
|
|
|
// Status syncing
|
|
static get STATUS_SYNCING() {
|
|
|
|
// Return status syncing
|
|
return 0;
|
|
}
|
|
|
|
// Status resyncing
|
|
static get STATUS_RESYNCING() {
|
|
|
|
// Return status resyncing
|
|
return Wallet.STATUS_SYNCING + 1;
|
|
}
|
|
|
|
// Status synced
|
|
static get STATUS_SYNCED() {
|
|
|
|
// Return status synced
|
|
return Wallet.STATUS_RESYNCING + 1;
|
|
}
|
|
|
|
// Status error
|
|
static get STATUS_ERROR() {
|
|
|
|
// Return status error
|
|
return Wallet.STATUS_SYNCED + 1;
|
|
}
|
|
|
|
// No sync index
|
|
static get NO_SYNC_INDEX() {
|
|
|
|
// Return no sync index
|
|
return null;
|
|
}
|
|
|
|
// Last sync index start index index
|
|
static get LAST_SYNC_INDEX_START_INDEX_INDEX() {
|
|
|
|
// Return last sync index start index index
|
|
return 0;
|
|
}
|
|
|
|
// Last sync index last retrieved index index
|
|
static get LAST_SYNC_INDEX_LAST_RETRIEVED_INDEX_INDEX() {
|
|
|
|
// Return last sync index last retrieved index index
|
|
return Wallet.LAST_SYNC_INDEX_START_INDEX_INDEX + 1;
|
|
}
|
|
|
|
// Coinbase identifier index
|
|
static get COINBASE_IDENTIFIER_INDEX() {
|
|
|
|
// Return coinbase identifier index
|
|
return 0;
|
|
}
|
|
|
|
// Coinbase commit index
|
|
static get COINBASE_COMMIT_INDEX() {
|
|
|
|
// Return coinbase commit index
|
|
return Wallet.COINBASE_IDENTIFIER_INDEX + 1;
|
|
}
|
|
|
|
// Coinbase proof index
|
|
static get COINBASE_PROOF_INDEX() {
|
|
|
|
// Return coinbase proof index
|
|
return Wallet.COINBASE_COMMIT_INDEX + 1;
|
|
}
|
|
|
|
// Coinbase excess index
|
|
static get COINBASE_EXCESS_INDEX() {
|
|
|
|
// Return coinbase excess index
|
|
return Wallet.COINBASE_PROOF_INDEX + 1;
|
|
}
|
|
|
|
// Coinbase excess signature index
|
|
static get COINBASE_EXCESS_SIGNATURE_INDEX() {
|
|
|
|
// Return coinbase excess signature index
|
|
return Wallet.COINBASE_EXCESS_INDEX + 1;
|
|
}
|
|
|
|
// Output amount index
|
|
static get OUTPUT_AMOUNT_INDEX() {
|
|
|
|
// Return output amount index
|
|
return 0;
|
|
}
|
|
|
|
// Output identifier index
|
|
static get OUTPUT_IDENTIFIER_INDEX() {
|
|
|
|
// Return output identifier index
|
|
return Wallet.OUTPUT_AMOUNT_INDEX + 1;
|
|
}
|
|
|
|
// Output switch type index
|
|
static get OUTPUT_SWITCH_TYPE_INDEX() {
|
|
|
|
// Return output switch type index
|
|
return Wallet.OUTPUT_IDENTIFIER_INDEX + 1;
|
|
}
|
|
|
|
// Output features index
|
|
static get OUTPUT_FEATURES_INDEX() {
|
|
|
|
// Return output features index
|
|
return Wallet.OUTPUT_SWITCH_TYPE_INDEX + 1;
|
|
}
|
|
|
|
// Output commit index
|
|
static get OUTPUT_COMMIT_INDEX() {
|
|
|
|
// Return output commit index
|
|
return Wallet.OUTPUT_FEATURES_INDEX + 1;
|
|
}
|
|
|
|
// Output proof index
|
|
static get OUTPUT_PROOF_INDEX() {
|
|
|
|
// Return output proof index
|
|
return Wallet.OUTPUT_COMMIT_INDEX + 1;
|
|
}
|
|
|
|
// Input amount index
|
|
static get INPUT_AMOUNT_INDEX() {
|
|
|
|
// Return input amount index
|
|
return 0;
|
|
}
|
|
|
|
// Input identifier index
|
|
static get INPUT_IDENTIFIER_INDEX() {
|
|
|
|
// Return input identifier index
|
|
return Wallet.INPUT_AMOUNT_INDEX + 1;
|
|
}
|
|
|
|
// Input switch type index
|
|
static get INPUT_SWITCH_TYPE_INDEX() {
|
|
|
|
// Return input switch type index
|
|
return Wallet.INPUT_IDENTIFIER_INDEX + 1;
|
|
}
|
|
|
|
// Input features index
|
|
static get INPUT_FEATURES_INDEX() {
|
|
|
|
// Return input features index
|
|
return Wallet.INPUT_SWITCH_TYPE_INDEX + 1;
|
|
}
|
|
|
|
// Input commit index
|
|
static get INPUT_COMMIT_INDEX() {
|
|
|
|
// Return input commit index
|
|
return Wallet.INPUT_FEATURES_INDEX + 1;
|
|
}
|
|
|
|
// Input key path index
|
|
static get INPUT_KEY_PATH_INDEX() {
|
|
|
|
// Return input key path index
|
|
return Wallet.INPUT_COMMIT_INDEX + 1;
|
|
}
|
|
|
|
// HTTP address type
|
|
static get HTTP_ADDRESS_TYPE() {
|
|
|
|
// Return HTTP address type
|
|
return "HTTP";
|
|
}
|
|
|
|
// Tor address type
|
|
static get TOR_ADDRESS_TYPE() {
|
|
|
|
// Return Tor address type
|
|
return "Tor";
|
|
}
|
|
|
|
// Match connection address type
|
|
static get MATCH_CONNECTION_ADDRESS_TYPE() {
|
|
|
|
// Return match connection address type
|
|
return "Match Connection";
|
|
}
|
|
|
|
// Disconnect event
|
|
static get DISCONNECT_EVENT() {
|
|
|
|
// Return disconnect event
|
|
return "WalletDisconnectEvent";
|
|
}
|
|
|
|
// Connect event
|
|
static get CONNECT_EVENT() {
|
|
|
|
// Return disconnect event
|
|
return "WalletConnectEvent";
|
|
}
|
|
|
|
// Hardware type change event
|
|
static get HARDWARE_TYPE_CHANGE_EVENT() {
|
|
|
|
// Return hardware type change event
|
|
return "WalletHardwareTypeChangeEvent";
|
|
}
|
|
|
|
// Encrypt seed and BIP39 salt encrypted seed index
|
|
static get ENCRYPT_SEED_AND_BIP39_SALT_ENCRYPTED_SEED_INDEX() {
|
|
|
|
// Return encrypt seed and BIP39 salt encrypted seed index
|
|
return 0;
|
|
}
|
|
|
|
// Encrypt seed and BIP39 salt encrypted BIP39 salt index
|
|
static get ENCRYPT_SEED_AND_BIP39_SALT_ENCRYPTED_BIP39_SALT_INDEX() {
|
|
|
|
// Return encrypt seed and BIP39 salt encrypted BIP39 salt index
|
|
return Wallet.ENCRYPT_SEED_AND_BIP39_SALT_ENCRYPTED_SEED_INDEX + 1;
|
|
}
|
|
|
|
// Decrypt seed and BIP39 salt decrypted seed index
|
|
static get DECRYPT_SEED_AND_BIP39_SALT_DECRYPTED_SEED_INDEX() {
|
|
|
|
// Return decrypt seed and BIP39 salt decrypted seed index
|
|
return 0;
|
|
}
|
|
|
|
// Decrypt seed and BIP39 salt decrypted BIP39 salt index
|
|
static get DECRYPT_SEED_AND_BIP39_SALT_DECRYPTED_BIP39_SALT_INDEX() {
|
|
|
|
// Return decrypt seed and BIP39 salt decrypted BIP39 salt index
|
|
return Wallet.DECRYPT_SEED_AND_BIP39_SALT_DECRYPTED_SEED_INDEX + 1;
|
|
}
|
|
|
|
// No proof
|
|
static get NO_PROOF() {
|
|
|
|
// Return no proof
|
|
return null;
|
|
}
|
|
|
|
// Private
|
|
|
|
// Get HTTP address
|
|
getHttpAddress() {
|
|
|
|
// Return HTTP address
|
|
return HTTPS_SERVER_ADDRESS + "/wallet/" + this.getAddressSuffix();
|
|
}
|
|
|
|
// Get Tor address
|
|
getTorAddress() {
|
|
|
|
// Return Tor address
|
|
return TOR_SERVER_ADDRESS + "/wallet/" + this.getAddressSuffix();
|
|
}
|
|
|
|
// Encrypt seed and BIP39 salt
|
|
encryptSeedAndBip39Salt(password, salt, numberOfIterations, initializationVector) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return getting key
|
|
return Wallet.getKey(password, salt, numberOfIterations).then(function(key) {
|
|
|
|
// Return encrypting the seed using key and initialization vector
|
|
return crypto["subtle"].encrypt({
|
|
|
|
// Name
|
|
"name": Wallet.ENCRYPTION_ALGORITHM,
|
|
|
|
// Initialization vector
|
|
"iv": initializationVector
|
|
|
|
}, key, self.seed.getSeed()).then(function(encryptedSeed) {
|
|
|
|
// Get encrypted seed in the correct format
|
|
encryptedSeed = new Uint8Array(encryptedSeed);
|
|
|
|
// Check if BIP39 salt exists
|
|
if(self.bip39Salt !== Wallet.NO_BIP39_SALT) {
|
|
|
|
// Return encrypting the BIP39 salt using key and initialization vector
|
|
return crypto["subtle"].encrypt({
|
|
|
|
// Name
|
|
"name": Wallet.ENCRYPTION_ALGORITHM,
|
|
|
|
// Initialization vector
|
|
"iv": initializationVector
|
|
|
|
}, key, self.bip39Salt).then(function(encryptedBip39Salt) {
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Get encrypted BIP39 salt in the correct format
|
|
encryptedBip39Salt = new Uint8Array(encryptedBip39Salt);
|
|
|
|
// Resolve
|
|
resolve([
|
|
|
|
// Encrypted seed
|
|
encryptedSeed,
|
|
|
|
// Encrypted BIP39 salt
|
|
encryptedBip39Salt
|
|
]);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Securely clear encrypted seed
|
|
encryptedSeed.fill(0);
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Resolve
|
|
resolve([
|
|
|
|
// Encrypted seed
|
|
encryptedSeed,
|
|
|
|
// No encrypted BIP39 salt
|
|
Wallet.NO_ENCRYPTED_BIP39_SALT
|
|
]);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Decrypt seed and BIP39 salt
|
|
decryptSeedAndBip39Salt(password, salt, numberOfIterations, initializationVector) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return getting key
|
|
return Wallet.getKey(password, salt, numberOfIterations).then(function(key) {
|
|
|
|
// Return decrypting the encrypted seed using key and initialization vector
|
|
return crypto["subtle"].decrypt({
|
|
|
|
// Name
|
|
"name": Wallet.ENCRYPTION_ALGORITHM,
|
|
|
|
// Initialization vector
|
|
"iv": initializationVector
|
|
|
|
}, key, self.getEncryptedSeed()).then(function(decryptedSeed) {
|
|
|
|
// Get decrypted seed in correct format
|
|
decryptedSeed = new Uint8Array(decryptedSeed);
|
|
|
|
// Check if encrypted BIP39 salt exists
|
|
if(self.getEncryptedBip39Salt() !== Wallet.NO_ENCRYPTED_BIP39_SALT) {
|
|
|
|
// Return decrypting the encrypted BIP39 salt using key and initialization vector
|
|
return crypto["subtle"].decrypt({
|
|
|
|
// Name
|
|
"name": Wallet.ENCRYPTION_ALGORITHM,
|
|
|
|
// Initialization vector
|
|
"iv": initializationVector
|
|
|
|
}, key, self.getEncryptedBip39Salt()).then(function(decryptedBip39Salt) {
|
|
|
|
// Get decrypted BIP39 salt in correct format
|
|
decryptedBip39Salt = new Uint8Array(decryptedBip39Salt);
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Resolve
|
|
resolve([
|
|
|
|
// Decrypted seed
|
|
decryptedSeed,
|
|
|
|
// Decrypted BIP39 salt
|
|
decryptedBip39Salt
|
|
]);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Securely clear decrypted seed
|
|
decryptedSeed.fill(0);
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Resolve
|
|
resolve([
|
|
|
|
// Decrypted seed
|
|
decryptedSeed,
|
|
|
|
// No BIP39 salt
|
|
Wallet.NO_BIP39_SALT
|
|
]);
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Encrypt root public key
|
|
encryptRootPublicKey(password, salt, numberOfIterations, initializationVector) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if wallet isn't open
|
|
if(self.isOpen() === false) {
|
|
|
|
// Reject error
|
|
reject("Wallet closed.");
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return getting key
|
|
return Wallet.getKey(password, salt, numberOfIterations).then(function(key) {
|
|
|
|
// Return encrypting the root public key using key and initialization vector
|
|
return crypto["subtle"].encrypt({
|
|
|
|
// Name
|
|
"name": Wallet.ENCRYPTION_ALGORITHM,
|
|
|
|
// Initialization vector
|
|
"iv": initializationVector
|
|
|
|
}, key, self.rootPublicKey).then(function(encryptedRootPublicKey) {
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Resolve encrypted root public key
|
|
resolve(new Uint8Array(encryptedRootPublicKey));
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Decrypt root public key
|
|
decryptRootPublicKey(password, salt, numberOfIterations, initializationVector) {
|
|
|
|
// Set self
|
|
var self = this;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return getting key
|
|
return Wallet.getKey(password, salt, numberOfIterations).then(function(key) {
|
|
|
|
// Return decrypting the encrypted root public key using key and initialization vector
|
|
return crypto["subtle"].decrypt({
|
|
|
|
// Name
|
|
"name": Wallet.ENCRYPTION_ALGORITHM,
|
|
|
|
// Initialization vector
|
|
"iv": initializationVector
|
|
|
|
}, key, self.getEncryptedRootPublicKey()).then(function(decryptedRootPublicKey) {
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Resolve decrypted root public key
|
|
resolve(new Uint8Array(decryptedRootPublicKey));
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// TODO Securely clear key
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Get key
|
|
static getKey(password, salt, numberOfIterations) {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Get the saved password pepper
|
|
var passwordPepper = localStorage.getItem(Wallet.PASSWORD_PEPPER_LOCAL_STORAGE_NAME);
|
|
|
|
// Check if password pepper exists and is valid
|
|
if(passwordPepper !== Common.INVALID_LOCAL_STORAGE_ITEM && Common.isHexString(passwordPepper) === true) {
|
|
|
|
// Initialize combined password
|
|
var combinedPassword = Common.mergeArrays([
|
|
|
|
// Password
|
|
password,
|
|
|
|
// Password pepper
|
|
Common.fromHexString(passwordPepper)
|
|
]);
|
|
|
|
// Return creating base key from password and password pepper
|
|
return crypto["subtle"].importKey("raw", combinedPassword, {
|
|
|
|
// Name
|
|
"name": Wallet.IMPORT_ALGORITHM
|
|
|
|
}, false, [
|
|
|
|
// Derive key
|
|
"deriveKey"
|
|
|
|
]).then(function(baseKey) {
|
|
|
|
// Securely clear combined password
|
|
combinedPassword.fill(0);
|
|
|
|
// Return deriving key from base key, salt, and number of iterations
|
|
return crypto["subtle"].deriveKey({
|
|
|
|
// Name
|
|
"name": Wallet.IMPORT_ALGORITHM,
|
|
|
|
// Salt
|
|
"salt": salt,
|
|
|
|
// Iterations
|
|
"iterations": numberOfIterations,
|
|
|
|
// Hash
|
|
"hash": Wallet.DIGEST_ALGORITHM
|
|
|
|
}, baseKey, {
|
|
|
|
// Name
|
|
"name": Wallet.ENCRYPTION_ALGORITHM,
|
|
|
|
// Length
|
|
"length": Wallet.ENCRYPTION_KEY_LENGTH
|
|
|
|
}, false, [
|
|
|
|
// Encrypt
|
|
"encrypt",
|
|
|
|
// Decrypt
|
|
"decrypt"
|
|
|
|
]).then(function(derivedKey) {
|
|
|
|
// TODO Securely clear baseKey
|
|
|
|
// Resolve derived key
|
|
resolve(derivedKey);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// TODO Securely clear baseKey
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Securely clear combined password
|
|
combinedPassword.fill(0);
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject
|
|
reject();
|
|
}
|
|
});
|
|
}
|
|
|
|
// To linear color space
|
|
static toLinearColorSpace(color) {
|
|
|
|
// Normalize color
|
|
var normalizedColor = color / Common.BYTE_MAX_VALUE;
|
|
|
|
// Return color in linear color space
|
|
return (normalizedColor <= 0.03928) ? normalizedColor / 12.92 : Math.pow(((normalizedColor + 0.055) / 1.055), 2.4);
|
|
}
|
|
|
|
// Get luminance
|
|
static getLuminance(red, green, blue) {
|
|
|
|
// Return luminance of colors in linear color space
|
|
return 0.2126 * Wallet.toLinearColorSpace(red) + 0.7152 * Wallet.toLinearColorSpace(green) + 0.0722 * Wallet.toLinearColorSpace(blue);
|
|
}
|
|
|
|
// Get random color
|
|
static getRandomColor() {
|
|
|
|
// Loop forever
|
|
while(true) {
|
|
|
|
// Get random red, green, and blue values
|
|
var red = Common.randomNumber(0, Common.BYTE_MAX_VALUE);
|
|
var green = Common.randomNumber(0, Common.BYTE_MAX_VALUE);
|
|
var blue = Common.randomNumber(0, Common.BYTE_MAX_VALUE);
|
|
|
|
// Get luminance of combined colors
|
|
var luminance = Wallet.getLuminance(red, green, blue);
|
|
|
|
// Check if luminance isn't too bright or too dark
|
|
if((luminance + 0.05) / (0 + 0.05) <= (1 + 0.05) / (luminance + 0.05) && luminance > 0.02)
|
|
|
|
// Return combined color
|
|
return "#" + Math.floor(red).toString(Common.HEX_NUMBER_BASE).padStart(Common.HEX_NUMBER_LENGTH, Common.HEX_NUMBER_PADDING) + Math.floor(green).toString(Common.HEX_NUMBER_BASE).padStart(Common.HEX_NUMBER_LENGTH, Common.HEX_NUMBER_PADDING) + Math.floor(blue).toString(Common.HEX_NUMBER_BASE).padStart(Common.HEX_NUMBER_LENGTH, Common.HEX_NUMBER_PADDING);
|
|
}
|
|
}
|
|
|
|
// No seed
|
|
static get NO_SEED() {
|
|
|
|
// Return no seed
|
|
return null;
|
|
}
|
|
|
|
// No root public key
|
|
static get NO_ROOT_PUBLIC_KEY() {
|
|
|
|
// Return no root public key
|
|
return null;
|
|
}
|
|
|
|
// No extended private key
|
|
static get NO_EXTENDED_PRIVATE_KEY() {
|
|
|
|
// Return no extended private key
|
|
return null;
|
|
}
|
|
|
|
// No hardware wallet
|
|
static get NO_HARDWARE_WALLET() {
|
|
|
|
// Return no hardware wallet
|
|
return null;
|
|
}
|
|
|
|
// No passphrase
|
|
static get NO_PASSPHRASE() {
|
|
|
|
// Return no passphrase
|
|
return null;
|
|
}
|
|
|
|
// No BIP39 salt
|
|
static get NO_BIP39_SALT() {
|
|
|
|
// Return no BIP39 salt
|
|
return null;
|
|
}
|
|
|
|
// Salt length
|
|
static get SALT_LENGTH() {
|
|
|
|
// Return salt length
|
|
return 32;
|
|
}
|
|
|
|
// Initialization vector length
|
|
static get INITIALIZATION_VECTOR_LENGTH() {
|
|
|
|
// Return initialization vector length
|
|
return 32;
|
|
}
|
|
|
|
// Default number of iterations
|
|
static get DEFAULT_NUMBER_OF_ITERATIONS() {
|
|
|
|
// Return default number of iterations
|
|
return 200000;
|
|
}
|
|
|
|
// Import algorithm
|
|
static get IMPORT_ALGORITHM() {
|
|
|
|
// Return import algorithm
|
|
return "PBKDF2";
|
|
}
|
|
|
|
// Encryption algorithm
|
|
static get ENCRYPTION_ALGORITHM() {
|
|
|
|
// Return encryption algorithm
|
|
return "AES-GCM";
|
|
}
|
|
|
|
// Encryption key length
|
|
static get ENCRYPTION_KEY_LENGTH() {
|
|
|
|
// Return encryption key length
|
|
return 256;
|
|
}
|
|
|
|
// Digest algorithm
|
|
static get DIGEST_ALGORITHM() {
|
|
|
|
// Return digest algorithm
|
|
return "SHA-512";
|
|
}
|
|
|
|
// Color pattern
|
|
static get COLOR_PATTERN() {
|
|
|
|
// Return whitespace pattern
|
|
return /^#[0-9A-F]{6}$/iu;
|
|
}
|
|
|
|
// Seed key
|
|
static get SEED_KEY() {
|
|
|
|
// Return seed key
|
|
return "IamVoldemort";
|
|
}
|
|
|
|
// Password pepper local storage name
|
|
static get PASSWORD_PEPPER_LOCAL_STORAGE_NAME() {
|
|
|
|
// Return password pepper local storage name
|
|
return "Password Pepper";
|
|
}
|
|
|
|
// Password pepper length
|
|
static get PASSWORD_PEPPER_LENGTH() {
|
|
|
|
// Return password peper length
|
|
return 32;
|
|
}
|
|
|
|
// Payment proof address Tor key index
|
|
static get PAYMENT_PROOF_TOR_ADDRESS_KEY_INDEX() {
|
|
|
|
// Return payment proof Tor address key index
|
|
return 0;
|
|
}
|
|
|
|
// Payment proof MQS address key index
|
|
static get PAYMENT_PROOF_MQS_ADDRESS_KEY_INDEX() {
|
|
|
|
// Return payment proof MQS address key index
|
|
return 0;
|
|
}
|
|
|
|
// Payment proof address Slatepack key index
|
|
static get PAYMENT_PROOF_SLATEPACK_ADDRESS_KEY_INDEX() {
|
|
|
|
// Return payment proof Slatepack address key index
|
|
return 0;
|
|
}
|
|
|
|
// Seed cookie digest algorithm
|
|
static get SEED_COOKIE_DIGEST_ALGORITHM() {
|
|
|
|
// Return seed cookie digest algorithm
|
|
return "SHA-512";
|
|
}
|
|
}
|
|
|
|
|
|
// Main function
|
|
|
|
// Set global object's wallet
|
|
globalThis["Wallet"] = Wallet;
|