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

feat: query denoms by admin #25

Merged
merged 3 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ and the following queries:
- `params`: Get the tokenfactory module parameters.
- `denom-authority-metadata`: Get the authority metadata of a denom.
- `denoms-from-creator`: Returns a list of all denoms created by a given creator.
- `denoms-from-admin`: Returns a list of all denoms for which a given address is the admin.

## Testing

Expand Down
20 changes: 20 additions & 0 deletions proto/osmosis/tokenfactory/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ service Query {
option (google.api.http).get =
"/osmosis/tokenfactory/v1beta1/denoms_from_creator/{creator}";
}

// DenomsFromAdmin defines a gRPC query method for fetching all
// denominations owned by a specific admin.
rpc DenomsFromAdmin(QueryDenomsFromAdminRequest)
returns (QueryDenomsFromAdminResponse) {
option (google.api.http).get =
"/osmosis/tokenfactory/v1beta1/denoms_from_admin/{admin}";
}
}

// QueryParamsRequest is the request type for the Query/Params RPC method.
Expand Down Expand Up @@ -69,3 +77,15 @@ message QueryDenomsFromCreatorRequest {
message QueryDenomsFromCreatorResponse {
repeated string denoms = 1 [ (gogoproto.moretags) = "yaml:\"denoms\"" ];
}

// QueryDenomsFromAdminRequest defines the request structure for the
// DenomsFromAdmin gRPC query.
message QueryDenomsFromAdminRequest {
string admin = 1 [ (gogoproto.moretags) = "yaml:\"admin\"" ];
}

// QueryDenomsFromAdminRequest defines the response structure for the
// DenomsFromAdmin gRPC query.
message QueryDenomsFromAdminResponse {
repeated string denoms = 1 [ (gogoproto.moretags) = "yaml:\"denoms\"" ];
}
29 changes: 29 additions & 0 deletions x/tokenfactory/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
GetParams(),
GetCmdDenomAuthorityMetadata(),
GetCmdDenomsFromCreator(),
GetCmdDenomsFromAdmin(),

Check warning on line 28 in x/tokenfactory/client/cli/query.go

View check run for this annotation

Codecov / codecov/patch

x/tokenfactory/client/cli/query.go#L28

Added line #L28 was not covered by tests
)

return cmd
Expand Down Expand Up @@ -114,3 +115,31 @@

return cmd
}

func GetCmdDenomsFromAdmin() *cobra.Command {
cmd := &cobra.Command{
Use: "denoms-from-admin [admin address] [flags]",
Short: "Returns a list of all tokens owned by a specific admin address",
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)

res, err := queryClient.DenomsFromAdmin(cmd.Context(), &types.QueryDenomsFromAdminRequest{
Admin: args[0],
})
if err != nil {
return err
}

Check warning on line 136 in x/tokenfactory/client/cli/query.go

View check run for this annotation

Codecov / codecov/patch

x/tokenfactory/client/cli/query.go#L119-L136

Added lines #L119 - L136 were not covered by tests

return clientCtx.PrintProto(res)

Check warning on line 138 in x/tokenfactory/client/cli/query.go

View check run for this annotation

Codecov / codecov/patch

x/tokenfactory/client/cli/query.go#L138

Added line #L138 was not covered by tests
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd

Check warning on line 144 in x/tokenfactory/client/cli/query.go

View check run for this annotation

Codecov / codecov/patch

x/tokenfactory/client/cli/query.go#L142-L144

Added lines #L142 - L144 were not covered by tests
}
19 changes: 19 additions & 0 deletions x/tokenfactory/keeper/admins.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,22 @@

return k.setAuthorityMetadata(ctx, denom, metadata)
}

