Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore: Make a state entry to find total amount of native assets IBC'd out #3019

Merged
merged 63 commits into from
Apr 22, 2023
Merged
Show file tree
Hide file tree
Changes from 57 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
8290b79
started
stackman27 Jan 16, 2023
1421e5a
added state and query
stackman27 Jan 16, 2023
93d8454
fixed balance
stackman27 Jan 16, 2023
f0768e9
nit
stackman27 Jan 16, 2023
7c868c6
carlos and nicholas feedback
stackman27 Jan 18, 2023
03023fc
addressed carlos comments 2
stackman27 Feb 8, 2023
2f5c571
rebased
stackman27 Feb 8, 2023
ffa737f
add extra tests and handle situation where source tokens have IBC denom
Feb 17, 2023
468f00f
fix typo
Feb 17, 2023
c6ba4c5
fix typo
Feb 17, 2023
e4972f0
alignment
Feb 17, 2023
6201c08
fix alignment
Feb 17, 2023
c8f6087
gofumpt
Feb 17, 2023
f6b6079
add error checking
Feb 17, 2023
7d44018
remove cache context and check escrow amount only on success tests cases
Feb 19, 2023
3948566
Update modules/apps/transfer/keeper/keeper.go
Feb 21, 2023
914cae0
add IsNativeDenom function to denom trace
Feb 23, 2023
df3f7e6
add support to track total escrow for IBC denoms when sender is source
Mar 1, 2023
f77f7a8
added panics
stackman27 Mar 13, 2023
f532101
nit
stackman27 Mar 13, 2023
daeacf8
fixed test
stackman27 Mar 15, 2023
bd3600f
Merge branch 'main' into stack/total-ibc-out
stackman27 Mar 15, 2023
5c676dd
Update proto/ibc/applications/transfer/v1/query.proto
Mar 23, 2023
b18c78e
Update proto/ibc/applications/transfer/v1/query.proto
Mar 23, 2023
01ff13d
address review comment/extend e2e transfer test
Mar 23, 2023
b1ba2b7
Merge branch 'main' into stack/total-ibc-out
Mar 23, 2023
15c5ef4
fix conflicts
Mar 23, 2023
ea7e76c
revert changes
Mar 23, 2023
72e871c
missing argument
Mar 23, 2023
6071ad2
fix typos
Mar 23, 2023
94357f8
fix test
Mar 23, 2023
ce36ec1
Merge branch 'main' into stack/total-ibc-out
stackman27 Mar 23, 2023
c9b304c
fix e2e test / add genesis
Mar 25, 2023
9569e8a
add wip upgrade test / fix support for amounts larger than int64
Mar 26, 2023
dfab5f8
add missing files
Mar 26, 2023
f3213d8
return plain string for escrow amount
Mar 26, 2023
fb426c1
fixing tests
Mar 26, 2023
659b10a
add test for set/get total escrow functions
Mar 26, 2023
2abcfb1
variable renaming
Mar 26, 2023
6d68dc3
add check on key format
Mar 26, 2023
aa54c5f
add tests for get all denom escrows query
Mar 27, 2023
9b25880
add extra testcase
Mar 27, 2023
28627f9
check denomination is valid in grpc query
Mar 27, 2023
920ae09
gofumpt
Mar 27, 2023
0ecabea
Merge branch 'main' into stack/total-ibc-out
Mar 27, 2023
966df1f
Merge branch 'main' into stack/total-ibc-out
Mar 29, 2023
3c2e47b
adding denoms escrow checks in upgrade e2e tests / break API of trans…
Mar 29, 2023
38a91ab
rename test names
Mar 30, 2023
817c888
Merge branch 'main' into stack/total-ibc-out
Mar 30, 2023
1574d3f
addressing a bunch of review comments
Apr 11, 2023
540e3ac
addressing more review comments
Apr 15, 2023
7310277
review comment
Apr 15, 2023
07d3266
Merge branch 'main' into stack/total-ibc-out
Apr 15, 2023
b3fcf69
e2e: add transfer query client
Apr 15, 2023
8057568
change grpc gateway URI for total escrow
Apr 15, 2023
e3267e8
position nit
Apr 17, 2023
a0757c9
address walkthrough comments
Apr 18, 2023
5ba4f59
import formatting
Apr 18, 2023
4047be9
comment out failing e2e test for now / rename function / add comments
Apr 22, 2023
77655f2
Merge branch 'main' into stack/total-ibc-out
Apr 22, 2023
9c036e4
rename receiver
Apr 22, 2023
aac5321
rename receiver (2)
Apr 22, 2023
107f4d6
comment out import
Apr 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/e2e-upgrade.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ jobs:
chain-upgrade-tag: pr-3164 # TODO: needs v7.1.0 when cut
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
upgrade-plan-name: "v7.1"
test-entry-point: "TestUpgradeTestSuite"
test: "TestV7ChainUpgradeAddLocalhost"
test: "TestV7ToV7_1ChainUpgrade"
upload-logs: true
2 changes: 1 addition & 1 deletion e2e/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/cosmos/ibc-go/e2e
go 1.19

