From 59b24490563d63b5c950aa6ff73d2cff2d1f4d6a Mon Sep 17 00:00:00 2001 From: ylsGit Date: Fri, 7 Apr 2023 14:02:38 +0800 Subject: [PATCH 1/4] add api: query erc20 contract by channel --- x/erc20/client/rest/rest.go | 24 +++++++++++++++++++++++ x/erc20/keeper/querier.go | 39 +++++++++++++++++++++++++++++++++++++ x/erc20/types/keys.go | 11 ++++++----- x/erc20/types/querier.go | 5 +++++ 4 files changed, 74 insertions(+), 5 deletions(-) diff --git a/x/erc20/client/rest/rest.go b/x/erc20/client/rest/rest.go index 84f8583d46..af9dcbfbe3 100644 --- a/x/erc20/client/rest/rest.go +++ b/x/erc20/client/rest/rest.go @@ -18,6 +18,7 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/erc20/token_mapping", tokenMappingHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/erc20/contract/{denom_hash}", contractByDenomHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/erc20/denom/{contract}", denomByContractHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/erc20/token_mapping_channel/{channel}/{denom}", tokenMappingChannelHandlerFn(cliCtx)).Methods("GET") } func tokenMappingHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { @@ -45,6 +46,29 @@ func tokenMappingHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { } } +func tokenMappingChannelHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + channel := mux.Vars(r)["channel"] + denom := mux.Vars(r)["denom"] + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + params := cliCtx.Codec.MustMarshalJSON(types.TokenMappingByChannelRequest{Channel: channel, BaseDenom: denom}) + res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.RouterKey, types.QueryTokenMappingChannel), params) + if err != nil { + sdkErr := comm.ParseSDKError(err.Error()) + comm.HandleErrorMsg(w, cliCtx, sdkErr.Code, sdkErr.Message) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, res) + } +} + func contractByDenomHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { denom := mux.Vars(r)["denom_hash"] diff --git a/x/erc20/keeper/querier.go b/x/erc20/keeper/querier.go index fdebe5b84a..f7086f19fd 100644 --- a/x/erc20/keeper/querier.go +++ b/x/erc20/keeper/querier.go @@ -1,6 +1,7 @@ package keeper import ( + "encoding/hex" "encoding/json" "fmt" @@ -25,6 +26,8 @@ func NewQuerier(keeper Keeper) sdk.Querier { switch path[0] { case types.QueryParameters: return queryParams(ctx, keeper) + case types.QueryTokenMappingChannel: + return queryTokenMappingChannel(ctx, req, keeper) case types.QueryTokenMapping: return queryTokenMapping(ctx, keeper) case types.QueryDenomByContract: @@ -48,6 +51,42 @@ func queryParams(ctx sdk.Context, keeper Keeper) (res []byte, err sdk.Error) { return res, nil } +func queryTokenMappingChannel(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) { + var params types.TokenMappingByChannelRequest + err := keeper.cdc.UnmarshalJSON(req.Data, ¶ms) + if err != nil { + return nil, common.ErrUnMarshalJSONFailed(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) + } + + trace := transfertypes.DenomTrace{ + Path: transfertypes.PortID + "/" + params.Channel, + BaseDenom: params.BaseDenom, + } + hash := trace.Hash() + _, found := keeper.transferKeeper.GetDenomTrace(ctx, hash) + if !found { + return nil, fmt.Errorf("the denom trace for the channel %s and denom %s is not found", params.Channel, params.BaseDenom) + } + + hexHash := hex.EncodeToString(hash) + denom := transfertypes.DenomPrefix + "/" + hexHash + contract, found := keeper.GetContractByDenom(ctx, denom) + if !found { + return nil, fmt.Errorf("the erc20 contract for the channel %s and denom %s is not found", params.Channel, params.BaseDenom) + } + mapping := types.QueryTokenMappingResponse{ + Denom: denom, + Contract: contract.String(), + Path: trace.Path, + BaseDenom: trace.BaseDenom, + } + res, errUnmarshal := codec.MarshalJSONIndent(types.ModuleCdc, mapping) + if errUnmarshal != nil { + return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", errUnmarshal.Error())) + } + return res, nil +} + func queryTokenMapping(ctx sdk.Context, keeper Keeper) ([]byte, error) { var mappings []types.QueryTokenMappingResponse keeper.IterateMapping(ctx, func(denom, contract string) bool { diff --git a/x/erc20/types/keys.go b/x/erc20/types/keys.go index 106dbe7c97..2a05fc7d4f 100644 --- a/x/erc20/types/keys.go +++ b/x/erc20/types/keys.go @@ -10,11 +10,12 @@ const ( // RouterKey uses module name for routing RouterKey = ModuleName - QueryParameters = "params" - QueryTokenMapping = "token-mapping" - QueryContractByDenom = "contract-by-denom" - QueryDenomByContract = "denom-by-contract" - QueryContractTem = "current-template-contract" + QueryParameters = "params" + QueryTokenMapping = "token-mapping" + QueryContractByDenom = "contract-by-denom" + QueryDenomByContract = "denom-by-contract" + QueryContractTem = "current-template-contract" + QueryTokenMappingChannel = "token-mapping-channel" ) // KVStore key prefixes diff --git a/x/erc20/types/querier.go b/x/erc20/types/querier.go index 33da53d2c2..e019f2bb66 100644 --- a/x/erc20/types/querier.go +++ b/x/erc20/types/querier.go @@ -19,3 +19,8 @@ type QueryTokenMappingResponse struct { Path string `json:"path,omitempty"` BaseDenom string `json:"base_denom,omitempty"` } + +type TokenMappingByChannelRequest struct { + Channel string `json:"channel"` + BaseDenom string `json:"base_denom"` +} From 7de7f7222e81e9d2e4941b29257f077bfb7de15f Mon Sep 17 00:00:00 2001 From: ylsGit Date: Fri, 7 Apr 2023 14:48:01 +0800 Subject: [PATCH 2/4] UseEncodedPath --- x/erc20/client/rest/rest.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/erc20/client/rest/rest.go b/x/erc20/client/rest/rest.go index af9dcbfbe3..0c02c4f737 100644 --- a/x/erc20/client/rest/rest.go +++ b/x/erc20/client/rest/rest.go @@ -19,6 +19,7 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/erc20/contract/{denom_hash}", contractByDenomHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/erc20/denom/{contract}", denomByContractHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/erc20/token_mapping_channel/{channel}/{denom}", tokenMappingChannelHandlerFn(cliCtx)).Methods("GET") + r.UseEncodedPath() } func tokenMappingHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { From 0d1aaea710004831288c8c6ed29544b3a231ea4a Mon Sep 17 00:00:00 2001 From: ylsGit Date: Fri, 7 Apr 2023 15:13:44 +0800 Subject: [PATCH 3/4] UseEncodedPath --- cmd/exchaind/rest.go | 2 +- x/erc20/client/rest/rest.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/exchaind/rest.go b/cmd/exchaind/rest.go index 2643047542..df6fdee81c 100644 --- a/cmd/exchaind/rest.go +++ b/cmd/exchaind/rest.go @@ -65,7 +65,7 @@ func registerGrpc(rs *lcd.RestServer) { } func registerRoutesV1(rs *lcd.RestServer, pathPrefix string) { - v1Router := rs.Mux.PathPrefix(fmt.Sprintf("/%s/v1", pathPrefix)).Name("v1").Subrouter() + v1Router := rs.Mux.PathPrefix(fmt.Sprintf("/%s/v1", pathPrefix)).Name("v1").Subrouter().UseEncodedPath() client.RegisterRoutes(rs.CliCtx, v1Router) authrest.RegisterRoutes(rs.CliCtx, v1Router, auth.StoreKey) bankrest.RegisterRoutes(rs.CliCtx, v1Router) diff --git a/x/erc20/client/rest/rest.go b/x/erc20/client/rest/rest.go index 0c02c4f737..af9dcbfbe3 100644 --- a/x/erc20/client/rest/rest.go +++ b/x/erc20/client/rest/rest.go @@ -19,7 +19,6 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/erc20/contract/{denom_hash}", contractByDenomHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/erc20/denom/{contract}", denomByContractHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/erc20/token_mapping_channel/{channel}/{denom}", tokenMappingChannelHandlerFn(cliCtx)).Methods("GET") - r.UseEncodedPath() } func tokenMappingHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { From a44ba4fc0b3151ae5c494fcafee19aa31fb40ad6 Mon Sep 17 00:00:00 2001 From: ylsGit Date: Fri, 7 Apr 2023 16:31:14 +0800 Subject: [PATCH 4/4] support multi channel --- cmd/exchaind/rest.go | 2 +- x/erc20/client/rest/rest.go | 6 +++--- x/erc20/keeper/querier.go | 8 +++++--- x/erc20/types/querier.go | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cmd/exchaind/rest.go b/cmd/exchaind/rest.go index df6fdee81c..2643047542 100644 --- a/cmd/exchaind/rest.go +++ b/cmd/exchaind/rest.go @@ -65,7 +65,7 @@ func registerGrpc(rs *lcd.RestServer) { } func registerRoutesV1(rs *lcd.RestServer, pathPrefix string) { - v1Router := rs.Mux.PathPrefix(fmt.Sprintf("/%s/v1", pathPrefix)).Name("v1").Subrouter().UseEncodedPath() + v1Router := rs.Mux.PathPrefix(fmt.Sprintf("/%s/v1", pathPrefix)).Name("v1").Subrouter() client.RegisterRoutes(rs.CliCtx, v1Router) authrest.RegisterRoutes(rs.CliCtx, v1Router, auth.StoreKey) bankrest.RegisterRoutes(rs.CliCtx, v1Router) diff --git a/x/erc20/client/rest/rest.go b/x/erc20/client/rest/rest.go index af9dcbfbe3..75f62c6481 100644 --- a/x/erc20/client/rest/rest.go +++ b/x/erc20/client/rest/rest.go @@ -18,7 +18,7 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/erc20/token_mapping", tokenMappingHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/erc20/contract/{denom_hash}", contractByDenomHandlerFn(cliCtx)).Methods("GET") r.HandleFunc("/erc20/denom/{contract}", denomByContractHandlerFn(cliCtx)).Methods("GET") - r.HandleFunc("/erc20/token_mapping_channel/{channel}/{denom}", tokenMappingChannelHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/erc20/token_mapping_channel/{channels}/{denom}", tokenMappingChannelHandlerFn(cliCtx)).Methods("GET") } func tokenMappingHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { @@ -48,7 +48,7 @@ func tokenMappingHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { func tokenMappingChannelHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - channel := mux.Vars(r)["channel"] + channels := mux.Vars(r)["channels"] denom := mux.Vars(r)["denom"] cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) @@ -56,7 +56,7 @@ func tokenMappingChannelHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { return } - params := cliCtx.Codec.MustMarshalJSON(types.TokenMappingByChannelRequest{Channel: channel, BaseDenom: denom}) + params := cliCtx.Codec.MustMarshalJSON(types.TokenMappingByChannelRequest{Channels: channels, BaseDenom: denom}) res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", types.RouterKey, types.QueryTokenMappingChannel), params) if err != nil { sdkErr := comm.ParseSDKError(err.Error()) diff --git a/x/erc20/keeper/querier.go b/x/erc20/keeper/querier.go index f7086f19fd..1790ecb18c 100644 --- a/x/erc20/keeper/querier.go +++ b/x/erc20/keeper/querier.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "strings" ethcmm "github.com/ethereum/go-ethereum/common" "github.com/okex/exchain/libs/cosmos-sdk/codec" @@ -58,21 +59,22 @@ func queryTokenMappingChannel(ctx sdk.Context, req abci.RequestQuery, keeper Kee return nil, common.ErrUnMarshalJSONFailed(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) } + path := transfertypes.PortID + "/" + strings.ReplaceAll(params.Channels, ",", "/"+transfertypes.PortID+"/") trace := transfertypes.DenomTrace{ - Path: transfertypes.PortID + "/" + params.Channel, + Path: path, BaseDenom: params.BaseDenom, } hash := trace.Hash() _, found := keeper.transferKeeper.GetDenomTrace(ctx, hash) if !found { - return nil, fmt.Errorf("the denom trace for the channel %s and denom %s is not found", params.Channel, params.BaseDenom) + return nil, fmt.Errorf("the denom trace for the channel %s and denom %s is not found", params.Channels, params.BaseDenom) } hexHash := hex.EncodeToString(hash) denom := transfertypes.DenomPrefix + "/" + hexHash contract, found := keeper.GetContractByDenom(ctx, denom) if !found { - return nil, fmt.Errorf("the erc20 contract for the channel %s and denom %s is not found", params.Channel, params.BaseDenom) + return nil, fmt.Errorf("the erc20 contract for the channel %s and denom %s is not found", params.Channels, params.BaseDenom) } mapping := types.QueryTokenMappingResponse{ Denom: denom, diff --git a/x/erc20/types/querier.go b/x/erc20/types/querier.go index e019f2bb66..742d43d117 100644 --- a/x/erc20/types/querier.go +++ b/x/erc20/types/querier.go @@ -21,6 +21,6 @@ type QueryTokenMappingResponse struct { } type TokenMappingByChannelRequest struct { - Channel string `json:"channel"` + Channels string `json:"channels"` BaseDenom string `json:"base_denom"` }