import { AccountSetBase , AccountSetOpts , MsgOpt } from "./base" ; import { HasCosmwasmQueries , QueriesSetBase , QueriesStore } from "../query" ; import { ChainGetter , CoinPrimitive } from "../common" ; import { StdFee } from "@cosmjs/launchpad" ; import { DenomHelper } from "@keplr-wallet/common" ; import { Dec , DecUtils } from "@keplr-wallet/unit" ; import { AppCurrency , KeplrSignOptions } from "@keplr-wallet/types" ; import { DeepReadonly , Optional } from "utility-types" ; import { cosmwasm } from "@keplr-wallet/cosmos" ; import { Buffer } from "buffer/" ; export interface HasCosmwasmAccount { cosmwasm : DeepReadonly < CosmwasmAccount > ; } export interface CosmwasmMsgOpts { readonly send : { readonly cw20 : Pick < MsgOpt , "gas" > ; } ; readonly executeWasm : Pick < MsgOpt , "type" > ; } export class AccountWithCosmwasm extends AccountSetBase < CosmwasmMsgOpts , HasCosmwasmQueries > implements HasCosmwasmAccount { public readonly cosmwasm : DeepReadonly < CosmwasmAccount > ; static readonly defaultMsgOpts : CosmwasmMsgOpts = { send : { cw20 : { gas : 150000 , } , } , executeWasm : { type : "wasm/MsgExecuteContract" , } , } ; constructor ( protected readonly eventListener , protected readonly chainGetter , protected readonly chainId , protected readonly queriesStore , protected readonly opts ) { super ( eventListener , chainGetter , chainId , queriesStore , opts ) ; this . cosmwasm = new CosmwasmAccount ( this , chainGetter , chainId , queriesStore ) ; } } export class CosmwasmAccount { constructor ( protected readonly base , protected readonly chainGetter , protected readonly chainId , protected readonly queriesStore ) { this . base . registerSendTokenFn ( this . processSendToken . bind ( this ) ) ; } protected async processSendToken ( amount , currency , recipient , memo , stdFee , signOptions ? , onTxEvents ? ) { const denomHelper = new DenomHelper ( currency . coinMinimalDenom ) ; switch ( denomHelper . type ) { case "cw20" : const actualAmount = ( ( ) => { let dec = new Dec ( amount ) ; dec = dec . mul ( DecUtils . getPrecisionDec ( currency . coinDecimals ) ) ; return dec . truncate ( ) . toString ( ) ; } ) ( ) ; if ( ! ( "type" in currency ) || currency . type !== "cw20" ) { throw new Error ( "Currency is not cw20" ) ; } await this . sendExecuteContractMsg ( "send" , currency . contractAddress , { transfer : { recipient : recipient , amount : actualAmount , } , } , [ ] , memo , { amount : stdFee . amount ?? [ ] , gas : stdFee . gas ?? this . base . msgOpts . send . cw20 . gas . toString ( ) , } , signOptions , this . txEventsWithPreOnFulfill ( onTxEvents , ( tx ) => { if ( tx . code == null || tx . code === 0 ) { const queryBalance = this . queries . queryBalances . getQueryBech32Address ( this . base . bech32Address ) . balances . find ( ( bal ) => { return ( bal . currency . coinMinimalDenom === currency . coinMinimalDenom ) ; } ) ; if ( queryBalance ) { queryBalance . fetch ( ) ; } } } ) ) ; return true ; } return false ; } async sendExecuteContractMsg ( type = "executeWasm" , contractAddress , obj , funds , memo = "" , stdFee , signOptions ? , onTxEvents ? ) { const msg = { type : this . base . msgOpts . executeWasm . type , value : { sender : this . base . bech32Address , contract : contractAddress , msg : obj , funds , } , } ; await this . base . sendMsgs ( type , { aminoMsgs : [ msg ] , protoMsgs : this . hasNoLegacyStdFeature ( ) ? [ { type_url : "/cosmwasm.wasm.v1.MsgExecuteContract" , value : cosmwasm . wasm . v1 . MsgExecuteContract . encode ( { sender : msg . value . sender , contract : msg . value . contract , msg : Buffer . from ( JSON . stringify ( msg . value . msg ) ) , funds : msg . value . funds , } ) . finish ( ) , } , ] : undefined , } , memo , { amount : stdFee . amount ?? [ ] , gas : stdFee . gas , } , signOptions , this . txEventsWithPreOnFulfill ( onTxEvents ) ) ; } protected txEventsWithPreOnFulfill ( onTxEvents , preOnFulfill ? ) { if ( ! onTxEvents ) { return ; } const onBroadcasted = typeof onTxEvents === "function" ? undefined : onTxEvents . onBroadcasted ; const onFulfill = typeof onTxEvents === "function" ? onTxEvents : onTxEvents . onFulfill ; return { onBroadcasted , onFulfill : onFulfill ? ( tx ) => { if ( preOnFulfill ) { preOnFulfill ( tx ) ; } onFulfill ( tx ) ; } : undefined , } ; } protected get queries ( ) : DeepReadonly < QueriesSetBase & HasCosmwasmQueries > { return this . queriesStore . get ( this . chainId ) ; } protected hasNoLegacyStdFeature ( ) { const chainInfo = this . chainGetter . getChain ( this . chainId ) ; return ( chainInfo . features != null && chainInfo . features . includes ( "no-legacy-stdTx" ) ) ; } }