// Copyright 2021 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 import { MessageHandler } from './MessageHandler'; import { Account } from './Account'; import type { AccountId, AccountManagerOptions, Auth, ClientOptions, CreateAccountPayload, WalletEventType, GenerateAddressOptions, LedgerNanoStatus, NodeInfoWrapper, SyncOptions, WalletEvent, } from '../types'; import { Event } from '../types'; /** The AccountManager class. */ export class AccountManager { private messageHandler: MessageHandler; constructor(options: AccountManagerOptions) { this.messageHandler = new MessageHandler(options); } /** * Backup the data to a Stronghold snapshot. */ async backup(destination: string, password: string): Promise { await this.messageHandler.sendMessage({ cmd: 'backup', payload: { destination, password, }, }); } /** * Transform a bech32 encoded address to a hex encoded address */ async bech32ToHex(bech32Address: string): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'bech32ToHex', payload: { bech32Address }, }); return JSON.parse(response).payload; } /** * Change the Stronghold password. */ async changeStrongholdPassword( currentPassword: string, newPassword: string, ): Promise { await this.messageHandler.sendMessage({ cmd: 'changeStrongholdPassword', payload: { currentPassword, newPassword, }, }); } /** * Clear the Stronghold password from memory. */ async clearStrongholdPassword(): Promise { await this.messageHandler.sendMessage({ cmd: 'clearStrongholdPassword', }); } /** * Create a new account. */ async createAccount(payload: CreateAccountPayload): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'createAccount', payload, }); return new Account(JSON.parse(response).payload, this.messageHandler); } /** * Destroy the AccountManager and drop its database connection. */ async destroy(): Promise { await this.messageHandler.destroy(); } /** * Emit a provided event for testing of the event system. */ async emitTestEvent(event: WalletEvent): Promise { await this.messageHandler.sendMessage({ cmd: 'emitTestEvent', payload: { event }, }); } /** * Generate a random BIP39 mnemonic. */ async generateMnemonic(): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'generateMnemonic', }); return JSON.parse(response).payload; } /** * Get an account by its alias or index. */ async getAccount(accountId: AccountId): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'getAccount', payload: { accountId }, }); const account = new Account( JSON.parse(response).payload, this.messageHandler, ); return account; } /** * Get all account indexes. */ async getAccountIndexes(): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'getAccountIndexes', }); return JSON.parse(response).payload; } /** * Get all accounts. */ async getAccounts(): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'getAccounts', }); const { payload } = JSON.parse(response); const accounts: Account[] = []; for (const account of payload) { accounts.push(new Account(account, this.messageHandler)); } return accounts; } /** * Generate an address without storing it. */ async generateEd25519Address( accountIndex: number, addressIndex: number, options?: GenerateAddressOptions, bech32Hrp?: string, ): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'generateEd25519Address', payload: { accountIndex, addressIndex, options, bech32Hrp, }, }); return JSON.parse(response).payload; } /** * Get the node info. */ async getNodeInfo(url?: string, auth?: Auth): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'getNodeInfo', payload: { url, auth }, }); return JSON.parse(response).payload; } /** * Get the status for a Ledger Nano. */ async getLedgerNanoStatus(): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'getLedgerNanoStatus', }); return JSON.parse(response).payload; } /** * Transform hex encoded address to bech32 encoded address. If no bech32Hrp * is provided, the AccountManager will attempt to retrieve it from the * NodeInfo. If this does not succeed, it will default to the Shimmer testnet bech32Hrp. */ async hexToBech32(hex: string, bech32Hrp?: string): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'hexToBech32', payload: { hex, bech32Hrp }, }); return JSON.parse(response).payload; } /** * Check if the Stronghold password has been set. */ async isStrongholdPasswordAvailable(): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'isStrongholdPasswordAvailable', }); return JSON.parse(response).payload; } /** * Listen to wallet events with a callback. An empty array will listen to all possible events. */ async listen( eventTypes: WalletEventType[], callback: (error: Error, result: Event) => void, ): Promise { return this.messageHandler.listen(eventTypes, callback); } /** * Clear the callbacks for provided events. An empty array will clear all listeners. */ async clearListeners(eventTypes: WalletEventType[]): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'clearListeners', payload: { eventTypes }, }); return JSON.parse(response).payload; } /** * Find accounts with unspent outputs. */ async recoverAccounts( accountStartIndex: number, accountGapLimit: number, addressGapLimit: number, syncOptions: SyncOptions, ): Promise { const response = await this.messageHandler.sendMessage({ cmd: 'recoverAccounts', payload: { accountStartIndex, accountGapLimit, addressGapLimit, syncOptions, }, }); const accounts: Account[] = []; for (const account of JSON.parse(response).payload) { accounts.push(new Account(account, this.messageHandler)); } return accounts; } /** * Delete the latest account. */ async removeLatestAccount(): Promise { await this.messageHandler.sendMessage({ cmd: 'removeLatestAccount', }); } /** * Restore a backup from a Stronghold file * Replaces client_options, coin_type, secret_manager and accounts. Returns an error if accounts were already created * If Stronghold is used as secret_manager, the existing Stronghold file will be overwritten. If a mnemonic was * stored, it will be gone. * if ignore_if_coin_type_mismatch is provided client options will not be restored * if ignore_if_coin_type_mismatch == true, client options coin type and accounts will not be restored if the cointype doesn't match * if ignore_if_bech32_hrp_mismatch == Some("rms"), but addresses have something different like "smr", no accounts * will be restored. */ async restoreBackup( source: string, password: string, ignoreIfCoinTypeMismatch?: boolean, ignoreIfBech32Mismatch?: string, ): Promise { await this.messageHandler.sendMessage({ cmd: 'restoreBackup', payload: { source, password, ignoreIfCoinTypeMismatch, ignoreIfBech32Mismatch, }, }); } /** * Set ClientOptions. */ async setClientOptions(clientOptions: ClientOptions): Promise { await this.messageHandler.sendMessage({ cmd: 'setClientOptions', payload: { clientOptions }, }); } /** * Set the Stronghold password. */ async setStrongholdPassword(password: string): Promise { await this.messageHandler.sendMessage({ cmd: 'setStrongholdPassword', payload: { password }, }); } /** * Set the interval after which the Stronghold password gets cleared from memory. */ async setStrongholdPasswordClearInterval( intervalInMilliseconds?: number, ): Promise { await this.messageHandler.sendMessage({ cmd: 'setStrongholdPasswordClearInterval', payload: { intervalInMilliseconds }, }); } /** * Start the background syncing process for all accounts. */ async startBackgroundSync( options?: SyncOptions, intervalInMilliseconds?: number, ): Promise { await this.messageHandler.sendMessage({ cmd: 'startBackgroundSync', payload: { options, intervalInMilliseconds, }, }); } /** * Stop the background syncing process for all accounts. */ async stopBackgroundSync(): Promise { await this.messageHandler.sendMessage({ cmd: 'stopBackgroundSync', }); } /** * Store a mnemonic in the Stronghold snapshot. */ async storeMnemonic(mnemonic: string): Promise { await this.messageHandler.sendMessage({ cmd: 'storeMnemonic', payload: { mnemonic }, }); } /** * Verify if a mnemonic is a valid BIP39 mnemonic. */ async verifyMnemonic(mnemonic: string): Promise { await this.messageHandler.sendMessage({ cmd: 'verifyMnemonic', payload: { mnemonic }, }); } /** * Update the authentication for the provided node. */ async updateNodeAuth(url: string, auth?: Auth): Promise { await this.messageHandler.sendMessage({ cmd: 'updateNodeAuth', payload: { url, auth }, }); } }