Skip to content
This repository has been archived by the owner on Jul 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #6 from jasonsong0/fix-register-coin-check
Browse files Browse the repository at this point in the history
Fix: wrong denom check at RegsterCoin and remove IBC-related tests
  • Loading branch information
jasonsong0 authored Jul 30, 2024
2 parents 87f2885 + 54cde68 commit 78a3997
Show file tree
Hide file tree
Showing 21 changed files with 1,001 additions and 559 deletions.
16 changes: 16 additions & 0 deletions proto/canto/erc20/v1/erc20.proto
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ message TokenPair {
Owner contract_owner = 4;
}

// TokenPairDenomIndex is a mapping of a token pair's denom to its token pair
// ID.
message TokenPairDenomIndex {
option (gogoproto.equal) = true;
string denom = 1;
bytes token_pair_id = 2;
}

// TokenPairERC20AddressIndex is a mapping of a token pair's ERC20 address to
// its token pair ID.
message TokenPairERC20AddressIndex {
option (gogoproto.equal) = true;
bytes erc20_address = 1;
bytes token_pair_id = 2;
}

// RegisterCoinProposal is a gov Content type to register a token pair for a
// native Cosmos coin.
message RegisterCoinProposal {
Expand Down
8 changes: 8 additions & 0 deletions proto/canto/erc20/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ message GenesisState {
Params params = 1 [ (gogoproto.nullable) = false ];
// registered token pairs
repeated TokenPair token_pairs = 2 [ (gogoproto.nullable) = false ];
// list of mappings from Cosmos denoms to token pair IDs, used for indexing
// token pairs by their denom
repeated TokenPairDenomIndex denom_indexes = 3
[ (gogoproto.nullable) = false ];
// list of mappings from ERC20 addresses to token pair IDs, used for indexing
// token pairs by their ERC20 address
repeated TokenPairERC20AddressIndex erc20_address_indexes = 4
[ (gogoproto.nullable) = false ];
}

// Params defines the erc20 module params
Expand Down
24 changes: 19 additions & 5 deletions x/erc20/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package erc20
import (
sdk "github.com/cosmos/cosmos-sdk/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
"github.com/ethereum/go-ethereum/common"

"github.com/Canto-Network/Canto/v7/x/erc20/keeper"
"github.com/Canto-Network/Canto/v7/x/erc20/types"
Expand All @@ -23,18 +24,31 @@ func InitGenesis(
panic("the erc20 module account has not been set")
}

// set token pair once
for _, pair := range data.TokenPairs {
id := pair.GetID()
k.SetTokenPair(ctx, pair)
k.SetDenomMap(ctx, pair.Denom, id)
k.SetERC20Map(ctx, pair.GetERC20Contract(), id)
}

// set indexes
// multiple token pairs should not be registered with the same denom,
// but if this happens, only the one in the index is valid.
for _, idx := range data.DenomIndexes {
id := idx.GetTokenPairId()
k.SetTokenPairIdByDenom(ctx, idx.Denom, id)
}
for _, idx := range data.Erc20AddressIndexes {
id := idx.GetTokenPairId()
k.SetTokenPairIdByERC20Addr(ctx, common.BytesToAddress(idx.Erc20Address), id)
}

}

// ExportGenesis export module status
func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState {
return &types.GenesisState{
Params: k.GetParams(ctx),
TokenPairs: k.GetTokenPairs(ctx),
Params: k.GetParams(ctx),
TokenPairs: k.GetTokenPairs(ctx),
DenomIndexes: k.GetAllTokenPairDenomIndexes(ctx),
Erc20AddressIndexes: k.GetAllTokenPairERC20AddressIndexes(ctx),
}
}
115 changes: 95 additions & 20 deletions x/erc20/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/suite"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -21,6 +22,70 @@ import (
"github.com/Canto-Network/Canto/v7/x/erc20/types"
)

