diff --git a/x/erc20/client/rest/rest.go b/x/erc20/client/rest/rest.go index 84f8583d46..75f62c6481 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/{channels}/{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) { + channels := mux.Vars(r)["channels"] + denom := mux.Vars(r)["denom"] + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + 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()) + 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..1790ecb18c 100644 --- a/x/erc20/keeper/querier.go +++ b/x/erc20/keeper/querier.go @@ -1,8 +1,10 @@ package keeper import ( + "encoding/hex" "encoding/json" "fmt" + "strings" ethcmm "github.com/ethereum/go-ethereum/common" "github.com/okex/exchain/libs/cosmos-sdk/codec" @@ -25,6 +27,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 +52,43 @@ 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())) + } + + path := transfertypes.PortID + "/" + strings.ReplaceAll(params.Channels, ",", "/"+transfertypes.PortID+"/") + trace := transfertypes.DenomTrace{ + 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.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.Channels, 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..742d43d117 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 { + Channels string `json:"channels"` + BaseDenom string `json:"base_denom"` +}