import { HasMapStore } from "../common" ; import { BACKGROUND_PORT , MessageRequester } from "@keplr-wallet/router" ; import { AddTokenMsg , GetTokensMsg , RemoveTokenMsg , SuggestTokenMsg , } from "@keplr-wallet/background" ; import { autorun , flow , makeObservable , observable } from "mobx" ; import { AppCurrency , ChainInfo } from "@keplr-wallet/types" ; import { DeepReadonly } from "utility-types" ; import { ChainStore } from "../chain" ; import { InteractionStore } from "./interaction" ; import { toGenerator } from "@keplr-wallet/common" ; import { ChainIdHelper } from "@keplr-wallet/cosmos" ; export class TokensStoreInner { @ observable . ref protected _tokens : AppCurrency [ ] = [ ] ; constructor ( protected readonly eventListener , protected readonly chainStore , protected readonly chainId , protected readonly requester ) { makeObservable ( this ) ; this . refreshTokens ( ) ; this . eventListener . addEventListener ( "keplr_keystoreunlock" , ( ) => { this . refreshTokens ( ) ; } ) ; this . eventListener . addEventListener ( "keplr_keystorechange" , ( ) => { this . refreshTokens ( ) ; } ) ; } get tokens ( ) : DeepReadonly < AppCurrency [ ] > { return this . _tokens ; } @ flow * refreshTokens ( ) { const chainInfo = this . chainStore . getChain ( this . chainId ) ; if ( chainInfo . features && ( chainInfo . features . includes ( "secretwasm" ) || chainInfo . features . includes ( "cosmwasm" ) ) ) { const msg = new GetTokensMsg ( this . chainId ) ; this . _tokens = yield * toGenerator ( this . requester . sendMessage ( BACKGROUND_PORT , msg ) ) ; } else { this . _tokens = [ ] ; } } @ flow * addToken ( currency ) { const msg = new AddTokenMsg ( this . chainId , currency ) ; yield this . requester . sendMessage ( BACKGROUND_PORT , msg ) ; yield this . refreshTokens ( ) ; } @ flow * removeToken ( currency ) { const msg = new RemoveTokenMsg ( this . chainId , currency ) ; yield this . requester . sendMessage ( BACKGROUND_PORT , msg ) ; yield this . refreshTokens ( ) ; } } export class TokensStore < C extends ChainInfo = ChainInfo > extends HasMapStore < TokensStoreInner > { protected prevTokens : Map < string , AppCurrency [ ] > = new Map ( ) ; constructor ( protected readonly eventListener , protected readonly chainStore , protected readonly requester , protected readonly interactionStore ) { super ( ( chainId ) => { return new TokensStoreInner ( this . eventListener , this . chainStore , chainId , this . requester ) ; } ) ; makeObservable ( this ) ; this . chainStore . addSetChainInfoHandler ( ( chainInfoInner ) => { autorun ( ( ) => { const chainIdentifier = ChainIdHelper . parse ( chainInfoInner . chainId ) ; const prevToken = this . prevTokens . get ( chainIdentifier . identifier ) ?? [ ] ; chainInfoInner . removeCurrencies ( ... prevToken . map ( ( token ) => token . coinMinimalDenom ) ) ; const inner = this . getTokensOf ( chainInfoInner . chainId ) ; chainInfoInner . addCurrencies ( ... inner . tokens ) ; this . prevTokens . set ( chainIdentifier . identifier , inner . tokens as AppCurrency [ ] ) ; } ) ; } ) ; } getTokensOf ( chainId ) { return this . get ( chainId ) ; } get waitingSuggestedToken ( ) { const datas = this . interactionStore . getDatas < { chainId : string ; contractAddress : string ; viewingKey ? : string ; } > ( SuggestTokenMsg . type ( ) ) ; if ( datas . length > 0 ) { return datas [ 0 ] ; } } @ flow * approveSuggestedToken ( appCurrency ) { const data = this . waitingSuggestedToken ; if ( data ) { yield this . interactionStore . approve ( SuggestTokenMsg . type ( ) , data . id , appCurrency ) ; yield this . getTokensOf ( data . data . chainId ) . refreshTokens ( ) ; } } @ flow * rejectSuggestedToken ( ) { const data = this . waitingSuggestedToken ; if ( data ) { yield this . interactionStore . reject ( SuggestTokenMsg . type ( ) , data . id ) ; } } @ flow * rejectAllSuggestedTokens ( ) { yield this . interactionStore . rejectAll ( SuggestTokenMsg . type ( ) ) ; } }