require (
cosmossdk.io/math v1.0.0
github.com/cometbft/cometbft v0.37.0
github.com/cosmos/cosmos-sdk v0.47.0
github.com/cosmos/gogoproto v1.4.7
Expand All @@ -27,7 +28,6 @@ require (
cosmossdk.io/core v0.6.0 // indirect
cosmossdk.io/depinject v1.0.0-alpha.3 // indirect
cosmossdk.io/errors v1.0.0-beta.7 // indirect
cosmossdk.io/math v1.0.0 // indirect
cosmossdk.io/tools/rosetta v0.2.1 // indirect
filippo.io/edwards25519 v1.0.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
Expand Down
17 changes: 17 additions & 0 deletions e2e/tests/transfer/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"
"time"

"cosmossdk.io/math"
paramsproposaltypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal"
"github.com/strangelove-ventures/interchaintest/v7/ibc"
test "github.com/strangelove-ventures/interchaintest/v7/testutil"
Expand Down Expand Up @@ -88,6 +89,12 @@ func (s *TransferTestSuite) TestMsgTransfer_Succeeds_Nonincentivized() {

expected := testvalues.StartingTokenAmount - testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance)

actualTotalEscrow, err := s.QueryTotalEscrowForDenom(ctx, chainA, chainADenom)
s.Require().NoError(err)

expectedTotalEscrow := math.NewInt(testvalues.IBCTransferAmount)
s.Require().Equal(expectedTotalEscrow, actualTotalEscrow)
})

t.Run("start relayer", func(t *testing.T) {
Expand Down Expand Up @@ -117,6 +124,10 @@ func (s *TransferTestSuite) TestMsgTransfer_Succeeds_Nonincentivized() {
s.Require().NoError(err)

s.Require().Equal(int64(0), actualBalance)

actualTotalEscrow, err := s.QueryTotalEscrowForDenom(ctx, chainB, chainBIBCToken.IBCDenom())
s.Require().NoError(err)
s.Require().Equal(math.ZeroInt(), actualTotalEscrow) // total escrow is zero because sending chain is not source for tokens
})

s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA, chainB), "failed to wait for blocks")
Expand All @@ -130,6 +141,12 @@ func (s *TransferTestSuite) TestMsgTransfer_Succeeds_Nonincentivized() {
expected := testvalues.StartingTokenAmount
s.Require().Equal(expected, actualBalance)
})

t.Run("tokens are un-escrowed", func(t *testing.T) {
actualTotalEscrow, err := s.QueryTotalEscrowForDenom(ctx, chainA, chainADenom)
s.Require().NoError(err)
s.Require().Equal(math.ZeroInt(), actualTotalEscrow) // total escrow is zero because tokens have come back
})
}

// TestMsgTransfer_Fails_InvalidAddress attempts to send an IBC transfer to an invalid address and ensures
Expand Down
68 changes: 61 additions & 7 deletions e2e/tests/upgrades/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"
"time"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
Expand Down Expand Up @@ -605,33 +606,86 @@ func (s *UpgradeTestSuite) TestV6ToV7ChainUpgrade() {
})
}