var (
uqstars = "utestdenom"
// The following test codes are to prove that multiple token pairs should not be registered
// with the same denom, but if this happens, only the one in the index is valid.
// uqstars1 and uqstars2 have same denom
// uqstars1 is deployed first.
uqstars1 = types.TokenPair{
Erc20Address: "0x2C68D1d6aB986Ff4640b51e1F14C716a076E44C4",
Denom: uqstars,
Enabled: true,
ContractOwner: types.OWNER_MODULE,
}
// uqstars2 is deployed later than uqstars1.
uqstars2 = types.TokenPair{
Erc20Address: "0xD32eB974468ed767338533842D2D4Cc90B9BAb46",
Denom: uqstars,
Enabled: true,
ContractOwner: types.OWNER_MODULE,
}
customERC20 = types.TokenPair{
Erc20Address: "0xC5e00D3b04563950941f7137B5AfA3a534F0D6d6",
Denom: "custom",
Enabled: true,
ContractOwner: types.OWNER_EXTERNAL,
}

tokenPairs = []types.TokenPair{
uqstars2,
// even if we put uqstars1 later, it should be disabled because
// uqstars2 is the deployed later than uqstars1
uqstars1,
customERC20,
}
// denomIdxs should be ordered by denom ascending to compare with GetAllTokenPairDenomIndexes
denomIdxs = []types.TokenPairDenomIndex{
{
Denom: customERC20.Denom,
TokenPairId: customERC20.GetID(),
},
{
Denom: uqstars,
// denomIdx must have the latest token pair id assigned
// if there are multiple token pairs with the same denom
TokenPairId: uqstars2.GetID(),
},
}
// erc20AddrIdxs should be ordered by erc20address ascending to compare with GetAllTokenPairERC20AddressIndexes
erc20AddrIdxs = []types.TokenPairERC20AddressIndex{
{
Erc20Address: common.HexToAddress(uqstars1.Erc20Address).Bytes(),
TokenPairId: uqstars2.GetID(),
},
{
Erc20Address: customERC20.GetERC20Contract().Bytes(),
TokenPairId: customERC20.GetID(),
},

{
Erc20Address: common.HexToAddress(uqstars2.Erc20Address).Bytes(),
TokenPairId: uqstars2.GetID(),
},
}
)

type GenesisTestSuite struct {
suite.Suite
ctx sdk.Context
Expand Down Expand Up @@ -82,14 +147,10 @@ func (suite *GenesisTestSuite) TestERC20InitGenesis() {
"custom genesis",
types.NewGenesisState(
types.DefaultParams(),
[]types.TokenPair{
{
Erc20Address: "0x5dCA2483280D9727c80b5518faC4556617fb19ZZ",
Denom: "coin",
Enabled: true,
ContractOwner: types.OWNER_MODULE,
},
}),
tokenPairs,
denomIdxs,
erc20AddrIdxs,
),
},
}

Expand All @@ -99,13 +160,23 @@ func (suite *GenesisTestSuite) TestERC20InitGenesis() {
erc20.InitGenesis(suite.ctx, suite.app.Erc20Keeper, suite.app.AccountKeeper, tc.genesisState)
})
params := suite.app.Erc20Keeper.GetParams(suite.ctx)
suite.Require().Equal(tc.genesisState.Params, params)