// GetDenomsFromAdmin returns all denoms for which the provided address is the admin
func (k Keeper) GetDenomsFromAdmin(ctx context.Context, admin string) ([]string, error) {
Reecepbcups marked this conversation as resolved.
Show resolved Hide resolved
iterator := k.GetAllDenomsIterator(ctx)
defer iterator.Close()

denoms := []string{}
for ; iterator.Valid(); iterator.Next() {
denom := string(iterator.Value())
metadata, err := k.GetAuthorityMetadata(sdk.UnwrapSDKContext(ctx), denom)
if err != nil {
return nil, err
}

Check warning on line 65 in x/tokenfactory/keeper/admins.go

View check run for this annotation

Codecov / codecov/patch

x/tokenfactory/keeper/admins.go#L64-L65

Added lines #L64 - L65 were not covered by tests
if metadata.Admin == admin {
denoms = append(denoms, denom)
}
}
return denoms, nil
}
48 changes: 48 additions & 0 deletions x/tokenfactory/keeper/admins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ func (suite *KeeperTestSuite) TestAdminMsgs() {
suite.Require().NoError(err)
suite.Require().Equal(suite.TestAccs[0].String(), queryRes.AuthorityMetadata.Admin)

// Test getting denoms from admin
adminRes, err := suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
Admin: suite.TestAccs[0].String(),
})
suite.Require().NoError(err)
suite.Require().Equal([]string{suite.defaultDenom}, adminRes.Denoms)

// Veriry that the other account has no denoms
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
Admin: suite.TestAccs[1].String(),
})
suite.Require().NoError(err)
suite.Require().Nil(adminRes.Denoms)

// Test minting to admins own account
_, err = suite.msgServer.Mint(suite.Ctx, types.NewMsgMint(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 10)))
addr0bal += 10
Expand Down Expand Up @@ -57,6 +71,20 @@ func (suite *KeeperTestSuite) TestAdminMsgs() {
suite.Require().NoError(err)
suite.Require().Equal(suite.TestAccs[1].String(), queryRes.AuthorityMetadata.Admin)

// Test query from admin returns the correct denoms. The old admin should have no denoms
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
Admin: suite.TestAccs[0].String(),
})
suite.Require().NoError(err)
suite.Require().Nil(adminRes.Denoms)

// The new admin should have the default denom
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
Admin: suite.TestAccs[1].String(),
})
suite.Require().NoError(err)
suite.Require().Equal([]string{suite.defaultDenom}, adminRes.Denoms)

// Make sure old admin can no longer do actions
_, err = suite.msgServer.Burn(suite.Ctx, types.NewMsgBurn(suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 5)))
suite.Require().Error(err)
Expand All @@ -75,6 +103,26 @@ func (suite *KeeperTestSuite) TestAdminMsgs() {
})
suite.Require().NoError(err)
suite.Require().Equal("", queryRes.AuthorityMetadata.Admin)

// Make sure retrieving denoms by admin works with empty admin
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
Admin: "",
})
suite.Require().NoError(err)
suite.Require().Equal([]string{suite.defaultDenom}, adminRes.Denoms)

// Make sure the other accounts are not admins
adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
Admin: suite.TestAccs[0].String(),
})
suite.Require().NoError(err)
suite.Require().Nil(adminRes.Denoms)

adminRes, err = suite.queryClient.DenomsFromAdmin(suite.Ctx.Context(), &types.QueryDenomsFromAdminRequest{
Admin: suite.TestAccs[1].String(),
})
suite.Require().NoError(err)
suite.Require().Nil(adminRes.Denoms)
}

// TestMintDenom ensures the following properties of the MintMessage:
Expand Down
1 change: 0 additions & 1 deletion x/tokenfactory/keeper/creators.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"

"cosmossdk.io/store"

sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand Down
9 changes: 9 additions & 0 deletions x/tokenfactory/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,12 @@
denoms := k.GetDenomsFromCreator(sdkCtx, req.GetCreator())
return &types.QueryDenomsFromCreatorResponse{Denoms: denoms}, nil
}

func (k Keeper) DenomsFromAdmin(ctx context.Context, req *types.QueryDenomsFromAdminRequest) (*types.QueryDenomsFromAdminResponse, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
denoms, err := k.GetDenomsFromAdmin(sdkCtx, req.GetAdmin())
if err != nil {
return nil, err
}

Check warning on line 42 in x/tokenfactory/keeper/grpc_query.go

View check run for this annotation

Codecov / codecov/patch

x/tokenfactory/keeper/grpc_query.go#L41-L42

Added lines #L41 - L42 were not covered by tests
return &types.QueryDenomsFromAdminResponse{Denoms: denoms}, nil
}
Loading
Loading