func (s *UpgradeTestSuite) TestV7ChainUpgradeAddLocalhost() {
func (s *UpgradeTestSuite) TestV7ToV7_1ChainUpgrade() {
t := s.T()
testCfg := testconfig.LoadConfig()

ctx := context.Background()
_, _ = s.SetupChainsRelayerAndChannel(ctx)
chain, _ := s.GetChains()
relayer, channelA := s.SetupChainsRelayerAndChannel(ctx)
chainA, chainB := s.GetChains()

chainADenom := chainA.Config().Denom

chainAWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
chainAAddress := chainAWallet.FormattedAddress()

chainBWallet := s.CreateUserOnChainB(ctx, testvalues.StartingTokenAmount)
chainBAddress := chainBWallet.FormattedAddress()

s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA, chainB), "failed to wait for blocks")

t.Run("transfer native tokens from chainA to chainB", func(t *testing.T) {
transferTxResp, err := s.Transfer(ctx, chainA, chainAWallet, channelA.PortID, channelA.ChannelID, testvalues.DefaultTransferAmount(chainADenom), chainAAddress, chainBAddress, s.GetTimeoutHeight(ctx, chainB), 0, "")
s.Require().NoError(err)
s.AssertValidTxResponse(transferTxResp)
})

t.Run("tokens are escrowed", func(t *testing.T) {
actualBalance, err := s.GetChainANativeBalance(ctx, chainAWallet)
s.Require().NoError(err)

expected := testvalues.StartingTokenAmount - testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance)

// Escrow amount for native denom is not stored in state because pre-upgrade version did not support this feature
actualTotalEscrow, err := s.QueryTotalEscrowForDenom(ctx, chainA, chainADenom)
s.Require().NoError(err)
s.Require().Equal(math.ZeroInt(), actualTotalEscrow)
})

t.Run("start relayer", func(t *testing.T) {
s.StartRelayer(relayer)
})

chainBIBCToken := testsuite.GetIBCToken(chainADenom, channelA.Counterparty.PortID, channelA.Counterparty.ChannelID)

t.Run("packet is relayed", func(t *testing.T) {
s.AssertPacketRelayed(ctx, chainA, channelA.PortID, channelA.ChannelID, 1)

s.Require().NoError(test.WaitForBlocks(ctx, 5, chain), "failed to wait for blocks")
actualBalance, err := chainB.GetBalance(ctx, chainBAddress, chainBIBCToken.IBCDenom())
s.Require().NoError(err)

expected := testvalues.IBCTransferAmount
s.Require().Equal(expected, actualBalance)
})

s.Require().NoError(test.WaitForBlocks(ctx, 5, chainA), "failed to wait for blocks")

t.Run("upgrade chain", func(t *testing.T) {
govProposalWallet := s.CreateUserOnChainA(ctx, testvalues.StartingTokenAmount)
s.UpgradeChain(ctx, chain, govProposalWallet, testCfg.UpgradeConfig.PlanName, testCfg.ChainConfigs[0].Tag, testCfg.UpgradeConfig.Tag)
s.UpgradeChain(ctx, chainA, govProposalWallet, testCfg.UpgradeConfig.PlanName, testCfg.ChainConfigs[0].Tag, testCfg.UpgradeConfig.Tag)
})

t.Run("ensure the localhost client is active and sentinel connection is stored in state", func(t *testing.T) {
status, err := s.QueryClientStatus(ctx, chain, exported.LocalhostClientID)
status, err := s.QueryClientStatus(ctx, chainA, exported.LocalhostClientID)
s.Require().NoError(err)
s.Require().Equal(exported.Active.String(), status)

connectionEnd, err := s.QueryConnection(ctx, chain, exported.LocalhostConnectionID)
connectionEnd, err := s.QueryConnection(ctx, chainA, exported.LocalhostConnectionID)
s.Require().NoError(err)
s.Require().Equal(connectiontypes.OPEN, connectionEnd.State)
s.Require().Equal(exported.LocalhostClientID, connectionEnd.ClientId)
s.Require().Equal(exported.LocalhostClientID, connectionEnd.Counterparty.ClientId)
s.Require().Equal(exported.LocalhostConnectionID, connectionEnd.Counterparty.ConnectionId)
})

