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

refactor: migrate bridge token data and update metadata alias #749

Merged
merged 1 commit into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ type CrossChainKeepers struct {
Layer2Keeper crosschainkeeper.Keeper
}

func (c CrossChainKeepers) ToSlice() []crosschainkeeper.Keeper {
return []crosschainkeeper.Keeper{
c.BscKeeper, c.PolygonKeeper, c.AvalancheKeeper, c.EthKeeper,
c.TronKeeper, c.ArbitrumKeeper, c.OptimismKeeper, c.Layer2Keeper,
}
}

type AppKeepers struct {
// keys to access the substores
keys map[string]*storetypes.KVStoreKey
Expand Down
2 changes: 1 addition & 1 deletion app/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func appModules(
layer2.NewAppModule(app.Layer2Keeper),
fxevm.NewAppModule(app.EvmKeeper, app.AccountKeeper, app.GetSubspace(evmtypes.ModuleName)),
feemarket.NewAppModule(app.FeeMarketKeeper, app.GetSubspace(feemarkettypes.ModuleName)),
erc20.NewAppModule(app.Erc20Keeper),
erc20.NewAppModule(app.GetKey(erc20types.StoreKey), appCodec, app.Erc20Keeper, app.BankKeeper, app.CrossChainKeepers.ToSlice()),
nulnut marked this conversation as resolved.
Show resolved Hide resolved
migrate.NewAppModule(app.MigrateKeeper),
ibctransfer.NewAppModule(app.IBCTransferKeeper),
consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper),
Expand Down
1 change: 1 addition & 0 deletions app/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ func newContext(t *testing.T, myApp *app.App, chainId string, deliveState bool)
} else {
ctx = myApp.GetContextForCheckTx(nil).WithBlockHeader(header)
}
ctx = ctx.WithChainID(chainId)
ctx = ctx.WithHeaderInfo(coreheader.Info{
Height: header.Height,
Time: header.Time,
Expand Down
25 changes: 25 additions & 0 deletions app/upgrades/v8/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ package v8
import (
"context"
"encoding/hex"
"strings"

storetypes "cosmossdk.io/store/types"
upgradetypes "cosmossdk.io/x/upgrade/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

"github.com/functionx/fx-core/v8/app/keepers"
fxtypes "github.com/functionx/fx-core/v8/types"
crosschainkeeper "github.com/functionx/fx-core/v8/x/crosschain/keeper"
"github.com/functionx/fx-core/v8/x/gov/keeper"
fxgovv8 "github.com/functionx/fx-core/v8/x/gov/migrations/v8"
Expand All @@ -38,6 +41,8 @@ func CreateUpgradeHandler(mm *module.Manager, configurator module.Configurator,
return fromVM, err
}

updateMetadata(cacheCtx, app.BankKeeper)

commit()
cacheCtx.Logger().Info("upgrade complete", "module", "upgrade")
return toVM, nil
Expand Down Expand Up @@ -75,3 +80,23 @@ func removeStoreKeys(ctx sdk.Context, storeKey *storetypes.KVStoreKey, keys [][]
deleteFn(key)
}
}

func updateMetadata(ctx sdk.Context, bankKeeper bankkeeper.Keeper) {
mds := bankKeeper.GetAllDenomMetaData(ctx)
for _, md := range mds {
if md.Base == fxtypes.DefaultDenom || len(md.DenomUnits) == 0 || len(md.DenomUnits[0].Aliases) == 0 {
continue
}
// remove alias
md.DenomUnits[0].Aliases = []string{}

// update pundix/purse base denom
newBase := strings.ToLower(md.Symbol)
if md.Base != newBase {
md.Base = newBase
md.DenomUnits[0].Denom = newBase
}

bankKeeper.SetDenomMetaData(ctx, md)
}
}
20 changes: 20 additions & 0 deletions x/crosschain/keeper/legacy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/functionx/fx-core/v8/x/crosschain/types"
)

// Deprecated: do not use, remove in v8
func (k Keeper) LegacyGetDenomBridgeToken(ctx sdk.Context, denom string) (*types.BridgeToken, bool) {
store := ctx.KVStore(k.storeKey)
data := store.Get(types.GetTokenToDenomKey(denom))
if len(data) == 0 {
return nil, false
}
return &types.BridgeToken{
Denom: denom,
Token: string(data),
}, true
}
21 changes: 21 additions & 0 deletions x/erc20/migrations/v8/legacy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package v8

import (
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/functionx/fx-core/v8/x/erc20/types"
)

func LegacyIsNativeERC20(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.BinaryCodec, denom string) bool {
store := ctx.KVStore(storeKey)
id := store.Get(append(types.KeyPrefixTokenPairByDenom, []byte(denom)...))
bz := store.Get(append(types.KeyPrefixTokenPair, id...))
if len(bz) == 0 {
return false
}
var tokenPair types.ERC20Token
cdc.MustUnmarshal(bz, &tokenPair)
return tokenPair.IsNativeERC20()
}
nulnut marked this conversation as resolved.
Show resolved Hide resolved
97 changes: 97 additions & 0 deletions x/erc20/migrations/v8/migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package v8

import (
"strings"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"

fxtypes "github.com/functionx/fx-core/v8/types"
arbitrumtypes "github.com/functionx/fx-core/v8/x/arbitrum/types"
ethtypes "github.com/functionx/fx-core/v8/x/eth/types"
optimismtypes "github.com/functionx/fx-core/v8/x/optimism/types"
)

func (m Migrator) MigrateToken(ctx sdk.Context) error {
// add FX bridge token
if err := m.addToken(ctx, fxtypes.DefaultDenom, ""); err != nil {
return err
}

mds := m.bankKeeper.GetAllDenomMetaData(ctx)
for _, md := range mds {
if len(md.DenomUnits) == 0 || len(md.DenomUnits[0].Aliases) == 0 {
continue
}
baseDenom := strings.ToLower(md.Symbol)
nulnut marked this conversation as resolved.
Show resolved Hide resolved
// add other bridge/ibc token
for _, alias := range md.DenomUnits[0].Aliases {
if err := m.addToken(ctx, baseDenom, alias); err != nil {
return err
}
}
// add pundix/purse token
if md.Base == baseDenom {
continue
}
if err := m.addToken(ctx, baseDenom, md.Base); err != nil {
return err
}
}
return nil
}

func (m Migrator) addToken(
ctx sdk.Context,
base, alias string,
) error {
if strings.HasPrefix(alias, ibctransfertypes.DenomPrefix+"/") {
return m.addIBCToken(ctx, base, alias)
}
return m.addBridgeToken(ctx, base, alias)
}

func (m Migrator) addIBCToken(ctx sdk.Context, base, alias string) error {
channel, found := getIBCDenomTrace(ctx, alias)
if !found {
return sdkerrors.ErrInvalidCoins.Wrapf("ibc denom hash not found: %s %s", base, alias)
}
ctx.Logger().Info("add ibc token", "base-denom", base, "alias", alias, "channel", channel)
return m.keeper.AddIBCToken(ctx, base, channel, alias)
}

func (m Migrator) addBridgeToken(
ctx sdk.Context,
base, alias string,
) error {
if getExcludeBridgeToken(ctx, alias) {
return nil
}
for _, ck := range m.crossChainKeepers {
canAddFxBridgeToken := base == fxtypes.DefaultDenom && ck.ModuleName() == ethtypes.ModuleName
canAddBridgeToken := strings.HasPrefix(alias, ck.ModuleName())
excludeModule := ck.ModuleName() != arbitrumtypes.ModuleName && ck.ModuleName() != optimismtypes.ModuleName
if ctx.ChainID() == fxtypes.MainnetChainId {
canAddBridgeToken = canAddBridgeToken && excludeModule
}
if !canAddFxBridgeToken && !canAddBridgeToken {
continue
}

if alias == "" { // FX token
alias = base
}
legacyBridgeToken, found := ck.LegacyGetDenomBridgeToken(ctx, alias)
if !found {
return sdkerrors.ErrKeyNotFound.Wrapf("module %s bridge token: %s", ck.ModuleName(), alias)
}
ctx.Logger().Info("add bridge token", "base-denom", base, "alias", alias, "module", ck.ModuleName(), "contract", legacyBridgeToken.Token)
isNativeErc20 := LegacyIsNativeERC20(ctx, m.storeKey, m.cdc, base)
if err := m.keeper.AddBridgeToken(ctx, base, ck.ModuleName(), legacyBridgeToken.Token, isNativeErc20); err != nil {
return err
}
break
}
return nil
}
nulnut marked this conversation as resolved.
Show resolved Hide resolved
34 changes: 34 additions & 0 deletions x/erc20/migrations/v8/migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package v8

import (
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"

crosschainkeeper "github.com/functionx/fx-core/v8/x/crosschain/keeper"
"github.com/functionx/fx-core/v8/x/erc20/keeper"
)

type Migrator struct {
storeKey storetypes.StoreKey
cdc codec.BinaryCodec
keeper keeper.Keeper
bankKeeper bankkeeper.Keeper
crossChainKeepers []crosschainkeeper.Keeper
}

func NewMigrator(storeKey storetypes.StoreKey, cdc codec.BinaryCodec, keeper keeper.Keeper, bk bankkeeper.Keeper, cks []crosschainkeeper.Keeper) Migrator {
return Migrator{
storeKey: storeKey,
cdc: cdc,
keeper: keeper,
bankKeeper: bk,
crossChainKeepers: cks,
}
}

// Migrate3to4 migrates from version 3 to 4.
func (m Migrator) Migrate3to4(ctx sdk.Context) error {
return m.MigrateToken(ctx)
}
nulnut marked this conversation as resolved.
Show resolved Hide resolved
81 changes: 81 additions & 0 deletions x/erc20/migrations/v8/token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package v8

import (
sdk "github.com/cosmos/cosmos-sdk/types"

fxtypes "github.com/functionx/fx-core/v8/types"
)

var (
testnetIBCDenomTrace = map[string]string{
// cosmoshub
"ibc/C892C98C728A916DFD74A8A6036DF0B6C9B590C813C4CA1E94402D20F7771174": "channel-90", // uatom

// osmosis
"ibc/DA227B314073473C4008CDFAE7D6629F5182891AA9A34403BF9CB0F2E380D274": "channel-119", // uosmo
"ibc/8B7A6637DC5F0921CB24D2F3A051E9797CA50EF728E72872219F0E85A1BFDDD9": "channel-119", // atom/osmo
"ibc/530063F78415D637217C28ACE7CC7A9ADCC7DD4E7D5A20CE5E143744BE33E685": "channel-119", // stosmo/tosmo
"ibc/A6D5D1C0A6BBA47E6BBC6C6CBEF531045599345A6CD4FC8B6447909C8D900B33": "channel-119", // tatom/tosmo
"ibc/C2D7826927DD7FF3EA2F9D3A93889EA09667429847C23007D3583DCEB98CD0BF": "channel-119", // usdc/tosmo
"ibc/8C8FA24B0CE2E2BE006A1D6CE7D14DD64C463D7887992832C8AE9EF4CEA6FC13": "channel-119", // wbtc/tosmo
"ibc/3DCFA7233C0E27C07223980CB233EB3D87F64FE4D5DBB88DBC744E0088AF7927": "channel-119", // weth/tosmo
}
mainnetIBCDenomTrace = map[string]string{
// cosmoshub
"ibc/A670D9568B3E399316EEDE40C1181B7AA4BD0695F0B37513CE9B95B977DFC12E": "channel-10", // uatom
"ibc/19FE4199D5E206A756AA8656D6CCECA3A50AECB081CC73126060D592BD93A15B": "channel-10", // uosmo(from cosmoshub)
"ibc/04734B17EDC1F68BA599D8387A8BB0266684F46D42F4D5C7667BF370D21D9B8E": "channel-10", // aevmos
"ibc/4E7EFFD6C691F22FEA1C3B72DB3C275AF595A48C769CBB79289BDBD109A1F39A": "channel-10", // inj
"ibc/B61B71A43BA8D837D866B6417CF65B391A9177B3C3391527BF88A1174C55D939": "channel-10", // uaxl
"ibc/DE7DEEC0A8B377C9C3292884B80BDF264BEE97EF2F85DABE2E46B00A2E15C29A": "channel-10", // ukava
"ibc/8136D7DCECF799F835497A02725092811BA22810F88A1D0678600E13CEB249BE": "channel-10", // uscrt
"ibc/5A730E758B54FDEFAC2696BC6A24342192DF8F3D2B0B947C6D26AF53E9E943CA": "channel-10", // ustrd

// osmosis
"ibc/D7B22A85AB15F44A3152EBF7F2D37B6061F66FAF637E42C287FC649F1F5CA348": "channel-19", // uosmo
"ibc/95B9D47D7890C9F3E9104DD1DA74D3CCD4890E453FE0F0A711E782CE77B13455": "channel-19", // ulvn(from osmosis)
"ibc/BE612CFB5445AD2F56FAE496C0848FA381F967970A4CA586B1F90123AA62C4D4": "channel-19", // atom/osmo
"ibc/1B68E41D8D074F645388189E46C0F480111936F136C06E57FF559AB052D5BF78": "channel-19", // akt/atom
"ibc/145B926094C7649D85679D577FE8D3FD713C8586346518BF838712D4498A37E3": "channel-19", // akt/osmo
"ibc/49ABFFC9B2823450EDF1D4548B5B6314B473E497CF454726575458E7FDF3C52B": "channel-19", // atom/qatom
"ibc/373E4EFF2671B14802D9B3AB3EAF0345FBED921949654EB115C5072DFEB93AB0": "channel-19", // atom/statom
"ibc/AC80A1534F33EBA754A4EFC4E6AC3672850CCD0CDE9666B635984FB41BE91DA1": "channel-19", // atom/stkatom
"ibc/16770A91B7849DAFC413E7094E2CD66A8E908DB8550D7AD7F9B2115F7E00AC33": "channel-19", // axl/osmo
"ibc/A283012C5CA64DE2B8C6B4979B9A99E5144AA30F707D0FE16ED3ADD0F0BEDB42": "channel-19", // cro/osmo
"ibc/E30827509649DBDA201E98E14EDD52116124D2BCFAF70BBA5E7CA2615E086A2C": "channel-19", // dai/osmo
"ibc/30033E46154DB10107B18AE42AFFEBD1FAF4C36AF0142F1156B0ECC1796227FE": "channel-19", // eth/osmo
"ibc/86C7F2DD93F556650BF0992A2F61CBBA42600BD7FFD3F98CCE74C9A1994EB565": "channel-19", // evmos/osmo
"ibc/97B0CC9611DFE37744BA8EE27B32DE9509FED9ECDFCE59434E0B549BAD67D83E": "channel-19", // inj/osmo
"ibc/E126BB8628A2259291A668E2C666C97D60D06C59717BD2E34290A6DEF8AA8D19": "channel-19", // juno/osmo
"ibc/1CC704EB23F1B0EAA9634F088E2F476937E3B4519782B996B63F096E69DBAF5B": "channel-19", // scrt/osmo
"ibc/DFF778E0F743B1FE66D6018051AB5395F7CB470B19673149F1422B9DE68CD62C": "channel-19", // stars/osmo
"ibc/69058D0A3D0E3E63DC4AA39571007277A16F968290084BD80AFFFA2831B4AD10": "channel-19", // stosmo/osmo
"ibc/FDF9794382805B73B7182E1155E9A74EAA0CB37CFEC547B66335E21CC55829C2": "channel-19", // strd/osmo
"ibc/D54952FCA1DAE3919B89F2D809A0400C372D5919480BA2FDC9FF4217384DA7CE": "channel-19", // usdc/nls
"ibc/8C412C753AF39C7A050A250FE4DD3B4975AE6B714F3D922E94E0DFA5F81EBEA0": "channel-19", // usdc/osmo
"ibc/A655D0A048B0FD73458D9E6F020ABBBC3DD39F2D3AEACD2DCD1B0EC26B5EC425": "channel-19", // wbtc/osmo

// chihuahua
"ibc/210FA8AD411B627A0EFAEF4580B0D61C707C2C9E138AAF5AA087B4864B1E3599": "channel-22", // uhuahua
}

testnetExcludeBridgeToken = map[string]bool{
"layer20xb1efb300876f993Dc6826f09E66FEaa1bc3A735F": true, // DEGEN
}
)

func getIBCDenomTrace(ctx sdk.Context, denom string) (trace string, ok bool) {
if ctx.ChainID() == fxtypes.TestnetChainId {
trace, ok = testnetIBCDenomTrace[denom]
} else {
trace, ok = mainnetIBCDenomTrace[denom]
}
return
}

func getExcludeBridgeToken(ctx sdk.Context, denom string) bool {
if ctx.ChainID() == fxtypes.TestnetChainId {
return testnetExcludeBridgeToken[denom]
}
return false
}
25 changes: 21 additions & 4 deletions x/erc20/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ import (
"fmt"

"cosmossdk.io/core/appmodule"
storetypes "cosmossdk.io/store/types"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
"github.com/grpc-ecosystem/grpc-gateway/runtime"

crosschainkeeper "github.com/functionx/fx-core/v8/x/crosschain/keeper"
"github.com/functionx/fx-core/v8/x/erc20/keeper"
v8 "github.com/functionx/fx-core/v8/x/erc20/migrations/v8"
"github.com/functionx/fx-core/v8/x/erc20/types"
)

Expand Down Expand Up @@ -73,14 +77,22 @@ func (AppModuleBasic) RegisterInterfaces(interfaceRegistry codectypes.InterfaceR
// AppModule implements the AppModule interface for the capability module.
type AppModule struct {
AppModuleBasic
keeper keeper.Keeper
storeKey storetypes.StoreKey
cdc codec.BinaryCodec
keeper keeper.Keeper
bankKeeper bankkeeper.Keeper
crossChainKeepers []crosschainkeeper.Keeper
}

// NewAppModule creates a new AppModule Object
func NewAppModule(keeper keeper.Keeper) AppModule {
func NewAppModule(storeKey storetypes.StoreKey, cdc codec.BinaryCodec, keeper keeper.Keeper, bk bankkeeper.Keeper, cks []crosschainkeeper.Keeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
keeper: keeper,
AppModuleBasic: AppModuleBasic{},
storeKey: storeKey,
cdc: cdc,
keeper: keeper,
bankKeeper: bk,
crossChainKeepers: cks,
}
}

Expand All @@ -98,6 +110,11 @@ func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServer(am.keeper))

m := v8.NewMigrator(am.storeKey, am.cdc, am.keeper, am.bankKeeper, am.crossChainKeepers)
if err := cfg.RegisterMigration(types.ModuleName, 3, m.Migrate3to4); err != nil {
panic(fmt.Sprintf("failed to migrate x/erc20 from version 3 to 4: %v", err))
}
}

// InitGenesis performs the capability module's genesis initialization It returns
Expand Down