tokenPairs := suite.app.Erc20Keeper.GetTokenPairs(suite.ctx)
suite.Require().Equal(tc.genesisState.Params, params)
if len(tokenPairs) > 0 {
suite.Require().Equal(tc.genesisState.TokenPairs, tokenPairs)
// The `tokenPairs` may not be sorted by tokenpair.id. For testing purposes, only check if the elements match.
suite.Require().ElementsMatch(tc.genesisState.TokenPairs, tokenPairs)
suite.Equal(denomIdxs, suite.app.Erc20Keeper.GetAllTokenPairDenomIndexes(suite.ctx))
suite.Equal(erc20AddrIdxs, suite.app.Erc20Keeper.GetAllTokenPairERC20AddressIndexes(suite.ctx))
suite.Equal(
uqstars2.GetID(), suite.app.Erc20Keeper.GetTokenPairIdByDenom(suite.ctx, uqstars),
"denom index must have latest token pair id",
)
} else {
suite.Require().Len(tc.genesisState.TokenPairs, 0)
suite.Len(tc.genesisState.TokenPairs, 0)
suite.Len(suite.app.Erc20Keeper.GetAllTokenPairDenomIndexes(suite.ctx), 0)
}
}
}
Expand All @@ -127,14 +198,10 @@ func (suite *GenesisTestSuite) TestErc20ExportGenesis() {
"custom genesis",
types.NewGenesisState(
types.DefaultParams(),
[]types.TokenPair{
{
Erc20Address: "0x5dCA2483280D9727c80b5518faC4556617fb19ZZ",
Denom: "coin",
Enabled: true,
ContractOwner: types.OWNER_MODULE,
},
}),
tokenPairs,
denomIdxs,
erc20AddrIdxs,
),
},
}

Expand All @@ -147,11 +214,19 @@ func (suite *GenesisTestSuite) TestErc20ExportGenesis() {

tokenPairs := suite.app.Erc20Keeper.GetTokenPairs(suite.ctx)
if len(tokenPairs) > 0 {
suite.Require().Equal(genesisExported.TokenPairs, tokenPairs)
// The `tokenPairs` may not be sorted by tokenpair.id. For testing purposes, only check if the elements match.
suite.Require().ElementsMatch(tc.genesisState.TokenPairs, tokenPairs)
suite.Equal(denomIdxs, suite.app.Erc20Keeper.GetAllTokenPairDenomIndexes(suite.ctx))
suite.Equal(erc20AddrIdxs, suite.app.Erc20Keeper.GetAllTokenPairERC20AddressIndexes(suite.ctx))
suite.Equal(
uqstars2.GetID(), suite.app.Erc20Keeper.GetTokenPairIdByDenom(suite.ctx, uqstars),
"denom index must have latest token pair id",
)
} else {
suite.Require().Len(genesisExported.TokenPairs, 0)
suite.Len(tc.genesisState.TokenPairs, 0)
suite.Len(suite.app.Erc20Keeper.GetAllTokenPairDenomIndexes(suite.ctx), 0)
suite.Len(suite.app.Erc20Keeper.GetAllTokenPairERC20AddressIndexes(suite.ctx), 0)
}
})
// }
}
}
2 changes: 1 addition & 1 deletion x/erc20/keeper/evm_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (h Hooks) PostTxProcessing(

// Check that the contract is a registered token pair
contractAddr := log.Address
id := h.k.GetERC20Map(ctx, contractAddr)
id := h.k.GetTokenPairIdByERC20Addr(ctx, contractAddr)
if len(id) == 0 {
continue
}
Expand Down
4 changes: 2 additions & 2 deletions x/erc20/keeper/evm_hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ func (suite *KeeperTestSuite) TestEvmHooksRegisteredERC20() {

suite.app.Erc20Keeper.DeleteTokenPair(suite.ctx, *pair)

suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, pair.GetID())
suite.app.Erc20Keeper.SetERC20Map(suite.ctx, pair.GetERC20Contract(), pair.GetID())
suite.app.Erc20Keeper.SetTokenPairIdByDenom(suite.ctx, pair.Denom, pair.GetID())
suite.app.Erc20Keeper.SetTokenPairIdByERC20Addr(suite.ctx, pair.GetERC20Contract(), pair.GetID())
// Mint 10 tokens to suite.address (owner)
_ = suite.MintERC20Token(contractAddr, suite.address, suite.address, big.NewInt(10))
suite.Commit()
Expand Down
8 changes: 4 additions & 4 deletions x/erc20/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ func (suite *KeeperTestSuite) TestTokenPair() {
addr := tests.GenerateAddress()
pair := types.NewTokenPair(addr, "coin", true, types.OWNER_MODULE)
suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair)
suite.app.Erc20Keeper.SetERC20Map(suite.ctx, addr, pair.GetID())
suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, pair.GetID())
suite.app.Erc20Keeper.SetTokenPairIdByERC20Addr(suite.ctx, addr, pair.GetID())
suite.app.Erc20Keeper.SetTokenPairIdByDenom(suite.ctx, pair.Denom, pair.GetID())

