UNPKG

mcps-sdk-js

Version:

MCPS JavaScript SDK

327 lines (298 loc) 8.81 kB
import { Client } from '../client'; import { Crypto } from '../utils'; import { SdkError } from '../errors'; import * as is from 'is_js'; import * as types from '../types'; /** * This module allows you to manage your local tendermint keystore (wallets) for mcps. * * **NOTE:** You need to implement the [[KeyDAO]] Interface first. * * @category Modules * @since v0.17 */ export class Keys { /** @hidden */ private client: Client; /** @hidden */ constructor(client: Client) { this.client = client; } /** * Create a new key * * @param name Name of the key * @param password Password for encrypting the keystore * @param type Pubkey Type * @returns Bech32 address and mnemonic * @since v0.17 */ add( name: string, password: string, type:types.PubkeyType = types.PubkeyType.secp256k1 ): { address: string; mnemonic: string } { if (is.empty(name)) { throw new SdkError(`Name of the key can not be empty`); } if (is.empty(password)) { throw new SdkError(`Password of the key can not be empty`); } if (!this.client.config.keyDAO.encrypt) { throw new SdkError(`Encrypt method of KeyDAO not implemented`); } const exists = this.client.config.keyDAO.read(name); if (exists) { throw new SdkError(`Key with name '${name}' already exists`); } const mnemonic = Crypto.generateMnemonic(); const privKey = Crypto.getPrivateKeyFromMnemonic(mnemonic); const pubKey = Crypto.getPublicKeyFromPrivateKey(privKey, type); const address = Crypto.getAddressFromPublicKey( pubKey, this.client.config.bech32Prefix.AccAddr ); const encryptedPrivKey = this.client.config.keyDAO.encrypt( privKey, password ); // Save the key to app this.client.config.keyDAO.write(name, { address, privKey: encryptedPrivKey, }); return { address, mnemonic }; } /** * Recover a key * * @param name Name of the key * @param password Password for encrypting the keystore * @param mnemonic Mnemonic of the key * @param type Pubkey Type * @param index The bip44 address index (default: 0) * @param derive Derive a private key using the default HD path (default: true) * @param saltPassword A passphrase for generating the salt, according to bip39 * @returns Bech32 address * @since v0.17 */ recover( name: string, password: string, mnemonic: string, type:types.PubkeyType = types.PubkeyType.secp256k1, index = 0, derive = true, saltPassword = '', ): string { if (is.empty(name)) { throw new SdkError(`Name of the key can not be empty`); } if (is.empty(password)) { throw new SdkError(`Password of the key can not be empty`); } if (is.empty(mnemonic)) { throw new SdkError(`Mnemonic of the key can not be empty`); } if (!this.client.config.keyDAO.encrypt) { throw new SdkError(`Encrypt method of KeyDAO not implemented`); } const exists = this.client.config.keyDAO.read(name); if (exists) { throw new SdkError(`Key with name '${name}' exists`); } const privKey = Crypto.getPrivateKeyFromMnemonic( mnemonic, index, derive, saltPassword ); const pubKey = Crypto.getPublicKeyFromPrivateKey(privKey, type); const address = Crypto.getAddressFromPublicKey( pubKey, this.client.config.bech32Prefix.AccAddr ); const encryptedPrivKey = this.client.config.keyDAO.encrypt( privKey, password ); // Save the key to app this.client.config.keyDAO.write(name, { address, privKey: encryptedPrivKey, }); return address; } /** * Import a key from keystore * * @param name Name of the key * @param password Password of the keystore * @param keystore Keystore json or object * @param type Pubkey Type * @returns Bech32 address * @since v0.17 */ import( name: string, password: string, keystore: string | types.Keystore, type:types.PubkeyType = types.PubkeyType.secp256k1 ): string { if (is.empty(name)) { throw new SdkError(`Name of the key can not be empty`); } if (is.empty(password)) { throw new SdkError(`Password of the key can not be empty`); } if (is.empty(keystore)) { throw new SdkError(`Keystore can not be empty`); } if (!this.client.config.keyDAO.encrypt) { throw new SdkError(`Encrypt method of KeyDAO not implemented`); } const exists = this.client.config.keyDAO.read(name); if (exists) { throw new SdkError(`Key with name '${name}' already exists`); } const privKey = Crypto.getPrivateKeyFromKeyStore(keystore, password); const pubKey = Crypto.getPublicKeyFromPrivateKey(privKey, type); const address = Crypto.getAddressFromPublicKey( pubKey, this.client.config.bech32Prefix.AccAddr ); const encryptedPrivKey = this.client.config.keyDAO.encrypt( privKey, password ); // Save the key to app this.client.config.keyDAO.write(name, { address, privKey: encryptedPrivKey, }); return address; } /** * Import a PrivateKey * * @param name Name of the key * @param password Password of the keystore * @param privateKey privateKey hex * @param type Pubkey Type * @returns Bech32 address * @since v0.17 */ importPrivateKey( name: string, password: string, privateKey: string, type:types.PubkeyType = types.PubkeyType.secp256k1 ): string { if (is.empty(name)) { throw new SdkError(`Name of the key can not be empty`); } if (is.empty(password)) { throw new SdkError(`Password of the key can not be empty`); } if (is.empty(privateKey)) { throw new SdkError(`privateKey can not be empty`); } const exists = this.client.config.keyDAO.read(name); if (exists) { throw new SdkError(`Key with name '${name}' already exists`); } const pubKey = Crypto.getPublicKeyFromPrivateKey(privateKey, type); const address = Crypto.getAddressFromPublicKey( pubKey, this.client.config.bech32Prefix.AccAddr ); const encryptedPrivKey = this.client.config.keyDAO.encrypt!( privateKey, password ); // Save the key to app this.client.config.keyDAO.write(name, { address, privKey: encryptedPrivKey, }); return address; } /** * Export keystore of a key * * @param name Name of the key * @param keyPassword Password of the key * @param keystorePassword Password for encrypting the keystore * @returns Keystore json * @since v0.17 */ export(name: string, keyPassword: string, keystorePassword: string): string { if (is.empty(name)) { throw new SdkError(`Name of the key can not be empty`); } if (is.empty(keyPassword)) { throw new SdkError(`Password of the key can not be empty`); } if (!this.client.config.keyDAO.decrypt) { throw new SdkError(`Decrypt method of KeyDAO not implemented`); } const keyObj = this.client.config.keyDAO.read(name); if (!keyObj) { throw new SdkError(`Key with name '${name}' not found`); } const privKey = this.client.config.keyDAO.decrypt( keyObj.privKey, keyPassword ); const keystore = Crypto.generateKeyStore( privKey, keystorePassword, this.client.config.bech32Prefix.AccAddr ); return JSON.stringify(keystore); } /** * Delete a key * * @param name Name of the key * @param password Password of the key * @since v0.17 */ delete(name: string, password: string) { if (is.empty(name)) { throw new SdkError(`Name of the key can not be empty`); } if (is.empty(password)) { throw new SdkError(`Password of the key can not be empty`); } if (!this.client.config.keyDAO.decrypt) { throw new SdkError(`Decrypt method of KeyDAO not implemented`); } const keyObj = this.client.config.keyDAO.read(name); if (!keyObj) { throw new SdkError(`Key with name '${name}' not found`); } // Check keystore password this.client.config.keyDAO.decrypt(keyObj.privKey, password); // Delete the key from app this.client.config.keyDAO.delete(name); } /** * Gets address of a key * * @param name Name of the key * @returns Bech32 address * @since v0.17 */ show(name: string) { if (is.empty(name)) { throw new SdkError(`Name of the key can not be empty`); } const keyObj = this.client.config.keyDAO.read(name); if (!keyObj) { throw new SdkError(`Key with name '${name}' not found`); } return keyObj.address; } // TODO: Ledger support }