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: add CLI and RPC endpoint from Pointee to Pointer mapping #1834

Merged
merged 5 commits into from
Sep 4, 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
15 changes: 15 additions & 0 deletions proto/evm/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ service Query {
rpc PointerVersion(QueryPointerVersionRequest) returns (QueryPointerVersionResponse) {
option (google.api.http).get = "/sei-protocol/seichain/evm/pointer_version";
}

rpc Pointee(QueryPointeeRequest) returns (QueryPointeeResponse) {
option (google.api.http).get = "/sei-protocol/seichain/evm/pointee";
}
}

message QuerySeiAddressByEVMAddressRequest {
Expand Down Expand Up @@ -75,3 +79,14 @@ message QueryPointerVersionResponse {
uint32 version = 1;
uint64 cw_code_id = 2;
}

message QueryPointeeRequest {
PointerType pointer_type = 1;
string pointer = 2;
}

message QueryPointeeResponse {
string pointee = 1;
uint32 version = 2;
bool exists = 3;
}
30 changes: 30 additions & 0 deletions x/evm/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func GetQueryCmd(_ string) *cobra.Command {
cmd.AddCommand(CmdQueryPayload())
cmd.AddCommand(CmdQueryPointer())
cmd.AddCommand(CmdQueryPointerVersion())
cmd.AddCommand(CmdQueryPointee())

return cmd
}
Expand Down Expand Up @@ -348,3 +349,32 @@ func CmdQueryPointerVersion() *cobra.Command {

return cmd
}

func CmdQueryPointee() *cobra.Command {
cmd := &cobra.Command{
Use: "pointee [type] [pointer]",
Short: "Get pointee address of the specified type (one of [NATIVE, CW20, CW721, ERC20, ERC721]) and pointer",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
ctx := cmd.Context()

res, err := queryClient.Pointee(ctx, &types.QueryPointeeRequest{
PointerType: types.PointerType(types.PointerType_value[args[0]]), Pointer: args[1],
})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
43 changes: 43 additions & 0 deletions x/evm/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,46 @@ func (q Querier) PointerVersion(c context.Context, req *types.QueryPointerVersio
return nil, errors.ErrUnsupported
}
}

func (q Querier) Pointee(c context.Context, req *types.QueryPointeeRequest) (*types.QueryPointeeResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
switch req.PointerType {
case types.PointerType_NATIVE:
p, v, e := q.Keeper.GetNativePointee(ctx, req.Pointer)
return &types.QueryPointeeResponse{
Pointee: p,
Version: uint32(v),
Exists: e,
}, nil
case types.PointerType_CW20:
p, v, e := q.Keeper.GetCW20Pointee(ctx, common.HexToAddress(req.Pointer))
return &types.QueryPointeeResponse{
Pointee: p,
Version: uint32(v),
Exists: e,
}, nil
case types.PointerType_CW721:
p, v, e := q.Keeper.GetCW721Pointee(ctx, common.HexToAddress(req.Pointer))
return &types.QueryPointeeResponse{
Pointee: p,
Version: uint32(v),
Exists: e,
}, nil
case types.PointerType_ERC20:
p, v, e := q.Keeper.GetERC20Pointee(ctx, req.Pointer)
return &types.QueryPointeeResponse{
Pointee: p.Hex(),
Version: uint32(v),
Exists: e,
}, nil
case types.PointerType_ERC721:
p, v, e := q.Keeper.GetERC721Pointee(ctx, req.Pointer)
return &types.QueryPointeeResponse{
Pointee: p.Hex(),
Version: uint32(v),
Exists: e,
}, nil
default:
return nil, errors.ErrUnsupported
}
}
116 changes: 116 additions & 0 deletions x/evm/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper_test

import (
"errors"
"testing"
"time"

Expand Down Expand Up @@ -47,3 +48,118 @@ func TestQueryPointer(t *testing.T) {
require.Nil(t, err)
require.Equal(t, types.QueryPointerResponse{Pointer: seiAddr5.String(), Version: uint32(erc721.CurrentVersion), Exists: true}, *res)
}

func TestQueryPointee(t *testing.T) {
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 also test for invalid / not registered yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point will add it

k, ctx := testkeeper.MockEVMKeeper()
_, pointerAddr1 := testkeeper.MockAddressPair()
seiAddr2, evmAddr2 := testkeeper.MockAddressPair()
seiAddr3, evmAddr3 := testkeeper.MockAddressPair()
seiAddr4, evmAddr4 := testkeeper.MockAddressPair()
seiAddr5, evmAddr5 := testkeeper.MockAddressPair()
goCtx := sdk.WrapSDKContext(ctx)

// Set up pointers for each type
k.SetERC20NativePointer(ctx, "ufoo", pointerAddr1)
k.SetERC20CW20Pointer(ctx, seiAddr2.String(), evmAddr2)
k.SetERC721CW721Pointer(ctx, seiAddr3.String(), evmAddr3)
k.SetCW20ERC20Pointer(ctx, evmAddr4, seiAddr4.String())
k.SetCW721ERC721Pointer(ctx, evmAddr5, seiAddr5.String())

q := keeper.Querier{k}

// Test for Native Pointee
res, err := q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_NATIVE, Pointer: pointerAddr1.Hex()})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: "ufoo", Version: uint32(native.CurrentVersion), Exists: true}, *res)

