Skip to content

Commit 59eb848

Browse files
authored
feat: query denoms by admin (#25)
* feat: query denoms by admin * docs: denoms-from-admin * fix: local docker
1 parent 9f137b7 commit 59eb848

File tree

9 files changed

+657
-39
lines changed

9 files changed

+657
-39
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ and the following queries:
6262
- `params`: Get the tokenfactory module parameters.
6363
- `denom-authority-metadata`: Get the authority metadata of a denom.
6464
- `denoms-from-creator`: Returns a list of all denoms created by a given creator.
65+
- `denoms-from-admin`: Returns a list of all denoms for which a given address is the admin.
6566

6667
## Testing
6768

proto/osmosis/tokenfactory/v1beta1/query.proto

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ service Query {
3232
option (google.api.http).get =
3333
"/osmosis/tokenfactory/v1beta1/denoms_from_creator/{creator}";
3434
}
35+
36+
// DenomsFromAdmin defines a gRPC query method for fetching all
37+
// denominations owned by a specific admin.
38+
rpc DenomsFromAdmin(QueryDenomsFromAdminRequest)
39+
returns (QueryDenomsFromAdminResponse) {
40+
option (google.api.http).get =
41+
"/osmosis/tokenfactory/v1beta1/denoms_from_admin/{admin}";
42+
}
3543
}
3644

3745
// QueryParamsRequest is the request type for the Query/Params RPC method.
@@ -69,3 +77,15 @@ message QueryDenomsFromCreatorRequest {
6977
message QueryDenomsFromCreatorResponse {
7078
repeated string denoms = 1 [ (gogoproto.moretags) = "yaml:\"denoms\"" ];
7179
}
80+
81+
// QueryDenomsFromAdminRequest defines the request structure for the
82+
// DenomsFromAdmin gRPC query.
83+
message QueryDenomsFromAdminRequest {
84+
string admin = 1 [ (gogoproto.moretags) = "yaml:\"admin\"" ];
85+
}
86+
87+
// QueryDenomsFromAdminRequest defines the response structure for the
88+
// DenomsFromAdmin gRPC query.
89+
message QueryDenomsFromAdminResponse {
90+
repeated string denoms = 1 [ (gogoproto.moretags) = "yaml:\"denoms\"" ];
91+
}

x/tokenfactory/client/cli/query.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ func GetQueryCmd() *cobra.Command {
2525
GetParams(),
2626
GetCmdDenomAuthorityMetadata(),
2727
GetCmdDenomsFromCreator(),
28+
GetCmdDenomsFromAdmin(),
2829
)
2930

3031
return cmd
@@ -114,3 +115,31 @@ func GetCmdDenomsFromCreator() *cobra.Command {
114115

115116
return cmd
116117
}
118+
119+
func GetCmdDenomsFromAdmin() *cobra.Command {
120+
cmd := &cobra.Command{
121+
Use: "denoms-from-admin [admin address] [flags]",
122+
Short: "Returns a list of all tokens owned by a specific admin address",
123+
Args: cobra.ExactArgs(1),
124+
RunE: func(cmd *cobra.Command, args []string) error {
125+
clientCtx, err := client.GetClientQueryContext(cmd)
126+
if err != nil {
127+
return err
128+
}
129+
queryClient := types.NewQueryClient(clientCtx)
130+
131+
res, err := queryClient.DenomsFromAdmin(cmd.Context(), &types.QueryDenomsFromAdminRequest{
132+
Admin: args[0],
133+
})
134+
if err != nil {
135+
return err
136+
}
137+
138+
return clientCtx.PrintProto(res)
139+
},
140+
}
141+
142+
flags.AddQueryFlagsToCmd(cmd)
143+
144+
return cmd
145+
}

x/tokenfactory/keeper/admins.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,22 @@ func (k Keeper) setAdmin(ctx context.Context, denom string, admin string) error
5050

5151
return k.setAuthorityMetadata(ctx, denom, metadata)
5252
}
53+
54+
// GetDenomsFromAdmin returns all denoms for which the provided address is the admin
55+
func (k Keeper) GetDenomsFromAdmin(ctx context.Context, admin string) ([]string, error) {
56+
iterator := k.GetAllDenomsIterator(ctx)
57+
defer iterator.Close()
58+
59+
denoms := []string{}
60+
for ; iterator.Valid(); iterator.Next() {
61+
denom := string(iterator.Value())
62+
metadata, err := k.GetAuthorityMetadata(sdk.UnwrapSDKContext(ctx), denom)
63+
if err != nil {
64+
return nil, err
65+
}
66+
if metadata.Admin == admin {
67+
denoms = append(denoms, denom)
68+
}
69+
}
70+
return denoms, nil
71+
}

