diff --git a/app/app.go b/app/app.go index d29cf5b7..343a0c93 100644 --- a/app/app.go +++ b/app/app.go @@ -424,6 +424,7 @@ func NewSommelierApp( keys[axelarcorktypes.StoreKey], app.GetSubspace(axelarcorktypes.ModuleName), app.AccountKeeper, + app.BankKeeper, app.StakingKeeper, app.TransferKeeper, app.DistrKeeper, @@ -974,7 +975,7 @@ func (app *SommelierApp) setupUpgradeStoreLoaders() { if upgradeInfo.Name == v7.UpgradeName { storeUpgrades = &storetypes.StoreUpgrades{ - Added: []string{auctiontypes.ModuleName, pubsubtypes.ModuleName}, + Added: []string{auctiontypes.ModuleName, axelarcorktypes.ModuleName, pubsubtypes.ModuleName}, } } @@ -1017,6 +1018,7 @@ func (app *SommelierApp) setupUpgradeHandlers() { app.mm, app.configurator, app.AuctionKeeper, + app.AxelarCorkKeeper, app.CellarFeesKeeper, app.ICAHostKeeper, app.PubsubKeeper, diff --git a/app/upgrades/v7/upgrades.go b/app/upgrades/v7/upgrades.go index 662e06c7..c229cabb 100644 --- a/app/upgrades/v7/upgrades.go +++ b/app/upgrades/v7/upgrades.go @@ -1,13 +1,18 @@ package v7 import ( + "time" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" icahostkeeper "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/host/keeper" icahosttypes "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/host/types" + ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" auctionkeeper "github.com/peggyjv/sommelier/v7/x/auction/keeper" auctiontypes "github.com/peggyjv/sommelier/v7/x/auction/types" + axelarcorkkeeper "github.com/peggyjv/sommelier/v7/x/axelarcork/keeper" + axelarcorktypes "github.com/peggyjv/sommelier/v7/x/axelarcork/types" cellarfeeskeeper "github.com/peggyjv/sommelier/v7/x/cellarfees/keeper" cellarfeestypes "github.com/peggyjv/sommelier/v7/x/cellarfees/types" pubsubkeeper "github.com/peggyjv/sommelier/v7/x/pubsub/keeper" @@ -18,6 +23,7 @@ func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, auctionKeeper auctionkeeper.Keeper, + axelarcorkKeeper axelarcorkkeeper.Keeper, cellarfeesKeeper cellarfeeskeeper.Keeper, icaHostKeeper icahostkeeper.Keeper, pubsubKeeper pubsubkeeper.Keeper, @@ -25,7 +31,6 @@ func CreateUpgradeHandler( return func(ctx sdk.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { ctx.Logger().Info("v7 upgrade: entering handler") - // TODO(bolten): get a sanity check on this // Now that we're on IBC V6, we can update the ICA host module to allow all message types rather than // the list we specified in the v6 upgrade -- a default of HostEnabled: true and the string "*" for messages icaParams := icahosttypes.DefaultParams() @@ -35,6 +40,7 @@ func CreateUpgradeHandler( // during the upgrade process. RunMigrations will migrate to the new cork version. Setting the consensus // version to 1 prevents RunMigrations from running InitGenesis itself. fromVM[auctiontypes.ModuleName] = mm.Modules[auctiontypes.ModuleName].ConsensusVersion() + fromVM[axelarcorktypes.ModuleName] = mm.Modules[axelarcorktypes.ModuleName].ConsensusVersion() fromVM[pubsubtypes.ModuleName] = mm.Modules[pubsubtypes.ModuleName].ConsensusVersion() // Params values were introduced in this upgrade but no migration was necessary, so we initialize the @@ -46,11 +52,12 @@ func CreateUpgradeHandler( ctx.Logger().Info("v7 upgrade: initializing auction genesis state") auctionInitGenesis(ctx, auctionKeeper) + ctx.Logger().Info("v7 upgrade: intializing axelarcork genesis state") + axelarcorkInitGenesis(ctx, axelarcorkKeeper) + ctx.Logger().Info("v7 upgrade: initializing pubsub genesis state") pubsubInitGenesis(ctx, pubsubKeeper) - //TODO(bolten): axelarcork module initialization - ctx.Logger().Info("v7 upgrade: running migrations and exiting handler") return mm.RunMigrations(ctx, configurator, fromVM) } @@ -132,6 +139,56 @@ func auctionInitGenesis(ctx sdk.Context, auctionKeeper auctionkeeper.Keeper) { auctionkeeper.InitGenesis(ctx, auctionKeeper, genesisState) } +// Initialize the Axelar cork module with the correct parameters. +func axelarcorkInitGenesis(ctx sdk.Context, axelarcorkKeeper axelarcorkkeeper.Keeper) { + genesisState := axelarcorktypes.DefaultGenesisState() + + genesisState.Params.Enabled = true + genesisState.Params.TimeoutDuration = uint64(6 * time.Hour) + genesisState.Params.IbcChannel = "channel-5" + genesisState.Params.IbcPort = ibctransfertypes.PortID + genesisState.Params.GmpAccount = "axelar1dv4u5k73pzqrxlzujxg3qp8kvc3pje7jtdvu72npnt5zhq05ejcsn5qme5s" + genesisState.Params.ExecutorAccount = "axelar1aythygn6z5thymj6tmzfwekzh05ewg3l7d6y89" + genesisState.Params.CorkTimeoutBlocks = 5000 + + genesisState.ChainConfigurations = axelarcorktypes.ChainConfigurations{ + Configurations: []*axelarcorktypes.ChainConfiguration{ + { + Name: "arbitrum", + Id: 42161, + ProxyAddress: "0xEe75bA2C81C04DcA4b0ED6d1B7077c188FEde4d2", + }, + { + Name: "Avalanche", + Id: 43114, + ProxyAddress: "0xEe75bA2C81C04DcA4b0ED6d1B7077c188FEde4d2", + }, + { + Name: "base", + Id: 8453, + ProxyAddress: "0xEe75bA2C81C04DcA4b0ED6d1B7077c188FEde4d2", + }, + { + Name: "binance", + Id: 56, + ProxyAddress: "0xEe75bA2C81C04DcA4b0ED6d1B7077c188FEde4d2", + }, + { + Name: "optimism", + Id: 10, + ProxyAddress: "0xEe75bA2C81C04DcA4b0ED6d1B7077c188FEde4d2", + }, + { + Name: "Polygon", + Id: 137, + ProxyAddress: "0xEe75bA2C81C04DcA4b0ED6d1B7077c188FEde4d2", + }, + }, + } + + axelarcorkkeeper.InitGenesis(ctx, axelarcorkKeeper, genesisState) +} + // Set up the initial pubsub state to mirror what is currently used in practice already, with 7seas as the // first publisher using its existing CA certificate, its default subscriptions as the already launched cellars, // and the subscribers as reflected in the steward-registry repo. diff --git a/x/axelarcork/keeper/abci.go b/x/axelarcork/keeper/abci.go index e7e180d8..c12dad07 100644 --- a/x/axelarcork/keeper/abci.go +++ b/x/axelarcork/keeper/abci.go @@ -24,13 +24,17 @@ func (k Keeper) EndBlocker(ctx sdk.Context) { k.Logger(ctx).Info("tallying scheduled cork votes", "height", fmt.Sprintf("%d", ctx.BlockHeight()), "chain id", config.Id) + // TODO(bolten): might not be a necessary fix, but GetApprovedScheduledAxelarCorks is kind of + // unexpectedly destructive -- it deletes all of the validator submitted entries for scheduled + // corks and returns a list of the winning ones, which are then set using SetWinningAxelarCork + // here, but it seems like an odd side effect of a Get function to delete stuff winningScheduledVotes := k.GetApprovedScheduledAxelarCorks(ctx, config.Id) if len(winningScheduledVotes) > 0 { k.Logger(ctx).Info("marking all winning scheduled cork votes as relayable", "winning votes", winningScheduledVotes, "chain id", config.Id) for _, c := range winningScheduledVotes { - k.SetWinningAxelarCork(ctx, config.Id, uint64(ctx.BlockHeight()), c.Deadline, c) + k.SetWinningAxelarCork(ctx, config.Id, uint64(ctx.BlockHeight()), c) } } @@ -39,7 +43,7 @@ func (k Keeper) EndBlocker(ctx sdk.Context) { "chain id", config.Id) timeoutHeight := uint64(ctx.BlockHeight()) - k.GetParamSet(ctx).CorkTimeoutBlocks - k.IterateWinningAxelarCorks(ctx, config.Id, func(_ common.Address, blockHeight uint64, deadline uint64, cork types.AxelarCork) (stop bool) { + k.IterateWinningAxelarCorks(ctx, config.Id, func(_ common.Address, blockHeight uint64, cork types.AxelarCork) (stop bool) { if blockHeight >= timeoutHeight { k.Logger(ctx).Info("deleting expired approved scheduled axelar cork", "scheduled height", fmt.Sprintf("%d", blockHeight), diff --git a/x/axelarcork/keeper/genesis.go b/x/axelarcork/keeper/genesis.go index 0be14e51..4a5a7da1 100644 --- a/x/axelarcork/keeper/genesis.go +++ b/x/axelarcork/keeper/genesis.go @@ -17,7 +17,6 @@ func InitGenesis(ctx sdk.Context, k Keeper, gs types.GenesisState) { if senderAccount == nil { panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) } - k.accountKeeper.SetModuleAccount(ctx, senderAccount) for i, config := range gs.ChainConfigurations.Configurations { @@ -43,6 +42,8 @@ func InitGenesis(ctx sdk.Context, k Keeper, gs types.GenesisState) { k.SetScheduledAxelarCork(ctx, scheduledCork.Cork.ChainId, scheduledCork.BlockHeight, valAddr, *scheduledCork.Cork) } + // TODO(bolten): not a huge risk since they can be re-sent, but the genesis state is missing WinningAxelarCorks + for _, n := range gs.AxelarContractCallNonces { if _, found := k.GetChainConfigurationByID(ctx, n.ChainId); !found { panic(fmt.Sprintf("chain configuration %d not found", n.ChainId)) diff --git a/x/axelarcork/keeper/keeper.go b/x/axelarcork/keeper/keeper.go index 8ed5e5f3..7641e3ac 100644 --- a/x/axelarcork/keeper/keeper.go +++ b/x/axelarcork/keeper/keeper.go @@ -22,6 +22,7 @@ type Keeper struct { cdc codec.BinaryCodec paramSpace paramtypes.Subspace accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper stakingKeeper types.StakingKeeper transferKeeper types.TransferKeeper distributionKeeper types.DistributionKeeper @@ -33,7 +34,7 @@ type Keeper struct { // NewKeeper creates a new x/axelarcork Keeper instance func NewKeeper( cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramtypes.Subspace, - accountKeeper types.AccountKeeper, stakingKeeper types.StakingKeeper, + accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, stakingKeeper types.StakingKeeper, transferKeeper types.TransferKeeper, distributionKeeper types.DistributionKeeper, wrapper types.ICS4Wrapper, gravityKeeper types.GravityKeeper, ) Keeper { @@ -47,6 +48,7 @@ func NewKeeper( cdc: cdc, paramSpace: paramSpace, accountKeeper: accountKeeper, + bankKeeper: bankKeeper, stakingKeeper: stakingKeeper, transferKeeper: transferKeeper, distributionKeeper: distributionKeeper, @@ -93,16 +95,16 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { func (k Keeper) SetScheduledAxelarCork(ctx sdk.Context, chainID uint64, blockHeight uint64, val sdk.ValAddress, cork types.AxelarCork) []byte { id := cork.IDHash(blockHeight) bz := k.cdc.MustMarshal(&cork) - ctx.KVStore(k.storeKey).Set(types.GetScheduledAxelarCorkKey(chainID, blockHeight, id, val, common.HexToAddress(cork.TargetContractAddress), cork.Deadline), bz) + ctx.KVStore(k.storeKey).Set(types.GetScheduledAxelarCorkKey(chainID, blockHeight, id, val, common.HexToAddress(cork.TargetContractAddress)), bz) return id } // GetScheduledAxelarCork gets the scheduled cork for a given validator // CONTRACT: must provide the validator address here not the delegate address -func (k Keeper) GetScheduledAxelarCork(ctx sdk.Context, chainID uint64, blockHeight uint64, id []byte, val sdk.ValAddress, contract common.Address, deadline uint64) (types.AxelarCork, bool) { +func (k Keeper) GetScheduledAxelarCork(ctx sdk.Context, chainID uint64, blockHeight uint64, id []byte, val sdk.ValAddress, contract common.Address) (types.AxelarCork, bool) { store := ctx.KVStore(k.storeKey) - bz := store.Get(types.GetScheduledAxelarCorkKey(chainID, blockHeight, id, val, contract, deadline)) + bz := store.Get(types.GetScheduledAxelarCorkKey(chainID, blockHeight, id, val, contract)) if len(bz) == 0 { return types.AxelarCork{}, false } @@ -114,20 +116,20 @@ func (k Keeper) GetScheduledAxelarCork(ctx sdk.Context, chainID uint64, blockHei // DeleteScheduledAxelarCork deletes the scheduled cork for a given validator // CONTRACT: must provide the validator address here not the delegate address -func (k Keeper) DeleteScheduledAxelarCork(ctx sdk.Context, chainID uint64, blockHeight uint64, id []byte, val sdk.ValAddress, contract common.Address, deadline uint64) { - ctx.KVStore(k.storeKey).Delete(types.GetScheduledAxelarCorkKey(chainID, blockHeight, id, val, contract, deadline)) +func (k Keeper) DeleteScheduledAxelarCork(ctx sdk.Context, chainID uint64, blockHeight uint64, id []byte, val sdk.ValAddress, contract common.Address) { + ctx.KVStore(k.storeKey).Delete(types.GetScheduledAxelarCorkKey(chainID, blockHeight, id, val, contract)) } // IterateScheduledAxelarCorks iterates over all scheduled corks by chain ID -func (k Keeper) IterateScheduledAxelarCorks(ctx sdk.Context, chainID uint64, cb func(val sdk.ValAddress, blockHeight uint64, id []byte, cel common.Address, deadline uint64, cork types.AxelarCork) (stop bool)) { +func (k Keeper) IterateScheduledAxelarCorks(ctx sdk.Context, chainID uint64, cb func(val sdk.ValAddress, blockHeight uint64, id []byte, cel common.Address, cork types.AxelarCork) (stop bool)) { k.IterateScheduledAxelarCorksByPrefix(ctx, types.GetScheduledAxelarCorkKeyPrefix(chainID), cb) } -func (k Keeper) IterateScheduledAxelarCorksByBlockHeight(ctx sdk.Context, chainID uint64, blockHeight uint64, cb func(val sdk.ValAddress, blockHeight uint64, id []byte, cel common.Address, deadline uint64, cork types.AxelarCork) (stop bool)) { +func (k Keeper) IterateScheduledAxelarCorksByBlockHeight(ctx sdk.Context, chainID uint64, blockHeight uint64, cb func(val sdk.ValAddress, blockHeight uint64, id []byte, cel common.Address, cork types.AxelarCork) (stop bool)) { k.IterateScheduledAxelarCorksByPrefix(ctx, types.GetScheduledAxelarCorkKeyByBlockHeightPrefix(chainID, blockHeight), cb) } -func (k Keeper) IterateScheduledAxelarCorksByPrefix(ctx sdk.Context, prefix []byte, cb func(val sdk.ValAddress, blockHeight uint64, id []byte, cel common.Address, deadline uint64, cork types.AxelarCork) (stop bool)) { +func (k Keeper) IterateScheduledAxelarCorksByPrefix(ctx sdk.Context, prefix []byte, cb func(val sdk.ValAddress, blockHeight uint64, id []byte, cel common.Address, cork types.AxelarCork) (stop bool)) { store := ctx.KVStore(k.storeKey) iter := sdk.KVStorePrefixIterator(store, prefix) defer iter.Close() @@ -141,10 +143,9 @@ func (k Keeper) IterateScheduledAxelarCorksByPrefix(ctx sdk.Context, prefix []by id := keyPair.Next(32) val := sdk.ValAddress(keyPair.Next(20)) contract := common.BytesToAddress(keyPair.Next(20)) - deadline := sdk.BigEndianToUint64(keyPair.Next(8)) k.cdc.MustUnmarshal(iter.Value(), &cork) - if cb(val, blockHeight, id, contract, deadline, cork) { + if cb(val, blockHeight, id, contract, cork) { break } } @@ -152,7 +153,7 @@ func (k Keeper) IterateScheduledAxelarCorksByPrefix(ctx sdk.Context, prefix []by func (k Keeper) GetScheduledAxelarCorks(ctx sdk.Context, chainID uint64) []*types.ScheduledAxelarCork { var scheduledCorks []*types.ScheduledAxelarCork - k.IterateScheduledAxelarCorks(ctx, chainID, func(val sdk.ValAddress, blockHeight uint64, id []byte, _ common.Address, _ uint64, cork types.AxelarCork) (stop bool) { + k.IterateScheduledAxelarCorks(ctx, chainID, func(val sdk.ValAddress, blockHeight uint64, id []byte, _ common.Address, cork types.AxelarCork) (stop bool) { scheduledCorks = append(scheduledCorks, &types.ScheduledAxelarCork{ Validator: val.String(), Cork: &cork, @@ -167,7 +168,7 @@ func (k Keeper) GetScheduledAxelarCorks(ctx sdk.Context, chainID uint64) []*type func (k Keeper) GetScheduledAxelarCorksByBlockHeight(ctx sdk.Context, chainID uint64, height uint64) []*types.ScheduledAxelarCork { var scheduledCorks []*types.ScheduledAxelarCork - k.IterateScheduledAxelarCorksByBlockHeight(ctx, chainID, height, func(val sdk.ValAddress, blockHeight uint64, Id []byte, _ common.Address, _ uint64, cork types.AxelarCork) (stop bool) { + k.IterateScheduledAxelarCorksByBlockHeight(ctx, chainID, height, func(val sdk.ValAddress, blockHeight uint64, Id []byte, _ common.Address, cork types.AxelarCork) (stop bool) { scheduledCorks = append(scheduledCorks, &types.ScheduledAxelarCork{ Validator: val.String(), Cork: &cork, @@ -183,7 +184,7 @@ func (k Keeper) GetScheduledAxelarCorksByBlockHeight(ctx sdk.Context, chainID ui func (k Keeper) GetScheduledAxelarCorksByID(ctx sdk.Context, chainID uint64, queriedID []byte) []*types.ScheduledAxelarCork { var scheduledCorks []*types.ScheduledAxelarCork - k.IterateScheduledAxelarCorks(ctx, chainID, func(val sdk.ValAddress, blockHeight uint64, id []byte, _ common.Address, _ uint64, cork types.AxelarCork) (stop bool) { + k.IterateScheduledAxelarCorks(ctx, chainID, func(val sdk.ValAddress, blockHeight uint64, id []byte, _ common.Address, cork types.AxelarCork) (stop bool) { if bytes.Equal(id, queriedID) { scheduledCorks = append(scheduledCorks, &types.ScheduledAxelarCork{ Validator: val.String(), @@ -203,12 +204,12 @@ func (k Keeper) GetScheduledAxelarCorksByID(ctx sdk.Context, chainID uint64, que // WinningCork // ///////////////// -func (k Keeper) SetWinningAxelarCork(ctx sdk.Context, chainID uint64, blockHeight uint64, deadline uint64, cork types.AxelarCork) { +func (k Keeper) SetWinningAxelarCork(ctx sdk.Context, chainID uint64, blockHeight uint64, cork types.AxelarCork) { bz := k.cdc.MustMarshal(&cork) - ctx.KVStore(k.storeKey).Set(types.GetWinningAxelarCorkKey(chainID, blockHeight, common.HexToAddress(cork.TargetContractAddress), deadline), bz) + ctx.KVStore(k.storeKey).Set(types.GetWinningAxelarCorkKey(chainID, blockHeight, common.HexToAddress(cork.TargetContractAddress)), bz) } -func (k Keeper) IterateWinningAxelarCorks(ctx sdk.Context, chainID uint64, cb func(contract common.Address, blockHeight uint64, deadline uint64, cork types.AxelarCork) (stop bool)) { +func (k Keeper) IterateWinningAxelarCorks(ctx sdk.Context, chainID uint64, cb func(contract common.Address, blockHeight uint64, cork types.AxelarCork) (stop bool)) { store := ctx.KVStore(k.storeKey) iter := sdk.KVStorePrefixIterator(store, types.GetWinningAxelarCorkKeyPrefix(chainID)) defer iter.Close() @@ -220,10 +221,9 @@ func (k Keeper) IterateWinningAxelarCorks(ctx sdk.Context, chainID uint64, cb fu keyPair.Next(8) // trim chain ID blockHeight := binary.BigEndian.Uint64(keyPair.Next(8)) contractAddress := common.BytesToAddress(keyPair.Next(20)) // contract - deadline := sdk.BigEndianToUint64(keyPair.Next(8)) k.cdc.MustUnmarshal(iter.Value(), &cork) - if cb(contractAddress, blockHeight, deadline, cork) { + if cb(contractAddress, blockHeight, cork) { break } } @@ -233,7 +233,7 @@ func (k Keeper) GetWinningAxelarCork(ctx sdk.Context, chainID uint64, contractAd var bh uint64 var c types.AxelarCork found := false - k.IterateWinningAxelarCorks(ctx, chainID, func(contract common.Address, blockHeight uint64, deadline uint64, cork types.AxelarCork) (stop bool) { + k.IterateWinningAxelarCorks(ctx, chainID, func(contract common.Address, blockHeight uint64, cork types.AxelarCork) (stop bool) { if contractAddr == contract { bh = blockHeight c = cork @@ -248,13 +248,13 @@ func (k Keeper) GetWinningAxelarCork(ctx sdk.Context, chainID uint64, contractAd } func (k Keeper) DeleteWinningAxelarCorkByBlockheight(ctx sdk.Context, chainID uint64, blockHeight uint64, cork types.AxelarCork) { - ctx.KVStore(k.storeKey).Delete(types.GetWinningAxelarCorkKey(chainID, blockHeight, common.HexToAddress(cork.TargetContractAddress), cork.Deadline)) + ctx.KVStore(k.storeKey).Delete(types.GetWinningAxelarCorkKey(chainID, blockHeight, common.HexToAddress(cork.TargetContractAddress))) } // TODO (Collin): Need pruning logic. This method is unused. func (k Keeper) DeleteWinningAxelarCork(ctx sdk.Context, chainID uint64, c types.AxelarCork) { - k.IterateWinningAxelarCorks(ctx, chainID, func(contract common.Address, blockHeight uint64, deadline uint64, cork types.AxelarCork) (stop bool) { + k.IterateWinningAxelarCorks(ctx, chainID, func(contract common.Address, blockHeight uint64, cork types.AxelarCork) (stop bool) { if c.Equals(cork) { k.DeleteWinningAxelarCorkByBlockheight(ctx, chainID, blockHeight, cork) @@ -273,7 +273,7 @@ func (k Keeper) GetScheduledBlockHeights(ctx sdk.Context, chainID uint64) []uint var heights []uint64 latestHeight := uint64(0) - k.IterateScheduledAxelarCorks(ctx, chainID, func(_ sdk.ValAddress, blockHeight uint64, _ []byte, _ common.Address, _ uint64, _ types.AxelarCork) (stop bool) { + k.IterateScheduledAxelarCorks(ctx, chainID, func(_ sdk.ValAddress, blockHeight uint64, _ []byte, _ common.Address, _ types.AxelarCork) (stop bool) { if blockHeight > latestHeight { heights = append(heights, blockHeight) } @@ -284,9 +284,9 @@ func (k Keeper) GetScheduledBlockHeights(ctx sdk.Context, chainID uint64) []uint return heights } -////////////////// +//////////////////////// // AxelarCork Results // -////////////////// +//////////////////////// func (k Keeper) SetAxelarCorkResult(ctx sdk.Context, chainID uint64, id []byte, corkResult types.AxelarCorkResult) { bz := k.cdc.MustMarshal(&corkResult) @@ -348,7 +348,7 @@ func (k Keeper) GetApprovedScheduledAxelarCorks(ctx sdk.Context, chainID uint64) totalPower := k.stakingKeeper.GetLastTotalPower(ctx) corks := []types.AxelarCork{} powers := []uint64{} - k.IterateScheduledAxelarCorksByBlockHeight(ctx, chainID, currentBlockHeight, func(val sdk.ValAddress, _ uint64, id []byte, addr common.Address, deadline uint64, cork types.AxelarCork) (stop bool) { + k.IterateScheduledAxelarCorksByBlockHeight(ctx, chainID, currentBlockHeight, func(val sdk.ValAddress, _ uint64, id []byte, addr common.Address, cork types.AxelarCork) (stop bool) { validator := k.stakingKeeper.Validator(ctx, val) validatorPower := uint64(validator.GetConsensusPower(k.stakingKeeper.PowerReduction(ctx))) found := false @@ -366,7 +366,7 @@ func (k Keeper) GetApprovedScheduledAxelarCorks(ctx sdk.Context, chainID uint64) powers = append(powers, validatorPower) } - k.DeleteScheduledAxelarCork(ctx, chainID, currentBlockHeight, id, val, addr, deadline) + k.DeleteScheduledAxelarCork(ctx, chainID, currentBlockHeight, id, val, addr) return false }) diff --git a/x/axelarcork/keeper/keeper_test.go b/x/axelarcork/keeper/keeper_test.go index f327c103..183af1d0 100644 --- a/x/axelarcork/keeper/keeper_test.go +++ b/x/axelarcork/keeper/keeper_test.go @@ -38,6 +38,7 @@ type KeeperTestSuite struct { ctx sdk.Context axelarcorkKeeper Keeper accountKeeper *mocks.MockAccountKeeper + bankKeeper *mocks.MockBankKeeper stakingKeeper *mocks.MockStakingKeeper transferKeeper *mocks.MockTransferKeeper distributionKeeper *mocks.MockDistributionKeeper @@ -63,6 +64,7 @@ func (suite *KeeperTestSuite) SetupTest() { defer ctrl.Finish() suite.accountKeeper = mocks.NewMockAccountKeeper(ctrl) + suite.bankKeeper = mocks.NewMockBankKeeper(ctrl) suite.stakingKeeper = mocks.NewMockStakingKeeper(ctrl) suite.transferKeeper = mocks.NewMockTransferKeeper(ctrl) suite.distributionKeeper = mocks.NewMockDistributionKeeper(ctrl) @@ -86,6 +88,7 @@ func (suite *KeeperTestSuite) SetupTest() { key, subSpace, suite.accountKeeper, + suite.bankKeeper, suite.stakingKeeper, suite.transferKeeper, suite.distributionKeeper, @@ -146,7 +149,7 @@ func (suite *KeeperTestSuite) TestSetGetDeleteScheduledCork() { expectedID := expectedCork.IDHash(testHeight) actualID := axelarcorkKeeper.SetScheduledAxelarCork(ctx, TestEVMChainID, testHeight, val, expectedCork) require.Equal(expectedID, actualID) - actualCork, found := axelarcorkKeeper.GetScheduledAxelarCork(ctx, TestEVMChainID, testHeight, actualID, val, sampleCellarAddr, deadline) + actualCork, found := axelarcorkKeeper.GetScheduledAxelarCork(ctx, TestEVMChainID, testHeight, actualID, val, sampleCellarAddr) require.True(found) require.Equal(expectedCork, actualCork) @@ -166,7 +169,7 @@ func (suite *KeeperTestSuite) TestSetGetDeleteScheduledCork() { require.Equal(testHeight, actualCorks[0].BlockHeight) require.Equal(hex.EncodeToString(expectedID), actualCorks[0].Id) - axelarcorkKeeper.DeleteScheduledAxelarCork(ctx, TestEVMChainID, testHeight, expectedID, sdk.ValAddress(val), sampleCellarAddr, deadline) + axelarcorkKeeper.DeleteScheduledAxelarCork(ctx, TestEVMChainID, testHeight, expectedID, sdk.ValAddress(val), sampleCellarAddr) require.Empty(axelarcorkKeeper.GetScheduledAxelarCorks(ctx, TestEVMChainID)) } diff --git a/x/axelarcork/keeper/msg_server.go b/x/axelarcork/keeper/msg_server.go index ac45c13a..a256a8fa 100644 --- a/x/axelarcork/keeper/msg_server.go +++ b/x/axelarcork/keeper/msg_server.go @@ -81,6 +81,13 @@ func (k Keeper) RelayCork(c context.Context, msg *types.MsgRelayAxelarCorkReques return nil, fmt.Errorf("no cork on chain %d found for address %s", config.Id, msg.TargetContractAddress) } + // transfer tokens to the module account + signer := msg.MustGetSigner() + err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, signer, types.ModuleName, sdk.NewCoins(msg.Token)) + if err != nil { + return nil, err + } + nonce := k.IncrementAxelarContractCallNonce(ctx, msg.ChainId, cork.TargetContractAddress) payload, err := types.EncodeLogicCallArgs(msg.TargetContractAddress, nonce, cork.Deadline, cork.EncodedContractCall) if err != nil { @@ -106,7 +113,7 @@ func (k Keeper) RelayCork(c context.Context, msg *types.MsgRelayAxelarCorkReques params.IbcPort, params.IbcChannel, msg.Token, - msg.Signer, + k.GetSenderAccount(ctx).GetAddress().String(), params.GmpAccount, clienttypes.ZeroHeight(), uint64(ctx.BlockTime().Add(time.Duration(params.TimeoutDuration)).UnixNano()), @@ -144,6 +151,13 @@ func (k Keeper) RelayProxyUpgrade(c context.Context, msg *types.MsgRelayAxelarPr return nil, fmt.Errorf("proxy upgrade call is not executable until height %d", upgradeData.ExecutableHeightThreshold) } + // transfer tokens to the module account + signer := msg.MustGetSigner() + err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, signer, types.ModuleName, sdk.NewCoins(msg.Token)) + if err != nil { + return nil, err + } + axelarMemo := types.AxelarBody{ DestinationChain: config.Name, DestinationAddress: config.ProxyAddress, @@ -163,7 +177,7 @@ func (k Keeper) RelayProxyUpgrade(c context.Context, msg *types.MsgRelayAxelarPr params.IbcPort, params.IbcChannel, msg.Token, - msg.Signer, + k.GetSenderAccount(ctx).GetAddress().String(), params.GmpAccount, clienttypes.ZeroHeight(), uint64(ctx.BlockTime().Add(time.Duration(params.TimeoutDuration)).UnixNano()), diff --git a/x/axelarcork/keeper/packet.go b/x/axelarcork/keeper/packet.go index d16b70b2..99c8c4fe 100644 --- a/x/axelarcork/keeper/packet.go +++ b/x/axelarcork/keeper/packet.go @@ -28,11 +28,32 @@ func (k Keeper) ValidateAxelarPacket(ctx sdk.Context, sourceChannel string, data return err } + // decoding some bech32 strings so our comparisons are guaranteed to be accurate + gmpAccountAddr, err := sdk.AccAddressFromBech32(params.GmpAccount) + if err != nil { + return fmt.Errorf("GmpAccount parameter is an invalid address: %s", params.GmpAccount) + } + + receiverAddr, err := sdk.AccAddressFromBech32(packetData.Receiver) + if err != nil { + return fmt.Errorf("receiver in IBC packet data is an invalid address: %s", packetData.Receiver) + } + + senderAddr, err := sdk.AccAddressFromBech32(packetData.Sender) + if err != nil { + return fmt.Errorf("sender in IBC packet data is an invalid address: %s", packetData.Sender) + } + // if we are not sending to the axelar gmp management account, we can skip - if packetData.Receiver != params.GmpAccount { + if !receiverAddr.Equals(gmpAccountAddr) { return nil } + // reject if the axelar module account is not the sender + if !senderAddr.Equals(k.GetSenderAccount(ctx).GetAddress()) { + return fmt.Errorf("sender to Axelar GMP account is not axelarcork module account: %s", packetData.Sender) + } + // if the memo field is empty, we can pass the message along if packetData.Memo == "" { return nil @@ -49,7 +70,18 @@ func (k Keeper) ValidateAxelarPacket(ctx sdk.Context, sourceChannel string, data return fmt.Errorf("configuration not found for chain %s", axelarBody.DestinationChain) } - if chainConfig.ProxyAddress != axelarBody.DestinationAddress { + // decoding some EVM addresses here so our comparisons are guaranteed to be accurate + if !common.IsHexAddress(chainConfig.ProxyAddress) { + return fmt.Errorf("proxy address in chain config is not valid, chain ID %d, address %s", chainConfig.Id, chainConfig.ProxyAddress) + } + proxyAddr := common.HexToAddress(chainConfig.ProxyAddress) + + if !common.IsHexAddress(axelarBody.DestinationAddress) { + return fmt.Errorf("axelar destination address is not a valid EVM address: %s", axelarBody.DestinationAddress) + } + axelarDestinationAddr := common.HexToAddress(axelarBody.DestinationAddress) + + if !bytes.Equal(axelarDestinationAddr.Bytes(), proxyAddr.Bytes()) { return fmt.Errorf("msg cannot bypass the proxy. expected addr %s, received %s", chainConfig.ProxyAddress, axelarBody.DestinationAddress) } @@ -59,6 +91,8 @@ func (k Keeper) ValidateAxelarPacket(ctx sdk.Context, sourceChannel string, data return fmt.Errorf("nonce cannot be zero") } + // TODO(bolten): is there any validation on the deadline worth doing? + blockHeight, winningCork, ok := k.GetWinningAxelarCork(ctx, chainConfig.Id, common.HexToAddress(targetContract)) if !ok { return fmt.Errorf("no cork expected for chain %s:%d at address %s", chainConfig.Name, chainConfig.Id, axelarBody.DestinationAddress) diff --git a/x/axelarcork/keeper/query_server.go b/x/axelarcork/keeper/query_server.go index 0171b703..2ef4204c 100644 --- a/x/axelarcork/keeper/query_server.go +++ b/x/axelarcork/keeper/query_server.go @@ -81,7 +81,7 @@ func (k Keeper) QueryScheduledCorks(c context.Context, req *types.QueryScheduled response := types.QueryScheduledCorksResponse{} - k.IterateScheduledAxelarCorks(ctx, config.Id, func(val sdk.ValAddress, blockHeight uint64, id []byte, cel common.Address, deadline uint64, cork types.AxelarCork) (stop bool) { + k.IterateScheduledAxelarCorks(ctx, config.Id, func(val sdk.ValAddress, blockHeight uint64, id []byte, cel common.Address, cork types.AxelarCork) (stop bool) { response.Corks = append(response.Corks, &types.ScheduledAxelarCork{ Cork: &cork, BlockHeight: blockHeight, diff --git a/x/axelarcork/keeper/setup_unit_test.go b/x/axelarcork/keeper/setup_unit_test.go index 3d60bd24..ce79cc7d 100644 --- a/x/axelarcork/keeper/setup_unit_test.go +++ b/x/axelarcork/keeper/setup_unit_test.go @@ -56,6 +56,7 @@ func setupCorkKeeper(t *testing.T) ( ctrl := gomock.NewController(t) mockAccountKeeper := mocks.NewMockAccountKeeper(ctrl) + mockBankKeeper := mocks.NewMockBankKeeper(ctrl) mockStakingKeeper := mocks.NewMockStakingKeeper(ctrl) mockTransferKeeper := mocks.NewMockTransferKeeper(ctrl) mockDistributionKeeper := mocks.NewMockDistributionKeeper(ctrl) @@ -67,6 +68,7 @@ func setupCorkKeeper(t *testing.T) ( storeKey, subSpace, mockAccountKeeper, + mockBankKeeper, mockStakingKeeper, mockTransferKeeper, mockDistributionKeeper, diff --git a/x/axelarcork/tests/mocks/expected_keepers_mocks.go b/x/axelarcork/tests/mocks/expected_keepers_mocks.go index 0692f9d4..50b8b919 100644 --- a/x/axelarcork/tests/mocks/expected_keepers_mocks.go +++ b/x/axelarcork/tests/mocks/expected_keepers_mocks.go @@ -11,12 +11,13 @@ import ( math "cosmossdk.io/math" types "github.com/cosmos/cosmos-sdk/types" types0 "github.com/cosmos/cosmos-sdk/x/auth/types" - types1 "github.com/cosmos/cosmos-sdk/x/capability/types" - types2 "github.com/cosmos/cosmos-sdk/x/distribution/types" - types3 "github.com/cosmos/cosmos-sdk/x/staking/types" - types4 "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" - types5 "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" - types6 "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + types1 "github.com/cosmos/cosmos-sdk/x/bank/types" + types2 "github.com/cosmos/cosmos-sdk/x/capability/types" + types3 "github.com/cosmos/cosmos-sdk/x/distribution/types" + types4 "github.com/cosmos/cosmos-sdk/x/staking/types" + types5 "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + types6 "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + types7 "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" exported "github.com/cosmos/ibc-go/v6/modules/core/exported" gomock "github.com/golang/mock/gomock" ) @@ -98,6 +99,114 @@ func (mr *MockAccountKeeperMockRecorder) SetModuleAccount(arg0, arg1 interface{} return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).SetModuleAccount), arg0, arg1) } +// MockBankKeeper is a mock of BankKeeper interface. +type MockBankKeeper struct { + ctrl *gomock.Controller + recorder *MockBankKeeperMockRecorder +} + +// MockBankKeeperMockRecorder is the mock recorder for MockBankKeeper. +type MockBankKeeperMockRecorder struct { + mock *MockBankKeeper +} + +// NewMockBankKeeper creates a new mock instance. +func NewMockBankKeeper(ctrl *gomock.Controller) *MockBankKeeper { + mock := &MockBankKeeper{ctrl: ctrl} + mock.recorder = &MockBankKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder { + return m.recorder +} + +// GetAllBalances mocks base method. +func (m *MockBankKeeper) GetAllBalances(ctx types.Context, addr types.AccAddress) types.Coins { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAllBalances", ctx, addr) + ret0, _ := ret[0].(types.Coins) + return ret0 +} + +// GetAllBalances indicates an expected call of GetAllBalances. +func (mr *MockBankKeeperMockRecorder) GetAllBalances(ctx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllBalances", reflect.TypeOf((*MockBankKeeper)(nil).GetAllBalances), ctx, addr) +} + +// GetDenomMetaData mocks base method. +func (m *MockBankKeeper) GetDenomMetaData(ctx types.Context, denom string) (types1.Metadata, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDenomMetaData", ctx, denom) + ret0, _ := ret[0].(types1.Metadata) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// GetDenomMetaData indicates an expected call of GetDenomMetaData. +func (mr *MockBankKeeperMockRecorder) GetDenomMetaData(ctx, denom interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDenomMetaData", reflect.TypeOf((*MockBankKeeper)(nil).GetDenomMetaData), ctx, denom) +} + +// GetSupply mocks base method. +func (m *MockBankKeeper) GetSupply(ctx types.Context, denom string) types.Coin { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSupply", ctx, denom) + ret0, _ := ret[0].(types.Coin) + return ret0 +} + +// GetSupply indicates an expected call of GetSupply. +func (mr *MockBankKeeperMockRecorder) GetSupply(ctx, denom interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSupply", reflect.TypeOf((*MockBankKeeper)(nil).GetSupply), ctx, denom) +} + +// SendCoinsFromAccountToModule mocks base method. +func (m *MockBankKeeper) SendCoinsFromAccountToModule(ctx types.Context, senderAddr types.AccAddress, recipientModule string, amt types.Coins) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendCoinsFromAccountToModule", ctx, senderAddr, recipientModule, amt) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendCoinsFromAccountToModule indicates an expected call of SendCoinsFromAccountToModule. +func (mr *MockBankKeeperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromAccountToModule", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromAccountToModule), ctx, senderAddr, recipientModule, amt) +} + +// SendCoinsFromModuleToAccount mocks base method. +func (m *MockBankKeeper) SendCoinsFromModuleToAccount(ctx types.Context, senderModule string, recipientAddr types.AccAddress, amt types.Coins) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendCoinsFromModuleToAccount", ctx, senderModule, recipientAddr, amt) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendCoinsFromModuleToAccount indicates an expected call of SendCoinsFromModuleToAccount. +func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToAccount", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromModuleToAccount), ctx, senderModule, recipientAddr, amt) +} + +// SendCoinsFromModuleToModule mocks base method. +func (m *MockBankKeeper) SendCoinsFromModuleToModule(ctx types.Context, senderModule, recipientModule string, amt types.Coins) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendCoinsFromModuleToModule", ctx, senderModule, recipientModule, amt) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendCoinsFromModuleToModule indicates an expected call of SendCoinsFromModuleToModule. +func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, amt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToModule", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromModuleToModule), ctx, senderModule, recipientModule, amt) +} + // MockICS4Wrapper is a mock of ICS4Wrapper interface. type MockICS4Wrapper struct { ctrl *gomock.Controller @@ -137,7 +246,7 @@ func (mr *MockICS4WrapperMockRecorder) GetAppVersion(ctx, portID, channelID inte } // SendPacket mocks base method. -func (m *MockICS4Wrapper) SendPacket(ctx types.Context, chanCap *types1.Capability, sourcePort, sourceChannel string, timeoutHeight types5.Height, timeoutTimestamp uint64, data []byte) (uint64, error) { +func (m *MockICS4Wrapper) SendPacket(ctx types.Context, chanCap *types2.Capability, sourcePort, sourceChannel string, timeoutHeight types6.Height, timeoutTimestamp uint64, data []byte) (uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SendPacket", ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) ret0, _ := ret[0].(uint64) @@ -152,7 +261,7 @@ func (mr *MockICS4WrapperMockRecorder) SendPacket(ctx, chanCap, sourcePort, sour } // WriteAcknowledgement mocks base method. -func (m *MockICS4Wrapper) WriteAcknowledgement(ctx types.Context, chanCap *types1.Capability, packet exported.PacketI, acknowledgement exported.Acknowledgement) error { +func (m *MockICS4Wrapper) WriteAcknowledgement(ctx types.Context, chanCap *types2.Capability, packet exported.PacketI, acknowledgement exported.Acknowledgement) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "WriteAcknowledgement", ctx, chanCap, packet, acknowledgement) ret0, _ := ret[0].(error) @@ -189,10 +298,10 @@ func (m *MockChannelKeeper) EXPECT() *MockChannelKeeperMockRecorder { } // GetChannel mocks base method. -func (m *MockChannelKeeper) GetChannel(ctx types.Context, portID, channelID string) (types6.Channel, bool) { +func (m *MockChannelKeeper) GetChannel(ctx types.Context, portID, channelID string) (types7.Channel, bool) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetChannel", ctx, portID, channelID) - ret0, _ := ret[0].(types6.Channel) + ret0, _ := ret[0].(types7.Channel) ret1, _ := ret[1].(bool) return ret0, ret1 } @@ -243,10 +352,10 @@ func (m *MockStakingKeeper) EXPECT() *MockStakingKeeperMockRecorder { } // GetBondedValidatorsByPower mocks base method. -func (m *MockStakingKeeper) GetBondedValidatorsByPower(ctx types.Context) []types3.Validator { +func (m *MockStakingKeeper) GetBondedValidatorsByPower(ctx types.Context) []types4.Validator { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetBondedValidatorsByPower", ctx) - ret0, _ := ret[0].([]types3.Validator) + ret0, _ := ret[0].([]types4.Validator) return ret0 } @@ -257,10 +366,10 @@ func (mr *MockStakingKeeperMockRecorder) GetBondedValidatorsByPower(ctx interfac } // GetLastTotalPower mocks base method. -func (m *MockStakingKeeper) GetLastTotalPower(ctx types.Context) types.Int { +func (m *MockStakingKeeper) GetLastTotalPower(ctx types.Context) math.Int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetLastTotalPower", ctx) - ret0, _ := ret[0].(types.Int) + ret0, _ := ret[0].(math.Int) return ret0 } @@ -285,7 +394,7 @@ func (mr *MockStakingKeeperMockRecorder) GetLastValidatorPower(ctx, operator int } // IterateBondedValidatorsByPower mocks base method. -func (m *MockStakingKeeper) IterateBondedValidatorsByPower(arg0 types.Context, arg1 func(int64, types3.ValidatorI) bool) { +func (m *MockStakingKeeper) IterateBondedValidatorsByPower(arg0 types.Context, arg1 func(int64, types4.ValidatorI) bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "IterateBondedValidatorsByPower", arg0, arg1) } @@ -297,7 +406,7 @@ func (mr *MockStakingKeeperMockRecorder) IterateBondedValidatorsByPower(arg0, ar } // IterateLastValidators mocks base method. -func (m *MockStakingKeeper) IterateLastValidators(arg0 types.Context, arg1 func(int64, types3.ValidatorI) bool) { +func (m *MockStakingKeeper) IterateLastValidators(arg0 types.Context, arg1 func(int64, types4.ValidatorI) bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "IterateLastValidators", arg0, arg1) } @@ -309,7 +418,7 @@ func (mr *MockStakingKeeperMockRecorder) IterateLastValidators(arg0, arg1 interf } // IterateValidators mocks base method. -func (m *MockStakingKeeper) IterateValidators(arg0 types.Context, arg1 func(int64, types3.ValidatorI) bool) { +func (m *MockStakingKeeper) IterateValidators(arg0 types.Context, arg1 func(int64, types4.ValidatorI) bool) { m.ctrl.T.Helper() m.ctrl.Call(m, "IterateValidators", arg0, arg1) } @@ -333,10 +442,10 @@ func (mr *MockStakingKeeperMockRecorder) Jail(arg0, arg1 interface{}) *gomock.Ca } // PowerReduction mocks base method. -func (m *MockStakingKeeper) PowerReduction(ctx types.Context) types.Int { +func (m *MockStakingKeeper) PowerReduction(ctx types.Context) math.Int { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PowerReduction", ctx) - ret0, _ := ret[0].(types.Int) + ret0, _ := ret[0].(math.Int) return ret0 } @@ -361,10 +470,10 @@ func (mr *MockStakingKeeperMockRecorder) Slash(arg0, arg1, arg2, arg3, arg4 inte } // Validator mocks base method. -func (m *MockStakingKeeper) Validator(arg0 types.Context, arg1 types.ValAddress) types3.ValidatorI { +func (m *MockStakingKeeper) Validator(arg0 types.Context, arg1 types.ValAddress) types4.ValidatorI { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Validator", arg0, arg1) - ret0, _ := ret[0].(types3.ValidatorI) + ret0, _ := ret[0].(types4.ValidatorI) return ret0 } @@ -375,10 +484,10 @@ func (mr *MockStakingKeeperMockRecorder) Validator(arg0, arg1 interface{}) *gomo } // ValidatorByConsAddr mocks base method. -func (m *MockStakingKeeper) ValidatorByConsAddr(arg0 types.Context, arg1 types.ConsAddress) types3.ValidatorI { +func (m *MockStakingKeeper) ValidatorByConsAddr(arg0 types.Context, arg1 types.ConsAddress) types4.ValidatorI { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ValidatorByConsAddr", arg0, arg1) - ret0, _ := ret[0].(types3.ValidatorI) + ret0, _ := ret[0].(types4.ValidatorI) return ret0 } @@ -412,10 +521,10 @@ func (m *MockTransferKeeper) EXPECT() *MockTransferKeeperMockRecorder { } // Transfer mocks base method. -func (m *MockTransferKeeper) Transfer(goCtx context.Context, msg *types4.MsgTransfer) (*types4.MsgTransferResponse, error) { +func (m *MockTransferKeeper) Transfer(goCtx context.Context, msg *types5.MsgTransfer) (*types5.MsgTransferResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Transfer", goCtx, msg) - ret0, _ := ret[0].(*types4.MsgTransferResponse) + ret0, _ := ret[0].(*types5.MsgTransferResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -450,10 +559,10 @@ func (m *MockDistributionKeeper) EXPECT() *MockDistributionKeeperMockRecorder { } // GetFeePool mocks base method. -func (m *MockDistributionKeeper) GetFeePool(ctx types.Context) types2.FeePool { +func (m *MockDistributionKeeper) GetFeePool(ctx types.Context) types3.FeePool { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetFeePool", ctx) - ret0, _ := ret[0].(types2.FeePool) + ret0, _ := ret[0].(types3.FeePool) return ret0 } @@ -464,7 +573,7 @@ func (mr *MockDistributionKeeperMockRecorder) GetFeePool(ctx interface{}) *gomoc } // SetFeePool mocks base method. -func (m *MockDistributionKeeper) SetFeePool(ctx types.Context, feePool types2.FeePool) { +func (m *MockDistributionKeeper) SetFeePool(ctx types.Context, feePool types3.FeePool) { m.ctrl.T.Helper() m.ctrl.Call(m, "SetFeePool", ctx, feePool) } diff --git a/x/axelarcork/tests/setup.go b/x/axelarcork/tests/setup.go index b98f3195..36b05e54 100644 --- a/x/axelarcork/tests/setup.go +++ b/x/axelarcork/tests/setup.go @@ -42,6 +42,7 @@ func NewTestSetup(t *testing.T, ctl *gomock.Controller) *Setup { initializer := newInitializer() accountKeeperMock := mocks.NewMockAccountKeeper(ctl) + bankKeeperMock := mocks.NewMockBankKeeper(ctl) transferKeeperMock := mocks.NewMockTransferKeeper(ctl) stakingKeeper := mocks.NewMockStakingKeeper(ctl) distributionKeeperMock := mocks.NewMockDistributionKeeper(ctl) @@ -51,7 +52,7 @@ func NewTestSetup(t *testing.T, ctl *gomock.Controller) *Setup { paramsKeeper := initializer.paramsKeeper() acKeeper := initializer.axelarcorkKeeper( - paramsKeeper, accountKeeperMock, stakingKeeper, transferKeeperMock, distributionKeeperMock, + paramsKeeper, accountKeeperMock, bankKeeperMock, stakingKeeper, transferKeeperMock, distributionKeeperMock, ics4WrapperMock, gravityKeeper) require.NoError(t, initializer.StateStore.LoadLatestVersion()) @@ -69,6 +70,7 @@ func NewTestSetup(t *testing.T, ctl *gomock.Controller) *Setup { Mocks: &testMocks{ AccountKeeperMock: accountKeeperMock, + BankKeeperMock: bankKeeperMock, TransferKeeperMock: transferKeeperMock, DistributionKeeperMock: distributionKeeperMock, IBCModuleMock: ibcModuleMock, @@ -95,6 +97,7 @@ type testKeepers struct { type testMocks struct { AccountKeeperMock *mocks.MockAccountKeeper + BankKeeperMock *mocks.MockBankKeeper TransferKeeperMock *mocks.MockTransferKeeper DistributionKeeperMock *mocks.MockDistributionKeeper IBCModuleMock *mocks.MockIBCModule @@ -145,6 +148,7 @@ func (i initializer) paramsKeeper() paramskeeper.Keeper { func (i initializer) axelarcorkKeeper( paramsKeeper paramskeeper.Keeper, accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, stakingKeeper types.StakingKeeper, transferKeeper types.TransferKeeper, distributionKeeper types.DistributionKeeper, @@ -160,6 +164,7 @@ func (i initializer) axelarcorkKeeper( storeKey, subspace, accountKeeper, + bankKeeper, stakingKeeper, transferKeeper, distributionKeeper, diff --git a/x/axelarcork/types/axelar_proxy.go b/x/axelarcork/types/axelar_proxy.go index 391f4b4a..400960b8 100644 --- a/x/axelarcork/types/axelar_proxy.go +++ b/x/axelarcork/types/axelar_proxy.go @@ -4,6 +4,7 @@ import ( fmt "fmt" "math/big" + errorsmod "cosmossdk.io/errors" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" ) @@ -30,6 +31,10 @@ func (ccn AxelarContractCallNonce) ValidateBasic() error { return fmt.Errorf("contract address cannot be empty") } + if !common.IsHexAddress(ccn.ContractAddress) { + return errorsmod.Wrapf(ErrInvalidEVMAddress, "%s", ccn.ContractAddress) + } + if ccn.ChainId == 0 { return fmt.Errorf("chain ID cannot be zero") } diff --git a/x/axelarcork/types/chain_config.go b/x/axelarcork/types/chain_config.go index 74b759be..dbbdf645 100644 --- a/x/axelarcork/types/chain_config.go +++ b/x/axelarcork/types/chain_config.go @@ -2,6 +2,9 @@ package types import ( "fmt" + + errorsmod "cosmossdk.io/errors" + "github.com/ethereum/go-ethereum/common" ) func (cc ChainConfiguration) ValidateBasic() error { @@ -9,6 +12,10 @@ func (cc ChainConfiguration) ValidateBasic() error { return fmt.Errorf("proxy address cannot be empty") } + if !common.IsHexAddress(cc.ProxyAddress) { + return errorsmod.Wrapf(ErrInvalidEVMAddress, "%s", cc.ProxyAddress) + } + if cc.Id == 0 { return fmt.Errorf("chain ID cannot be zero") } diff --git a/x/axelarcork/types/expected_keepers.go b/x/axelarcork/types/expected_keepers.go index dcdefa82..7384b173 100644 --- a/x/axelarcork/types/expected_keepers.go +++ b/x/axelarcork/types/expected_keepers.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -28,6 +29,16 @@ type AccountKeeper interface { SetModuleAccount(sdk.Context, authtypes.ModuleAccountI) } +// BankKeeper defines the expected bank keeper methods +type BankKeeper interface { + GetSupply(ctx sdk.Context, denom string) sdk.Coin + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool) +} + type ICS4Wrapper interface { WriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, acknowledgement ibcexported.Acknowledgement) error SendPacket(ctx sdk.Context, chanCap *capabilitytypes.Capability, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte) (sequence uint64, err error) diff --git a/x/axelarcork/types/keys.go b/x/axelarcork/types/keys.go index d0f41e55..dacf52bc 100644 --- a/x/axelarcork/types/keys.go +++ b/x/axelarcork/types/keys.go @@ -74,9 +74,9 @@ func GetScheduledAxelarCorkKeyByBlockHeightPrefix(chainID uint64, blockHeight ui return append(GetScheduledAxelarCorkKeyPrefix(chainID), sdk.Uint64ToBigEndian(blockHeight)...) } -func GetScheduledAxelarCorkKey(chainID uint64, blockHeight uint64, id []byte, val sdk.ValAddress, contract common.Address, deadline uint64) []byte { +func GetScheduledAxelarCorkKey(chainID uint64, blockHeight uint64, id []byte, val sdk.ValAddress, contract common.Address) []byte { blockHeightBytes := sdk.Uint64ToBigEndian(blockHeight) - return bytes.Join([][]byte{GetScheduledAxelarCorkKeyPrefix(chainID), blockHeightBytes, id, val.Bytes(), contract.Bytes(), sdk.Uint64ToBigEndian(deadline)}, []byte{}) + return bytes.Join([][]byte{GetScheduledAxelarCorkKeyPrefix(chainID), blockHeightBytes, id, val.Bytes(), contract.Bytes()}, []byte{}) } func GetAxelarCorkResultPrefix(chainID uint64) []byte { @@ -101,10 +101,10 @@ func GetWinningAxelarCorkKeyPrefix(chainID uint64) []byte { return bytes.Join([][]byte{{WinningCorkPrefix}, cid}, []byte{}) } -func GetWinningAxelarCorkKey(chainID uint64, blockheight uint64, address common.Address, deadline uint64) []byte { +func GetWinningAxelarCorkKey(chainID uint64, blockheight uint64, address common.Address) []byte { bh := make([]byte, 8) binary.BigEndian.PutUint64(bh, blockheight) - return bytes.Join([][]byte{GetWinningAxelarCorkKeyPrefix(chainID), bh, address.Bytes(), sdk.Uint64ToBigEndian(deadline)}, []byte{}) + return bytes.Join([][]byte{GetWinningAxelarCorkKeyPrefix(chainID), bh, address.Bytes()}, []byte{}) } func GetAxelarContractCallNonceKey(chainID uint64, contractAddress common.Address) []byte { diff --git a/x/axelarcork/types/msgs.go b/x/axelarcork/types/msgs.go index d9343a38..58f42913 100644 --- a/x/axelarcork/types/msgs.go +++ b/x/axelarcork/types/msgs.go @@ -21,9 +21,9 @@ const ( TypeMsgRelayAxelarProxyUpgradeRequest = "axelar_proxy_upgrade_relay" ) -//////////////////////////// +////////////////////////////////// // MsgScheduleAxelarCorkRequest // -//////////////////////////// +////////////////////////////////// // NewMsgScheduleCorkRequest return a new MsgScheduleAxelarCorkRequest func NewMsgScheduleCorkRequest(chainID uint64, body []byte, address common.Address, deadline uint64, blockHeight uint64, signer sdk.AccAddress) (*MsgScheduleAxelarCorkRequest, error) { @@ -73,9 +73,9 @@ func (m *MsgScheduleAxelarCorkRequest) MustGetSigner() sdk.AccAddress { return addr } -///////////////////////// +/////////////////////////////// // MsgRelayAxelarCorkRequest // -///////////////////////// +/////////////////////////////// // Route implements sdk.Msg func (m *MsgRelayAxelarCorkRequest) Route() string { return ModuleName } @@ -93,6 +93,10 @@ func (m *MsgRelayAxelarCorkRequest) ValidateBasic() error { return fmt.Errorf("cannot relay a cork to an empty address") } + if !common.IsHexAddress(m.TargetContractAddress) { + return errorsmod.Wrapf(ErrInvalidEVMAddress, "%s", m.TargetContractAddress) + } + return nil } @@ -115,9 +119,9 @@ func (m *MsgRelayAxelarCorkRequest) MustGetSigner() sdk.AccAddress { return addr } -/////////////////////////////// +/////////////////////////////////////// // MsgRelayAxelarProxyUpgradeRequest // -/////////////////////////////// +/////////////////////////////////////// // Route implements sdk.Msg func (m *MsgRelayAxelarProxyUpgradeRequest) Route() string { return ModuleName } @@ -155,9 +159,9 @@ func (m *MsgRelayAxelarProxyUpgradeRequest) MustGetSigner() sdk.AccAddress { return addr } -/////////////////////////// +///////////////////////////////// // MsgBumpAxelarCorkGasRequest // -/////////////////////////// +///////////////////////////////// // Route implements sdk.Msg func (m *MsgBumpAxelarCorkGasRequest) Route() string { return ModuleName } @@ -193,9 +197,9 @@ func (m *MsgBumpAxelarCorkGasRequest) MustGetSigner() sdk.AccAddress { return addr } -/////////////////////////// +//////////////////////////////// // MsgCancelAxelarCorkRequest // -/////////////////////////// +//////////////////////////////// // Route implements sdk.Msg func (m *MsgCancelAxelarCorkRequest) Route() string { return ModuleName } @@ -209,6 +213,14 @@ func (m *MsgCancelAxelarCorkRequest) ValidateBasic() error { return errorsmod.Wrap(sdkerrors.ErrInvalidAddress, err.Error()) } + if m.TargetContractAddress == "" { + return fmt.Errorf("cannot relay a cork to an empty address") + } + + if !common.IsHexAddress(m.TargetContractAddress) { + return errorsmod.Wrapf(ErrInvalidEVMAddress, "%s", m.TargetContractAddress) + } + return nil } diff --git a/x/axelarcork/types/proposal.go b/x/axelarcork/types/proposal.go index 00e9539a..9deee249 100644 --- a/x/axelarcork/types/proposal.go +++ b/x/axelarcork/types/proposal.go @@ -91,6 +91,12 @@ func (m *AddAxelarManagedCellarIDsProposal) ValidateBasic() error { return fmt.Errorf("can't have an add prosoposal with no cellars") } + for _, cellarID := range m.CellarIds.Ids { + if !common.IsHexAddress(cellarID) { + return errorsmod.Wrapf(ErrInvalidEVMAddress, "%s", cellarID) + } + } + return nil } diff --git a/x/cork/keeper/msg_server.go b/x/cork/keeper/msg_server.go index fba75ccf..21ff45e3 100644 --- a/x/cork/keeper/msg_server.go +++ b/x/cork/keeper/msg_server.go @@ -19,6 +19,12 @@ var _ types.MsgServer = Keeper{} func (k Keeper) ScheduleCork(c context.Context, msg *types.MsgScheduleCorkRequest) (*types.MsgScheduleCorkResponse, error) { ctx := sdk.UnwrapSDKContext(c) + signer := msg.MustGetSigner() + validatorAddr := k.gravityKeeper.GetOrchestratorValidatorAddress(ctx, signer) + if validatorAddr == nil { + return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "signer %s is not a delegate", signer.String()) + } + if !k.HasCellarID(ctx, common.HexToAddress(msg.Cork.TargetContractAddress)) { return nil, types.ErrUnmanagedCellarAddress } @@ -27,12 +33,6 @@ func (k Keeper) ScheduleCork(c context.Context, msg *types.MsgScheduleCorkReques return nil, types.ErrSchedulingInThePast } - signer := msg.MustGetSigner() - validatorAddr := k.gravityKeeper.GetOrchestratorValidatorAddress(ctx, signer) - if validatorAddr == nil { - return nil, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "signer %s is not a delegate", signer.String()) - } - corkID := k.SetScheduledCork(ctx, msg.BlockHeight, validatorAddr, *msg.Cork) ctx.EventManager().EmitEvents(