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(evmutil): add allow list for evm-convertible sdk denoms #1590

Merged
merged 14 commits into from
May 19, 2023
Merged
Show file tree
Hide file tree
Changes from 11 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions app/ante/eip712_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
1 change: 1 addition & 0 deletions ci/env/kava-protonet/genesis.json
Original file line number Diff line number Diff line change
Expand Up @@ -2004,6 +2004,7 @@
"evmutil": {
"accounts": [],
"params": {
"allowed_native_denoms": [],
"enabled_conversion_pairs": [
{
"kava_erc20_address": "0xBb304f44b7EFD865361F2AD973d8ebA433893ABC",
Expand Down
23 changes: 23 additions & 0 deletions docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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. |



Expand Down
17 changes: 17 additions & 0 deletions proto/kava/evmutil/v1beta1/conversion_pair.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
7 changes: 7 additions & 0 deletions proto/kava/evmutil/v1beta1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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"
];
}
8 changes: 8 additions & 0 deletions x/evmutil/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
24 changes: 23 additions & 1 deletion x/evmutil/spec/02_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ 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
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
Expand All @@ -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.
Expand Down
20 changes: 17 additions & 3 deletions x/evmutil/spec/05_params.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`:

Expand All @@ -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.
1 change: 1 addition & 0 deletions x/evmutil/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ func (suite *Suite) SetupTest() {
"erc20/usdc",
),
),
types.NewAllowedNativeCoinERC20Tokens(),
))

queryHelper := baseapp.NewQueryServerTestHelper(suite.Ctx, suite.App.InterfaceRegistry())
Expand Down
90 changes: 90 additions & 0 deletions x/evmutil/types/conversion_pair.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down Expand Up @@ -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()
}
Loading