Skip to content

Commit

Permalink
feat: add CLI and RPC endpoint from Pointee to Pointer mapping (#1834)
Browse files Browse the repository at this point in the history
* feat: add CLI and RPC endpoint from Pointee to Pointer mapping

---------

Co-authored-by: blindchaser <[email protected]>
  • Loading branch information
blindchaser and blindchaser authored Sep 4, 2024
1 parent 7e79510 commit c58e08e
Show file tree
Hide file tree
Showing 7 changed files with 859 additions and 41 deletions.
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) {
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

0 comments on commit c58e08e

Please sign in to comment.