diff --git a/changelog.md b/changelog.md index a9b7f0b428..b5ac8bbca4 100644 --- a/changelog.md +++ b/changelog.md @@ -40,6 +40,7 @@ * [1584](https://github.com/zeta-chain/node/pull/1584) - allow to run E2E tests on any networks * [1753](https://github.com/zeta-chain/node/pull/1753) - fix gosec errors on usage of rand package +* [1762](https://github.com/zeta-chain/node/pull/1762) - improve coverage for fungibile module ### CI diff --git a/testutil/keeper/fungible.go b/testutil/keeper/fungible.go index 0ef4e981f4..5f9f2b0cfd 100644 --- a/testutil/keeper/fungible.go +++ b/testutil/keeper/fungible.go @@ -1,6 +1,7 @@ package keeper import ( + "math/big" "testing" "github.com/cosmos/cosmos-sdk/codec" @@ -8,9 +9,13 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + "github.com/evmos/ethermint/x/evm/statedb" + evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" tmdb "github.com/tendermint/tm-db" fungiblemocks "github.com/zeta-chain/zetacore/testutil/keeper/mocks/fungible" + "github.com/zeta-chain/zetacore/testutil/sample" fungiblemodule "github.com/zeta-chain/zetacore/x/fungible" "github.com/zeta-chain/zetacore/x/fungible/keeper" "github.com/zeta-chain/zetacore/x/fungible/types" @@ -164,8 +169,73 @@ func GetFungibleObserverMock(t testing.TB, keeper *keeper.Keeper) *fungiblemocks return fok } -func GetFungibleEVMMock(t testing.TB, keeper *keeper.Keeper) *fungiblemocks.FungibleEVMKeeper { +func GetFungibleEVMMock(t testing.TB, keeper *keeper.Keeper) *FungibleMockEVMKeeper { fek, ok := keeper.GetEVMKeeper().(*fungiblemocks.FungibleEVMKeeper) require.True(t, ok) - return fek + return &FungibleMockEVMKeeper{ + FungibleEVMKeeper: fek, + } +} + +type FungibleMockEVMKeeper struct { + *fungiblemocks.FungibleEVMKeeper +} + +func (m *FungibleMockEVMKeeper) SetupMockEVMKeeperForSystemContractDeployment() { + gasRes := &evmtypes.EstimateGasResponse{Gas: 1000} + m.On("WithChainID", mock.Anything).Maybe().Return(mock.Anything) + m.On("ChainID").Maybe().Return(big.NewInt(1)) + m.On( + "EstimateGas", + mock.Anything, + mock.Anything, + ).Return(gasRes, nil) + m.MockEVMSuccessCallTimes(5) + m.On( + "GetAccount", + mock.Anything, + mock.Anything, + ).Return(&statedb.Account{ + Nonce: 1, + }) + m.On( + "GetCode", + mock.Anything, + mock.Anything, + ).Return([]byte{1, 2, 3}) +} + +func (m *FungibleMockEVMKeeper) MockEVMSuccessCallOnce() { + m.MockEVMSuccessCallOnceWithReturn(&evmtypes.MsgEthereumTxResponse{}) +} + +func (m *FungibleMockEVMKeeper) MockEVMSuccessCallTimes(times int) { + m.MockEVMSuccessCallTimesWithReturn(&evmtypes.MsgEthereumTxResponse{}, times) +} + +func (m *FungibleMockEVMKeeper) MockEVMSuccessCallOnceWithReturn(ret *evmtypes.MsgEthereumTxResponse) { + m.MockEVMSuccessCallTimesWithReturn(ret, 1) +} + +func (m *FungibleMockEVMKeeper) MockEVMSuccessCallTimesWithReturn(ret *evmtypes.MsgEthereumTxResponse, times int) { + if ret == nil { + ret = &evmtypes.MsgEthereumTxResponse{} + } + m.On( + "ApplyMessage", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return(ret, nil).Times(times) +} + +func (m *FungibleMockEVMKeeper) MockEVMFailCallOnce() { + m.On( + "ApplyMessage", + mock.Anything, + mock.Anything, + mock.Anything, + mock.Anything, + ).Return(&evmtypes.MsgEthereumTxResponse{}, sample.ErrSample).Once() } diff --git a/testutil/keeper/mocks/fungible/evm.go b/testutil/keeper/mocks/fungible/evm.go index bdfd9e8130..b59f7d477e 100644 --- a/testutil/keeper/mocks/fungible/evm.go +++ b/testutil/keeper/mocks/fungible/evm.go @@ -146,6 +146,26 @@ func (_m *FungibleEVMKeeper) GetBlockBloomTransient(ctx types.Context) *big.Int return r0 } +// GetCode provides a mock function with given fields: ctx, codeHash +func (_m *FungibleEVMKeeper) GetCode(ctx types.Context, codeHash common.Hash) []byte { + ret := _m.Called(ctx, codeHash) + + if len(ret) == 0 { + panic("no return value specified for GetCode") + } + + var r0 []byte + if rf, ok := ret.Get(0).(func(types.Context, common.Hash) []byte); ok { + r0 = rf(ctx, codeHash) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + return r0 +} + // GetLogSizeTransient provides a mock function with given fields: ctx func (_m *FungibleEVMKeeper) GetLogSizeTransient(ctx types.Context) uint64 { ret := _m.Called(ctx) diff --git a/x/fungible/keeper/evm_test.go b/x/fungible/keeper/evm_test.go index b6810a6998..df8037aa06 100644 --- a/x/fungible/keeper/evm_test.go +++ b/x/fungible/keeper/evm_test.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - evmkeeper "github.com/evmos/ethermint/x/evm/keeper" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -18,7 +17,6 @@ import ( "github.com/zeta-chain/zetacore/testutil/contracts" testkeeper "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" - "github.com/zeta-chain/zetacore/x/fungible/keeper" fungiblekeeper "github.com/zeta-chain/zetacore/x/fungible/keeper" "github.com/zeta-chain/zetacore/x/fungible/types" ) @@ -33,7 +31,7 @@ func getValidChainID(t *testing.T) int64 { } // require that a contract has been deployed by checking stored code is non-empty. -func assertContractDeployment(t *testing.T, k *evmkeeper.Keeper, ctx sdk.Context, contractAddress common.Address) { +func assertContractDeployment(t *testing.T, k types.EVMKeeper, ctx sdk.Context, contractAddress common.Address) { acc := k.GetAccount(ctx, contractAddress) require.NotNil(t, acc) @@ -41,12 +39,22 @@ func assertContractDeployment(t *testing.T, k *evmkeeper.Keeper, ctx sdk.Context require.NotEmpty(t, code) } +func deploySystemContractsWithMockEvmKeeper( + t *testing.T, + ctx sdk.Context, + k *fungiblekeeper.Keeper, + mockEVMKeeper *testkeeper.FungibleMockEVMKeeper, +) (wzeta, uniswapV2Factory, uniswapV2Router, connector, systemContract common.Address) { + mockEVMKeeper.SetupMockEVMKeeperForSystemContractDeployment() + return deploySystemContracts(t, ctx, k, mockEVMKeeper) +} + // deploySystemContracts deploys the system contracts and returns their addresses. func deploySystemContracts( t *testing.T, ctx sdk.Context, k *fungiblekeeper.Keeper, - evmk *evmkeeper.Keeper, + evmk types.EVMKeeper, ) (wzeta, uniswapV2Factory, uniswapV2Router, connector, systemContract common.Address) { var err error @@ -82,7 +90,7 @@ func deploySystemContracts( func assertExampleBarValue( t *testing.T, ctx sdk.Context, - k *keeper.Keeper, + k *fungiblekeeper.Keeper, address common.Address, expected int64, ) { @@ -99,6 +107,7 @@ func assertExampleBarValue( false, "bar", ) + require.NoError(t, err) unpacked, err := exampleABI.Unpack("bar", res.Ret) require.NoError(t, err) require.NotZero(t, len(unpacked)) @@ -263,6 +272,7 @@ func TestKeeper_DepositZRC20AndCallContract(t *testing.T) { false, "bar", ) + require.NoError(t, err) unpacked, err := exampleABI.Unpack("bar", res.Ret) require.NoError(t, err) require.NotZero(t, len(unpacked)) @@ -448,13 +458,7 @@ func TestKeeper_CallEVMWithData(t *testing.T) { mock.Anything, &evmtypes.EthCallRequest{Args: args, GasCap: config.DefaultGasCap}, ).Return(gasRes, nil) - mockEVMKeeper.On( - "ApplyMessage", - ctx, - mock.Anything, - mock.Anything, - mock.Anything, - ).Return(msgRes, nil) + mockEVMKeeper.MockEVMSuccessCallOnce() mockEVMKeeper.On("WithChainID", mock.Anything).Maybe().Return(ctx) mockEVMKeeper.On("ChainID").Maybe().Return(big.NewInt(1)) @@ -497,13 +501,7 @@ func TestKeeper_CallEVMWithData(t *testing.T) { mock.Anything, sdk.AccAddress(fromAddr.Bytes()), ).Return(uint64(1), nil) - mockEVMKeeper.On( - "ApplyMessage", - ctx, - mock.Anything, - mock.Anything, - mock.Anything, - ).Return(msgRes, nil) + mockEVMKeeper.MockEVMSuccessCallOnce() mockEVMKeeper.On("WithChainID", mock.Anything).Maybe().Return(ctx) mockEVMKeeper.On("ChainID").Maybe().Return(big.NewInt(1)) @@ -604,7 +602,6 @@ func TestKeeper_CallEVMWithData(t *testing.T) { Data: (*hexutil.Bytes)(&data), }) gasRes := &evmtypes.EstimateGasResponse{Gas: 1000} - msgRes := &evmtypes.MsgEthereumTxResponse{} // Set up mocked methods mockAuthKeeper.On( @@ -617,13 +614,7 @@ func TestKeeper_CallEVMWithData(t *testing.T) { mock.Anything, &evmtypes.EthCallRequest{Args: args, GasCap: config.DefaultGasCap}, ).Return(gasRes, nil) - mockEVMKeeper.On( - "ApplyMessage", - ctx, - mock.Anything, - mock.Anything, - mock.Anything, - ).Return(msgRes, sample.ErrSample) + mockEVMKeeper.MockEVMFailCallOnce() mockEVMKeeper.On("WithChainID", mock.Anything).Maybe().Return(ctx) mockEVMKeeper.On("ChainID").Maybe().Return(big.NewInt(1)) diff --git a/x/fungible/keeper/foreign_coins.go b/x/fungible/keeper/foreign_coins.go index faa96d2876..028c961609 100644 --- a/x/fungible/keeper/foreign_coins.go +++ b/x/fungible/keeper/foreign_coins.go @@ -1,8 +1,6 @@ package keeper import ( - "fmt" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" @@ -12,7 +10,7 @@ import ( // SetForeignCoins set a specific foreignCoins in the store from its index func (k Keeper) SetForeignCoins(ctx sdk.Context, foreignCoins types.ForeignCoins) { - p := types.KeyPrefix(fmt.Sprintf("%s", types.ForeignCoinsKeyPrefix)) + p := types.KeyPrefix(types.ForeignCoinsKeyPrefix) store := prefix.NewStore(ctx.KVStore(k.storeKey), p) b := k.cdc.MustMarshal(&foreignCoins) store.Set(types.ForeignCoinsKey( @@ -25,7 +23,7 @@ func (k Keeper) GetForeignCoins( ctx sdk.Context, zrc20Addr string, ) (val types.ForeignCoins, found bool) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(fmt.Sprintf("%s", types.ForeignCoinsKeyPrefix))) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ForeignCoinsKeyPrefix)) b := store.Get(types.ForeignCoinsKey( zrc20Addr, @@ -51,7 +49,7 @@ func (k Keeper) RemoveForeignCoins( // GetAllForeignCoinsForChain returns all foreignCoins on a given chain func (k Keeper) GetAllForeignCoinsForChain(ctx sdk.Context, foreignChainID int64) (list []types.ForeignCoins) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(fmt.Sprintf("%s", types.ForeignCoinsKeyPrefix))) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ForeignCoinsKeyPrefix)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) defer iterator.Close() @@ -68,7 +66,7 @@ func (k Keeper) GetAllForeignCoinsForChain(ctx sdk.Context, foreignChainID int64 // GetAllForeignCoins returns all foreignCoins func (k Keeper) GetAllForeignCoins(ctx sdk.Context) (list []types.ForeignCoins) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(fmt.Sprintf("%s", types.ForeignCoinsKeyPrefix))) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ForeignCoinsKeyPrefix)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) defer iterator.Close() diff --git a/x/fungible/keeper/gas_coin_and_pool_test.go b/x/fungible/keeper/gas_coin_and_pool_test.go index 9bdd139fdc..b6f05431ac 100644 --- a/x/fungible/keeper/gas_coin_and_pool_test.go +++ b/x/fungible/keeper/gas_coin_and_pool_test.go @@ -19,7 +19,7 @@ func setupGasCoin( t *testing.T, ctx sdk.Context, k *fungiblekeeper.Keeper, - evmk *evmkeeper.Keeper, + evmk types.EVMKeeper, chainID int64, assetName string, symbol string, diff --git a/x/fungible/keeper/gas_price.go b/x/fungible/keeper/gas_price.go index 3f2ee63d28..58ca702b69 100644 --- a/x/fungible/keeper/gas_price.go +++ b/x/fungible/keeper/gas_price.go @@ -12,6 +12,9 @@ import ( // SetGasPrice sets gas price on the system contract in zEVM; return the gasUsed and error code func (k Keeper) SetGasPrice(ctx sdk.Context, chainid *big.Int, gasPrice *big.Int) (uint64, error) { + if gasPrice == nil { + return 0, sdkerrors.Wrapf(types.ErrNilGasPrice, "gas price param should be set") + } system, found := k.GetSystemContract(ctx) if !found { return 0, sdkerrors.Wrapf(types.ErrContractNotFound, "system contract state variable not found") diff --git a/x/fungible/keeper/gas_price_test.go b/x/fungible/keeper/gas_price_test.go index ec1bf267d8..acd03d359b 100644 --- a/x/fungible/keeper/gas_price_test.go +++ b/x/fungible/keeper/gas_price_test.go @@ -36,6 +36,47 @@ func TestKeeper_SetGasPrice(t *testing.T) { require.Equal(t, big.NewInt(42), queryGasPrice(big.NewInt(1))) } +func TestKeeper_SetGasPriceContractNotFound(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + _, err := k.SetGasPrice(ctx, big.NewInt(1), big.NewInt(42)) + require.ErrorIs(t, err, types.ErrContractNotFound) +} + +func TestKeeper_SetNilGasPrice(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + _, err := k.SetGasPrice(ctx, big.NewInt(1), nil) + require.ErrorIs(t, err, types.ErrNilGasPrice) +} + +func TestKeeper_SetGasPriceContractIs0x0(t *testing.T) { + k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) + k.SetSystemContract(ctx, types.SystemContract{}) + + _, err := k.SetGasPrice(ctx, big.NewInt(1), big.NewInt(42)) + require.ErrorIs(t, err, types.ErrContractNotFound) +} + +func TestKeeper_SetGasPriceReverts(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMFailCallOnce() + _, err := k.SetGasPrice(ctx, big.NewInt(1), big.NewInt(1)) + require.ErrorIs(t, err, types.ErrContractCall) +} + func TestKeeper_SetGasCoin(t *testing.T) { k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) @@ -50,6 +91,41 @@ func TestKeeper_SetGasCoin(t *testing.T) { require.Equal(t, gas.Hex(), found.Hex()) } +func TestKeeper_SetGasCoinContractNotFound(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + gas := sample.EthAddress() + + err := k.SetGasCoin(ctx, big.NewInt(1), gas) + require.ErrorIs(t, err, types.ErrContractNotFound) +} + +func TestKeeper_SetGasCoinContractIs0x0(t *testing.T) { + k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + gas := sample.EthAddress() + + deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) + k.SetSystemContract(ctx, types.SystemContract{}) + + err := k.SetGasCoin(ctx, big.NewInt(1), gas) + require.ErrorIs(t, err, types.ErrContractNotFound) +} + +func TestKeeper_SetGasCoinReverts(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMFailCallOnce() + err := k.SetGasCoin(ctx, big.NewInt(1), sample.EthAddress()) + require.ErrorIs(t, err, types.ErrContractCall) +} + func TestKeeper_SetGasZetaPool(t *testing.T) { k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) @@ -73,3 +149,38 @@ func TestKeeper_SetGasZetaPool(t *testing.T) { require.NoError(t, err) require.NotEqual(t, ethcommon.Address{}, queryZetaPool(big.NewInt(1))) } + +func TestKeeper_SetGasZetaPoolContractNotFound(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + zrc20 := sample.EthAddress() + + err := k.SetGasZetaPool(ctx, big.NewInt(1), zrc20) + require.ErrorIs(t, err, types.ErrContractNotFound) +} + +func TestKeeper_SetGasZetaPoolContractIs0x0(t *testing.T) { + k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + zrc20 := sample.EthAddress() + + deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) + k.SetSystemContract(ctx, types.SystemContract{}) + + err := k.SetGasZetaPool(ctx, big.NewInt(1), zrc20) + require.ErrorIs(t, err, types.ErrContractNotFound) +} + +func TestKeeper_SetGasZetaPoolReverts(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMFailCallOnce() + err := k.SetGasZetaPool(ctx, big.NewInt(1), sample.EthAddress()) + require.ErrorIs(t, err, types.ErrContractCall) +} diff --git a/x/fungible/keeper/msg_server_update_system_contract_test.go b/x/fungible/keeper/msg_server_update_system_contract_test.go index b464da209c..0fbc261c47 100644 --- a/x/fungible/keeper/msg_server_update_system_contract_test.go +++ b/x/fungible/keeper/msg_server_update_system_contract_test.go @@ -6,9 +6,10 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/common" + evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/stretchr/testify/require" "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/systemcontract.sol" - "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" + zrc20 "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" zetacommon "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/testutil/sample" @@ -74,6 +75,49 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { require.Equal(t, newSystemContract.Hex(), queryZRC20SystemContract(gas2)) }) + t.Run("can update and overwrite the system contract if system contract not found", func(t *testing.T) { + k, ctx, _, zk := keepertest.FungibleKeeper(t) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin, observertypes.Policy_Type_group2) + + wzeta, err := k.DeployWZETA(ctx) + require.NoError(t, err) + + factory, err := k.DeployUniswapV2Factory(ctx) + require.NoError(t, err) + + router, err := k.DeployUniswapV2Router02(ctx, factory, wzeta) + require.NoError(t, err) + + // deploy a new system contracts + newSystemContract, err := k.DeployContract(ctx, systemcontract.SystemContractMetaData, wzeta, factory, router) + require.NoError(t, err) + + // can update the system contract + _, err = msgServer.UpdateSystemContract(ctx, types.NewMsgUpdateSystemContract(admin, newSystemContract.Hex())) + require.NoError(t, err) + + // can retrieve the system contract + sc, found := k.GetSystemContract(ctx) + require.True(t, found) + require.Equal(t, newSystemContract.Hex(), sc.SystemContract) + + // deploy a new system contracts + newSystemContract, err = k.DeployContract(ctx, systemcontract.SystemContractMetaData, wzeta, factory, router) + require.NoError(t, err) + + // can overwrite the previous system contract + _, err = msgServer.UpdateSystemContract(ctx, types.NewMsgUpdateSystemContract(admin, newSystemContract.Hex())) + require.NoError(t, err) + + // can retrieve the system contract + sc, found = k.GetSystemContract(ctx) + require.True(t, found) + require.Equal(t, newSystemContract.Hex(), sc.SystemContract) + }) + t.Run("should not update the system contract if not admin", func(t *testing.T) { k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) msgServer := keeper.NewMsgServerImpl(*k) @@ -109,4 +153,68 @@ func TestKeeper_UpdateSystemContract(t *testing.T) { require.Error(t, err) require.ErrorIs(t, err, sdkerrors.ErrInvalidAddress) }) + + t.Run("should not update if any of 3 evm calls for foreign coin fail", func(t *testing.T) { + k, ctx, _, zk := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + msgServer := keeper.NewMsgServerImpl(*k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + admin := sample.AccAddress() + setAdminPolicies(ctx, zk, admin, observertypes.Policy_Type_group2) + + chains := zetacommon.DefaultChainsList() + require.True(t, len(chains) > 1) + require.NotNil(t, chains[0]) + chainID1 := chains[0].ChainId + + wzeta, factory, router, _, _ := deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + // setup mocks and setup gas coin + var encodedAddress [32]byte + copy(encodedAddress[12:], router[:]) + uniswapMock := &evmtypes.MsgEthereumTxResponse{ + Ret: encodedAddress[:], + } + mockEVMKeeper.MockEVMSuccessCallTimes(4) + mockEVMKeeper.MockEVMSuccessCallOnceWithReturn(uniswapMock) + mockEVMKeeper.MockEVMSuccessCallOnce() + + addLiqMockReturn := &evmtypes.MsgEthereumTxResponse{ + Ret: make([]byte, 3*32), + } + mockEVMKeeper.MockEVMSuccessCallOnceWithReturn(addLiqMockReturn) + + setupGasCoin(t, ctx, k, mockEVMKeeper, chainID1, "foo", "foo") + + // deploy a new system contracts + mockEVMKeeper.MockEVMSuccessCallOnce() + newSystemContract, err := k.DeployContract(ctx, systemcontract.SystemContractMetaData, wzeta, factory, router) + require.NoError(t, err) + + // fail on first evm call + mockEVMKeeper.MockEVMFailCallOnce() + + // can't update the system contract + _, err = msgServer.UpdateSystemContract(ctx, types.NewMsgUpdateSystemContract(admin, newSystemContract.Hex())) + require.ErrorIs(t, err, types.ErrContractCall) + + // fail on second evm call + mockEVMKeeper.MockEVMSuccessCallOnce() + mockEVMKeeper.MockEVMFailCallOnce() + + // can't update the system contract + _, err = msgServer.UpdateSystemContract(ctx, types.NewMsgUpdateSystemContract(admin, newSystemContract.Hex())) + require.ErrorIs(t, err, types.ErrContractCall) + + // fail on third evm call + mockEVMKeeper.MockEVMSuccessCallTimes(2) + mockEVMKeeper.MockEVMFailCallOnce() + + // can't update the system contract + _, err = msgServer.UpdateSystemContract(ctx, types.NewMsgUpdateSystemContract(admin, newSystemContract.Hex())) + require.ErrorIs(t, err, types.ErrContractCall) + }) } diff --git a/x/fungible/keeper/msg_server_update_zrc20_paused_status_test.go b/x/fungible/keeper/msg_server_update_zrc20_paused_status_test.go index bc4238a780..82b6beb977 100644 --- a/x/fungible/keeper/msg_server_update_zrc20_paused_status_test.go +++ b/x/fungible/keeper/msg_server_update_zrc20_paused_status_test.go @@ -156,12 +156,13 @@ func TestKeeper_UpdateZRC20PausedStatus(t *testing.T) { []string{sample.EthAddress().String()}, types.UpdatePausedStatusAction_PAUSE, )) + require.ErrorIs(t, err, sdkerrors.ErrUnauthorized) admin := sample.AccAddress() setAdminPolicies(ctx, zk, admin, observertypes.Policy_Type_group1) _, err = msgServer.UpdateZRC20PausedStatus(ctx, types.NewMsgUpdateZRC20PausedStatus( - sample.AccAddress(), + admin, []string{sample.EthAddress().String()}, types.UpdatePausedStatusAction_UNPAUSE, )) diff --git a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go index 108c70c664..29a5e157ae 100644 --- a/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go +++ b/x/fungible/keeper/msg_server_update_zrc20_withdraw_fee_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "errors" "math/big" "testing" @@ -176,32 +175,14 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { require.NoError(t, err) protocolFlatFee, err := zrc20ABI.Methods["PROTOCOL_FLAT_FEE"].Outputs.Pack(big.NewInt(42)) require.NoError(t, err) - mockEVMKeeper.On( - "ApplyMessage", - mock.Anything, - mock.Anything, - mock.Anything, - false, - ).Return(&evmtypes.MsgEthereumTxResponse{Ret: protocolFlatFee}, nil) + mockEVMKeeper.MockEVMSuccessCallOnceWithReturn(&evmtypes.MsgEthereumTxResponse{Ret: protocolFlatFee}) gasLimit, err := zrc20ABI.Methods["GAS_LIMIT"].Outputs.Pack(big.NewInt(42)) require.NoError(t, err) - mockEVMKeeper.On( - "ApplyMessage", - mock.Anything, - mock.Anything, - mock.Anything, - false, - ).Return(&evmtypes.MsgEthereumTxResponse{Ret: gasLimit}, nil) + mockEVMKeeper.MockEVMSuccessCallOnceWithReturn(&evmtypes.MsgEthereumTxResponse{Ret: gasLimit}) // this is the update call (commit == true) - mockEVMKeeper.On( - "ApplyMessage", - mock.Anything, - mock.Anything, - mock.Anything, - true, - ).Return(&evmtypes.MsgEthereumTxResponse{}, errors.New("transaction failed")) + mockEVMKeeper.MockEVMFailCallOnce() _, err = msgServer.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( admin, @@ -239,32 +220,14 @@ func TestKeeper_UpdateZRC20WithdrawFee(t *testing.T) { require.NoError(t, err) protocolFlatFee, err := zrc20ABI.Methods["PROTOCOL_FLAT_FEE"].Outputs.Pack(big.NewInt(42)) require.NoError(t, err) - mockEVMKeeper.On( - "ApplyMessage", - mock.Anything, - mock.Anything, - mock.Anything, - false, - ).Return(&evmtypes.MsgEthereumTxResponse{Ret: protocolFlatFee}, nil) + mockEVMKeeper.MockEVMSuccessCallOnceWithReturn(&evmtypes.MsgEthereumTxResponse{Ret: protocolFlatFee}) gasLimit, err := zrc20ABI.Methods["GAS_LIMIT"].Outputs.Pack(big.NewInt(42)) require.NoError(t, err) - mockEVMKeeper.On( - "ApplyMessage", - mock.Anything, - mock.Anything, - mock.Anything, - false, - ).Return(&evmtypes.MsgEthereumTxResponse{Ret: gasLimit}, nil) + mockEVMKeeper.MockEVMSuccessCallOnceWithReturn(&evmtypes.MsgEthereumTxResponse{Ret: gasLimit}) // this is the update call (commit == true) - mockEVMKeeper.On( - "ApplyMessage", - mock.Anything, - mock.Anything, - mock.Anything, - true, - ).Return(&evmtypes.MsgEthereumTxResponse{}, errors.New("transaction failed")) + mockEVMKeeper.MockEVMFailCallOnce() _, err = msgServer.UpdateZRC20WithdrawFee(ctx, types.NewMsgUpdateZRC20WithdrawFee( admin, diff --git a/x/fungible/keeper/system_contract.go b/x/fungible/keeper/system_contract.go index a6e1ae8e03..be531f1597 100644 --- a/x/fungible/keeper/system_contract.go +++ b/x/fungible/keeper/system_contract.go @@ -77,7 +77,8 @@ func (k *Keeper) GetWZetaContractAddress(ctx sdk.Context) (ethcommon.Address, er "wZetaContractAddress", ) if err != nil { - return ethcommon.Address{}, cosmoserrors.Wrapf(err, "failed to call wZetaContractAddress") + return ethcommon.Address{}, cosmoserrors.Wrapf(types.ErrContractCall, "failed to call wZetaContractAddress (%s)", err.Error()) + } type AddressResponse struct { Value ethcommon.Address @@ -113,7 +114,7 @@ func (k *Keeper) GetUniswapV2FactoryAddress(ctx sdk.Context) (ethcommon.Address, "uniswapv2FactoryAddress", ) if err != nil { - return ethcommon.Address{}, cosmoserrors.Wrapf(err, "failed to call uniswapv2FactoryAddress") + return ethcommon.Address{}, cosmoserrors.Wrapf(types.ErrContractCall, "failed to call uniswapv2FactoryAddress (%s)", err.Error()) } type AddressResponse struct { Value ethcommon.Address @@ -149,7 +150,7 @@ func (k *Keeper) GetUniswapV2Router02Address(ctx sdk.Context) (ethcommon.Address "uniswapv2Router02Address", ) if err != nil { - return ethcommon.Address{}, cosmoserrors.Wrapf(err, "failed to call uniswapv2Router02Address") + return ethcommon.Address{}, cosmoserrors.Wrapf(types.ErrContractCall, "failed to call uniswapv2Router02Address (%s)", err.Error()) } type AddressResponse struct { Value ethcommon.Address @@ -185,7 +186,7 @@ func (k *Keeper) CallWZetaDeposit(ctx sdk.Context, sender ethcommon.Address, amo "deposit", ) if err != nil { - return cosmoserrors.Wrapf(err, "failed to call wzeta deposit") + return cosmoserrors.Wrapf(types.ErrContractCall, "failed to call wzeta deposit (%s)", err.Error()) } return nil } @@ -215,7 +216,7 @@ func (k *Keeper) QueryWZetaBalanceOf(ctx sdk.Context, addr ethcommon.Address) (* addr, ) if err != nil { - return nil, cosmoserrors.Wrapf(err, "failed to call balanceOf") + return nil, cosmoserrors.Wrapf(types.ErrContractCall, "failed to call balanceOf (%s)", err.Error()) } type BigIntResponse struct { @@ -254,7 +255,7 @@ func (k *Keeper) QuerySystemContractGasCoinZRC20(ctx sdk.Context, chainid *big.I chainid, ) if err != nil { - return ethcommon.Address{}, cosmoserrors.Wrapf(err, "failed to call gasCoinZRC20ByChainId") + return ethcommon.Address{}, cosmoserrors.Wrapf(types.ErrContractCall, "failed to call gasCoinZRC20ByChainId (%s)", err.Error()) } type AddressResponse struct { diff --git a/x/fungible/keeper/system_contract_test.go b/x/fungible/keeper/system_contract_test.go index 3874f52435..e2340cb4c1 100644 --- a/x/fungible/keeper/system_contract_test.go +++ b/x/fungible/keeper/system_contract_test.go @@ -52,6 +52,42 @@ func TestKeeper_GetWZetaContractAddress(t *testing.T) { require.Equal(t, wzeta, found) } +func TestKeeper_GetWZetaContractAddressFails(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + _, err := k.GetWZetaContractAddress(ctx) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrStateVariableNotFound) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMFailCallOnce() + _, err = k.GetWZetaContractAddress(ctx) + require.ErrorIs(t, err, types.ErrContractCall) +} + +func TestKeeper_GetWZetaContractAddressFailsToUnpack(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + _, err := k.GetWZetaContractAddress(ctx) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrStateVariableNotFound) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMSuccessCallOnce() + _, err = k.GetWZetaContractAddress(ctx) + require.ErrorIs(t, err, types.ErrABIUnpack) +} + func TestKeeper_GetUniswapV2FactoryAddress(t *testing.T) { k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) @@ -66,6 +102,42 @@ func TestKeeper_GetUniswapV2FactoryAddress(t *testing.T) { require.Equal(t, factory, found) } +func TestKeeper_GetUniswapV2FactoryAddressFails(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + _, err := k.GetUniswapV2FactoryAddress(ctx) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrStateVariableNotFound) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMFailCallOnce() + _, err = k.GetUniswapV2FactoryAddress(ctx) + require.ErrorIs(t, err, types.ErrContractCall) +} + +func TestKeeper_GetUniswapV2FactoryAddressFailsToUnpack(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + _, err := k.GetUniswapV2FactoryAddress(ctx) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrStateVariableNotFound) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMSuccessCallOnce() + _, err = k.GetUniswapV2FactoryAddress(ctx) + require.ErrorIs(t, err, types.ErrABIUnpack) +} + func TestKeeper_GetUniswapV2Router02Address(t *testing.T) { k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) @@ -80,6 +152,42 @@ func TestKeeper_GetUniswapV2Router02Address(t *testing.T) { require.Equal(t, router, found) } +func TestKeeper_GetUniswapV2Router02AddressFails(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + _, err := k.GetUniswapV2Router02Address(ctx) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrStateVariableNotFound) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMFailCallOnce() + _, err = k.GetUniswapV2Router02Address(ctx) + require.ErrorIs(t, err, types.ErrContractCall) +} + +func TestKeeper_GetUniswapV2Router02AddressFailsToUnpack(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + _, err := k.GetUniswapV2Router02Address(ctx) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrStateVariableNotFound) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMSuccessCallOnce() + _, err = k.GetUniswapV2Router02Address(ctx) + require.ErrorIs(t, err, types.ErrABIUnpack) +} + func TestKeeper_CallWZetaDeposit(t *testing.T) { k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) @@ -108,6 +216,90 @@ func TestKeeper_CallWZetaDeposit(t *testing.T) { require.Equal(t, big.NewInt(42), balance) } +func TestKeeper_CallWZetaDepositFails(t *testing.T) { + k, ctx, sdkk, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + // mint tokens + addr := sample.Bech32AccAddress() + ethAddr := common.BytesToAddress(addr.Bytes()) + coins := sample.Coins() + err := sdkk.BankKeeper.MintCoins(ctx, types.ModuleName, sample.Coins()) + require.NoError(t, err) + err = sdkk.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, coins) + require.NoError(t, err) + + // fail if no system contract + err = k.CallWZetaDeposit(ctx, ethAddr, big.NewInt(42)) + require.Error(t, err) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + // deposit + mockEVMKeeper.MockEVMFailCallOnce() + err = k.CallWZetaDeposit(ctx, ethAddr, big.NewInt(42)) + require.ErrorIs(t, err, types.ErrContractCall) +} + +func TestKeeper_QueryWZetaBalanceOfFails(t *testing.T) { + k, ctx, sdkk, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + // mint tokens + addr := sample.Bech32AccAddress() + ethAddr := common.BytesToAddress(addr.Bytes()) + coins := sample.Coins() + err := sdkk.BankKeeper.MintCoins(ctx, types.ModuleName, sample.Coins()) + require.NoError(t, err) + err = sdkk.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, coins) + require.NoError(t, err) + + // fail if no system contract + err = k.CallWZetaDeposit(ctx, ethAddr, big.NewInt(42)) + require.Error(t, err) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + // query + mockEVMKeeper.MockEVMFailCallOnce() + _, err = k.QueryWZetaBalanceOf(ctx, ethAddr) + require.ErrorIs(t, err, types.ErrContractCall) +} + +func TestKeeper_QueryWZetaBalanceOfFailsToUnpack(t *testing.T) { + k, ctx, sdkk, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + // mint tokens + addr := sample.Bech32AccAddress() + ethAddr := common.BytesToAddress(addr.Bytes()) + coins := sample.Coins() + err := sdkk.BankKeeper.MintCoins(ctx, types.ModuleName, sample.Coins()) + require.NoError(t, err) + err = sdkk.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, coins) + require.NoError(t, err) + + // fail if no system contract + err = k.CallWZetaDeposit(ctx, ethAddr, big.NewInt(42)) + require.Error(t, err) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + // query + mockEVMKeeper.MockEVMSuccessCallOnce() + _, err = k.QueryWZetaBalanceOf(ctx, ethAddr) + require.ErrorIs(t, err, types.ErrABIUnpack) +} + func TestKeeper_QuerySystemContractGasCoinZRC20(t *testing.T) { k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) @@ -124,3 +316,43 @@ func TestKeeper_QuerySystemContractGasCoinZRC20(t *testing.T) { require.NoError(t, err) require.Equal(t, zrc20, found) } + +func TestKeeper_QuerySystemContractGasCoinZRC20Fails(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + chainID := getValidChainID(t) + + _, err := k.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chainID)) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrStateVariableNotFound) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMFailCallOnce() + _, err = k.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chainID)) + require.ErrorIs(t, err, types.ErrContractCall) +} + +func TestKeeper_QuerySystemContractGasCoinZRC20FailsToUnpack(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{ + UseEVMMock: true, + }) + mockEVMKeeper := keepertest.GetFungibleEVMMock(t, k) + k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + chainID := getValidChainID(t) + + _, err := k.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chainID)) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrStateVariableNotFound) + + deploySystemContractsWithMockEvmKeeper(t, ctx, k, mockEVMKeeper) + + mockEVMKeeper.MockEVMSuccessCallOnce() + _, err = k.QuerySystemContractGasCoinZRC20(ctx, big.NewInt(chainID)) + require.ErrorIs(t, err, types.ErrABIUnpack) +} diff --git a/x/fungible/types/errors.go b/x/fungible/types/errors.go index 2652442b4a..ddcef768e5 100644 --- a/x/fungible/types/errors.go +++ b/x/fungible/types/errors.go @@ -27,4 +27,5 @@ var ( ErrCallNonContract = sdkerrors.Register(ModuleName, 1124, "can't call a non-contract address") ErrForeignCoinAlreadyExist = sdkerrors.Register(ModuleName, 1125, "foreign coin already exist") ErrInvalidHash = sdkerrors.Register(ModuleName, 1126, "invalid hash") + ErrNilGasPrice = sdkerrors.Register(ModuleName, 1127, "nil gas price") ) diff --git a/x/fungible/types/expected_keepers.go b/x/fungible/types/expected_keepers.go index 5fbef0d279..180642b2af 100644 --- a/x/fungible/types/expected_keepers.go +++ b/x/fungible/types/expected_keepers.go @@ -50,5 +50,6 @@ type EVMKeeper interface { commit bool, ) (*evmtypes.MsgEthereumTxResponse, error) GetAccount(ctx sdk.Context, addr ethcommon.Address) *statedb.Account + GetCode(ctx sdk.Context, codeHash ethcommon.Hash) []byte SetAccount(ctx sdk.Context, addr ethcommon.Address, account statedb.Account) error }