diff --git a/app/upgrades/nextupgrade/testdata/neutron_interchain_txs.wasm b/app/upgrades/nextupgrade/testdata/neutron_interchain_txs.wasm new file mode 100644 index 000000000..6f3dc56be Binary files /dev/null and b/app/upgrades/nextupgrade/testdata/neutron_interchain_txs.wasm differ diff --git a/app/upgrades/nextupgrade/upgrades.go b/app/upgrades/nextupgrade/upgrades.go index 3ac120b4c..dec75c001 100644 --- a/app/upgrades/nextupgrade/upgrades.go +++ b/app/upgrades/nextupgrade/upgrades.go @@ -3,6 +3,7 @@ package nextupgrade import ( "fmt" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/cosmos/cosmos-sdk/baseapp" consensuskeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" @@ -80,7 +81,7 @@ func CreateUpgradeHandler( } ctx.Logger().Info("Migrating interchaintxs module parameters...") - if err := setInterchainTxsParams(ctx, keepers.ParamsKeeper, storeKeys.GetKey(interchaintxstypes.StoreKey), codec); err != nil { + if err := setInterchainTxsParams(ctx, keepers.ParamsKeeper, storeKeys.GetKey(interchaintxstypes.StoreKey), storeKeys.GetKey(wasmtypes.StoreKey), codec); err != nil { return nil, err } @@ -226,7 +227,7 @@ func migrateInterchainQueriesParams(ctx sdk.Context, paramsKeepers paramskeeper. return nil } -func setInterchainTxsParams(ctx sdk.Context, paramsKeepers paramskeeper.Keeper, storeKey storetypes.StoreKey, codec codec.Codec) error { +func setInterchainTxsParams(ctx sdk.Context, paramsKeepers paramskeeper.Keeper, storeKey storetypes.StoreKey, wasmStoreKey storetypes.StoreKey, codec codec.Codec) error { store := ctx.KVStore(storeKey) var currParams interchaintxstypes.Params subspace, _ := paramsKeepers.GetSubspace(interchaintxstypes.StoreKey) @@ -239,6 +240,13 @@ func setInterchainTxsParams(ctx sdk.Context, paramsKeepers paramskeeper.Keeper, bz := codec.MustMarshal(&currParams) store.Set(interchaintxstypes.ParamsKey, bz) + + wasmStore := ctx.KVStore(wasmStoreKey) + bzWasm := wasmStore.Get(wasmtypes.KeySequenceCodeID) + if bzWasm == nil { + return fmt.Errorf("KeySequenceCodeID not found during the upgrade") + } + store.Set(interchaintxstypes.ICARegistrationFeeFirstCodeID, bzWasm) return nil } diff --git a/app/upgrades/nextupgrade/upgrades_test.go b/app/upgrades/nextupgrade/upgrades_test.go index ebba89756..bd4180a9c 100644 --- a/app/upgrades/nextupgrade/upgrades_test.go +++ b/app/upgrades/nextupgrade/upgrades_test.go @@ -3,7 +3,9 @@ package nextupgrade_test import ( "testing" + "github.com/CosmWasm/wasmd/x/wasm/keeper" adminmoduletypes "github.com/cosmos/admin-module/x/adminmodule/types" + "github.com/cosmos/cosmos-sdk/types/errors" crontypes "github.com/neutron-org/neutron/x/cron/types" feeburnertypes "github.com/neutron-org/neutron/x/feeburner/types" @@ -61,6 +63,9 @@ func (suite *UpgradeTestSuite) SetupTest() { subspace, _ = app.ParamsKeeper.GetSubspace(interchaintxstypes.StoreKey) pICAtx := interchaintxstypes.DefaultParams() subspace.SetParamSet(ctx, &pICAtx) + + codeIDBefore := suite.StoreTestCode(ctx, sdk.AccAddress("neutron1weweewe"), "testdata/neutron_interchain_txs.wasm") + suite.InstantiateTestContract(ctx, sdk.AccAddress("neutron1weweewe"), codeIDBefore) } func (suite *UpgradeTestSuite) TestGlobalFeesUpgrade() { @@ -159,3 +164,46 @@ func (suite *UpgradeTestSuite) TestAdminModuleUpgrade() { suite.Require().NoError(err) suite.Require().Equal(uint64(1), id) } + +func (suite *UpgradeTestSuite) TestRegisterInterchainAccountCreationFee() { + var ( + app = suite.GetNeutronZoneApp(suite.ChainA) + ctx = suite.ChainA.GetContext() + ) + + suite.FundAcc(sdk.AccAddress("neutron1weweewe"), sdk.NewCoins(sdk.NewCoin("untrn", sdk.NewInt(10000)))) + contractKeeper := keeper.NewDefaultPermissionKeeper(app.WasmKeeper) + // store contract for register ica w/o fees + codeIDBefore := suite.StoreTestCode(ctx, sdk.AccAddress("neutron1_ica"), "testdata/neutron_interchain_txs.wasm") + contractAddressBeforeUpgrade := suite.InstantiateTestContract(ctx, sdk.AccAddress("neutron1_ica"), codeIDBefore) + + upgrade := upgradetypes.Plan{ + Name: nextupgrade.UpgradeName, + Info: "some text here", + Height: 100, + } + app.UpgradeKeeper.ApplyUpgrade(ctx, upgrade) + + lastCodeID := app.InterchainTxsKeeper.GetICARegistrationFeeFirstCodeID(ctx) + // ensure that wasm module stores next code id + suite.Require().Equal(lastCodeID, codeIDBefore+1) + + // store contract after upgrade + codeID := suite.StoreTestCode(ctx, sdk.AccAddress("neutron1_ica"), "testdata/neutron_interchain_txs.wasm") + contractAddressAfterUpgrade := suite.InstantiateTestContract(ctx, sdk.AccAddress("neutron1_ica"), codeID) + // register w/o actual fees + jsonStringBeforeUpgrade := `{"register": {"connection_id":"connection-1","interchain_account_id":"test-2"}}` + byteEncodedMsgBeforeUpgrade := []byte(jsonStringBeforeUpgrade) + _, err := contractKeeper.Execute(ctx, contractAddressBeforeUpgrade, sdk.AccAddress("neutron1_ica"), byteEncodedMsgBeforeUpgrade, nil) + suite.Require().NoError(err) + + // register with fees + jsonStringAfterUpgrade := `{"register": {"connection_id":"connection-1","interchain_account_id":"test-3"}}` + byteEncodedMsgAfterUpgrade := []byte(jsonStringAfterUpgrade) + _, err = contractKeeper.Execute(ctx, contractAddressAfterUpgrade, sdk.AccAddress("neutron1weweewe"), byteEncodedMsgAfterUpgrade, sdk.NewCoins(sdk.NewCoin("untrn", sdk.NewInt(1000)))) + suite.Require().NoError(err) + + // failed register due lack of fees (fees required) + _, err = contractKeeper.Execute(ctx, contractAddressAfterUpgrade, sdk.AccAddress("neutron1weweewe"), byteEncodedMsgAfterUpgrade, nil) + suite.ErrorIs(err, errors.ErrInsufficientFunds) +} diff --git a/testutil/mocks/contractmanager/types/expected_keepers.go b/testutil/mocks/contractmanager/types/expected_keepers.go index d27f64e5f..c69dcf649 100644 --- a/testutil/mocks/contractmanager/types/expected_keepers.go +++ b/testutil/mocks/contractmanager/types/expected_keepers.go @@ -7,6 +7,7 @@ package mock_types import ( reflect "reflect" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" types "github.com/cosmos/cosmos-sdk/types" gomock "github.com/golang/mock/gomock" types0 "github.com/neutron-org/neutron/x/contractmanager/types" @@ -18,6 +19,11 @@ type MockWasmKeeper struct { recorder *MockWasmKeeperMockRecorder } +func (m *MockWasmKeeper) GetContractInfo(ctx types.Context, contractAddress types.AccAddress) *wasmtypes.ContractInfo { + //TODO implement me + panic("implement me") +} + // MockWasmKeeperMockRecorder is the mock recorder for MockWasmKeeper. type MockWasmKeeperMockRecorder struct { mock *MockWasmKeeper diff --git a/testutil/mocks/interchaintxs/types/expected_keepers.go b/testutil/mocks/interchaintxs/types/expected_keepers.go index 4b098863c..de9a6d792 100644 --- a/testutil/mocks/interchaintxs/types/expected_keepers.go +++ b/testutil/mocks/interchaintxs/types/expected_keepers.go @@ -7,6 +7,7 @@ package mock_types import ( reflect "reflect" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" 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" @@ -111,6 +112,10 @@ type MockWasmKeeper struct { recorder *MockWasmKeeperMockRecorder } +func (m *MockWasmKeeper) GetContractInfo(ctx types.Context, contractAddress types.AccAddress) *wasmtypes.ContractInfo { + return &wasmtypes.ContractInfo{CodeID: 1} +} + // MockWasmKeeperMockRecorder is the mock recorder for MockWasmKeeper. type MockWasmKeeperMockRecorder struct { mock *MockWasmKeeper diff --git a/testutil/test_helpers.go b/testutil/test_helpers.go index edab3f004..54ad72935 100644 --- a/testutil/test_helpers.go +++ b/testutil/test_helpers.go @@ -281,8 +281,9 @@ func (suite *IBCConnectionTestSuite) GetNeutronZoneApp(chain *ibctesting.TestCha return testApp } -func (suite *IBCConnectionTestSuite) StoreReflectCode(ctx sdk.Context, addr sdk.AccAddress, path string) uint64 { +func (suite *IBCConnectionTestSuite) StoreTestCode(ctx sdk.Context, addr sdk.AccAddress, path string) uint64 { // wasm file built with https://github.com/neutron-org/neutron-contracts/tree/main/contracts/reflect + // wasm file built with https://github.com/neutron-org/neutron-dev/tree/feat/ica-register-fee-update/contracts/neutron_interchain_txs wasmCode, err := os.ReadFile(path) suite.Require().NoError(err) @@ -292,7 +293,7 @@ func (suite *IBCConnectionTestSuite) StoreReflectCode(ctx sdk.Context, addr sdk. return codeID } -func (suite *IBCConnectionTestSuite) InstantiateReflectContract(ctx sdk.Context, funder sdk.AccAddress, codeID uint64) sdk.AccAddress { +func (suite *IBCConnectionTestSuite) InstantiateTestContract(ctx sdk.Context, funder sdk.AccAddress, codeID uint64) sdk.AccAddress { initMsgBz := []byte("{}") contractKeeper := keeper.NewDefaultPermissionKeeper(suite.GetNeutronZoneApp(suite.ChainA).WasmKeeper) addr, _, err := contractKeeper.Instantiate(ctx, codeID, funder, funder, initMsgBz, "demo contract", nil) diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index 83ff57763..e4d8142f1 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -79,7 +79,7 @@ type SubmitTxResponse struct { type RegisterInterchainAccount struct { ConnectionId string `json:"connection_id"` InterchainAccountId string `json:"interchain_account_id"` - RegisterFee sdk.Coins `json:"register_fee"` + RegisterFee sdk.Coins `json:"register_fee,omitempty"` } // RegisterInterchainAccountResponse holds response for RegisterInterchainAccount. diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index a130dae31..3a12a7e4f 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -707,7 +707,7 @@ func (m *CustomMessenger) performRegisterInterchainAccount(ctx sdk.Context, cont FromAddress: contractAddr.String(), ConnectionId: reg.ConnectionId, InterchainAccountId: reg.InterchainAccountId, - RegisterFee: reg.RegisterFee, + RegisterFee: getRegisterFee(reg.RegisterFee), } if err := msg.ValidateBasic(); err != nil { return nil, errors.Wrap(err, "failed to validate incoming RegisterInterchainAccount message") @@ -921,3 +921,10 @@ func (m *CustomMessenger) isAdmin(ctx sdk.Context, contractAddr sdk.AccAddress) return false } + +func getRegisterFee(fee sdk.Coins) sdk.Coins { + if fee == nil { + return make(sdk.Coins, 0) + } + return fee +} diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index 6008a058f..a79dd73db 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -75,8 +75,8 @@ func (suite *CustomMessengerTestSuite) SetupTest() { func (suite *CustomMessengerTestSuite) TestRegisterInterchainAccount() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) err := suite.neutron.FeeBurnerKeeper.SetParams(suite.ctx, feeburnertypes.Params{ @@ -111,8 +111,8 @@ func (suite *CustomMessengerTestSuite) TestRegisterInterchainAccount() { func (suite *CustomMessengerTestSuite) TestRegisterInterchainAccountLongID() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) // Craft RegisterInterchainAccount message @@ -135,8 +135,8 @@ func (suite *CustomMessengerTestSuite) TestRegisterInterchainAccountLongID() { func (suite *CustomMessengerTestSuite) TestRegisterInterchainQuery() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) err := testutil.SetupICAPath(suite.Path, suite.contractAddress.String()) @@ -173,8 +173,8 @@ func (suite *CustomMessengerTestSuite) TestRegisterInterchainQuery() { } func (suite *CustomMessengerTestSuite) TestCreateDenomMsg() { - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress() @@ -201,8 +201,8 @@ func (suite *CustomMessengerTestSuite) TestMintMsg() { lucky = keeper.RandomAccountAddress(suite.T()) // We don't care what this address is ) - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress() @@ -377,8 +377,8 @@ func (suite *CustomMessengerTestSuite) TestRemoveInterchainQueryFailed() { func (suite *CustomMessengerTestSuite) TestSubmitTx() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress() @@ -410,8 +410,8 @@ func (suite *CustomMessengerTestSuite) TestSubmitTx() { func (suite *CustomMessengerTestSuite) TestSubmitTxTooMuchTxs() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) err := testutil.SetupICAPath(suite.Path, suite.contractAddress.String()) @@ -507,8 +507,8 @@ func (suite *CustomMessengerTestSuite) TestSoftwareUpgradeProposal() { func (suite *CustomMessengerTestSuite) TestTooMuchProposals() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) err := testutil.SetupICAPath(suite.Path, suite.contractAddress.String()) @@ -547,8 +547,8 @@ func (suite *CustomMessengerTestSuite) TestTooMuchProposals() { func (suite *CustomMessengerTestSuite) TestNoProposals() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) err := testutil.SetupICAPath(suite.Path, suite.contractAddress.String()) @@ -572,8 +572,8 @@ func (suite *CustomMessengerTestSuite) TestNoProposals() { func (suite *CustomMessengerTestSuite) TestAddRemoveSchedule() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) // Set admin so that we can execute this proposal without permission error @@ -625,8 +625,8 @@ func (suite *CustomMessengerTestSuite) TestAddRemoveSchedule() { func (suite *CustomMessengerTestSuite) TestResubmitFailureAck() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) // Add failure @@ -660,8 +660,8 @@ func (suite *CustomMessengerTestSuite) TestResubmitFailureAck() { func (suite *CustomMessengerTestSuite) TestResubmitFailureTimeout() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) // Add failure @@ -692,8 +692,8 @@ func (suite *CustomMessengerTestSuite) TestResubmitFailureTimeout() { func (suite *CustomMessengerTestSuite) TestResubmitFailureFromDifferentContract() { // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") - suite.contractAddress = suite.InstantiateReflectContract(suite.ctx, suite.contractOwner, codeID) + codeID := suite.StoreTestCode(suite.ctx, suite.contractOwner, "../testdata/reflect.wasm") + suite.contractAddress = suite.InstantiateTestContract(suite.ctx, suite.contractOwner, codeID) suite.Require().NotEmpty(suite.contractAddress) // Add failure diff --git a/wasmbinding/test/custom_query_test.go b/wasmbinding/test/custom_query_test.go index 9180bf079..cdc185060 100644 --- a/wasmbinding/test/custom_query_test.go +++ b/wasmbinding/test/custom_query_test.go @@ -37,8 +37,8 @@ func (suite *CustomQuerierTestSuite) TestInterchainQueryResult() { ) // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(ctx, owner, "../testdata/reflect.wasm") - contractAddress := suite.InstantiateReflectContract(ctx, owner, codeID) + codeID := suite.StoreTestCode(ctx, owner, "../testdata/reflect.wasm") + contractAddress := suite.InstantiateTestContract(ctx, owner, codeID) suite.Require().NotEmpty(contractAddress) // Register and submit query result @@ -109,8 +109,8 @@ func (suite *CustomQuerierTestSuite) TestInterchainQueryResultNotFound() { ) // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(ctx, owner, "../testdata/reflect.wasm") - contractAddress := suite.InstantiateReflectContract(ctx, owner, codeID) + codeID := suite.StoreTestCode(ctx, owner, "../testdata/reflect.wasm") + contractAddress := suite.InstantiateTestContract(ctx, owner, codeID) suite.Require().NotEmpty(contractAddress) // Query interchain query result @@ -132,8 +132,8 @@ func (suite *CustomQuerierTestSuite) TestInterchainAccountAddress() { ) // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(ctx, owner, "../testdata/reflect.wasm") - contractAddress := suite.InstantiateReflectContract(ctx, owner, codeID) + codeID := suite.StoreTestCode(ctx, owner, "../testdata/reflect.wasm") + contractAddress := suite.InstantiateTestContract(ctx, owner, codeID) suite.Require().NotEmpty(contractAddress) err := testutil.SetupICAPath(suite.Path, contractAddress.String()) @@ -164,8 +164,8 @@ func (suite *CustomQuerierTestSuite) TestUnknownInterchainAcc() { ) // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(ctx, owner, "../testdata/reflect.wasm") - contractAddress := suite.InstantiateReflectContract(ctx, owner, codeID) + codeID := suite.StoreTestCode(ctx, owner, "../testdata/reflect.wasm") + contractAddress := suite.InstantiateTestContract(ctx, owner, codeID) suite.Require().NotEmpty(contractAddress) err := testutil.SetupICAPath(suite.Path, contractAddress.String()) @@ -192,8 +192,8 @@ func (suite *CustomQuerierTestSuite) TestMinIbcFee() { ) // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(ctx, owner, "../testdata/reflect.wasm") - contractAddress := suite.InstantiateReflectContract(ctx, owner, codeID) + codeID := suite.StoreTestCode(ctx, owner, "../testdata/reflect.wasm") + contractAddress := suite.InstantiateTestContract(ctx, owner, codeID) suite.Require().NotEmpty(contractAddress) query := bindings.NeutronQuery{ @@ -224,8 +224,8 @@ func (suite *CustomQuerierTestSuite) TestFullDenom() { ) // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(ctx, owner, "../testdata/reflect.wasm") - contractAddress := suite.InstantiateReflectContract(ctx, owner, codeID) + codeID := suite.StoreTestCode(ctx, owner, "../testdata/reflect.wasm") + contractAddress := suite.InstantiateTestContract(ctx, owner, codeID) suite.Require().NotEmpty(contractAddress) query := bindings.NeutronQuery{ @@ -257,8 +257,8 @@ func (suite *CustomQuerierTestSuite) TestDenomAdmin() { suite.Require().NoError(err) // Store code and instantiate reflect contract - codeID := suite.StoreReflectCode(ctx, owner, "../testdata/reflect.wasm") - contractAddress := suite.InstantiateReflectContract(ctx, owner, codeID) + codeID := suite.StoreTestCode(ctx, owner, "../testdata/reflect.wasm") + contractAddress := suite.InstantiateTestContract(ctx, owner, codeID) suite.Require().NotEmpty(contractAddress) senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress() diff --git a/x/contractmanager/types/expected_keepers.go b/x/contractmanager/types/expected_keepers.go index 88db20887..f30e346b8 100644 --- a/x/contractmanager/types/expected_keepers.go +++ b/x/contractmanager/types/expected_keepers.go @@ -1,12 +1,14 @@ package types import ( + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" sdk "github.com/cosmos/cosmos-sdk/types" ) // WasmKeeper defines the expected interface needed to cam cosmwasm contracts. type WasmKeeper interface { HasContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) bool + GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *wasmtypes.ContractInfo Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) ([]byte, error) } diff --git a/x/interchainqueries/keeper/grpc_query_test.go b/x/interchainqueries/keeper/grpc_query_test.go index ee3eb7a5c..391d58d0f 100644 --- a/x/interchainqueries/keeper/grpc_query_test.go +++ b/x/interchainqueries/keeper/grpc_query_test.go @@ -476,8 +476,8 @@ func (suite *KeeperTestSuite) TestQueryResult() { clientKey := host.FullClientStateKey(suite.Path.EndpointB.ClientID) ctx := suite.ChainA.GetContext() contractOwner := wasmKeeper.RandomAccountAddress(suite.T()) - codeID := suite.StoreReflectCode(ctx, contractOwner, reflectContractPath) - contractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + contractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) registerMsg := iqtypes.MsgRegisterInterchainQuery{ ConnectionId: suite.Path.EndpointA.ConnectionID, Keys: []*iqtypes.KVKey{ diff --git a/x/interchainqueries/keeper/keeper_test.go b/x/interchainqueries/keeper/keeper_test.go index beaca0287..704815240 100644 --- a/x/interchainqueries/keeper/keeper_test.go +++ b/x/interchainqueries/keeper/keeper_test.go @@ -126,8 +126,8 @@ func (suite *KeeperTestSuite) TestRegisterInterchainQuery() { ) // Store code and instantiate reflect contract. - codeID := suite.StoreReflectCode(ctx, contractOwner, reflectContractPath) - contractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + contractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) suite.Require().NotEmpty(contractAddress) err := testutil.SetupICAPath(suite.Path, contractAddress.String()) @@ -383,8 +383,8 @@ func (suite *KeeperTestSuite) TestUpdateInterchainQuery() { ctx = suite.ChainA.GetContext() contractOwner = wasmKeeper.RandomAccountAddress(suite.T()) ) - codeID := suite.StoreReflectCode(ctx, contractOwner, reflectContractPath) - newContractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + newContractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) suite.Require().NotEmpty(newContractAddress) msg = iqtypes.MsgUpdateInterchainQueryRequest{ QueryId: 1, @@ -411,8 +411,8 @@ func (suite *KeeperTestSuite) TestUpdateInterchainQuery() { ) // Store code and instantiate reflect contract. - codeID := suite.StoreReflectCode(ctx, contractOwner, reflectContractPath) - contractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + contractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) suite.Require().NotEmpty(contractAddress) err := testutil.SetupICAPath(suite.Path, contractAddress.String()) @@ -553,8 +553,8 @@ func (suite *KeeperTestSuite) TestRemoveInterchainQuery() { ctx = suite.ChainA.GetContext() contractOwner = wasmKeeper.RandomAccountAddress(suite.T()) ) - codeID := suite.StoreReflectCode(ctx, contractOwner, reflectContractPath) - newContractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + newContractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) suite.Require().NotEmpty(newContractAddress) msg = iqtypes.MsgRemoveInterchainQueryRequest{ QueryId: 1, @@ -583,8 +583,8 @@ func (suite *KeeperTestSuite) TestRemoveInterchainQuery() { ) // Store code and instantiate reflect contract. - codeID := suite.StoreReflectCode(ctx, contractOwner, reflectContractPath) - contractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + contractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) suite.Require().NotEmpty(contractAddress) err := testutil.SetupICAPath(suite.Path, contractAddress.String()) @@ -1421,8 +1421,8 @@ func (suite *KeeperTestSuite) TestSubmitInterchainQueryResult() { ) // Store code and instantiate reflect contract. - codeID := suite.StoreReflectCode(ctx, contractOwner, reflectContractPath) - contractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + contractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) suite.Require().NotEmpty(contractAddress) err := testutil.SetupICAPath(suite.Path, contractAddress.String()) @@ -1691,8 +1691,8 @@ func (suite *KeeperTestSuite) TestRemoveFreshlyCreatedICQ() { ) // Store code and instantiate reflect contract. - codeID := suite.StoreReflectCode(ctx, contractOwner, reflectContractPath) - contractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + contractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) suite.Require().NotEmpty(contractAddress) // Top up contract address with native coins for deposit @@ -1724,7 +1724,7 @@ func (suite *KeeperTestSuite) TestRemoveFreshlyCreatedICQ() { suite.Require().Equal(params.QuerySubmitTimeout, registeredQuery.SubmitTimeout) suite.Require().Greater(uint64(ctx.BlockHeight()), registeredQuery.LastSubmittedResultLocalHeight+registeredQuery.SubmitTimeout) - newContractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + newContractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) suite.Require().NotEmpty(newContractAddress) resp, err := msgSrv.RemoveInterchainQuery(sdk.WrapSDKContext(ctx), &iqtypes.MsgRemoveInterchainQueryRequest{ QueryId: 1, diff --git a/x/interchainqueries/keeper/process_block_results_test.go b/x/interchainqueries/keeper/process_block_results_test.go index 8313f6a71..198acffca 100644 --- a/x/interchainqueries/keeper/process_block_results_test.go +++ b/x/interchainqueries/keeper/process_block_results_test.go @@ -272,8 +272,8 @@ func (suite *KeeperTestSuite) TestUnpackAndVerifyHeaders() { ) // Store code and instantiate reflect contract. - codeID := suite.StoreReflectCode(ctx, contractOwner, reflectContractPath) - contractAddress := suite.InstantiateReflectContract(ctx, contractOwner, codeID) + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + contractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) suite.Require().NotEmpty(contractAddress) err := testutil.SetupICAPath(suite.Path, contractAddress.String()) diff --git a/x/interchaintxs/keeper/keeper.go b/x/interchaintxs/keeper/keeper.go index be503d56f..ab65451af 100644 --- a/x/interchaintxs/keeper/keeper.go +++ b/x/interchaintxs/keeper/keeper.go @@ -92,3 +92,14 @@ func (k Keeper) ChargeFee(ctx sdk.Context, payer sdk.AccAddress, fee sdk.Coins) func (k Keeper) GetAuthority() string { return k.authority } + +// GetICARegistrationFeeFirstCodeID returns code id, starting from which we charge fee for ICA registration +func (k Keeper) GetICARegistrationFeeFirstCodeID(ctx sdk.Context) (codeID uint64) { + store := ctx.KVStore(k.storeKey) + bytes := store.Get(types.ICARegistrationFeeFirstCodeID) + if bytes == nil { + k.Logger(ctx).Debug("Fee register ICA code id key don't exists, GetLastCodeID returns 0") + return 0 + } + return sdk.BigEndianToUint64(bytes) +} diff --git a/x/interchaintxs/keeper/msg_server.go b/x/interchaintxs/keeper/msg_server.go index 9e79b0690..ace0f34f5 100644 --- a/x/interchaintxs/keeper/msg_server.go +++ b/x/interchaintxs/keeper/msg_server.go @@ -47,8 +47,11 @@ func (k Keeper) RegisterInterchainAccount(goCtx context.Context, msg *ictxtypes. return nil, errors.Wrapf(ictxtypes.ErrNotContract, "%s is not a contract address", msg.FromAddress) } - if err := k.ChargeFee(ctx, senderAddr, msg.RegisterFee); err != nil { - return nil, errors.Wrapf(err, "failed to charge fees to pay for RegisterInterchainAccount msg: %s", msg) + // if contract is stored after [last] upgrade, we're not going charge fees for register ICA + if k.sudoKeeper.GetContractInfo(ctx, senderAddr).CodeID >= k.GetICARegistrationFeeFirstCodeID(ctx) { + if err := k.ChargeFee(ctx, senderAddr, msg.RegisterFee); err != nil { + return nil, errors.Wrapf(err, "failed to charge fees to pay for RegisterInterchainAccount msg: %s", msg) + } } icaOwner := ictxtypes.NewICAOwnerFromAddress(senderAddr, msg.InterchainAccountId) diff --git a/x/interchaintxs/types/expected_keepers.go b/x/interchaintxs/types/expected_keepers.go index 6c777acbf..f565e1059 100644 --- a/x/interchaintxs/types/expected_keepers.go +++ b/x/interchaintxs/types/expected_keepers.go @@ -1,6 +1,7 @@ package types import ( + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" @@ -25,6 +26,7 @@ type BankKeeper interface { type WasmKeeper interface { HasContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) bool + GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *wasmtypes.ContractInfo Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) ([]byte, error) } diff --git a/x/interchaintxs/types/keys.go b/x/interchaintxs/types/keys.go index beaf14ae2..7fd3d09c1 100644 --- a/x/interchaintxs/types/keys.go +++ b/x/interchaintxs/types/keys.go @@ -18,7 +18,11 @@ const ( ) const ( + // parameters key prefixParamsKey = iota + 1 + // prefix of code id, starting from which we charge fee for ICA registration + prefixICARegistrationFeeFirstCodeID = iota + 2 ) var ParamsKey = []byte{prefixParamsKey} +var ICARegistrationFeeFirstCodeID = []byte{prefixICARegistrationFeeFirstCodeID} diff --git a/x/transfer/keeper/keeper_test.go b/x/transfer/keeper/keeper_test.go index f9636cf35..c8b857836 100644 --- a/x/transfer/keeper/keeper_test.go +++ b/x/transfer/keeper/keeper_test.go @@ -90,8 +90,8 @@ func (suite KeeperTestSuite) TestTransfer() { //nolint:govet // it's a test so i testOwner := sdktypes.MustAccAddressFromBech32(testutil.TestOwnerAddress) // Store code and instantiate reflect contract. - codeID := suite.StoreReflectCode(ctx, testOwner, reflectContractPath) - contractAddress := suite.InstantiateReflectContract(ctx, testOwner, codeID) + codeID := suite.StoreTestCode(ctx, testOwner, reflectContractPath) + contractAddress := suite.InstantiateTestContract(ctx, testOwner, codeID) suite.Require().NotEmpty(contractAddress) ctx = suite.ChainA.GetContext()