req = &types.QueryTokenPairRequest{
Token: pair.Erc20Address,
Expand All @@ -131,8 +131,8 @@ func (suite *KeeperTestSuite) TestTokenPair() {
func() {
addr := tests.GenerateAddress()
pair := types.NewTokenPair(addr, "coin", true, types.OWNER_MODULE)
suite.app.Erc20Keeper.SetERC20Map(suite.ctx, addr, pair.GetID())
suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, pair.GetID())
suite.app.Erc20Keeper.SetTokenPairIdByERC20Addr(suite.ctx, addr, pair.GetID())
suite.app.Erc20Keeper.SetTokenPairIdByDenom(suite.ctx, pair.Denom, pair.GetID())

req = &types.QueryTokenPairRequest{
Token: pair.Erc20Address,
Expand Down
20 changes: 10 additions & 10 deletions x/erc20/keeper/mint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ func (suite *KeeperTestSuite) TestMintingEnabled() {
func() {
expPair.Enabled = false
suite.app.Erc20Keeper.SetTokenPair(suite.ctx, expPair)
suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id)
suite.app.Erc20Keeper.SetTokenPairIdByDenom(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetTokenPairIdByERC20Addr(suite.ctx, expPair.GetERC20Contract(), id)
},
false,
},
Expand All @@ -50,8 +50,8 @@ func (suite *KeeperTestSuite) TestMintingEnabled() {
func() {
expPair.Enabled = true
suite.app.Erc20Keeper.SetTokenPair(suite.ctx, expPair)
suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id)
suite.app.Erc20Keeper.SetTokenPairIdByDenom(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetTokenPairIdByERC20Addr(suite.ctx, expPair.GetERC20Contract(), id)

params := banktypes.DefaultParams()
params.SendEnabled = []*banktypes.SendEnabled{
Expand All @@ -64,17 +64,17 @@ func (suite *KeeperTestSuite) TestMintingEnabled() {
{
"token not registered",
func() {
suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id)
suite.app.Erc20Keeper.SetTokenPairIdByDenom(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetTokenPairIdByERC20Addr(suite.ctx, expPair.GetERC20Contract(), id)
},
false,
},
{
"receiver address is blocked (module account)",
func() {
suite.app.Erc20Keeper.SetTokenPair(suite.ctx, expPair)
suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id)
suite.app.Erc20Keeper.SetTokenPairIdByDenom(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetTokenPairIdByERC20Addr(suite.ctx, expPair.GetERC20Contract(), id)

acc := suite.app.AccountKeeper.GetModuleAccount(suite.ctx, types.ModuleName)
receiver = acc.GetAddress()
Expand All @@ -85,8 +85,8 @@ func (suite *KeeperTestSuite) TestMintingEnabled() {
"ok",
func() {
suite.app.Erc20Keeper.SetTokenPair(suite.ctx, expPair)
suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id)
suite.app.Erc20Keeper.SetTokenPairIdByDenom(suite.ctx, expPair.Denom, id)
suite.app.Erc20Keeper.SetTokenPairIdByERC20Addr(suite.ctx, expPair.GetERC20Contract(), id)

receiver = sdk.AccAddress(tests.GenerateAddress().Bytes())
},
Expand Down
Loading

0 comments on commit 78a3997

Please sign in to comment.