func (chain *TestChain) GetClientState(clientID string) exported.ClientState {
	clientState, found := chain.App.IBCKeeper.ClientKeeper.GetClientState(chain.GetContext(), clientID)
	require.True(chain.t, found)
	return clientState
}
GetClientState retrieves the client state for the provided clientID. The client is
expected to exist otherwise testing will fail.
package ibctesting
import (
	"bytes"
	"fmt"
	"strconv"
	"testing"
	"time"
	"github.com/stretchr/testify/require"
	abci "github.com/tendermint/tendermint/abci/types"
	"github.com/tendermint/tendermint/crypto/tmhash"
	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
	tmprotoversion "github.com/tendermint/tendermint/proto/tendermint/version"
	tmtypes "github.com/tendermint/tendermint/types"
	tmversion "github.com/tendermint/tendermint/version"
	"github.com/cosmos/cosmos-sdk/client"
	"github.com/cosmos/cosmos-sdk/codec"
	"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
	sdk "github.com/cosmos/cosmos-sdk/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
	capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
	"github.com/cosmos/cosmos-sdk/x/staking/teststaking"
	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
	clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types"
	connectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types"
	channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
	commitmenttypes "github.com/cosmos/ibc-go/modules/core/23-commitment/types"
	host "github.com/cosmos/ibc-go/modules/core/24-host"
	"github.com/cosmos/ibc-go/modules/core/exported"
	"github.com/cosmos/ibc-go/modules/core/types"
	ibctmtypes "github.com/cosmos/ibc-go/modules/light-clients/07-tendermint/types"
	"github.com/cosmos/ibc-go/testing/mock"
	simapp "github.com/desmos-labs/desmos/v2/app"
	profilestypes "github.com/desmos-labs/desmos/v2/x/profiles/types"
)
const (
	TrustingPeriod  = time.Hour * 24 * 7 * 2
	UnbondingPeriod = time.Hour * 24 * 7 * 3
	MaxClockDrift   = time.Second * 10
	DefaultDelayPeriod uint64 = 0
)
var (
	DefaultOpenInitVersion *connectiontypes.Version
	DefaultTrustLevel      = ibctmtypes.DefaultTrustLevel
	UpgradePath            = []string{"upgrade", "upgradedIBCState"}
	ConnectionVersion      = connectiontypes.ExportedVersionsToProto(connectiontypes.GetCompatibleVersions())[0]
)
type TestChain struct {
	t *testing.T
	App           *simapp.DesmosApp
	ChainID       string
	LastHeader    *ibctmtypes.Header  
	CurrentHeader tmproto.Header      
	QueryServer   types.QueryServer
	TxConfig      client.TxConfig
	Codec         codec.BinaryCodec
	Vals    *tmtypes.ValidatorSet
	Signers []tmtypes.PrivValidator
	PrivKey cryptotypes.PrivKey
	Account authtypes.AccountI
	ClientIDs   []string           
	Connections []*TestConnection  
}
func NewTestChain(t *testing.T, chainID string) *TestChain {
	privVal := mock.NewPV()
	pubKey, err := privVal.GetPubKey()
	require.NoError(t, err)
	validator := tmtypes.NewValidator(pubKey, 1)
	valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
	signers := []tmtypes.PrivValidator{privVal}
	senderPrivKey := secp256k1.GenPrivKey()
	acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
	balance := banktypes.Balance{
		Address: acc.GetAddress().String(),
		Coins:   sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
	}
	app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, balance)
	header := tmproto.Header{
		ChainID: chainID,
		Height:  1,
		Time:    globalStartTime,
	}
	txConfig := simapp.MakeTestEncodingConfig().TxConfig
	chain := &TestChain{
		t:             t,
		ChainID:       chainID,
		App:           app,
		CurrentHeader: header,
		QueryServer:   app.IBCKeeper,
		TxConfig:      txConfig,
		Codec:         app.AppCodec(),
		Vals:          valSet,
		Signers:       signers,
		PrivKey:       senderPrivKey,
		Account:       acc,
		ClientIDs:     make([]string, 0),
		Connections:   make([]*TestConnection, 0),
	}
	chain.NextBlock()
	return chain
}
func (chain *TestChain) GetContext() sdk.Context {
	return chain.App.BaseApp.NewContext(false, chain.CurrentHeader)
}
func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) {
	res := chain.App.Query(abci.RequestQuery{
		Path:   fmt.Sprintf("store/%s/key", host.StoreKey),
		Height: chain.App.LastBlockHeight() - 1,
		Data:   key,
		Prove:  true,
	})
	merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps)
	require.NoError(chain.t, err)
	proof, err := chain.App.AppCodec().Marshal(&merkleProof)
	require.NoError(chain.t, err)
	revision := clienttypes.ParseChainID(chain.ChainID)
	return proof, clienttypes.NewHeight(revision, uint64(res.Height)+1)
}
func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) {
	res := chain.App.Query(abci.RequestQuery{
		Path:   "store/upgrade/key",
		Height: int64(height - 1),
		Data:   key,
		Prove:  true,
	})
	merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps)
	require.NoError(chain.t, err)
	proof, err := chain.App.AppCodec().Marshal(&merkleProof)
	require.NoError(chain.t, err)
	revision := clienttypes.ParseChainID(chain.ChainID)
	return proof, clienttypes.NewHeight(revision, uint64(res.Height+1))
}
func (chain *TestChain) QueryClientStateProof(clientID string) (exported.ClientState, []byte) {
	clientState, found := chain.App.IBCKeeper.ClientKeeper.GetClientState(chain.GetContext(), clientID)
	require.True(chain.t, found)
	clientKey := host.FullClientStateKey(clientID)
	proofClient, _ := chain.QueryProof(clientKey)
	return clientState, proofClient
}
func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clienttypes.Height) {
	clientState := chain.GetClientState(clientID)
	consensusHeight := clientState.GetLatestHeight().(clienttypes.Height)
	consensusKey := host.FullConsensusStateKey(clientID, consensusHeight)
	proofConsensus, _ := chain.QueryProof(consensusKey)
	return proofConsensus, consensusHeight
}
func (chain *TestChain) NextBlock() {
	chain.LastHeader = chain.CurrentTMClientHeader()
	chain.CurrentHeader = tmproto.Header{
		ChainID: chain.ChainID,
		Height:  chain.App.LastBlockHeight() + 1,
		AppHash: chain.App.LastCommitID().Hash,
		Time:               chain.CurrentHeader.Time,
		ValidatorsHash:     chain.Vals.Hash(),
		NextValidatorsHash: chain.Vals.Hash(),
	}
	chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader})
}
func (chain *TestChain) sendMsgs(msgs ...sdk.Msg) error {
	_, err := chain.SendMsgs(msgs...)
	return err
}
func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) {
	_, r, err := SignCheckDeliver(
		chain.t,
		chain.TxConfig,
		chain.App.BaseApp,
		chain.GetContext().BlockHeader(),
		msgs,
		chain.ChainID,
		[]uint64{chain.Account.GetAccountNumber()},
		[]uint64{chain.Account.GetSequence()},
		true, true, chain.PrivKey,
	)
	if err != nil {
		return nil, err
	}
	chain.NextBlock()
	chain.Account.SetSequence(chain.Account.GetSequence() + 1)
	return r, nil
}