import { Injectable } from '@angular/core' ; import { UtilService } from "./util.service" ; import { ApiService } from "./api.service" ; import { BigNumber } from 'bignumber.js' ; import { AddressBookService } from "./address-book.service" ; import * as CryptoJS from 'crypto-js' ; import { WorkPoolService } from "./work-pool.service" ; import { WebsocketService } from "./websocket.service" ; import { NanoBlockService } from "./nano-block.service" ; import { NotificationService } from "./notification.service" ; import { AppSettingsService } from "./app-settings.service" ; import { PriceService } from "./price.service" ; import { LedgerService } from "./ledger.service" ; export type WalletType = "seed" | "ledger" | "privateKey" ; export interface WalletAccount { id : string ; frontier : string | null ; secret : any ; keyPair : any ; index : number ; balance : BigNumber ; pending : BigNumber ; balanceRaw : BigNumber ; pendingRaw : BigNumber ; balanceFiat : number ; pendingFiat : number ; addressBookName : string | null ; } export interface FullWallet { type : WalletType ; seedBytes : any ; seed : string | null ; balance : BigNumber ; pending : BigNumber ; balanceRaw : BigNumber ; pendingRaw : BigNumber ; balanceFiat : number ; pendingFiat : number ; hasPending : boolean ; accounts : WalletAccount [ ] ; accountsIndex : number ; locked : boolean ; password : string ; } export interface BaseApiAccount { account_version : string ; balance : string ; block_count : string ; frontier : string ; modified_timestamp : string ; open_block : string ; pending : string ; representative : string ; representative_block : string ; weight : string ; } export interface WalletApiAccount extends BaseApiAccount { addressBookName ? : string | null ; id ? : string ; } @ Injectable ( ) export class WalletService { nano = 1000000000000000000000000 ; storeKey = `nanovault-wallet` ; wallet : FullWallet = { type : 'seed' , seedBytes : null , seed : '' , balance : new BigNumber ( 0 ) , pending : new BigNumber ( 0 ) , balanceRaw : new BigNumber ( 0 ) , pendingRaw : new BigNumber ( 0 ) , balanceFiat : 0 , pendingFiat : 0 , hasPending : false , accounts : [ ] , accountsIndex : 0 , locked : false , password : '' , } ; processingPending = false ; pendingBlocks = [ ] ; successfulBlocks = [ ] ; constructor ( private util , private api , private appSettings , private addressBook , private price , private workPool , private websocket , private nanoBlock , private ledgerService , private notifications ) { this . websocket . newTransactions$ . subscribe ( async ( transaction ) => { if ( ! transaction ) return ; const walletAccountIDs = this . wallet . accounts . map ( a => a . id ) ; if ( transaction . block . type == 'send' && walletAccountIDs . indexOf ( transaction . block . destination ) !== - 1 ) { const walletAccount = this . wallet . accounts . find ( a => a . id === transaction . block . destination ) ; if ( walletAccount ) { if ( this . wallet . locked ) { this . notifications . sendWarning ( `New incoming transaction - unlock the wallet to receive it!` , { length : 0 , identifier : 'pending-locked' } ) ; } this . addPendingBlock ( walletAccount . id , transaction . hash , transaction . amount ) ; await this . processPendingBlocks ( ) ; } } else if ( transaction . block . type == 'state' ) { if ( this . wallet . locked ) { this . notifications . sendWarning ( `New incoming transaction - unlock the wallet to receive it!` , { length : 0 , identifier : 'pending-locked' } ) ; } await this . processStateBlock ( transaction ) ; } await this . reloadBalances ( false ) ; } ) ; this . addressBook . addressBook$ . subscribe ( newAddressBook => { this . reloadAddressBook ( ) ; } ) ; } async processStateBlock ( transaction ) { if ( transaction . is_send === 'true' && transaction . block . link_as_account ) { const walletAccount = this . wallet . accounts . find ( a => a . id === transaction . block . link_as_account ) ; if ( ! walletAccount ) return ; const txAmount = new BigNumber ( transaction . amount ) ; if ( this . wallet . pending . lte ( 0 ) ) { this . wallet . pending = this . wallet . pending . plus ( txAmount ) ; this . wallet . pendingRaw = this . wallet . pendingRaw . plus ( txAmount . mod ( this . nano ) ) ; this . wallet . pendingFiat += this . util . nano . rawToMnano ( txAmount ) . times ( this . price . price . lastPrice ) . toNumber ( ) ; this . wallet . hasPending = true ; } if ( this . appSettings . settings . minimumReceive ) { const minAmount = this . util . nano . mnanoToRaw ( this . appSettings . settings . minimumReceive ) ; if ( txAmount . gt ( minAmount ) ) { this . addPendingBlock ( walletAccount . id , transaction . hash , txAmount ) ; } else { console . log ( `Found new pending block that was below minimum receive amount: ` , transaction . amount , this . appSettings . settings . minimumReceive ) ; } } else { this . addPendingBlock ( walletAccount . id , transaction . hash , txAmount ) ; } await this . processPendingBlocks ( ) ; } else { const walletAccount = this . wallet . accounts . find ( a => a . id === transaction . block . link_as_account ) ; if ( ! walletAccount ) return ; } } reloadAddressBook ( ) { this . wallet . accounts . forEach ( account => { account . addressBookName = this . addressBook . getAccountName ( account . id ) ; } ) ; } getWalletAccount ( accountID ) { return this . wallet . accounts . find ( a => a . id == accountID ) ; } async patchOldSavedData ( ) { const walletData = localStorage . getItem ( this . storeKey ) ; if ( ! walletData ) return true ; const walletJson = JSON . parse ( walletData ) ; if ( walletJson . accounts ) { const newAccounts = walletJson . accounts . map ( account => { if ( account . id . indexOf ( 'xrb_' ) !== - 1 ) { account . id = account . id . replace ( 'xrb_' , 'nano_' ) ; } return account ; } ) ; walletJson . accounts = newAccounts ; } localStorage . setItem ( this . storeKey , JSON . stringify ( walletJson ) ) ; return true ; } async loadStoredWallet ( ) { this . resetWallet ( ) ; const walletData = localStorage . getItem ( this . storeKey ) ; if ( ! walletData ) return this . wallet ; const walletJson = JSON . parse ( walletData ) ; const walletType = walletJson . type || 'seed' ; this . wallet . type = walletType ; if ( walletType === 'seed' ) { this . wallet . seed = walletJson . seed ; this . wallet . seedBytes = this . util . hex . toUint8 ( walletJson . seed ) ; } if ( walletType === 'seed' || walletType === 'privateKey' ) { this . wallet . locked = walletJson . locked ; this . wallet . password = walletJson . password || null ; } if ( walletType === 'ledger' ) { } this . wallet . accountsIndex = walletJson . accountsIndex || 0 ; if ( walletJson . accounts && walletJson . accounts . length ) { walletJson . accounts . forEach ( account => this . loadWalletAccount ( account . index , account . id ) ) ; } else { if ( ! this . wallet . locked ) { await this . loadAccountsFromIndex ( ) ; } } await this . reloadBalances ( true ) ; if ( walletType === 'ledger' ) { this . ledgerService . loadLedger ( true ) ; } return this . wallet ; } async loadImportedWallet ( seed , password , accountsIndex = 1 ) { this . resetWallet ( ) ; this . wallet . seed = seed ; this . wallet . seedBytes = this . util . hex . toUint8 ( seed ) ; this . wallet . accountsIndex = accountsIndex ; this . wallet . password = password ; for ( let i = 0 ; i < accountsIndex ; i ++ ) { await this . addWalletAccount ( i , false ) ; } await this . reloadBalances ( true ) ; if ( this . wallet . accounts . length ) { this . websocket . subscribeAccounts ( this . wallet . accounts . map ( a => a . id ) ) ; } return this . wallet ; } async loadAccountsFromIndex ( ) { this . wallet . accounts = [ ] ; for ( let i = 0 ; i < this . wallet . accountsIndex ; i ++ ) { await this . addWalletAccount ( i , false ) ; } } generateExportData ( ) { const exportData = { accountsIndex : this . wallet . accountsIndex , } ; if ( this . wallet . locked ) { exportData . seed = this . wallet . seed ; } else { exportData . seed = CryptoJS . AES . encrypt ( this . wallet . seed , this . wallet . password ) . toString ( ) ; } return exportData ; } generateExportUrl ( ) { const exportData = this . generateExportData ( ) ; const base64Data = btoa ( JSON . stringify ( exportData ) ) ; return `https://nanovault.io/import-wallet#${ base64Data }` ; } lockWallet ( ) { if ( ! this . wallet . seed || ! this . wallet . password ) return ; const encryptedSeed = CryptoJS . AES . encrypt ( this . wallet . seed , this . wallet . password ) ; this . wallet . seed = encryptedSeed . toString ( ) ; this . wallet . seedBytes = null ; this . wallet . accounts . forEach ( a => { a . keyPair = null ; a . secret = null ; } ) ; this . wallet . locked = true ; this . wallet . password = '' ; this . saveWalletExport ( ) ; return true ; } unlockWallet ( password ) { try { const decryptedBytes = CryptoJS . AES . decrypt ( this . wallet . seed , password ) ; const decryptedSeed = decryptedBytes . toString ( CryptoJS . enc . Utf8 ) ; if ( ! decryptedSeed || decryptedSeed . length !== 64 ) return false ; this . wallet . seed = decryptedSeed ; this . wallet . seedBytes = this . util . hex . toUint8 ( this . wallet . seed ) ; this . wallet . accounts . forEach ( a => { a . secret = this . util . account . generateAccountSecretKeyBytes ( this . wallet . seedBytes , a . index ) ; a . keyPair = this . util . account . generateAccountKeyPair ( a . secret ) ; } ) ; this . wallet . locked = false ; this . wallet . password = password ; this . notifications . removeNotification ( 'pending-locked' ) ; if ( this . wallet . accounts . length < this . wallet . accountsIndex ) { this . loadAccountsFromIndex ( ) . then ( ( ) => this . reloadBalances ( ) ) ; } this . processPendingBlocks ( ) ; this . saveWalletExport ( ) ; return true ; } catch ( err ) { return false ; } } walletIsLocked ( ) { return this . wallet . locked ; } async createWalletFromSeed ( seed , emptyAccountBuffer = 10 ) { this . resetWallet ( ) ; this . wallet . seed = seed ; this . wallet . seedBytes = this . util . hex . toUint8 ( seed ) ; let emptyTicker = 0 ; let usedIndices = [ ] ; let greatestUsedIndex = 0 ; const batchSize = emptyAccountBuffer + 1 ; for ( let batch = 0 ; emptyTicker < emptyAccountBuffer ; batch ++ ) { let batchAccounts = { } ; let batchAccountsArray = [ ] ; for ( let i = 0 ; i < batchSize ; i ++ ) { const index = batch * batchSize + i ; const accountBytes = this . util . account . generateAccountSecretKeyBytes ( this . wallet . seedBytes , index ) ; const accountKeyPair = this . util . account . generateAccountKeyPair ( accountBytes ) ; const accountAddress = this . util . account . getPublicAccountID ( accountKeyPair . publicKey ) ; batchAccounts [ accountAddress ] = { index : index , publicKey : this . util . uint8 . toHex ( accountKeyPair . publicKey ) . toUpperCase ( ) , used : false } ; batchAccountsArray . push ( accountAddress ) ; } let batchResponse = await this . api . accountsFrontiers ( batchAccountsArray ) ; for ( let accountID in batchResponse . frontiers ) { const frontier = batchResponse . frontiers [ accountID ] ; if ( frontier !== batchAccounts [ accountID ] . publicKey ) { batchAccounts [ accountID ] . used = true ; } } for ( let accountID in batchAccounts ) { let account = batchAccounts [ accountID ] ; if ( account . used ) { usedIndices . push ( account . index ) ; if ( account . index > greatestUsedIndex ) { greatestUsedIndex = account . index ; emptyTicker = 0 ; } } else { if ( account . index > greatestUsedIndex ) { emptyTicker ++ ; } } } } if ( usedIndices . length > 0 ) { for ( let i = 0 ; i < usedIndices . length - 1 ; i ++ ) { this . addWalletAccount ( usedIndices [ i ] , false ) ; } this . addWalletAccount ( usedIndices . length - 1 , true ) ; } else { this . addWalletAccount ( ) ; } return this . wallet . seed ; } createNewWallet ( ) { this . resetWallet ( ) ; const seedBytes = this . util . account . generateSeedBytes ( ) ; this . wallet . seedBytes = seedBytes ; this . wallet . seed = this . util . hex . fromUint8 ( seedBytes ) ; this . addWalletAccount ( ) ; return this . wallet . seed ; } createLedgerWallet ( ) { this . resetWallet ( ) ; this . wallet . type = 'ledger' ; const newAccount = this . addWalletAccount ( 0 ) ; return this . wallet ; } async createLedgerAccount ( index ) { const account = await this . ledgerService . getLedgerAccount ( index ) ; const accountID = account . address ; const nanoAccountID = accountID . replace ( 'xrb_' , 'nano_' ) ; const addressBookName = this . addressBook . getAccountName ( nanoAccountID ) ; const newAccount = { id : nanoAccountID , frontier : null , secret : null , keyPair : null , balance : new BigNumber ( 0 ) , pending : new BigNumber ( 0 ) , balanceRaw : new BigNumber ( 0 ) , pendingRaw : new BigNumber ( 0 ) , balanceFiat : 0 , pendingFiat : 0 , index : index , addressBookName , } ; return newAccount ; } async createSeedAccount ( index ) { const accountBytes = this . util . account . generateAccountSecretKeyBytes ( this . wallet . seedBytes , index ) ; const accountKeyPair = this . util . account . generateAccountKeyPair ( accountBytes ) ; const accountName = this . util . account . getPublicAccountID ( accountKeyPair . publicKey ) ; const addressBookName = this . addressBook . getAccountName ( accountName ) ; const newAccount = { id : accountName , frontier : null , secret : accountBytes , keyPair : accountKeyPair , balance : new BigNumber ( 0 ) , pending : new BigNumber ( 0 ) , balanceRaw : new BigNumber ( 0 ) , pendingRaw : new BigNumber ( 0 ) , balanceFiat : 0 , pendingFiat : 0 , index : index , addressBookName , } ; return newAccount ; } /**
     * Reset wallet to a base state, without changing reference to the main object
     */ resetWallet ( ) { if ( this . wallet . accounts . length ) { this . websocket . unsubscribeAccounts ( this . wallet . accounts . map ( a => a . id ) ) ; } this . wallet . type = 'seed' ; this . wallet . password = '' ; this . wallet . locked = false ; this . wallet . seed = '' ; this . wallet . seedBytes = null ; this . wallet . accounts = [ ] ; this . wallet . accountsIndex = 0 ; this . wallet . balance = new BigNumber ( 0 ) ; this . wallet . pending = new BigNumber ( 0 ) ; this . wallet . balanceFiat = 0 ; this . wallet . pendingFiat = 0 ; this . wallet . hasPending = false ; } isConfigured ( ) { switch ( this . wallet . type ) { case 'seed' : return ! ! this . wallet . seed ; case 'ledger' : return true ; case 'privateKey' : return false ; } } isLocked ( ) { switch ( this . wallet . type ) { case 'privateKey' : case 'seed' : return this . wallet . locked ; case 'ledger' : return false ; } } isLedgerWallet ( ) { return this . wallet . type === 'ledger' ; } hasPendingTransactions ( ) { return this . wallet . hasPending ; } reloadFiatBalances ( ) { const fiatPrice = this . price . price . lastPrice ; this . wallet . accounts . forEach ( account => { account . balanceFiat = this . util . nano . rawToMnano ( account . balance ) . times ( fiatPrice ) . toNumber ( ) ; account . pendingFiat = this . util . nano . rawToMnano ( account . pending ) . times ( fiatPrice ) . toNumber ( ) ; } ) ; this . wallet . balanceFiat = this . util . nano . rawToMnano ( this . wallet . balance ) . times ( fiatPrice ) . toNumber ( ) ; this . wallet . pendingFiat = this . util . nano . rawToMnano ( this . wallet . pending ) . times ( fiatPrice ) . toNumber ( ) ; } async reloadBalances ( reloadPending = true ) { const fiatPrice = this . price . price . lastPrice ; this . wallet . balance = new BigNumber ( 0 ) ; this . wallet . pending = new BigNumber ( 0 ) ; this . wallet . balanceRaw = new BigNumber ( 0 ) ; this . wallet . pendingRaw = new BigNumber ( 0 ) ; this . wallet . balanceFiat = 0 ; this . wallet . pendingFiat = 0 ; this . wallet . hasPending = false ; const accountIDs = this . wallet . accounts . map ( a => a . id ) ; const accounts = await this . api . accountsBalances ( accountIDs ) ; const frontiers = await this . api . accountsFrontiers ( accountIDs ) ; let walletBalance = new BigNumber ( 0 ) ; let walletPending = new BigNumber ( 0 ) ; for ( const accountID in accounts . balances ) { if ( ! accounts . balances . hasOwnProperty ( accountID ) ) continue ; const walletAccount = this . wallet . accounts . find ( a => a . id == accountID ) ; if ( ! walletAccount ) continue ; walletAccount . balance = new BigNumber ( accounts . balances [ accountID ] . balance ) ; walletAccount . pending = new BigNumber ( accounts . balances [ accountID ] . pending ) ; walletAccount . balanceRaw = new BigNumber ( walletAccount . balance ) . mod ( this . nano ) ; walletAccount . pendingRaw = new BigNumber ( walletAccount . pending ) . mod ( this . nano ) ; walletAccount . balanceFiat = this . util . nano . rawToMnano ( walletAccount . balance ) . times ( fiatPrice ) . toNumber ( ) ; walletAccount . pendingFiat = this . util . nano . rawToMnano ( walletAccount . pending ) . times ( fiatPrice ) . toNumber ( ) ; walletAccount . frontier = frontiers . frontiers [ accountID ] || null ; walletBalance = walletBalance . plus ( walletAccount . balance ) ; walletPending = walletPending . plus ( walletAccount . pending ) ; } let hasPending = false ; if ( ! reloadPending && walletPending . gt ( 0 ) ) { hasPending = true ; } if ( walletPending . gt ( 0 ) ) { if ( this . appSettings . settings . minimumReceive ) { const minAmount = this . util . nano . mnanoToRaw ( this . appSettings . settings . minimumReceive ) ; const pending = await this . api . accountsPendingLimit ( this . wallet . accounts . map ( a => a . id ) , minAmount . toString ( 10 ) ) ; if ( pending && pending . blocks ) { for ( let block in pending . blocks ) { if ( ! pending . blocks . hasOwnProperty ( block ) ) { continue ; } if ( pending . blocks [ block ] ) { hasPending = true ; } else { console . log ( 'Pendling loop - no match, skipping? ' , block ) ; } } } } else { hasPending = true ; } } const hashes = this . wallet . accounts . map ( account => account . frontier || this . util . account . getAccountPublicKey ( account . id ) ) ; hashes . forEach ( hash => this . workPool . addWorkToCache ( hash ) ) ; this . wallet . balance = walletBalance ; this . wallet . pending = walletPending ; this . wallet . balanceRaw = new BigNumber ( walletBalance ) . mod ( this . nano ) ; this . wallet . pendingRaw = new BigNumber ( walletPending ) . mod ( this . nano ) ; this . wallet . balanceFiat = this . util . nano . rawToMnano ( walletBalance ) . times ( fiatPrice ) . toNumber ( ) ; this . wallet . pendingFiat = this . util . nano . rawToMnano ( walletPending ) . times ( fiatPrice ) . toNumber ( ) ; this . wallet . hasPending = hasPending ; if ( reloadPending && walletPending . gt ( 0 ) ) { await this . loadPendingBlocksForWallet ( ) ; } } async loadWalletAccount ( accountIndex , accountID ) { let index = accountIndex ; const addressBookName = this . addressBook . getAccountName ( accountID ) ; const newAccount = { id : accountID , frontier : null , secret : null , keyPair : null , balance : new BigNumber ( 0 ) , pending : new BigNumber ( 0 ) , balanceRaw : new BigNumber ( 0 ) , pendingRaw : new BigNumber ( 0 ) , balanceFiat : 0 , pendingFiat : 0 , index : index , addressBookName , } ; this . wallet . accounts . push ( newAccount ) ; this . websocket . subscribeAccounts ( [ accountID ] ) ; return newAccount ; } async addWalletAccount ( accountIndex = null , reloadBalances = true ) { let index = accountIndex ; if ( index === null ) { index = 0 ; while ( this . wallet . accounts . find ( a => a . index === index ) ) index ++ ; } let newAccount ; if ( this . wallet . type === 'privateKey' ) { throw new Error ( `Cannot add another account in private key mode` ) ; } else if ( this . wallet . type === 'seed' ) { newAccount = await this . createSeedAccount ( index ) ; } else if ( this . wallet . type === 'ledger' ) { try { newAccount = await this . createLedgerAccount ( index ) ; } catch ( err ) { throw err ; } } this . wallet . accounts . push ( newAccount ) ; let nextIndex = 0 ; while ( this . wallet . accounts . find ( a => a . index === nextIndex ) ) nextIndex ++ ; this . wallet . accountsIndex = nextIndex ; if ( reloadBalances ) await this . reloadBalances ( ) ; this . websocket . subscribeAccounts ( [ newAccount . id ] ) ; this . saveWalletExport ( ) ; return newAccount ; } async removeWalletAccount ( accountID ) { const walletAccount = this . getWalletAccount ( accountID ) ; if ( ! walletAccount ) throw new Error ( `Account is not in wallet` ) ; const walletAccountIndex = this . wallet . accounts . findIndex ( a => a . id === accountID ) ; if ( walletAccountIndex === - 1 ) throw new Error ( `Account is not in wallet` ) ; this . wallet . accounts . splice ( walletAccountIndex , 1 ) ; if ( walletAccount . index < this . wallet . accountsIndex ) { this . wallet . accountsIndex = walletAccount . index ; } this . websocket . unsubscribeAccounts ( [ accountID ] ) ; await this . reloadBalances ( ) ; this . saveWalletExport ( ) ; return true ; } addPendingBlock ( accountID , blockHash , amount ) { if ( this . successfulBlocks . indexOf ( blockHash ) !== - 1 ) return ; const existingHash = this . pendingBlocks . find ( b => b . hash == blockHash ) ; if ( existingHash ) return ; this . pendingBlocks . push ( { account : accountID , hash : blockHash , amount : amount } ) ; this . wallet . hasPending = true ; } async loadPendingBlocksForWallet ( ) { if ( ! this . wallet . accounts . length ) return ; let pending ; if ( this . appSettings . settings . minimumReceive ) { const minAmount = this . util . nano . mnanoToRaw ( this . appSettings . settings . minimumReceive ) ; pending = await this . api . accountsPendingLimit ( this . wallet . accounts . map ( a => a . id ) , minAmount . toString ( 10 ) ) ; } else { pending = await this . api . accountsPending ( this . wallet . accounts . map ( a => a . id ) ) ; } if ( ! pending || ! pending . blocks ) return ; for ( let account in pending . blocks ) { if ( ! pending . blocks . hasOwnProperty ( account ) ) continue ; for ( let block in pending . blocks [ account ] ) { if ( ! pending . blocks [ account ] . hasOwnProperty ( block ) ) continue ; if ( pending . blocks [ account ] == '' ) continue ; this . addPendingBlock ( account , block , pending . blocks [ account ] [ block ] . amount ) ; } } if ( this . pendingBlocks . length ) { this . processPendingBlocks ( ) ; } } async processPendingBlocks ( ) { if ( this . processingPending || this . wallet . locked || ! this . pendingBlocks . length ) return ; this . processingPending = true ; const nextBlock = this . pendingBlocks [ 0 ] ; if ( this . successfulBlocks . find ( b => b . hash == nextBlock . hash ) ) { return setTimeout ( ( ) => this . processPendingBlocks ( ) , 1500 ) ; } const walletAccount = this . getWalletAccount ( nextBlock . account ) ; if ( ! walletAccount ) return ; const newHash = await this . nanoBlock . generateReceive ( walletAccount , nextBlock . hash , this . isLedgerWallet ( ) ) ; if ( newHash ) { if ( this . successfulBlocks . length >= 15 ) this . successfulBlocks . shift ( ) ; this . successfulBlocks . push ( nextBlock . hash ) ; const receiveAmount = this . util . nano . rawToMnano ( nextBlock . amount ) ; this . notifications . sendSuccess ( `Successfully received ${ receiveAmount . isZero ( ) ? '' : receiveAmount . toFixed ( 6 ) } Nano!` ) ; await this . reloadBalances ( ) ; } else { if ( this . isLedgerWallet ( ) ) { return null ; } return this . notifications . sendError ( `There was a problem performing the receive transaction, try manually!` ) ; } this . pendingBlocks . shift ( ) ; this . processingPending = false ; setTimeout ( ( ) => this . processPendingBlocks ( ) , 1500 ) ; } saveWalletExport ( ) { const exportData = this . generateWalletExport ( ) ; switch ( this . appSettings . settings . walletStore ) { case 'none' : this . removeWalletData ( ) ; break ; default : case 'localStorage' : localStorage . setItem ( this . storeKey , JSON . stringify ( exportData ) ) ; break ; } } removeWalletData ( ) { localStorage . removeItem ( this . storeKey ) ; } generateWalletExport ( ) { let data = { type : this . wallet . type , accounts : this . wallet . accounts . map ( a => ( { id : a . id , index : a . index } ) ) , accountsIndex : this . wallet . accountsIndex , } ; if ( this . wallet . type === 'ledger' ) { } if ( this . wallet . type === 'seed' ) { if ( ! this . wallet . locked ) { const encryptedSeed = CryptoJS . AES . encrypt ( this . wallet . seed , this . wallet . password || '' ) ; data . seed = encryptedSeed . toString ( ) ; } else { data . seed = this . wallet . seed ; } data . locked = true ; } return data ; } async getAccountsDetails ( ) { return await Promise . all ( this . wallet . accounts . map ( account => this . api . accountInfo ( account . id ) . then ( res => { res . id = account . id ; res . addressBookName = account . addressBookName ; return res ; } ) ) ) ; } }