import { BACKGROUND_PORT , MessageRequester } from "@keplr-wallet/router" ; import { AddLedgerKeyMsg , AddMnemonicKeyMsg , AddPrivateKeyMsg , BIP44HDPath , ChangeKeyRingMsg , CreateLedgerKeyMsg , CreateMnemonicKeyMsg , CreatePrivateKeyMsg , DeleteKeyRingMsg , UpdateNameKeyRingMsg , GetIsKeyStoreCoinTypeSetMsg , GetMultiKeyStoreInfoMsg , KeyRingStatus , LockKeyRingMsg , MultiKeyStoreInfoWithSelected , RestoreKeyRingMsg , SetKeyStoreCoinTypeMsg , ShowKeyRingMsg , UnlockKeyRingMsg , KeyRing , CheckPasswordMsg , ExportKeyRingData , ExportKeyRingDatasMsg , } from "@keplr-wallet/background" ; import { computed , flow , makeObservable , observable , runInAction } from "mobx" ; import { InteractionStore } from "./interaction" ; import { ChainGetter } from "../common" ; import { BIP44 } from "@keplr-wallet/types" ; import { DeepReadonly } from "utility-types" ; import { toGenerator } from "@keplr-wallet/common" ; export class KeyRingSelectablesStore { @ observable isInitializing : boolean = false ; @ observable protected _isKeyStoreCoinTypeSet : boolean = false ; @ observable . ref _selectables : { path : BIP44 ; bech32Address : string ; } [ ] = [ ] ; constructor ( protected readonly chainGetter , protected readonly requester , protected readonly chainId , protected readonly keyRingStore ) { makeObservable ( this ) ; this . refresh ( ) ; } @ computed get needSelectCoinType ( ) : boolean { const chainInfo = this . chainGetter . getChain ( this . chainId ) ; if ( ! chainInfo . alternativeBIP44s || chainInfo . alternativeBIP44s . length === 0 ) { return false ; } return ! this . isInitializing && ! this . _isKeyStoreCoinTypeSet ; } get selectables ( ) : DeepReadonly < { path : BIP44 ; bech32Address : string ; } [ ] > { return this . _selectables ; } @ flow * refresh ( ) { if ( this . keyRingStore . keyRingType !== "mnemonic" ) { this . isInitializing = false ; this . _isKeyStoreCoinTypeSet = true ; this . _selectables = [ ] ; return ; } this . isInitializing = true ; const chainInfo = this . chainGetter . getChain ( this . chainId ) ; const msg = new GetIsKeyStoreCoinTypeSetMsg ( this . chainId , [ chainInfo . bip44 , ... ( chainInfo . alternativeBIP44s ?? [ ] ) , ] ) ; const seletables = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; if ( seletables . length === 0 ) { this . _isKeyStoreCoinTypeSet = true ; } else if ( seletables . length === 1 ) { yield this . keyRingStore . setKeyStoreCoinType ( this . chainId , seletables [ 0 ] . path . coinType ) ; this . _isKeyStoreCoinTypeSet = true ; } else { this . _selectables = seletables ; this . _isKeyStoreCoinTypeSet = false ; } this . isInitializing = false ; } } export class KeyRingStore { @ observable status : KeyRingStatus = KeyRingStatus . NOTLOADED ; @ observable multiKeyStoreInfo : MultiKeyStoreInfoWithSelected = [ ] ; @ observable . shallow protected selectablesMap : Map < string , KeyRingSelectablesStore > = new Map ( ) ; protected keyStoreChangedListeners : ( ( ) => void ) [ ] = [ ] ; constructor ( protected readonly eventDispatcher , public readonly defaultKdf , protected readonly chainGetter , protected readonly requester , protected readonly interactionStore ) { makeObservable ( this ) ; this . restore ( ) ; } @ computed get keyRingType ( ) : string { const keyStore = this . multiKeyStoreInfo . find ( ( keyStore ) => keyStore . selected ) ; if ( ! keyStore ) { return "none" ; } else { return KeyRing . getTypeOfKeyStore ( keyStore ) ; } } @ flow * createMnemonicKey ( mnemonic , password , meta , bip44HDPath , kdf = this . defaultKdf ) { const msg = new CreateMnemonicKeyMsg ( kdf , mnemonic , password , meta , bip44HDPath ) ; const result = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; this . status = result . status ; this . multiKeyStoreInfo = result . multiKeyStoreInfo ; } @ flow * createPrivateKey ( privateKey , password , meta , kdf = this . defaultKdf ) { const msg = new CreatePrivateKeyMsg ( kdf , privateKey , password , meta ) ; const result = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; this . status = result . status ; this . multiKeyStoreInfo = result . multiKeyStoreInfo ; } @ flow * createLedgerKey ( password , meta , bip44HDPath , kdf = this . defaultKdf ) { const msg = new CreateLedgerKeyMsg ( kdf , password , meta , bip44HDPath ) ; const result = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; this . status = result . status ; this . multiKeyStoreInfo = result . multiKeyStoreInfo ; } @ flow * addMnemonicKey ( mnemonic , meta , bip44HDPath , kdf = this . defaultKdf ) { const msg = new AddMnemonicKeyMsg ( kdf , mnemonic , meta , bip44HDPath ) ; this . multiKeyStoreInfo = ( yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ) . multiKeyStoreInfo ; } @ flow * addPrivateKey ( privateKey , meta , kdf = this . defaultKdf ) { const msg = new AddPrivateKeyMsg ( kdf , privateKey , meta ) ; this . multiKeyStoreInfo = ( yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ) . multiKeyStoreInfo ; } @ flow * addLedgerKey ( meta , bip44HDPath , kdf = this . defaultKdf ) { const msg = new AddLedgerKeyMsg ( kdf , meta , bip44HDPath ) ; this . multiKeyStoreInfo = ( yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ) . multiKeyStoreInfo ; } @ flow * changeKeyRing ( index ) { const msg = new ChangeKeyRingMsg ( index ) ; this . multiKeyStoreInfo = ( yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ) . multiKeyStoreInfo ; this . dispatchKeyStoreChangeEvent ( ) ; this . selectablesMap . forEach ( ( selectables ) => selectables . refresh ( ) ) ; } @ flow * lock ( ) { const msg = new LockKeyRingMsg ( ) ; const result = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; this . status = result . status ; } @ flow * unlock ( password ) { const msg = new UnlockKeyRingMsg ( password ) ; const result = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; this . status = result . status ; for ( const interaction of this . interactionStore . getDatas ( "unlock" ) ) { yield this . interactionStore . approve ( "unlock" , interaction . id , { } ) ; } this . dispatchKeyStoreChangeEvent ( ) ; this . selectablesMap . forEach ( ( selectables ) => selectables . refresh ( ) ) ; } @ flow * rejectAll ( ) { yield this . interactionStore . rejectAll ( "unlock" ) ; } @ flow protected * restore ( ) { const msg = new RestoreKeyRingMsg ( ) ; const result = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; this . status = result . status ; this . multiKeyStoreInfo = result . multiKeyStoreInfo ; } async showKeyRing ( index , password ) { const msg = new ShowKeyRingMsg ( index , password ) ; return await this . requester . sendMessage ( BACKGROUND_PORT , msg ) ; } @ flow * deleteKeyRing ( index , password ) { const selectedIndex = this . multiKeyStoreInfo . findIndex ( ( keyStore ) => keyStore . selected ) ; const msg = new DeleteKeyRingMsg ( index , password ) ; const result = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; this . status = result . status ; this . multiKeyStoreInfo = result . multiKeyStoreInfo ; if ( selectedIndex === index ) { this . dispatchKeyStoreChangeEvent ( ) ; this . selectablesMap . forEach ( ( selectables ) => selectables . refresh ( ) ) ; } } @ flow * updateNameKeyRing ( index , name ) { const msg = new UpdateNameKeyRingMsg ( index , name ) ; const result = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; this . multiKeyStoreInfo = result . multiKeyStoreInfo ; const selectedIndex = this . multiKeyStoreInfo . findIndex ( ( keyStore ) => keyStore . selected ) ; if ( selectedIndex === index ) { this . dispatchKeyStoreChangeEvent ( ) ; } } async checkPassword ( password ) { return await this . requester . sendMessage ( BACKGROUND_PORT , new CheckPasswordMsg ( password ) ) ; } getKeyStoreSelectables ( chainId ) { if ( ! this . selectablesMap . has ( chainId ) ) { runInAction ( ( ) => { this . selectablesMap . set ( chainId , new KeyRingSelectablesStore ( this . chainGetter , this . requester , chainId , this ) ) ; } ) ; } return this . selectablesMap . get ( chainId ) ! ; } @ flow * setKeyStoreCoinType ( chainId , coinType ) { const status = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , new SetKeyStoreCoinTypeMsg ( chainId , coinType ) ) ) ; this . multiKeyStoreInfo = ( yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , new GetMultiKeyStoreInfoMsg ( ) ) ) ) . multiKeyStoreInfo ; this . status = status ; this . dispatchKeyStoreChangeEvent ( ) ; this . selectablesMap . forEach ( ( selectables ) => selectables . refresh ( ) ) ; } async exportKeyRingDatas ( password ) { return await this . requester . sendMessage ( BACKGROUND_PORT , new ExportKeyRingDatasMsg ( password ) ) ; } protected dispatchKeyStoreChangeEvent ( ) { this . eventDispatcher . dispatchEvent ( "keplr_keystorechange" ) ; for ( const listener of this . keyStoreChangedListeners ) { listener ( ) ; } } addKeyStoreChangedListener ( listener ) { this . keyStoreChangedListeners . push ( listener ) ; } removeKeyStoreChangedListener ( listener ) { const i = this . keyStoreChangedListeners . indexOf ( listener ) ; if ( i >= 0 ) { this . keyStoreChangedListeners . splice ( i , 1 ) ; } } }