// Test for CW20 Pointee
res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_CW20, Pointer: evmAddr2.Hex()})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: seiAddr2.String(), Version: uint32(cw20.CurrentVersion(ctx)), Exists: true}, *res)

// Test for CW721 Pointee
res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_CW721, Pointer: evmAddr3.Hex()})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: seiAddr3.String(), Version: uint32(cw721.CurrentVersion), Exists: true}, *res)

// Test for ERC20 Pointee
res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_ERC20, Pointer: seiAddr4.String()})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: evmAddr4.Hex(), Version: uint32(erc20.CurrentVersion), Exists: true}, *res)

// Test for ERC721 Pointee
res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_ERC721, Pointer: seiAddr5.String()})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: evmAddr5.Hex(), Version: uint32(erc721.CurrentVersion), Exists: true}, *res)

// Test for not registered Native Pointee
res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_NATIVE, Pointer: "0x1234567890123456789012345678901234567890"})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false}, *res)

// Test for not registered CW20 Pointee
res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_CW20, Pointer: "0x1234567890123456789012345678901234567890"})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false}, *res)

// Test for not registered CW721 Pointee
res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_CW721, Pointer: "0x1234567890123456789012345678901234567890"})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false}, *res)

// Test for not registered ERC20 Pointee
res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_ERC20, Pointer: "sei1notregistered"})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: "0x0000000000000000000000000000000000000000", Version: 0, Exists: false}, *res)

// Test for not registered ERC721 Pointee
res, err = q.Pointee(goCtx, &types.QueryPointeeRequest{PointerType: types.PointerType_ERC721, Pointer: "sei1notregistered"})
require.Nil(t, err)
require.Equal(t, types.QueryPointeeResponse{Pointee: "0x0000000000000000000000000000000000000000", Version: 0, Exists: false}, *res)

// Test cases for invalid inputs
testCases := []struct {
name string
req *types.QueryPointeeRequest
expectedRes *types.QueryPointeeResponse
expectedErr error
}{
{
name: "Invalid pointer type",
req: &types.QueryPointeeRequest{PointerType: 999, Pointer: pointerAddr1.Hex()},
expectedRes: nil,
expectedErr: errors.ErrUnsupported,
},
{
name: "Empty pointer",
req: &types.QueryPointeeRequest{PointerType: types.PointerType_NATIVE, Pointer: ""},
expectedRes: &types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false},
expectedErr: nil,
},
{
name: "Invalid hex address for EVM-based pointer types",
req: &types.QueryPointeeRequest{PointerType: types.PointerType_CW20, Pointer: "not-a-hex-address"},
expectedRes: &types.QueryPointeeResponse{Pointee: "", Version: 0, Exists: false},
expectedErr: nil,
},
{
name: "Invalid bech32 address for Cosmos-based pointer types",
req: &types.QueryPointeeRequest{PointerType: types.PointerType_ERC20, Pointer: "not-a-bech32-address"},
expectedRes: &types.QueryPointeeResponse{Pointee: "0x0000000000000000000000000000000000000000", Version: 0, Exists: false},
expectedErr: nil,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
res, err := q.Pointee(goCtx, tc.req)
if tc.expectedErr != nil {
require.ErrorIs(t, err, tc.expectedErr)
require.Nil(t, res)
} else {
require.NoError(t, err)
require.Equal(t, tc.expectedRes, res)
}
})
}
}
42 changes: 42 additions & 0 deletions x/evm/keeper/pointer.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,45 @@ func (k *Keeper) GetStoredPointerCodeID(ctx sdk.Context, pointerType types.Point
}
return binary.BigEndian.Uint64(bz)
}

func (k *Keeper) GetCW20Pointee(ctx sdk.Context, erc20Address common.Address) (cw20Address string, version uint16, exists bool) {
addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(erc20Address))
if exists {
cw20Address = string(addrBz)
}
return
}

func (k *Keeper) GetCW721Pointee(ctx sdk.Context, erc721Address common.Address) (cw721Address string, version uint16, exists bool) {
addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(erc721Address))
if exists {
cw721Address = string(addrBz)
}
return
}

func (k *Keeper) GetERC20Pointee(ctx sdk.Context, cw20Address string) (erc20Address common.Address, version uint16, exists bool) {
addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(common.BytesToAddress([]byte(cw20Address))))
if exists {
erc20Address = common.BytesToAddress(addrBz)
}
return
}

func (k *Keeper) GetERC721Pointee(ctx sdk.Context, cw721Address string) (erc721Address common.Address, version uint16, exists bool) {
addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(common.BytesToAddress([]byte(cw721Address))))
if exists {
erc721Address = common.BytesToAddress(addrBz)
}
return
}

func (k *Keeper) GetNativePointee(ctx sdk.Context, erc20Address string) (token string, version uint16, exists bool) {
// Ensure the key matches how it was set in SetERC20NativePointer
key := types.PointerReverseRegistryKey(common.HexToAddress(erc20Address))
addrBz, version, exists := k.GetPointerInfo(ctx, key)
if exists {
token = string(addrBz)
}
return
}
Loading
Loading