feat(evmutil): add allow list for evm-convertible sdk denoms (#1590)

* add proto for allowed sdk denoms -> evm conversion

* add validation for AllowedNativeCoinERC20Token

* add validation for AllowedNativeCoinERC20Tokens

* add AllowedNativeDenoms into params & genesis

* add evmutil Params.Validate() test

* fix eip712 ante test

* update changelog

* update internal testnet genesis.json

* update state & param specs

updates to the sections describing functionality will be updated once
that functionality actually exists... :)

* update field decimal -> decimals

field now matches erc20 spec

* add validation decimals will cast to uint8

* add v2 store migration for evmutil

* create & register evmutil migrations

* adds migrator to evmutil's keeper
* sets up Migrate1To2 migration
* registers migration in module
* updates GetParams to properly handle historic block queries

* add unit test for GetParams with historic store
This commit is contained in:
Robert Pirtle 2023-05-19 16:01:46 -07:00 committed by GitHub
parent 362e39abf6
commit ff709d73e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1051 additions and 62 deletions

View File

@ -36,6 +36,9 @@ Ref: https://keepachangelog.com/en/1.0.0/
## [Unreleased]
## Features
- (evmutil) [#1590] Add allow list param of sdk native denoms that can be transferred to evm
## [v0.23.0]
### Improvements
@ -237,6 +240,7 @@ the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.38.4/CHANGELOG.md).
- [#257](https://github.com/Kava-Labs/kava/pulls/257) Include scripts to run
large-scale simulations remotely using aws-batch
[#1590]: https://github.com/Kava-Labs/kava/pull/1590
[#1568]: https://github.com/Kava-Labs/kava/pull/1568
[#1567]: https://github.com/Kava-Labs/kava/pull/1567
[#1566]: https://github.com/Kava-Labs/kava/pull/1566

View File

@ -335,15 +335,16 @@ func (suite *EIP712TestSuite) SetupTest() {
suite.usdcEVMAddr = pair.GetAddress()
// Add a contract to evmutil conversion pair
suite.evmutilKeeper.SetParams(suite.ctx, evmutiltypes.NewParams(
evmutilParams := suite.evmutilKeeper.GetParams(suite.ctx)
evmutilParams.EnabledConversionPairs =
evmutiltypes.NewConversionPairs(
evmutiltypes.NewConversionPair(
// First contract evmutil module deploys
evmutiltestutil.MustNewInternalEVMAddressFromString("0x15932E26f5BD4923d46a2b205191C4b5d5f43FE3"),
"erc20/usdc",
),
),
))
)
suite.evmutilKeeper.SetParams(suite.ctx, evmutilParams)
// allow msgs through evm eip712
evmKeeper := suite.tApp.GetEvmKeeper()

View File

@ -2004,6 +2004,7 @@
"evmutil": {
"accounts": [],
"params": {
"allowed_native_denoms": [],
"enabled_conversion_pairs": [
{
"kava_erc20_address": "0xBb304f44b7EFD865361F2AD973d8ebA433893ABC",

View File

@ -247,6 +247,7 @@
- [Msg](#kava.earn.v1beta1.Msg)
- [kava/evmutil/v1beta1/conversion_pair.proto](#kava/evmutil/v1beta1/conversion_pair.proto)
- [AllowedNativeCoinERC20Token](#kava.evmutil.v1beta1.AllowedNativeCoinERC20Token)
- [ConversionPair](#kava.evmutil.v1beta1.ConversionPair)
- [kava/evmutil/v1beta1/genesis.proto](#kava/evmutil/v1beta1/genesis.proto)
@ -3658,6 +3659,27 @@ Msg defines the earn Msg service.
<a name="kava.evmutil.v1beta1.AllowedNativeCoinERC20Token"></a>
### AllowedNativeCoinERC20Token
AllowedNativeCoinERC20Token defines allowed sdk denom & metadata
for evm token representations of sdk assets.
NOTE: once evm token contracts are deployed, changes to metadata for a given
sdk_denom will not change metadata of deployed contract.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `sdk_denom` | [string](#string) | | Denom of the sdk.Coin |
| `name` | [string](#string) | | Name of ERC20 contract |
| `symbol` | [string](#string) | | Symbol of ERC20 contract |
| `decimals` | [uint32](#uint32) | | Number of decimals ERC20 contract is deployed with. |
<a name="kava.evmutil.v1beta1.ConversionPair"></a>
### ConversionPair
@ -3732,6 +3754,7 @@ Params defines the evmutil module params
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `enabled_conversion_pairs` | [ConversionPair](#kava.evmutil.v1beta1.ConversionPair) | repeated | enabled_conversion_pairs defines the list of conversion pairs allowed to be converted between Kava ERC20 and sdk.Coin |
| `allowed_native_denoms` | [AllowedNativeCoinERC20Token](#kava.evmutil.v1beta1.AllowedNativeCoinERC20Token) | repeated | allowed_native_denoms is a list of denom & erc20 token metadata pairs. if a denom is in the list, it is allowed to be converted to an erc20 in the evm. |

View File

@ -21,3 +21,20 @@ message ConversionPair {
// Denom of the corresponding sdk.Coin
string denom = 2;
}
// AllowedNativeCoinERC20Token defines allowed sdk denom & metadata
// for evm token representations of sdk assets.
// NOTE: once evm token contracts are deployed, changes to metadata for a given
// sdk_denom will not change metadata of deployed contract.
message AllowedNativeCoinERC20Token {
option (gogoproto.goproto_getters) = false;
// Denom of the sdk.Coin
string sdk_denom = 1;
// Name of ERC20 contract
string name = 2;
// Symbol of ERC20 contract
string symbol = 3;
// Number of decimals ERC20 contract is deployed with.
uint32 decimals = 4;
}

View File

@ -44,4 +44,11 @@ message Params {
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "ConversionPairs"
];
// allowed_native_denoms is a list of denom & erc20 token metadata pairs.
// if a denom is in the list, it is allowed to be converted to an erc20 in the evm.
repeated AllowedNativeCoinERC20Token allowed_native_denoms = 1 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "AllowedNativeCoinERC20Tokens"
];
}

View File

@ -79,6 +79,14 @@ func (s *genesisTestSuite) TestExportGenesis() {
KavaERC20Address: testutil.MustNewInternalEVMAddressFromString("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2").Bytes(),
Denom: "weth"},
}
params.AllowedNativeDenoms = []types.AllowedNativeCoinERC20Token{
{
SdkDenom: "hard",
Name: "Kava EVM HARD",
Symbol: "HARD",
Decimals: 6,
},
}
s.Keeper.SetParams(s.Ctx, params)
gs := evmutil.ExportGenesis(s.Ctx, s.Keeper)
s.Require().Equal(gs.Accounts, accounts)

View File

@ -0,0 +1,23 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
v2 "github.com/kava-labs/kava/x/evmutil/migrations/v2"
)
// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
}
// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{
keeper: keeper,
}
}
// Migrate1to2 migrates from version 1 to 2.
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v2.MigrateStore(ctx, m.keeper.paramSubspace)
}

View File

@ -11,7 +11,7 @@ import (
// GetParams returns the total set of evm parameters.
func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
k.paramSubspace.GetParamSet(ctx, &params)
k.paramSubspace.GetParamSetIfExists(ctx, &params)
return params
}

View File

@ -5,6 +5,9 @@ import (
"github.com/stretchr/testify/suite"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/evmutil/keeper"
"github.com/kava-labs/kava/x/evmutil/testutil"
"github.com/kava-labs/kava/x/evmutil/types"
)
@ -34,3 +37,26 @@ func (suite *ParamsTestSuite) TestEnabledConversionPair() {
suite.Require().NoError(err)
suite.Require().Equal(expPair, actualPair)
}
func (suite *ParamsTestSuite) TestHistoricParamsQuery() {
// setup a params store that lacks allowed_native_denoms param (as was the case in v1)
oldParamStore := suite.App.GetParamsKeeper().Subspace("test_subspace_for_evmutil")
oldParamStore.WithKeyTable(types.ParamKeyTable())
oldParamStore.Set(suite.Ctx, types.KeyEnabledConversionPairs, types.ConversionPairs{})
suite.True(oldParamStore.Has(suite.Ctx, types.KeyEnabledConversionPairs))
suite.False(oldParamStore.Has(suite.Ctx, types.KeyAllowedNativeDenoms))
oldStateKeeper := keeper.NewKeeper(
suite.App.AppCodec(),
sdk.NewKVStoreKey(types.StoreKey),
oldParamStore,
suite.App.GetBankKeeper(),
suite.App.GetAccountKeeper(),
)
// prior to making GetParams() use GetParamSetIfExists, this would panic.
suite.NotPanics(func() {
_ = oldStateKeeper.GetParams(suite.Ctx)
})
}

View File

@ -0,0 +1,23 @@
package v2
import (
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/kava-labs/kava/x/evmutil/types"
)
// MigrateStore performs in-place store migrations for consensus version 2
// V2 adds the allowed_native_denoms param to parameters.
func MigrateStore(ctx sdk.Context, paramstore paramtypes.Subspace) error {
migrateParamsStore(ctx, paramstore)
return nil
}
// migrateParamsStore ensures the param key table exists and has the allowed_native_denoms property
func migrateParamsStore(ctx sdk.Context, paramstore paramtypes.Subspace) {
if !paramstore.HasKeyTable() {
paramstore.WithKeyTable(types.ParamKeyTable())
}
paramstore.Set(ctx, types.KeyAllowedNativeDenoms, types.DefaultAllowedNativeDenoms)
}

View File

@ -0,0 +1,54 @@
package v2_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
v2evmutil "github.com/kava-labs/kava/x/evmutil/migrations/v2"
"github.com/kava-labs/kava/x/evmutil/types"
)
func TestStoreMigrationAddsKeyTableIncludingNewParam(t *testing.T) {
encCfg := simapp.MakeTestEncodingConfig()
evmutilKey := sdk.NewKVStoreKey(types.ModuleName)
tEvmutilKey := sdk.NewTransientStoreKey("transient_test")
ctx := testutil.DefaultContext(evmutilKey, tEvmutilKey)
paramstore := paramtypes.NewSubspace(encCfg.Codec, encCfg.Amino, evmutilKey, tEvmutilKey, types.ModuleName)
// Check param doesn't exist before
require.False(t, paramstore.Has(ctx, types.KeyAllowedNativeDenoms))
// Run migrations.
err := v2evmutil.MigrateStore(ctx, paramstore)
require.NoError(t, err)
// Make sure the new params are set.
require.True(t, paramstore.Has(ctx, types.KeyAllowedNativeDenoms))
}
func TestStoreMigrationSetsNewParamOnExistingKeyTable(t *testing.T) {
encCfg := simapp.MakeTestEncodingConfig()
evmutilKey := sdk.NewKVStoreKey(types.ModuleName)
tEvmutilKey := sdk.NewTransientStoreKey("transient_test")
ctx := testutil.DefaultContext(evmutilKey, tEvmutilKey)
paramstore := paramtypes.NewSubspace(encCfg.Codec, encCfg.Amino, evmutilKey, tEvmutilKey, types.ModuleName)
paramstore.WithKeyTable(types.ParamKeyTable())
// expect it to have key table
require.True(t, paramstore.HasKeyTable())
// expect it to not have new param
require.False(t, paramstore.Has(ctx, types.KeyAllowedNativeDenoms))
// Run migrations.
err := v2evmutil.MigrateStore(ctx, paramstore)
require.NoError(t, err)
// Make sure the new params are set.
require.True(t, paramstore.Has(ctx, types.KeyAllowedNativeDenoms))
}

View File

@ -21,7 +21,7 @@ import (
)
// ConsensusVersion defines the current module consensus version.
const ConsensusVersion = 1
const ConsensusVersion = 2
var (
_ module.AppModule = AppModule{}
@ -127,6 +127,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServerImpl(am.keeper))
m := keeper.NewMigrator(am.keeper)
cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
}
// RegisterInvariants registers evmutil module's invariants.

View File

@ -6,7 +6,7 @@ order: 2
## Parameters and Genesis State
`Parameters` define the list of conversion pairs allowed to be converted between Kava ERC20 tokens and sdk.Coins.
`Parameters` define the list of conversion pairs allowed to be converted between Kava ERC20 tokens & sdk.Coins, and the list of native sdk.Coins that are allowed to be converted to ERC20s.
```protobuf
// Params defines the evmutil module params
@ -14,6 +14,10 @@ message Params {
// enabled_conversion_pairs defines the list of conversion pairs allowed to be
// converted between Kava ERC20 and sdk.Coin
repeated ConversionPair enabled_conversion_pairs = 4;
// allowed_native_denoms is a list of denom & erc20 token metadata pairs.
// if a denom is in the list, it is allowed to be converted to an erc20 in the evm.
repeated AllowedNativeCoinERC20Token allowed_native_denoms = 1;
}
// ConversionPair defines a Kava ERC20 address and corresponding denom that is
@ -24,6 +28,24 @@ message ConversionPair {
// Denom of the corresponding sdk.Coin
string denom = 2;
}
// AllowedNativeCoinERC20Token defines allowed sdk denom & metadata
// for evm token representations of sdk assets.
// NOTE: once evm token contracts are deployed, changes to metadata for a given
// sdk_denom will not change metadata of deployed contract.
message AllowedNativeCoinERC20Token {
option (gogoproto.goproto_getters) = false;
// Denom of the sdk.Coin
string sdk_denom = 1;
// Name of ERC20 contract
string name = 2;
// Symbol of ERC20 contract
string symbol = 3;
// Number of decimals ERC20 contract is deployed with.
uint32 decimal = 4;
}
```
`GenesisState` defines the state that must be persisted when the blockchain stops/restarts in order for normal function of the evmutil module to resume.

View File

@ -6,9 +6,10 @@ order: 5
The evmutil module contains the following parameters:
| Key | Type | Example |
| ---------------------- | ---------------------- | ------------- |
| EnabledConversionPairs | array (ConversionPair) | [{see below}] |
| Key | Type | Example |
| ---------------------- | ------------------------------------ | ------------- |
| EnabledConversionPairs | array (ConversionPair) | [{see below}] |
| AllowedNativeDenoms | array (AllowedNativeCoinERC20Tokens) | [{see below}] |
Example parameters for `ConversionPair`:
@ -17,6 +18,19 @@ Example parameters for `ConversionPair`:
| kava_erc20_Address | string | "0x43d8814fdfb9b8854422df13f1c66e34e4fa91fd" | ERC20 contract address |
| denom | string | "erc20/chain/usdc" | sdk.Coin denom for the ERC20 token |
Example parameters for `AllowedNativeCoinERC20Token`:
| Key | Type | Example | Description |
| --------- | ------ | ---------------------------------------------------------------------- | -------------------------------------------------- |
| sdk_denom | string | "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2" | denom of the sdk.Coin |
| name | string | "Kava-wrapped Atom" | name field of the erc20 token |
| symbol | string | "kATOM" | symbol field of the erc20 token |
| decimal | uint32 | 6 | decimal field of the erc20 token, for display only |
## EnabledConversionPairs
The enabled conversion pairs parameter is an array of ConversionPair entries mapping an erc20 address to a sdk.Coin denom. Only erc20 contract addresses that are in this list can be converted to sdk.Coin and vice versa.
## AllowedNativeDenoms
The allowed native denoms parameter is an array of AllowedNativeCoinERC20Token entries. They include the sdk.Coin denom and metadata for the ERC20 representation of the asset in Kava's EVM. Coins may only be transferred to the EVM if they are included in this list. A token in this list will have an ERC20 token contract deployed on first conversion. The token will be deployed with the metadata included in the AllowedNativeCoinERC20Token. Once deployed, changes to the metadata will not affect or change the deployed contract.

View File

@ -156,6 +156,7 @@ func (suite *Suite) SetupTest() {
"erc20/usdc",
),
),
types.NewAllowedNativeCoinERC20Tokens(),
))
queryHelper := baseapp.NewQueryServerTestHelper(suite.Ctx, suite.App.InterfaceRegistry())

View File

@ -3,12 +3,18 @@ package types
import (
bytes "bytes"
"encoding/hex"
"errors"
"fmt"
"math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
)
///////////////
// EVM -> SDK
///////////////
// NewConversionPair returns a new ConversionPair.
func NewConversionPair(address InternalEVMAddress, denom string) ConversionPair {
return ConversionPair{
@ -87,3 +93,87 @@ func validateConversionPairs(i interface{}) error {
return pairs.Validate()
}
///////////////
// SDK -> EVM
///////////////
// NewAllowedNativeCoinERC20Token returns an AllowedNativeCoinERC20Token
func NewAllowedNativeCoinERC20Token(
sdkDenom, name, symbol string,
decimal uint32,
) AllowedNativeCoinERC20Token {
return AllowedNativeCoinERC20Token{
SdkDenom: sdkDenom,
Name: name,
Symbol: symbol,
Decimals: decimal,
}
}
// Validate validates the fields of a single AllowedNativeCoinERC20Token
func (token AllowedNativeCoinERC20Token) Validate() error {
// disallow empty string fields
if err := sdk.ValidateDenom(token.SdkDenom); err != nil {
return fmt.Errorf("allowed native coin erc20 token's sdk denom is invalid: %v", err)
}
if token.Name == "" {
return errors.New("allowed native coin erc20 token's name cannot be empty")
}
if token.Symbol == "" {
return errors.New("allowed native coin erc20 token's symbol cannot be empty")
}
// ensure decimals will properly cast to uint8 of erc20 spec
if token.Decimals > math.MaxUint8 {
return fmt.Errorf("allowed native coin erc20 token's decimals must be less than 256, found %d", token.Decimals)
}
return nil
}
// AllowedNativeCoinERC20Tokens defines a slice of AllowedNativeCoinERC20Token
type AllowedNativeCoinERC20Tokens []AllowedNativeCoinERC20Token
// NewAllowedNativeCoinERC20Tokens returns AllowedNativeCoinERC20Tokens from the provided values.
func NewAllowedNativeCoinERC20Tokens(pairs ...AllowedNativeCoinERC20Token) AllowedNativeCoinERC20Tokens {
return AllowedNativeCoinERC20Tokens(pairs)
}
// Validate checks that all containing tokens are valid and that there are
// no duplicate denoms or symbols.
func (tokens AllowedNativeCoinERC20Tokens) Validate() error {
// Disallow multiple instances of a single sdk_denom or evm symbol
denoms := make(map[string]struct{}, len(tokens))
symbols := make(map[string]struct{}, len(tokens))
for i, t := range tokens {
if err := t.Validate(); err != nil {
return fmt.Errorf("invalid token at index %d: %s", i, err)
}
if _, found := denoms[t.SdkDenom]; found {
return fmt.Errorf("found duplicate token with sdk denom %s", t.SdkDenom)
}
if _, found := symbols[t.Symbol]; found {
return fmt.Errorf("found duplicate token with symbol %s", t.Symbol)
}
denoms[t.SdkDenom] = struct{}{}
symbols[t.Symbol] = struct{}{}
}
return nil
}
// validateAllowedNativeCoinERC20Tokens validates an interface as AllowedNativeCoinERC20Tokens
func validateAllowedNativeCoinERC20Tokens(i interface{}) error {
pairs, ok := i.(AllowedNativeCoinERC20Tokens)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
return pairs.Validate()
}

View File

@ -66,8 +66,57 @@ func (m *ConversionPair) XXX_DiscardUnknown() {
var xxx_messageInfo_ConversionPair proto.InternalMessageInfo
// AllowedNativeCoinERC20Token defines allowed sdk denom & metadata
// for evm token representations of sdk assets.
// NOTE: once evm token contracts are deployed, changes to metadata for a given
// sdk_denom will not change metadata of deployed contract.
type AllowedNativeCoinERC20Token struct {
// Denom of the sdk.Coin
SdkDenom string `protobuf:"bytes,1,opt,name=sdk_denom,json=sdkDenom,proto3" json:"sdk_denom,omitempty"`
// Name of ERC20 contract
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
// Symbol of ERC20 contract
Symbol string `protobuf:"bytes,3,opt,name=symbol,proto3" json:"symbol,omitempty"`
// Number of decimals ERC20 contract is deployed with.
Decimals uint32 `protobuf:"varint,4,opt,name=decimals,proto3" json:"decimals,omitempty"`
}
func (m *AllowedNativeCoinERC20Token) Reset() { *m = AllowedNativeCoinERC20Token{} }
func (m *AllowedNativeCoinERC20Token) String() string { return proto.CompactTextString(m) }
func (*AllowedNativeCoinERC20Token) ProtoMessage() {}
func (*AllowedNativeCoinERC20Token) Descriptor() ([]byte, []int) {
return fileDescriptor_e1396d08199817d0, []int{1}
}
func (m *AllowedNativeCoinERC20Token) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *AllowedNativeCoinERC20Token) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_AllowedNativeCoinERC20Token.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *AllowedNativeCoinERC20Token) XXX_Merge(src proto.Message) {
xxx_messageInfo_AllowedNativeCoinERC20Token.Merge(m, src)
}
func (m *AllowedNativeCoinERC20Token) XXX_Size() int {
return m.Size()
}
func (m *AllowedNativeCoinERC20Token) XXX_DiscardUnknown() {
xxx_messageInfo_AllowedNativeCoinERC20Token.DiscardUnknown(m)
}
var xxx_messageInfo_AllowedNativeCoinERC20Token proto.InternalMessageInfo
func init() {
proto.RegisterType((*ConversionPair)(nil), "kava.evmutil.v1beta1.ConversionPair")
proto.RegisterType((*AllowedNativeCoinERC20Token)(nil), "kava.evmutil.v1beta1.AllowedNativeCoinERC20Token")
}
func init() {
@ -75,24 +124,30 @@ func init() {
}
var fileDescriptor_e1396d08199817d0 = []byte{
// 264 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0xca, 0x4e, 0x2c, 0x4b,
0xd4, 0x4f, 0x2d, 0xcb, 0x2d, 0x2d, 0xc9, 0xcc, 0xd1, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34,
0xd4, 0x4f, 0xce, 0xcf, 0x2b, 0x4b, 0x2d, 0x2a, 0xce, 0xcc, 0xcf, 0x8b, 0x2f, 0x48, 0xcc, 0x2c,
0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x01, 0xa9, 0xd5, 0x83, 0xaa, 0xd5, 0x83, 0xaa,
0x95, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x2b, 0xd0, 0x07, 0xb1, 0x20, 0x6a, 0x95, 0x6a, 0xb8,
0xf8, 0x9c, 0xe1, 0x86, 0x04, 0x24, 0x66, 0x16, 0x09, 0xf9, 0x71, 0x09, 0x81, 0xf4, 0xc7, 0xa7,
0x16, 0x25, 0x1b, 0x19, 0xc4, 0x27, 0xa6, 0xa4, 0x14, 0xa5, 0x16, 0x17, 0x4b, 0x30, 0x2a, 0x30,
0x6a, 0xf0, 0x38, 0x29, 0x3c, 0xba, 0x27, 0x2f, 0xe0, 0x9d, 0x58, 0x96, 0xe8, 0x1a, 0xe4, 0x6c,
0x64, 0xe0, 0x08, 0x91, 0xfb, 0x75, 0x4f, 0x9e, 0xc3, 0x23, 0xb5, 0xc2, 0xa9, 0xb2, 0x24, 0xb5,
0x38, 0x48, 0x00, 0xa4, 0xd7, 0x15, 0xa4, 0x15, 0x2a, 0x2b, 0x24, 0xc2, 0xc5, 0x9a, 0x92, 0x9a,
0x97, 0x9f, 0x2b, 0xc1, 0xa4, 0xc0, 0xa8, 0xc1, 0x19, 0x04, 0xe1, 0x58, 0xb1, 0x74, 0x2c, 0x90,
0x67, 0x70, 0xf2, 0x7e, 0xf0, 0x50, 0x8e, 0x71, 0xc5, 0x23, 0x39, 0xc6, 0x13, 0x8f, 0xe4, 0x18,
0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5,
0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, 0x4c, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce,
0xcf, 0xd5, 0x07, 0x19, 0xad, 0x9b, 0x93, 0x98, 0x54, 0x0c, 0x66, 0xe9, 0x57, 0xc0, 0x83, 0xa3,
0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, 0x0d, 0xec, 0x23, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff,
0x60, 0x36, 0x37, 0x7f, 0x2b, 0x01, 0x00, 0x00,
// 355 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x91, 0xcf, 0x6a, 0xea, 0x40,
0x18, 0xc5, 0x33, 0xf7, 0x7a, 0x45, 0x87, 0xdb, 0x22, 0x83, 0x94, 0xa0, 0x30, 0x06, 0x57, 0xb6,
0xd0, 0x44, 0xed, 0xae, 0x3b, 0xb5, 0x42, 0x41, 0x90, 0x12, 0xba, 0xea, 0x26, 0x4c, 0x92, 0x0f,
0x3b, 0xe4, 0xcf, 0x48, 0x26, 0xa6, 0x0a, 0x7d, 0x00, 0x97, 0x7d, 0x84, 0x2e, 0xfb, 0x28, 0x5d,
0xba, 0xec, 0x4a, 0x6c, 0x7c, 0x8b, 0xae, 0x4a, 0xfe, 0xe0, 0xee, 0x9c, 0xf9, 0xce, 0xef, 0x30,
0x33, 0x1f, 0xbe, 0xf2, 0x58, 0xc2, 0x0c, 0x48, 0x82, 0x55, 0xcc, 0x7d, 0x23, 0x19, 0xd8, 0x10,
0xb3, 0x81, 0xe1, 0x88, 0x30, 0x81, 0x48, 0x72, 0x11, 0x5a, 0x4b, 0xc6, 0x23, 0x7d, 0x19, 0x89,
0x58, 0x90, 0x66, 0x96, 0xd5, 0xcb, 0xac, 0x5e, 0x66, 0x5b, 0xcd, 0x85, 0x58, 0x88, 0x3c, 0x60,
0x64, 0xaa, 0xc8, 0x76, 0x5f, 0xf1, 0xf9, 0xe4, 0x54, 0xf2, 0xc0, 0x78, 0x44, 0xe6, 0x98, 0x64,
0xbc, 0x05, 0x91, 0x33, 0xec, 0x5b, 0xcc, 0x75, 0x23, 0x90, 0x52, 0x45, 0x1a, 0xea, 0xfd, 0x1f,
0x6b, 0xe9, 0xbe, 0xd3, 0x98, 0xb1, 0x84, 0x4d, 0xcd, 0xc9, 0xb0, 0x3f, 0x2a, 0x66, 0x3f, 0xfb,
0x4e, 0xed, 0x1e, 0xd6, 0xe3, 0x4d, 0x0c, 0xd2, 0x6c, 0x64, 0xec, 0x34, 0x43, 0xcb, 0x29, 0x69,
0xe2, 0x7f, 0x2e, 0x84, 0x22, 0x50, 0xff, 0x68, 0xa8, 0x57, 0x37, 0x0b, 0x73, 0x5b, 0xd9, 0xbe,
0x77, 0x94, 0xee, 0x16, 0xe1, 0xf6, 0xc8, 0xf7, 0xc5, 0x0b, 0xb8, 0x73, 0x16, 0xf3, 0x04, 0x26,
0x82, 0x87, 0x79, 0xf7, 0xa3, 0xf0, 0x20, 0x24, 0x6d, 0x5c, 0x97, 0xae, 0x67, 0x15, 0x3c, 0xca,
0xf9, 0x9a, 0x74, 0xbd, 0xbb, 0xcc, 0x13, 0x82, 0x2b, 0x21, 0x0b, 0xa0, 0xec, 0xcd, 0x35, 0xb9,
0xc0, 0x55, 0xb9, 0x09, 0x6c, 0xe1, 0xab, 0x7f, 0xf3, 0xd3, 0xd2, 0x91, 0x16, 0xae, 0xb9, 0xe0,
0xf0, 0x80, 0xf9, 0x52, 0xad, 0x68, 0xa8, 0x77, 0x66, 0x9e, 0x7c, 0x71, 0x95, 0xf1, 0xec, 0xf0,
0x4d, 0xd1, 0x47, 0x4a, 0xd1, 0x67, 0x4a, 0xd1, 0x2e, 0xa5, 0xe8, 0x90, 0x52, 0xf4, 0x76, 0xa4,
0xca, 0xee, 0x48, 0x95, 0xaf, 0x23, 0x55, 0x9e, 0x2e, 0x17, 0x3c, 0x7e, 0x5e, 0xd9, 0xba, 0x23,
0x02, 0x23, 0x7b, 0xe5, 0xb5, 0xcf, 0x6c, 0x99, 0x2b, 0x63, 0x7d, 0xda, 0x4c, 0xbc, 0x59, 0x82,
0xb4, 0xab, 0xf9, 0xe7, 0xde, 0xfc, 0x06, 0x00, 0x00, 0xff, 0xff, 0x49, 0x37, 0x2c, 0xa6, 0xb6,
0x01, 0x00, 0x00,
}
func (this *ConversionPair) VerboseEqual(that interface{}) error {
@ -155,6 +210,78 @@ func (this *ConversionPair) Equal(that interface{}) bool {
}
return true
}
func (this *AllowedNativeCoinERC20Token) VerboseEqual(that interface{}) error {
if that == nil {
if this == nil {
return nil
}
return fmt.Errorf("that == nil && this != nil")
}
that1, ok := that.(*AllowedNativeCoinERC20Token)
if !ok {
that2, ok := that.(AllowedNativeCoinERC20Token)
if ok {
that1 = &that2
} else {
return fmt.Errorf("that is not of type *AllowedNativeCoinERC20Token")
}
}
if that1 == nil {
if this == nil {
return nil
}
return fmt.Errorf("that is type *AllowedNativeCoinERC20Token but is nil && this != nil")
} else if this == nil {
return fmt.Errorf("that is type *AllowedNativeCoinERC20Token but is not nil && this == nil")
}
if this.SdkDenom != that1.SdkDenom {
return fmt.Errorf("SdkDenom this(%v) Not Equal that(%v)", this.SdkDenom, that1.SdkDenom)
}
if this.Name != that1.Name {
return fmt.Errorf("Name this(%v) Not Equal that(%v)", this.Name, that1.Name)
}
if this.Symbol != that1.Symbol {
return fmt.Errorf("Symbol this(%v) Not Equal that(%v)", this.Symbol, that1.Symbol)
}
if this.Decimals != that1.Decimals {
return fmt.Errorf("Decimals this(%v) Not Equal that(%v)", this.Decimals, that1.Decimals)
}
return nil
}
func (this *AllowedNativeCoinERC20Token) Equal(that interface{}) bool {
if that == nil {
return this == nil
}
that1, ok := that.(*AllowedNativeCoinERC20Token)
if !ok {
that2, ok := that.(AllowedNativeCoinERC20Token)
if ok {
that1 = &that2
} else {
return false
}
}
if that1 == nil {
return this == nil
} else if this == nil {
return false
}
if this.SdkDenom != that1.SdkDenom {
return false
}
if this.Name != that1.Name {
return false
}
if this.Symbol != that1.Symbol {
return false
}
if this.Decimals != that1.Decimals {
return false
}
return true
}
func (m *ConversionPair) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@ -192,6 +319,55 @@ func (m *ConversionPair) MarshalToSizedBuffer(dAtA []byte) (int, error) {
return len(dAtA) - i, nil
}
func (m *AllowedNativeCoinERC20Token) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *AllowedNativeCoinERC20Token) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *AllowedNativeCoinERC20Token) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Decimals != 0 {
i = encodeVarintConversionPair(dAtA, i, uint64(m.Decimals))
i--
dAtA[i] = 0x20
}
if len(m.Symbol) > 0 {
i -= len(m.Symbol)
copy(dAtA[i:], m.Symbol)
i = encodeVarintConversionPair(dAtA, i, uint64(len(m.Symbol)))
i--
dAtA[i] = 0x1a
}
if len(m.Name) > 0 {
i -= len(m.Name)
copy(dAtA[i:], m.Name)
i = encodeVarintConversionPair(dAtA, i, uint64(len(m.Name)))
i--
dAtA[i] = 0x12
}
if len(m.SdkDenom) > 0 {
i -= len(m.SdkDenom)
copy(dAtA[i:], m.SdkDenom)
i = encodeVarintConversionPair(dAtA, i, uint64(len(m.SdkDenom)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintConversionPair(dAtA []byte, offset int, v uint64) int {
offset -= sovConversionPair(v)
base := offset
@ -220,6 +396,30 @@ func (m *ConversionPair) Size() (n int) {
return n
}
func (m *AllowedNativeCoinERC20Token) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.SdkDenom)
if l > 0 {
n += 1 + l + sovConversionPair(uint64(l))
}
l = len(m.Name)
if l > 0 {
n += 1 + l + sovConversionPair(uint64(l))
}
l = len(m.Symbol)
if l > 0 {
n += 1 + l + sovConversionPair(uint64(l))
}
if m.Decimals != 0 {
n += 1 + sovConversionPair(uint64(m.Decimals))
}
return n
}
func sovConversionPair(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
@ -342,6 +542,171 @@ func (m *ConversionPair) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *AllowedNativeCoinERC20Token) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConversionPair
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: AllowedNativeCoinERC20Token: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: AllowedNativeCoinERC20Token: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SdkDenom", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConversionPair
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthConversionPair
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthConversionPair
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.SdkDenom = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConversionPair
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthConversionPair
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthConversionPair
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Symbol", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConversionPair
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthConversionPair
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthConversionPair
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Symbol = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Decimals", wireType)
}
m.Decimals = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowConversionPair
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Decimals |= uint32(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipConversionPair(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthConversionPair
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipConversionPair(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0

View File

@ -231,3 +231,125 @@ func TestConversionPairs_Validate(t *testing.T) {
})
}
}
func TestAllowedNativeCoinERC20Token_Validate(t *testing.T) {
testCases := []struct {
name string
token types.AllowedNativeCoinERC20Token
expErr string
}{
{
name: "valid token",
token: types.NewAllowedNativeCoinERC20Token("uatom", "Kava-wrapped ATOM", "kATOM", 6),
expErr: "",
},
{
name: "valid - highest allowed decimals",
token: types.NewAllowedNativeCoinERC20Token("uatom", "Kava-wrapped ATOM", "kATOM", 255),
expErr: "",
},
{
name: "invalid - Empty SdkDenom",
token: types.AllowedNativeCoinERC20Token{
SdkDenom: "",
Name: "Example Token",
Symbol: "ETK",
Decimals: 0,
},
expErr: "sdk denom is invalid",
},
{
name: "invalid - Empty Name",
token: types.AllowedNativeCoinERC20Token{
SdkDenom: "example_denom",
Name: "",
Symbol: "ETK",
Decimals: 6,
},
expErr: "name cannot be empty",
},
{
name: "invalid - Empty Symbol",
token: types.AllowedNativeCoinERC20Token{
SdkDenom: "example_denom",
Name: "Example Token",
Symbol: "",
Decimals: 6,
},
expErr: "symbol cannot be empty",
},
{
name: "invalid - decimals higher than uint8",
token: types.NewAllowedNativeCoinERC20Token("uatom", "Kava-wrapped ATOM", "kATOM", 256),
expErr: "decimals must be less than 256",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := tc.token.Validate()
if tc.expErr != "" {
require.ErrorContains(t, err, tc.expErr, "Expected validation error")
} else {
require.NoError(t, err, "Expected no validation error")
}
})
}
}
func TestAllowedNativeCoinERC20Tokens_Validate(t *testing.T) {
token1 := types.NewAllowedNativeCoinERC20Token("denom1", "Token 1", "TK1", 6)
token2 := types.NewAllowedNativeCoinERC20Token("denom2", "Token 2", "TK2", 0)
invalidToken := types.NewAllowedNativeCoinERC20Token("", "No SDK Denom Token", "TK3", 18)
testCases := []struct {
name string
tokens types.AllowedNativeCoinERC20Tokens
expErr string
}{
{
name: "valid - no tokens",
tokens: types.NewAllowedNativeCoinERC20Tokens(),
expErr: "",
},
{
name: "valid - one token",
tokens: types.NewAllowedNativeCoinERC20Tokens(token1),
expErr: "",
},
{
name: "valid - multiple tokens",
tokens: types.NewAllowedNativeCoinERC20Tokens(token1, token2),
expErr: "",
},
{
name: "invalid - contains invalid token",
tokens: types.NewAllowedNativeCoinERC20Tokens(token1, token2, invalidToken),
expErr: "invalid token at index 2",
},
{
name: "invalid - duplicate denoms",
tokens: types.NewAllowedNativeCoinERC20Tokens(token1, token2, token1),
expErr: "found duplicate token with sdk denom denom1",
},
{
name: "invalid - duplicate symbol",
tokens: types.NewAllowedNativeCoinERC20Tokens(
token1,
types.NewAllowedNativeCoinERC20Token("diff", "Diff Denom, Same Symbol", "TK1", 6),
),
expErr: "found duplicate token with symbol TK1",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := tc.tokens.Validate()
if tc.expErr != "" {
require.ErrorContains(t, err, tc.expErr, "Expected validation error")
} else {
require.NoError(t, err, "Expected no validation error")
}
})
}
}

View File

@ -111,6 +111,9 @@ type Params struct {
// enabled_conversion_pairs defines the list of conversion pairs allowed to be
// converted between Kava ERC20 and sdk.Coin
EnabledConversionPairs ConversionPairs `protobuf:"bytes,4,rep,name=enabled_conversion_pairs,json=enabledConversionPairs,proto3,castrepeated=ConversionPairs" json:"enabled_conversion_pairs"`
// allowed_native_denoms is a list of denom & erc20 token metadata pairs.
// if a denom is in the list, it is allowed to be converted to an erc20 in the evm.
AllowedNativeDenoms AllowedNativeCoinERC20Tokens `protobuf:"bytes,1,rep,name=allowed_native_denoms,json=allowedNativeDenoms,proto3,castrepeated=AllowedNativeCoinERC20Tokens" json:"allowed_native_denoms"`
}
func (m *Params) Reset() { *m = Params{} }
@ -153,6 +156,13 @@ func (m *Params) GetEnabledConversionPairs() ConversionPairs {
return nil
}
func (m *Params) GetAllowedNativeDenoms() AllowedNativeCoinERC20Tokens {
if m != nil {
return m.AllowedNativeDenoms
}
return nil
}
func init() {
proto.RegisterType((*GenesisState)(nil), "kava.evmutil.v1beta1.GenesisState")
proto.RegisterType((*Account)(nil), "kava.evmutil.v1beta1.Account")
@ -164,35 +174,38 @@ func init() {
}
var fileDescriptor_d916ab97b8e628c2 = []byte{
// 434 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x41, 0x8b, 0xd3, 0x40,
0x14, 0xc7, 0x33, 0x5a, 0x5a, 0x9d, 0x5d, 0x10, 0xe2, 0xa2, 0x71, 0xd1, 0xc9, 0x52, 0x44, 0xaa,
0x90, 0x84, 0x5d, 0x6f, 0x45, 0x90, 0xc6, 0x83, 0x16, 0x2f, 0x25, 0x82, 0x07, 0x2f, 0x65, 0x92,
0x0c, 0x31, 0x34, 0x99, 0x09, 0x99, 0x69, 0xb4, 0x47, 0x6f, 0x1e, 0xf5, 0x1b, 0x78, 0x14, 0xcf,
0xfd, 0x10, 0x05, 0x2f, 0xa5, 0x27, 0xf1, 0x50, 0x6b, 0xfa, 0x2d, 0x3c, 0x49, 0x32, 0xd3, 0xa2,
0x25, 0x87, 0x3d, 0x65, 0xf2, 0xe7, 0xff, 0x7f, 0xef, 0xf7, 0xde, 0x0c, 0xec, 0x4e, 0x70, 0x81,
0x1d, 0x52, 0xa4, 0x53, 0x11, 0x27, 0x4e, 0x71, 0xee, 0x13, 0x81, 0xcf, 0x9d, 0x88, 0x50, 0xc2,
0x63, 0x6e, 0x67, 0x39, 0x13, 0x4c, 0x3f, 0xa9, 0x3c, 0xb6, 0xf2, 0xd8, 0xca, 0x73, 0x7a, 0x27,
0x60, 0x3c, 0x65, 0x7c, 0x5c, 0x7b, 0x1c, 0xf9, 0x23, 0x03, 0xa7, 0x27, 0x11, 0x8b, 0x98, 0xd4,
0xab, 0x93, 0x52, 0x1f, 0x35, 0xb6, 0x0a, 0x18, 0x2d, 0x48, 0xce, 0x63, 0x46, 0xc7, 0x19, 0x8e,
0x73, 0xe9, 0xed, 0x7e, 0x06, 0xf0, 0xf8, 0xb9, 0x84, 0x78, 0x25, 0xb0, 0x20, 0xfa, 0x53, 0x78,
0x0d, 0x07, 0x01, 0x9b, 0x52, 0xc1, 0x0d, 0x70, 0x76, 0xb5, 0x77, 0x74, 0x71, 0xcf, 0x6e, 0xc2,
0xb2, 0x07, 0xd2, 0xe5, 0xb6, 0x16, 0x6b, 0x53, 0xf3, 0xf6, 0x21, 0xbd, 0x0f, 0xdb, 0x19, 0xce,
0x71, 0xca, 0x8d, 0x2b, 0x67, 0xa0, 0x77, 0x74, 0x71, 0xb7, 0x39, 0x3e, 0xaa, 0x3d, 0x2a, 0xad,
0x12, 0xfd, 0xd6, 0xc7, 0x2f, 0xa6, 0xd6, 0xfd, 0x0e, 0x60, 0x47, 0x55, 0xd7, 0x7d, 0xd8, 0xc1,
0x61, 0x98, 0x13, 0x5e, 0xd1, 0x80, 0xde, 0xb1, 0xfb, 0xe2, 0xcf, 0xda, 0xb4, 0xa2, 0x58, 0xbc,
0x9d, 0xfa, 0x76, 0xc0, 0x52, 0xb5, 0x0f, 0xf5, 0xb1, 0x78, 0x38, 0x71, 0xc4, 0x2c, 0x23, 0xbc,
0xc2, 0x1b, 0xc8, 0xe0, 0x6a, 0x6e, 0xdd, 0x54, 0x5b, 0x53, 0x8a, 0x3b, 0x13, 0x84, 0x7b, 0xbb,
0xc2, 0xfa, 0x6b, 0xd8, 0xf1, 0x71, 0x82, 0x69, 0x40, 0x6a, 0xe4, 0xeb, 0xee, 0x93, 0x0a, 0xea,
0xe7, 0xda, 0x7c, 0x70, 0x89, 0x3e, 0x43, 0x2a, 0x56, 0x73, 0x0b, 0xaa, 0x06, 0x43, 0x2a, 0xbc,
0x5d, 0x31, 0x35, 0xcd, 0x07, 0x00, 0xdb, 0x72, 0x58, 0xfd, 0x1d, 0x34, 0x08, 0xc5, 0x7e, 0x42,
0xc2, 0xf1, 0xc1, 0x6d, 0x70, 0xa3, 0x55, 0xef, 0xfa, 0x7e, 0xf3, 0xb2, 0x9e, 0xed, 0xdd, 0x23,
0x1c, 0xe7, 0xee, 0xed, 0x8a, 0xef, 0xdb, 0x2f, 0xf3, 0xc6, 0xff, 0x3a, 0xf7, 0x6e, 0xa9, 0xf2,
0x07, 0xba, 0xfb, 0x72, 0xf3, 0x1b, 0x81, 0xaf, 0x25, 0x02, 0x8b, 0x12, 0x81, 0x65, 0x89, 0xc0,
0xa6, 0x44, 0xe0, 0xd3, 0x16, 0x69, 0xcb, 0x2d, 0xd2, 0x7e, 0x6c, 0x91, 0xf6, 0xe6, 0xe1, 0x3f,
0xa3, 0x56, 0x08, 0x56, 0x82, 0x7d, 0x5e, 0x9f, 0x9c, 0xf7, 0xfb, 0xa7, 0x54, 0x4f, 0xec, 0xb7,
0xeb, 0x97, 0xf3, 0xf8, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x32, 0x69, 0x99, 0x1c, 0xd2, 0x02,
0x00, 0x00,
// 492 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x41, 0x6b, 0xd4, 0x40,
0x14, 0xce, 0xd4, 0x65, 0x57, 0xa7, 0x05, 0x21, 0xad, 0xba, 0x96, 0x9a, 0x94, 0xa5, 0xc8, 0x2a,
0x24, 0x71, 0xd7, 0x5b, 0x11, 0xa4, 0x59, 0x45, 0x8b, 0x20, 0x25, 0x8a, 0x07, 0x2f, 0xe1, 0x25,
0x19, 0xd6, 0xb0, 0xc9, 0xcc, 0x92, 0x99, 0x4d, 0xed, 0x3f, 0x10, 0x3c, 0xa8, 0xff, 0xc0, 0xa3,
0x78, 0xee, 0x8f, 0x28, 0x78, 0x29, 0x3d, 0x89, 0x87, 0xb5, 0xee, 0xfe, 0x0b, 0x4f, 0x92, 0x99,
0xd9, 0xa5, 0x96, 0x55, 0x7a, 0xca, 0xe4, 0x9b, 0xef, 0x7b, 0xef, 0x9b, 0xef, 0x3d, 0xdc, 0x1a,
0x40, 0x09, 0x1e, 0x29, 0xf3, 0x91, 0x48, 0x33, 0xaf, 0xec, 0x44, 0x44, 0x40, 0xc7, 0xeb, 0x13,
0x4a, 0x78, 0xca, 0xdd, 0x61, 0xc1, 0x04, 0x33, 0xd7, 0x2a, 0x8e, 0xab, 0x39, 0xae, 0xe6, 0xac,
0xdf, 0x8c, 0x19, 0xcf, 0x19, 0x0f, 0x25, 0xc7, 0x53, 0x3f, 0x4a, 0xb0, 0xbe, 0xd6, 0x67, 0x7d,
0xa6, 0xf0, 0xea, 0xa4, 0xd1, 0xbb, 0x0b, 0x5b, 0xc5, 0x8c, 0x96, 0xa4, 0xe0, 0x29, 0xa3, 0xe1,
0x10, 0xd2, 0x42, 0x71, 0x5b, 0x9f, 0x10, 0x5e, 0x79, 0xa2, 0x4c, 0xbc, 0x10, 0x20, 0x88, 0xf9,
0x10, 0x5f, 0x86, 0x38, 0x66, 0x23, 0x2a, 0x78, 0x13, 0x6d, 0x5e, 0x6a, 0x2f, 0x77, 0x6f, 0xb9,
0x8b, 0x6c, 0xb9, 0x3b, 0x8a, 0xe5, 0xd7, 0x8e, 0xc6, 0xb6, 0x11, 0xcc, 0x45, 0xe6, 0x36, 0xae,
0x0f, 0xa1, 0x80, 0x9c, 0x37, 0x97, 0x36, 0x51, 0x7b, 0xb9, 0xbb, 0xb1, 0x58, 0xbe, 0x27, 0x39,
0x5a, 0xad, 0x15, 0xdb, 0xb5, 0x77, 0x9f, 0x6d, 0xa3, 0xf5, 0x0d, 0xe1, 0x86, 0xae, 0x6e, 0x46,
0xb8, 0x01, 0x49, 0x52, 0x10, 0x5e, 0xb9, 0x41, 0xed, 0x15, 0xff, 0xe9, 0xef, 0xb1, 0xed, 0xf4,
0x53, 0xf1, 0x66, 0x14, 0xb9, 0x31, 0xcb, 0x75, 0x1e, 0xfa, 0xe3, 0xf0, 0x64, 0xe0, 0x89, 0x83,
0x21, 0xe1, 0x95, 0xbd, 0x1d, 0x25, 0x3c, 0x39, 0x74, 0x56, 0x75, 0x6a, 0x1a, 0xf1, 0x0f, 0x04,
0xe1, 0xc1, 0xac, 0xb0, 0xf9, 0x0a, 0x37, 0x22, 0xc8, 0x80, 0xc6, 0x44, 0x5a, 0xbe, 0xe2, 0x3f,
0xa8, 0x4c, 0xfd, 0x18, 0xdb, 0xb7, 0x2f, 0xd0, 0x67, 0x97, 0x8a, 0x93, 0x43, 0x07, 0xeb, 0x06,
0xbb, 0x54, 0x04, 0xb3, 0x62, 0xfa, 0x35, 0x1f, 0x96, 0x70, 0x5d, 0x3d, 0xd6, 0xdc, 0xc7, 0x4d,
0x42, 0x21, 0xca, 0x48, 0x12, 0x9e, 0x9b, 0x06, 0x6f, 0xd6, 0x64, 0xd6, 0x5b, 0x8b, 0xc3, 0xea,
0xcd, 0xd9, 0x7b, 0x90, 0x16, 0xfe, 0x8d, 0xca, 0xdf, 0xd7, 0x9f, 0xf6, 0xd5, 0xbf, 0x71, 0x1e,
0x5c, 0xd7, 0xe5, 0xcf, 0xe1, 0xe6, 0x7b, 0x84, 0xaf, 0x41, 0x96, 0xb1, 0x7d, 0x92, 0x84, 0x14,
0x44, 0x5a, 0x92, 0x30, 0x21, 0x94, 0xe5, 0xb3, 0x11, 0x77, 0xfe, 0x31, 0x62, 0x25, 0x79, 0x2e,
0x15, 0x3d, 0x96, 0xd2, 0xc7, 0x41, 0xaf, 0x7b, 0xef, 0x25, 0x1b, 0x10, 0xea, 0x6f, 0x69, 0x0f,
0x1b, 0xff, 0x21, 0xf1, 0x60, 0x15, 0xce, 0xde, 0x3e, 0x92, 0x3d, 0xfd, 0x67, 0xa7, 0xbf, 0x2c,
0xf4, 0x65, 0x62, 0xa1, 0xa3, 0x89, 0x85, 0x8e, 0x27, 0x16, 0x3a, 0x9d, 0x58, 0xe8, 0xe3, 0xd4,
0x32, 0x8e, 0xa7, 0x96, 0xf1, 0x7d, 0x6a, 0x19, 0xaf, 0xef, 0x9c, 0x09, 0xbe, 0x72, 0xe6, 0x64,
0x10, 0x71, 0x79, 0xf2, 0xde, 0xce, 0x17, 0x5b, 0xe6, 0x1f, 0xd5, 0xe5, 0x1e, 0xdf, 0xff, 0x13,
0x00, 0x00, 0xff, 0xff, 0xa3, 0x52, 0xb0, 0x81, 0x60, 0x03, 0x00, 0x00,
}
func (this *GenesisState) VerboseEqual(that interface{}) error {
@ -358,6 +371,14 @@ func (this *Params) VerboseEqual(that interface{}) error {
return fmt.Errorf("EnabledConversionPairs this[%v](%v) Not Equal that[%v](%v)", i, this.EnabledConversionPairs[i], i, that1.EnabledConversionPairs[i])
}
}
if len(this.AllowedNativeDenoms) != len(that1.AllowedNativeDenoms) {
return fmt.Errorf("AllowedNativeDenoms this(%v) Not Equal that(%v)", len(this.AllowedNativeDenoms), len(that1.AllowedNativeDenoms))
}
for i := range this.AllowedNativeDenoms {
if !this.AllowedNativeDenoms[i].Equal(&that1.AllowedNativeDenoms[i]) {
return fmt.Errorf("AllowedNativeDenoms this[%v](%v) Not Equal that[%v](%v)", i, this.AllowedNativeDenoms[i], i, that1.AllowedNativeDenoms[i])
}
}
return nil
}
func (this *Params) Equal(that interface{}) bool {
@ -387,6 +408,14 @@ func (this *Params) Equal(that interface{}) bool {
return false
}
}
if len(this.AllowedNativeDenoms) != len(that1.AllowedNativeDenoms) {
return false
}
for i := range this.AllowedNativeDenoms {
if !this.AllowedNativeDenoms[i].Equal(&that1.AllowedNativeDenoms[i]) {
return false
}
}
return true
}
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
@ -510,6 +539,20 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) {
dAtA[i] = 0x22
}
}
if len(m.AllowedNativeDenoms) > 0 {
for iNdEx := len(m.AllowedNativeDenoms) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.AllowedNativeDenoms[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
@ -562,6 +605,12 @@ func (m *Params) Size() (n int) {
}
var l int
_ = l
if len(m.AllowedNativeDenoms) > 0 {
for _, e := range m.AllowedNativeDenoms {
l = e.Size()
n += 1 + l + sovGenesis(uint64(l))
}
}
if len(m.EnabledConversionPairs) > 0 {
for _, e := range m.EnabledConversionPairs {
l = e.Size()
@ -841,6 +890,40 @@ func (m *Params) Unmarshal(dAtA []byte) error {
return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AllowedNativeDenoms", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.AllowedNativeDenoms = append(m.AllowedNativeDenoms, AllowedNativeCoinERC20Token{})
if err := m.AllowedNativeDenoms[len(m.AllowedNativeDenoms)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field EnabledConversionPairs", wireType)

View File

@ -47,9 +47,12 @@ func TestGenesisState_Validate(t *testing.T) {
{Address: addrs[0], Balance: sdkmath.NewInt(100)},
{Address: addrs[1], Balance: sdkmath.NewInt(150)},
},
params: types.NewParams(types.NewConversionPairs(
types.NewConversionPair(types.NewInternalEVMAddress(common.HexToAddress("0xinvalidaddress")), "weth"),
)),
params: types.NewParams(
types.NewConversionPairs(
types.NewConversionPair(types.NewInternalEVMAddress(common.HexToAddress("0xinvalidaddress")), "weth"),
),
types.NewAllowedNativeCoinERC20Tokens(),
),
success: false,
},
{

View File

@ -6,8 +6,10 @@ import (
// Parameter keys and default values
var (
KeyEnabledConversionPairs = []byte("EnabledConversionPairs")
DefaultConversionPairs = ConversionPairs{}
KeyEnabledConversionPairs = []byte("EnabledConversionPairs")
DefaultConversionPairs = ConversionPairs{}
KeyAllowedNativeDenoms = []byte("AllowedNativeDenoms")
DefaultAllowedNativeDenoms = AllowedNativeCoinERC20Tokens{}
)
// ParamKeyTable for evmutil module.
@ -20,15 +22,18 @@ func ParamKeyTable() paramtypes.KeyTable {
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(KeyEnabledConversionPairs, &p.EnabledConversionPairs, validateConversionPairs),
paramtypes.NewParamSetPair(KeyAllowedNativeDenoms, &p.AllowedNativeDenoms, validateAllowedNativeCoinERC20Tokens),
}
}
// NewParams returns new evmutil module Params.
func NewParams(
conversionPairs ConversionPairs,
allowedNativeDenoms AllowedNativeCoinERC20Tokens,
) Params {
return Params{
EnabledConversionPairs: conversionPairs,
AllowedNativeDenoms: allowedNativeDenoms,
}
}
@ -36,13 +41,17 @@ func NewParams(
func DefaultParams() Params {
return NewParams(
DefaultConversionPairs,
DefaultAllowedNativeDenoms,
)
}
// Validate returns an error if the Parmas is invalid.
// Validate returns an error if the Params is invalid.
func (p *Params) Validate() error {
if err := p.EnabledConversionPairs.Validate(); err != nil {
return err
}
if err := p.AllowedNativeDenoms.Validate(); err != nil {
return err
}
return nil
}

View File

@ -34,9 +34,13 @@ func (suite *ParamsTestSuite) TestMarshalYAML() {
"usdc",
),
)
allowedNativeDenoms := types.NewAllowedNativeCoinERC20Tokens(
types.NewAllowedNativeCoinERC20Token("denom", "Sdk Denom!", "DENOM", 6),
)
p := types.NewParams(
conversionPairs,
allowedNativeDenoms,
)
data, err := yaml.Marshal(p)
@ -47,6 +51,8 @@ func (suite *ParamsTestSuite) TestMarshalYAML() {
suite.Require().NoError(err)
_, ok := params["enabled_conversion_pairs"]
suite.Require().True(ok, "enabled_conversion_pairs should exist in yaml")
_, ok = params["allowed_native_denoms"]
suite.Require().True(ok, "allowed_native_denoms should exist in yaml")
}
func (suite *ParamsTestSuite) TestParamSetPairs_EnabledConversionPairs() {
@ -70,6 +76,90 @@ func (suite *ParamsTestSuite) TestParamSetPairs_EnabledConversionPairs() {
suite.Require().EqualError(paramSetPair.ValidatorFn(struct{}{}), "invalid parameter type: struct {}")
}
func (suite *ParamsTestSuite) TestParamSetPairs_AllowedNativeDenoms() {
suite.Require().Equal([]byte("AllowedNativeDenoms"), types.KeyAllowedNativeDenoms)
defaultParams := types.DefaultParams()
var paramSetPair *paramstypes.ParamSetPair
for _, pair := range defaultParams.ParamSetPairs() {
if bytes.Equal(pair.Key, types.KeyAllowedNativeDenoms) {
paramSetPair = &pair
break
}
}
suite.Require().NotNil(paramSetPair)
pairs, ok := paramSetPair.Value.(*types.AllowedNativeCoinERC20Tokens)
suite.Require().True(ok)
suite.Require().Equal(pairs, &defaultParams.AllowedNativeDenoms)
suite.Require().Nil(paramSetPair.ValidatorFn(*pairs))
suite.Require().EqualError(paramSetPair.ValidatorFn(struct{}{}), "invalid parameter type: struct {}")
}
func (suite *ParamsTestSuite) TestParams_Validate() {
validConversionPairs := types.NewConversionPairs(
types.NewConversionPair(
testutil.MustNewInternalEVMAddressFromString("0x0000000000000000000000000000000000000001"),
"usdc",
),
)
invalidConversionPairs := types.NewConversionPairs(
types.NewConversionPair(
testutil.MustNewInternalEVMAddressFromString("0x000000000000000000000000000000000000000A"),
"kava",
),
types.NewConversionPair(
testutil.MustNewInternalEVMAddressFromString("0x000000000000000000000000000000000000000B"),
"kava", // duplicate denom!
),
)
validAllowedNativeDenoms := types.NewAllowedNativeCoinERC20Tokens(
types.NewAllowedNativeCoinERC20Token("hard", "EVM Hard", "HARD", 6),
)
invalidAllowedNativeDenoms := types.NewAllowedNativeCoinERC20Tokens(
types.NewAllowedNativeCoinERC20Token("", "Invalid Token", "NOPE", 0), // empty sdk denom
)
testCases := []struct {
name string
params types.Params
expErr string
}{
{
name: "valid - empty",
params: types.NewParams(types.NewConversionPairs(), types.NewAllowedNativeCoinERC20Tokens()),
expErr: "",
},
{
name: "valid - with data",
params: types.NewParams(validConversionPairs, validAllowedNativeDenoms),
expErr: "",
},
{
name: "invalid - invalid conversion pair",
params: types.NewParams(invalidConversionPairs, validAllowedNativeDenoms),
expErr: "found duplicate",
},
{
name: "invalid - invalid allowed native denoms",
params: types.NewParams(validConversionPairs, invalidAllowedNativeDenoms),
expErr: "invalid token",
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
err := tc.params.Validate()
if tc.expErr != "" {
suite.ErrorContains(err, tc.expErr, "Expected validation error")
} else {
suite.NoError(err, "Expected no validation error")
}
})
}
}
func TestParamsTestSuite(t *testing.T) {
suite.Run(t, new(ParamsTestSuite))
}