x/tokenfactory/keeper/admins_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@ func (suite *KeeperTestSuite) TestAdminMsgs() {
2323
suite.Require().NoError(err)
2424
suite.Require().Equal(suite.TestAccs[0].String(), queryRes.AuthorityMetadata.Admin)
2525

26+
// Test getting denoms from admin
27+
adminRes, err := suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
28+
Admin: suite.TestAccs[0].String(),
29+
})
30+
suite.Require().NoError(err)
31+
suite.Require().Equal([]string{suite.defaultDenom}, adminRes.Denoms)
32+
33+
// Veriry that the other account has no denoms
34+
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
35+
Admin: suite.TestAccs[1].String(),
36+
})
37+
suite.Require().NoError(err)
38+
suite.Require().Nil(adminRes.Denoms)
39+
2640
// Test minting to admins own account
2741
_, err = suite.msgServer.Mint(suite.Ctx, types.NewMsgMint(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 10)))
2842
addr0bal += 10
@@ -57,6 +71,20 @@ func (suite *KeeperTestSuite) TestAdminMsgs() {
5771
suite.Require().NoError(err)
5872
suite.Require().Equal(suite.TestAccs[1].String(), queryRes.AuthorityMetadata.Admin)
5973

74+
// Test query from admin returns the correct denoms. The old admin should have no denoms
75+
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
76+
Admin: suite.TestAccs[0].String(),
77+
})
78+
suite.Require().NoError(err)
79+
suite.Require().Nil(adminRes.Denoms)
80+
81+
// The new admin should have the default denom
82+
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
83+
Admin: suite.TestAccs[1].String(),
84+
})
85+
suite.Require().NoError(err)
86+
suite.Require().Equal([]string{suite.defaultDenom}, adminRes.Denoms)
87+
6088
// Make sure old admin can no longer do actions
6189
_, err = suite.msgServer.Burn(suite.Ctx, types.NewMsgBurn(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 5)))
6290
suite.Require().Error(err)
@@ -75,6 +103,26 @@ func (suite *KeeperTestSuite) TestAdminMsgs() {
75103
})
76104
suite.Require().NoError(err)
77105
suite.Require().Equal("", queryRes.AuthorityMetadata.Admin)
106+
107+
// Make sure retrieving denoms by admin works with empty admin
108+
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
109+
Admin: "",
110+
})
111+
suite.Require().NoError(err)
112+
suite.Require().Equal([]string{suite.defaultDenom}, adminRes.Denoms)
113+
114+
// Make sure the other accounts are not admins
115+
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
116+
Admin: suite.TestAccs[0].String(),
117+
})
118+
suite.Require().NoError(err)
119+
suite.Require().Nil(adminRes.Denoms)
120+
121+
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
122+
Admin: suite.TestAccs[1].String(),
123+
})
124+
suite.Require().NoError(err)
125+
suite.Require().Nil(adminRes.Denoms)
78126
}
79127

80128
// TestMintDenom ensures the following properties of the MintMessage:

x/tokenfactory/keeper/creators.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55

66
"cosmossdk.io/store"
7-
87
sdk "github.com/cosmos/cosmos-sdk/types"
98
)
109

x/tokenfactory/keeper/grpc_query.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,12 @@ func (k Keeper) DenomsFromCreator(ctx context.Context, req *types.QueryDenomsFro
3333
denoms := k.GetDenomsFromCreator(sdkCtx, req.GetCreator())
3434
return &types.QueryDenomsFromCreatorResponse{Denoms: denoms}, nil
3535
}
36+
37+
func (k Keeper) DenomsFromAdmin(ctx context.Context, req *types.QueryDenomsFromAdminRequest) (*types.QueryDenomsFromAdminResponse, error) {
38+
sdkCtx := sdk.UnwrapSDKContext(ctx)
39+
denoms, err := k.GetDenomsFromAdmin(sdkCtx, req.GetAdmin())
40+
if err != nil {
41+
return nil, err
42+
}
43+
return &types.QueryDenomsFromAdminResponse{Denoms: denoms}, nil
44+
}

0 commit comments

Comments
 (0)