import { IAmountConfig , TxChainSetter } from "../tx" ; import { ChainGetter , CoinPrimitive , CosmosMsgOpts , } from "@keplr-wallet/stores" ; import { AppCurrency } from "@keplr-wallet/types" ; import { action , computed , makeObservable , observable } from "mobx" ; import { Coin , CoinPretty , Int } from "@keplr-wallet/unit" ; import { SignDocHelper } from "./index" ; import { useState } from "react" ; import { computedFn } from "mobx-utils" ; import { Msg } from "@cosmjs/launchpad" ; import { cosmos } from "@keplr-wallet/cosmos" ; export class SignDocAmountConfig extends TxChainSetter implements IAmountConfig { @ observable . ref protected msgOpts : CosmosMsgOpts ; @ observable . ref protected signDocHelper ? : SignDocHelper = undefined ; @ observable protected _sender : string ; @ observable protected _disableBalanceCheck : boolean = false ; constructor ( chainGetter , initialChainId , msgOpts , sender ) { super ( chainGetter , initialChainId ) ; this . msgOpts = msgOpts ; this . _sender = sender ; makeObservable ( this ) ; } @ action setMsgOpts ( opts ) { this . msgOpts = opts ; } @ action setSignDocHelper ( signDocHelper ) { this . signDocHelper = signDocHelper ; } @ computed get amount ( ) : string { const primitive = this . getAmountPrimitive ( ) ; return new CoinPretty ( this . sendCurrency , new Int ( primitive . amount ) ) . toString ( ) ; } get sendCurrency ( ) : AppCurrency { const chainInfo = this . chainInfo ; if ( chainInfo . feeCurrencies . length > 0 ) { return chainInfo . feeCurrencies [ 0 ] ; } return chainInfo . currencies [ 0 ] ; } get sendableCurrencies ( ) : AppCurrency [ ] { return [ this . sendCurrency ] ; } @ action setSender ( sender ) { this . _sender = sender ; } get sender ( ) : string { return this . _sender ; } getAmountPrimitive = computedFn ( ( ) : CoinPrimitive => { if ( this . disableBalanceCheck || ! this . signDocHelper ?. signDocWrapper || this . chainInfo . feeCurrencies . length === 0 ) { return { amount : "0" , denom : this . sendCurrency . coinMinimalDenom , } ; } if ( this . signDocHelper . signDocWrapper . mode === "amino" ) { return this . computeAmountInAminoMsgs ( this . signDocHelper . signDocWrapper . aminoSignDoc . msgs ) ; } else { return this . computeAmountInProtoMsgs ( this . signDocHelper . signDocWrapper . protoSignDoc . txMsgs ) ; } } ) ; protected computeAmountInAminoMsgs ( msgs ) { const amount = new Coin ( this . sendCurrency . coinMinimalDenom , new Int ( 0 ) ) ; for ( const msg of msgs ) { try { switch ( msg . type ) { case this . msgOpts . send . native . type : if ( msg . value . from_address && msg . value . from_address !== this . sender ) { return { amount : "0" , denom : this . sendCurrency . coinMinimalDenom , } ; } if ( msg . value . amount && Array . isArray ( msg . value . amount ) ) { for ( const amountInMsg of msg . value . amount ) { if ( amountInMsg . denom === amount . denom ) { amount . amount = amount . amount . add ( new Int ( amountInMsg . amount ) ) ; } } } break ; case this . msgOpts . delegate . type : if ( msg . value . delegator_address && msg . value . delegator_address !== this . sender ) { return { amount : "0" , denom : this . sendCurrency . coinMinimalDenom , } ; } if ( msg . value . amount && msg . value . amount . denom === amount . denom ) { amount . amount = amount . amount . add ( new Int ( msg . value . amount . amount ) ) ; } break ; } } catch ( e ) { console . log ( `Error on the parsing the msg: ${ e . message || e . toString ( ) }` ) ; } } return { amount : amount . amount . toString ( ) , denom : amount . denom , } ; } protected computeAmountInProtoMsgs ( msgs ) { const amount = new Coin ( this . sendCurrency . coinMinimalDenom , new Int ( 0 ) ) ; for ( const msg of msgs ) { try { switch ( msg . constructor ) { case cosmos . bank . v1beta1 . MsgSend : const sendMsg = msg as cosmos . bank . v1beta1 . MsgSend ; if ( sendMsg . fromAddress && sendMsg . fromAddress !== this . sender ) { return { amount : "0" , denom : this . sendCurrency . coinMinimalDenom , } ; } for ( const amountInMsg of sendMsg . amount ) { if ( amountInMsg . denom === amount . denom && amountInMsg . amount ) { amount . amount = amount . amount . add ( new Int ( amountInMsg . amount ) ) ; } } break ; case cosmos . staking . v1beta1 . MsgDelegate : const delegateMsg = msg as cosmos . staking . v1beta1 . MsgDelegate ; if ( delegateMsg . delegatorAddress && delegateMsg . delegatorAddress !== this . sender ) { return { amount : "0" , denom : this . sendCurrency . coinMinimalDenom , } ; } if ( delegateMsg . amount ?. denom === amount . denom && delegateMsg . amount . amount ) { amount . amount = amount . amount . add ( new Int ( delegateMsg . amount . amount ) ) ; } break ; } } catch ( e ) { console . log ( `Error on the parsing the msg: ${ e . message || e . toString ( ) }` ) ; } } return { amount : amount . amount . toString ( ) , denom : amount . denom , } ; } getError ( ) { return undefined ; } setIsMax ( _ ) { } toggleIsMax ( ) { } get isMax ( ) : boolean { return false ; } get fraction ( ) : number | undefined { return undefined ; } setFraction ( _ ) { } setAmount ( ) { } setSendCurrency ( ) { } @ action setDisableBalanceCheck ( bool ) { this . _disableBalanceCheck = bool ; } get disableBalanceCheck ( ) : boolean { return this . _disableBalanceCheck ; } } export const useSignDocAmountConfig = ( chainGetter , chainId , msgOpts , sender ) => { const [ config ] = useState ( ( ) => new SignDocAmountConfig ( chainGetter , chainId , msgOpts , sender ) ) ; config . setChain ( chainId ) ; config . setMsgOpts ( msgOpts ) ; config . setSender ( sender ) ; return config ; } ;