Skip to content

Commit

Permalink
implement Msg types & unit test validation
Browse files Browse the repository at this point in the history
  • Loading branch information
pirtleshell committed May 19, 2023
1 parent f5c189b commit 116e7e9
Show file tree
Hide file tree
Showing 4 changed files with 189 additions and 11 deletions.
2 changes: 1 addition & 1 deletion x/evmutil/keeper/erc20_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (suite *ERC20TestSuite) TestDeployKavaWrappedNativeCoinERC20Contract() {
})

suite.Run("deploys contract with expected metadata & permissions", func() {
caller, privKey := suite.RandomAccount()
caller, privKey := testutil.RandomEvmAccount()

token := types.NewAllowedNativeCoinERC20Token("hard", "EVM HARD", "HARD", 6)
addr, err := suite.Keeper.DeployKavaWrappedNativeCoinERC20Contract(suite.Ctx, token)
Expand Down
20 changes: 11 additions & 9 deletions x/evmutil/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ func (suite *Suite) SetupTest() {
suite.EvmModuleAddr = suite.AccountKeeper.GetModuleAddress(evmtypes.ModuleName)

// test evm user keys that have no minting permissions
addr, privKey := suite.RandomAccount()
addr, privKey := RandomEvmAccount()
suite.Key1 = privKey
suite.Key1Addr = types.NewInternalEVMAddress(addr)
_, suite.Key2 = suite.RandomAccount()
_, suite.Key2 = RandomEvmAccount()

_, addrs := app.GeneratePrivKeyAddressPairs(4)
suite.Addrs = addrs
Expand Down Expand Up @@ -180,13 +180,6 @@ func (suite *Suite) Commit() {
suite.Ctx = suite.App.NewContext(false, header)
}

func (suite *Suite) RandomAccount() (common.Address, *ethsecp256k1.PrivKey) {
privKey, err := ethsecp256k1.GenerateKey()
suite.NoError(err)
addr := common.BytesToAddress(privKey.PubKey().Address())
return addr, privKey
}

func (suite *Suite) FundAccountWithKava(addr sdk.AccAddress, coins sdk.Coins) {
ukava := coins.AmountOf("ukava")
if ukava.IsPositive() {
Expand Down Expand Up @@ -409,3 +402,12 @@ func MustNewInternalEVMAddressFromString(addrStr string) types.InternalEVMAddres

return addr
}

func RandomEvmAccount() (common.Address, *ethsecp256k1.PrivKey) {
privKey, err := ethsecp256k1.GenerateKey()
if err != nil {
panic(err)
}
addr := common.BytesToAddress(privKey.PubKey().Address())
return addr, privKey
}
66 changes: 65 additions & 1 deletion x/evmutil/types/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,26 @@ import (
// ensure Msg interface compliance at compile time
var (
_ sdk.Msg = &MsgConvertCoinToERC20{}
_ sdk.Msg = &MsgConvertERC20ToCoin{}
_ legacytx.LegacyMsg = &MsgConvertCoinToERC20{}
_ sdk.Msg = &MsgConvertERC20ToCoin{}
_ legacytx.LegacyMsg = &MsgConvertERC20ToCoin{}

_ sdk.Msg = &MsgConvertNativeCoinToERC20{}
_ legacytx.LegacyMsg = &MsgConvertNativeCoinToERC20{}
)

// legacy message types
const (
TypeMsgConvertCoinToERC20 = "evmutil_convert_coin_to_erc20"
TypeMsgConvertERC20ToCoin = "evmutil_convert_erc20_to_coin"

TypeMsgConvertNativeCoinToERC20 = "evmutil_convert_native_coin_to_erc20"
)

////////////////////////////
// EVM-native assets -> SDK
////////////////////////////

// NewMsgConvertCoinToERC20 returns a new MsgConvertCoinToERC20
func NewMsgConvertCoinToERC20(
initiator string,
Expand Down Expand Up @@ -146,3 +155,58 @@ func (msg MsgConvertERC20ToCoin) Route() string {
func (msg MsgConvertERC20ToCoin) Type() string {
return TypeMsgConvertERC20ToCoin
}

////////////////////////////
// SDK-native assets -> EVM
////////////////////////////

// NewMsgConvertNativeCoinToERC20 returns a new MsgConvertNativeCoinToERC20
func NewMsgConvertNativeCoinToERC20(
initiator string,
receiver string,
amount sdk.Coin,
) MsgConvertNativeCoinToERC20 {
return MsgConvertNativeCoinToERC20{
Initiator: initiator,
Receiver: receiver,
Amount: &amount,
}
}

// GetSigners implements types.Msg
func (msg MsgConvertNativeCoinToERC20) GetSigners() []sdk.AccAddress {
sender, err := sdk.AccAddressFromBech32(msg.Initiator)
if err != nil {
panic(err)
}
return []sdk.AccAddress{sender}
}

// ValidateBasic implements types.Msg
func (msg MsgConvertNativeCoinToERC20) ValidateBasic() error {
_, err := sdk.AccAddressFromBech32(msg.Initiator)
if err != nil {
return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid initiator address (%s): %s", msg.Initiator, err.Error())
}

if !common.IsHexAddress(msg.Receiver) {
return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "receiver is not a valid hex address (%s)", msg.Receiver)
}

if msg.Amount.IsNil() || !msg.Amount.IsValid() || msg.Amount.IsZero() {
return errorsmod.Wrapf(sdkerrors.ErrInvalidCoins, "'%s'", msg.Amount)
}

return nil
}

// GetSignBytes implements legacytx.LegacyMsg
func (msg MsgConvertNativeCoinToERC20) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg))
}

// Route implements legacytx.LegacyMsg
func (MsgConvertNativeCoinToERC20) Route() string { return RouterKey }

// Type implements legacytx.LegacyMsg
func (MsgConvertNativeCoinToERC20) Type() string { return TypeMsgConvertNativeCoinToERC20 }
112 changes: 112 additions & 0 deletions x/evmutil/types/msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/evmutil/testutil"
"github.com/kava-labs/kava/x/evmutil/types"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -198,3 +199,114 @@ func TestMsgConvertERC20ToCoin(t *testing.T) {
})
}
}