t.Run("ensure escrow amount for native denom is stored in state", func(t *testing.T) {
actualTotalEscrow, err := s.QueryTotalEscrowForDenom(ctx, chainA, chainADenom)
s.Require().NoError(err)

expectedTotalEscrow := math.NewInt(testvalues.IBCTransferAmount)
s.Require().Equal(expectedTotalEscrow, actualTotalEscrow) // migration has run and total escrow amount has been set
})
}

// RegisterInterchainAccount will attempt to register an interchain account on the counterparty chain.
Expand Down
17 changes: 17 additions & 0 deletions e2e/testsuite/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"sort"

"cosmossdk.io/math"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -22,6 +23,7 @@ import (

controllertypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/types"
feetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types"
transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
Expand All @@ -35,6 +37,7 @@ type GRPCClients struct {
ClientQueryClient clienttypes.QueryClient
ConnectionQueryClient connectiontypes.QueryClient
ChannelQueryClient channeltypes.QueryClient
TransferQueryClient transfertypes.QueryClient
FeeQueryClient feetypes.QueryClient
ICAQueryClient controllertypes.QueryClient
InterTxQueryClient intertxtypes.QueryClient
Expand Down Expand Up @@ -72,6 +75,7 @@ func (s *E2ETestSuite) InitGRPCClients(chain *cosmos.CosmosChain) {
s.grpcClients[chain.Config().ChainID] = GRPCClients{
ClientQueryClient: clienttypes.NewQueryClient(grpcConn),
ChannelQueryClient: channeltypes.NewQueryClient(grpcConn),
TransferQueryClient: transfertypes.NewQueryClient(grpcConn),
FeeQueryClient: feetypes.NewQueryClient(grpcConn),
ICAQueryClient: controllertypes.NewQueryClient(grpcConn),
InterTxQueryClient: intertxtypes.NewQueryClient(grpcConn),
Expand Down Expand Up @@ -158,6 +162,19 @@ func (s *E2ETestSuite) QueryPacketCommitment(ctx context.Context, chain ibc.Chai
return res.Commitment, nil
}

// QueryTotalEscrowForDenom queries the total amount of tokens in escrow for a denom
func (s *E2ETestSuite) QueryTotalEscrowForDenom(ctx context.Context, chain ibc.Chain, denom string) (math.Int, error) {
queryClient := s.GetChainGRCPClients(chain).TransferQueryClient
res, err := queryClient.TotalEscrowForDenom(ctx, &transfertypes.QueryTotalEscrowForDenomRequest{
Denom: denom,
})
if err != nil {
return math.ZeroInt(), err
}

return res.Amount, nil
}

// QueryInterchainAccount queries the interchain account for the given owner and connectionID.
func (s *E2ETestSuite) QueryInterchainAccount(ctx context.Context, chain ibc.Chain, owner, connectionID string) (string, error) {
queryClient := s.GetChainGRCPClients(chain).ICAQueryClient
Expand Down
1 change: 1 addition & 0 deletions modules/apps/transfer/client/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func GetQueryCmd() *cobra.Command {
GetCmdParams(),
GetCmdQueryEscrowAddress(),
GetCmdQueryDenomHash(),
GetCmdQueryTotalEscrowForDenom(),
)

return queryCmd
Expand Down
33 changes: 33 additions & 0 deletions modules/apps/transfer/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,36 @@ func GetCmdQueryDenomHash() *cobra.Command {
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

// GetCmdQueryTotalEscrowForDenom defines the command to query the total amount of tokens in escrow for a denom
func GetCmdQueryTotalEscrowForDenom() *cobra.Command {
crodriguezvega marked this conversation as resolved.
Show resolved Hide resolved
cmd := &cobra.Command{
Use: "token-escrow [denom]",
Short: "Query the total amount of tokens in escrow for a denom",
Long: "Query the total amount of tokens in escrow for a denom",
Example: fmt.Sprintf("%s query ibc-transfer token-escrow uosmo", version.AppName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryTotalEscrowForDenomRequest{
Denom: args[0],
}

res, err := queryClient.TotalEscrowForDenom(cmd.Context(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)
return cmd
}
13 changes: 10 additions & 3 deletions modules/apps/transfer/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,20 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) {
}

k.SetParams(ctx, state.Params)

// Every denom will have only one total escrow amount, since any
// duplicate entry will fail validation in Validate of GenesisState
for _, denomEscrow := range state.TotalEscrowed {
k.SetTotalEscrowForDenom(ctx, denomEscrow.Denom, denomEscrow.Amount)
}
}

// ExportGenesis exports ibc-transfer module's portID and denom trace info into its genesis state.
func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
return &types.GenesisState{
PortId: k.GetPort(ctx),
DenomTraces: k.GetAllDenomTraces(ctx),
Params: k.GetParams(ctx),
PortId: k.GetPort(ctx),
DenomTraces: k.GetAllDenomTraces(ctx),
Params: k.GetParams(ctx),
TotalEscrowed: k.GetAllTotalEscrowed(ctx),
}
}
38 changes: 27 additions & 11 deletions modules/apps/transfer/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,51 @@ package keeper_test
import (
"fmt"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
crodriguezvega marked this conversation as resolved.
Show resolved Hide resolved
)

func (suite *KeeperTestSuite) TestGenesis() {
var (
path string
traces types.Traces
)
getTrace := func(index uint) string {
return fmt.Sprintf("transfer/channelToChain%d", index)
}

for i := 0; i < 5; i++ {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I refactored this to make it more table-test like.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we pull these changes out into a separate pr to main?

prefix := fmt.Sprintf("transfer/channelToChain%d", i)
if i == 0 {
path = prefix
} else {
path = prefix + "/" + path
var (
traces types.Traces
escrows sdk.Coins
pathsAndEscrowAmounts = []struct {
path string
escrow string
}{
{getTrace(0), "10"},
{fmt.Sprintf("%s/%s", getTrace(1), getTrace(0)), "100000"},
{fmt.Sprintf("%s/%s/%s", getTrace(2), getTrace(1), getTrace(0)), "10000000000"},
{fmt.Sprintf("%s/%s/%s/%s", getTrace(3), getTrace(2), getTrace(1), getTrace(0)), "1000000000000000"},
{fmt.Sprintf("%s/%s/%s/%s/%s", getTrace(4), getTrace(3), getTrace(2), getTrace(1), getTrace(0)), "100000000000000000000"},
}
)

for _, pathAndEscrowMount := range pathsAndEscrowAmounts {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo? pathAndEscrowAmount?

denomTrace := types.DenomTrace{
BaseDenom: "uatom",
Path: path,
Path: pathAndEscrowMount.path,
}
traces = append(types.Traces{denomTrace}, traces...)
suite.chainA.GetSimApp().TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), denomTrace)

denom := denomTrace.IBCDenom()
amount, ok := math.NewIntFromString(pathAndEscrowMount.escrow)
suite.Require().True(ok)
escrows = append(sdk.NewCoins(sdk.NewCoin(denom, amount)), escrows...)
suite.chainA.GetSimApp().TransferKeeper.SetTotalEscrowForDenom(suite.chainA.GetContext(), denom, amount)
}

genesis := suite.chainA.GetSimApp().TransferKeeper.ExportGenesis(suite.chainA.GetContext())

suite.Require().Equal(types.PortID, genesis.PortId)
suite.Require().Equal(traces.Sort(), genesis.DenomTraces)
suite.Require().Equal(escrows.Sort(), genesis.TotalEscrowed)

suite.Require().NotPanics(func() {
suite.chainA.GetSimApp().TransferKeeper.InitGenesis(suite.chainA.GetContext(), *genesis)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a test for InitGenesis?

Expand Down
19 changes: 19 additions & 0 deletions modules/apps/transfer/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,22 @@ func (q Keeper) EscrowAddress(c context.Context, req *types.QueryEscrowAddressRe
EscrowAddress: addr.String(),
}, nil
}

// TotalEscrowForDenom implements the TotalEscrowForDenom gRPC method.
func (q Keeper) TotalEscrowForDenom(c context.Context, req *types.QueryTotalEscrowForDenomRequest) (*types.QueryTotalEscrowForDenomResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}

ctx := sdk.UnwrapSDKContext(c)

if err := sdk.ValidateDenom(req.Denom); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}

denomAmount := q.GetTotalEscrowForDenom(ctx, req.Denom)

return &types.QueryTotalEscrowForDenomResponse{
Amount: denomAmount,
}, nil
}
Loading