func TestConvertNativeCoinToERC20_ValidateBasic(t *testing.T) {
validKavaAddr := app.RandomAddress()
validHexAddr, _ := testutil.RandomEvmAccount()
invalidAddr := "not-an-address"
validAmount := sdk.NewInt64Coin("hard", 5e3)

testCases := []struct {
name string
initiator string
receiver string
amount sdk.Coin
expectedErr string
}{
{
name: "valid",
initiator: validKavaAddr.String(),
receiver: validHexAddr.String(),
amount: validAmount,
expectedErr: "",
},
{
name: "invalid - sending to kava addr",
initiator: validKavaAddr.String(),
receiver: app.RandomAddress().String(),
amount: validAmount,
expectedErr: "receiver is not a valid hex address",
},
{
name: "invalid - invalid initiator",
initiator: invalidAddr,
receiver: app.RandomAddress().String(),
amount: validAmount,
expectedErr: "invalid initiator address",
},
{
name: "invalid - invalid receiver",
initiator: validKavaAddr.String(),
receiver: invalidAddr,
amount: validAmount,
expectedErr: "receiver is not a valid hex address",
},
{
name: "invalid - invalid amount - nil",
initiator: validKavaAddr.String(),
receiver: validHexAddr.String(),
amount: sdk.Coin{},
expectedErr: "invalid coins",
},
{
name: "invalid - invalid amount - zero",
initiator: validKavaAddr.String(),
receiver: validHexAddr.String(),
amount: sdk.NewInt64Coin("magic", 0),
expectedErr: "invalid coins",
},
{
name: "invalid - invalid amount - negative",
initiator: validKavaAddr.String(),
receiver: validHexAddr.String(),
amount: sdk.Coin{Denom: "magic", Amount: sdkmath.NewInt(-42)},
expectedErr: "invalid coins",
},
{
name: "invalid - invalid amount - invalid denom",
initiator: validKavaAddr.String(),
receiver: validHexAddr.String(),
amount: sdk.Coin{Denom: "", Amount: sdkmath.NewInt(42)},
expectedErr: "invalid coins",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
msg := types.NewMsgConvertNativeCoinToERC20(
tc.initiator,
tc.receiver,
tc.amount,
)
err := msg.ValidateBasic()

if tc.expectedErr != "" {
require.ErrorContains(t, err, tc.expectedErr)
} else {
require.NoError(t, err)
require.Equal(t, "evmutil", msg.Route())
require.Equal(t, "evmutil_convert_native_coin_to_erc20", msg.Type())
require.NotPanics(t, func() { _ = msg.GetSignBytes() })
}
})
}
}

func TestConvertNativeCoinToERC20_GetSigners(t *testing.T) {
t.Run("valid", func(t *testing.T) {
initiator := app.RandomAddress()
signers := types.MsgConvertNativeCoinToERC20{
Initiator: initiator.String(),
}.GetSigners()
require.Len(t, signers, 1)
require.Equal(t, initiator, signers[0])
})

t.Run("panics when depositor is invalid", func(t *testing.T) {
require.Panics(t, func() {
types.MsgConvertNativeCoinToERC20{
Initiator: "not-an-address",
}.GetSigners()
})
})
}

0 comments on commit 116e7e9

Please sign in to comment.