diff --git a/CHANGELOG.md b/CHANGELOG.md index d70b3edc71..bc87fb36f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ * [#2070](https://github.com/crypto-org-chain/cronos/pull/2070) fix(ci): fix github pr labeler to match v6 format. * [#2069](https://github.com/crypto-org-chain/cronos/pull/2069) fix(test): flaky test_mempool integration test. * [#2071](https://github.com/crypto-org-chain/cronos/pull/2071) fix(test): fix flaky ibc and versiondb integration tests. +* [#2099](https://github.com/crypto-org-chain/cronos/pull/2099) fix(cronos): add contract authorization check to SendCroToIbcHandler + ### Chores: * [#1986](https://github.com/crypto-org-chain/cronos/pull/1986) Remove unused precompiles diff --git a/app/upgrades.go b/app/upgrades.go index 3b15f7471b..8703cdd36a 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -8,6 +8,7 @@ import ( host "github.com/cosmos/ibc-go/v11/modules/core/24-host" ibcexported "github.com/cosmos/ibc-go/v11/modules/core/exported" + "github.com/ethereum/go-ethereum/common" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/runtime" @@ -19,11 +20,23 @@ import ( const planName = "v1.8" +// croBridgeContractAddresses are the EVM addresses of CroBridge contracts +// authorized on Cronos mainnet. Empty list disables the SendCroToIbc hook. +var croBridgeContractAddresses = []string{ + "0x6b1b50c2223eb31E0d4683b046ea9C6CB0D0ea4F", + "0xCE13a6F3d4167CE958f4764D423e6D62a114c751", +} + // RegisterUpgradeHandlers returns if store loader is overridden. // No store-key churn from v0.53→v0.54 in this app, so the default // MaxVersionStoreLoader (set by the caller when this returns false) // covers both regular and upgrade-height boots. func (app *App) RegisterUpgradeHandlers(cdc codec.BinaryCodec, maxVersion int64) bool { + for _, addr := range croBridgeContractAddresses { + if !common.IsHexAddress(addr) || (common.HexToAddress(addr) == common.Address{}) { + panic(fmt.Sprintf("invalid croBridgeContractAddresses entry %q: must be a non-zero EVM hex address", addr)) + } + } app.UpgradeKeeper.SetUpgradeHandler(planName, func(ctx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { toVM, err := app.ModuleManager.RunMigrations(ctx, app.configurator, fromVM) @@ -50,6 +63,14 @@ func (app *App) RegisterUpgradeHandlers(cdc codec.BinaryCodec, maxVersion int64) )); err != nil { return toVM, fmt.Errorf("prune stale ibc consensus state subkeys: %w", err) } + // Set CroBridgeContractAddresses to authorize the canonical CroBridge contracts + // for the SendCroToIbc hook. This closes the unauthenticated-drain vulnerability + // where any contract emitting __CronosSendCroToIbc could drain CRO balances. + cronosParams := app.CronosKeeper.GetParams(sdkCtx) + cronosParams.CroBridgeContractAddresses = croBridgeContractAddresses + if err := app.CronosKeeper.SetParams(sdkCtx, cronosParams); err != nil { + return toVM, fmt.Errorf("set cro bridge contract addresses: %w", err) + } return toVM, nil }, ) diff --git a/app/upgrades_test.go b/app/upgrades_test.go index f78c00687c..a641fbdb4b 100644 --- a/app/upgrades_test.go +++ b/app/upgrades_test.go @@ -6,6 +6,7 @@ import ( dbm "github.com/cosmos/cosmos-db" host "github.com/cosmos/ibc-go/v11/modules/core/24-host" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "cosmossdk.io/log/v2" @@ -60,3 +61,30 @@ func TestPruneStaleIBCConsensusStateSubkeys(t *testing.T) { require.NotNil(t, store.Get([]byte(k)), "canonical key %s must survive second run", k) } } + +// TestUpgradeV18CroBridgeContractAddresses verifies that: +// 1. croBridgeContractAddresses are all valid EVM addresses. +// 2. The upgrade handler param migration correctly persists the values via SetParams/GetParams. +func TestUpgradeV18CroBridgeContractAddresses(t *testing.T) { + for _, addr := range croBridgeContractAddresses { + require.True(t, common.IsHexAddress(addr), + "croBridgeContractAddresses entry must be a valid EVM hex address, got: %s", + addr) + require.NotEqual(t, common.Address{}, common.HexToAddress(addr), + "croBridgeContractAddresses entry must not be the zero address, got: %s", + addr) + } + + // Verify the migration code path: GetParams → mutate → SetParams → GetParams round-trips correctly. + a := Setup(t, "") + ctx := a.NewContext(false) + + // Apply the same mutation the upgrade handler performs. + params := a.CronosKeeper.GetParams(ctx) + params.CroBridgeContractAddresses = croBridgeContractAddresses + require.NoError(t, a.CronosKeeper.SetParams(ctx, params)) + + stored := a.CronosKeeper.GetParams(ctx) + require.ElementsMatch(t, croBridgeContractAddresses, stored.CroBridgeContractAddresses, + "CroBridgeContractAddresses not persisted by SetParams") +} diff --git a/integration_tests/test_gov_update_params.py b/integration_tests/test_gov_update_params.py index 31e6b2a7fc..4fca820dea 100644 --- a/integration_tests/test_gov_update_params.py +++ b/integration_tests/test_gov_update_params.py @@ -52,6 +52,7 @@ def test_evm_update_param(cronos, tmp_path): def test_gov_update_params(cronos): params = { "cronos_admin": "crc12luku6uxehhak02py4rcz65zu0swh7wjsrw0pp", + "cro_bridge_contract_addresses": [], "enable_auto_deployment": False, "ibc_cro_denom": "ibc/6411AE2ADA1E73DB59DB151" "A8988F9B7D5E7E233D8414DB6817F8F1A01600000", diff --git a/integration_tests/test_ibc.py b/integration_tests/test_ibc.py index 28b581e811..793a3a8c81 100644 --- a/integration_tests/test_ibc.py +++ b/integration_tests/test_ibc.py @@ -20,6 +20,7 @@ deploy_contract, parse_events_rpc, send_transaction, + submit_gov_proposal, wait_for_fn, ) @@ -186,6 +187,35 @@ def test_cro_bridge_contract(ibc): # case 2: use CroBridge contract w3 = ibc.cronos.w3 contract = deploy_contract(w3, CONTRACTS["CroBridge"]) + + # Authorize the deployed CroBridge contract via governance before making + # the bridge call. Without this, SendCroToIbcHandler rejects all callers. + cli = ibc.cronos.cosmos_cli() + gov_params = cli.query_params() + gov_params["cro_bridge_contract_addresses"] = [contract.address] + update_msg = "/cronos.MsgUpdateParams" + submit_gov_proposal( + ibc.cronos, + update_msg, + messages=[ + { + "@type": update_msg, + "authority": module_address("gov"), + "params": gov_params, + } + ], + ) + + # Verify the param was stored correctly + stored_params = cli.query_params() + stored_addresses = [ + a.lower() for a in stored_params.get("cro_bridge_contract_addresses", []) + ] + assert contract.address.lower() in stored_addresses, ( + f"cro_bridge_contract_addresses does not contain " + f"{contract.address}: {stored_params}" + ) + tx = contract.functions.send_cro_to_crypto_org(dst_addr).build_transaction( { "from": ADDRS["signer2"], diff --git a/integration_tests/test_upgrade.py b/integration_tests/test_upgrade.py index 44cb393355..e1e1ff4d53 100644 --- a/integration_tests/test_upgrade.py +++ b/integration_tests/test_upgrade.py @@ -376,6 +376,13 @@ def do_upgrade(plan_name, target, mode=None): check_basic_tx(c) check_ibc_client_states(ports.api_port(base_port), ibc_snapshot) + # Verify CroBridgeContractAddresses param was written by the upgrade handler. + cronos_params = cli.query_params() + assert cronos_params.get("cro_bridge_contract_addresses", []) == [ + "0x6b1b50c2223eb31E0d4683b046ea9C6CB0D0ea4F", + "0xCE13a6F3d4167CE958f4764D423e6D62a114c751", + ], f"unexpected cro_bridge_contract_addresses: {cronos_params}" + tx_af = w3.provider.make_request(method, params) assert tx_af.get("result") == tx_bf.get("result"), tx_af diff --git a/proto/cronos/cronos.proto b/proto/cronos/cronos.proto index eea74fb137..91dab86b40 100644 --- a/proto/cronos/cronos.proto +++ b/proto/cronos/cronos.proto @@ -14,6 +14,8 @@ message Params { string cronos_admin = 3; bool enable_auto_deployment = 4; uint64 max_callback_gas = 5; + // the authorized contract addresses for the SendCroToIbc hook; empty list disables the hook + repeated string cro_bridge_contract_addresses = 6; } // TokenMappingChangeProposal defines a proposal to change one token mapping. diff --git a/x/cronos/keeper/evmhandlers/send_cro_to_ibc.go b/x/cronos/keeper/evmhandlers/send_cro_to_ibc.go index 1f538335e8..026bee356e 100644 --- a/x/cronos/keeper/evmhandlers/send_cro_to_ibc.go +++ b/x/cronos/keeper/evmhandlers/send_cro_to_ibc.go @@ -1,7 +1,9 @@ package evmhandler import ( + "fmt" "math/big" + "slices" cronoskeeper "github.com/crypto-org-chain/cronos/x/cronos/keeper" "github.com/crypto-org-chain/cronos/x/cronos/types" @@ -70,6 +72,13 @@ func (h SendCroToIbcHandler) Handle( data []byte, _ func(contractAddress common.Address, logSig common.Hash, logData []byte), ) error { + authorizedBridges := h.cronosKeeper.GetParams(ctx).CroBridgeContractAddresses + if !slices.ContainsFunc(authorizedBridges, func(addr string) bool { + return common.HexToAddress(addr) == contract + }) { + return fmt.Errorf("contract %s is not authorized to use SendCroToIbc hook", contract) + } + unpacked, err := SendCroToIbcEvent.Inputs.Unpack(data) if err != nil { // log and ignore diff --git a/x/cronos/keeper/evmhandlers_test.go b/x/cronos/keeper/evmhandlers_test.go index b962653ec5..7cf80bb2a3 100644 --- a/x/cronos/keeper/evmhandlers_test.go +++ b/x/cronos/keeper/evmhandlers_test.go @@ -356,9 +356,62 @@ func (suite *KeeperTestSuite) TestSendCroToIbcHandler() { postcheck func() error error }{ + { + "unauthorized contract (param not set), expect fail", + func() { + params := suite.app.CronosKeeper.GetParams(suite.ctx) + params.CroBridgeContractAddresses = []string{} + err := suite.app.CronosKeeper.SetParams(suite.ctx, params) + suite.Require().NoError(err) + + coin := sdk.NewCoin(suite.evmParam.EvmDenom, sdkmath.NewInt(1230000000500)) + err = suite.MintCoins(contract.Bytes(), sdk.NewCoins(coin)) + suite.Require().NoError(err) + topics = []common.Hash{ + evmhandlers.SendCroToIbcEvent.ID, + } + input, _ := evmhandlers.SendToIbcEvent.Inputs.NonIndexed().Pack( + sender, + "recipient", + coin.Amount.BigInt(), + ) + data = input + }, + func() {}, + fmt.Errorf("contract %s is not authorized to use SendCroToIbc hook", contract), + }, + { + "unauthorized contract (different address in param), expect fail", + func() { + params := suite.app.CronosKeeper.GetParams(suite.ctx) + params.CroBridgeContractAddresses = []string{common.BigToAddress(big.NewInt(0x999)).Hex()} + err := suite.app.CronosKeeper.SetParams(suite.ctx, params) + suite.Require().NoError(err) + + coin := sdk.NewCoin(suite.evmParam.EvmDenom, sdkmath.NewInt(1230000000500)) + err = suite.MintCoins(contract.Bytes(), sdk.NewCoins(coin)) + suite.Require().NoError(err) + topics = []common.Hash{ + evmhandlers.SendCroToIbcEvent.ID, + } + input, _ := evmhandlers.SendToIbcEvent.Inputs.NonIndexed().Pack( + sender, + "recipient", + coin.Amount.BigInt(), + ) + data = input + }, + func() {}, + fmt.Errorf("contract %s is not authorized to use SendCroToIbc hook", contract), + }, { "not enough balance, fail", func() { + params := suite.app.CronosKeeper.GetParams(suite.ctx) + params.CroBridgeContractAddresses = []string{contract.Hex()} + err := suite.app.CronosKeeper.SetParams(suite.ctx, params) + suite.Require().NoError(err) + coin := sdk.NewCoin(suite.evmParam.EvmDenom, sdkmath.NewInt(10000000000000)) topics = []common.Hash{ evmhandlers.SendCroToIbcEvent.ID, @@ -377,8 +430,13 @@ func (suite *KeeperTestSuite) TestSendCroToIbcHandler() { { "success send cro to ibc", func() { + params := suite.app.CronosKeeper.GetParams(suite.ctx) + params.CroBridgeContractAddresses = []string{contract.Hex()} + err := suite.app.CronosKeeper.SetParams(suite.ctx, params) + suite.Require().NoError(err) + coin := sdk.NewCoin(suite.evmParam.EvmDenom, sdkmath.NewInt(1230000000500)) - err := suite.MintCoins(contract.Bytes(), sdk.NewCoins(coin)) + err = suite.MintCoins(contract.Bytes(), sdk.NewCoins(coin)) suite.Require().NoError(err) balance := suite.app.BankKeeper.GetBalance(suite.ctx, contract.Bytes(), suite.evmParam.EvmDenom) diff --git a/x/cronos/simulation/genesis.go b/x/cronos/simulation/genesis.go index 1fa283a211..c20d96061d 100644 --- a/x/cronos/simulation/genesis.go +++ b/x/cronos/simulation/genesis.go @@ -77,11 +77,11 @@ func RandomizedGenState(simState *module.SimulationState) { ) simState.AppParams.GetOrGenerate( - maxCallbackGasKey, &ibcTimeout, simState.Rand, - func(r *rand.Rand) { maxCallbackGas = GenIbcTimeout(r) }, + maxCallbackGasKey, &maxCallbackGas, simState.Rand, + func(r *rand.Rand) { maxCallbackGas = GenMaxCallbackGas(r) }, ) - params := types.NewParams(ibcCroDenom, ibcTimeout, cronosAdmin, enableAutoDeployment, maxCallbackGas) + params := types.NewParams(ibcCroDenom, ibcTimeout, cronosAdmin, enableAutoDeployment, maxCallbackGas, []string{}) cronosGenesis := &types.GenesisState{ Params: params, ExternalContracts: nil, diff --git a/x/cronos/types/cronos.pb.go b/x/cronos/types/cronos.pb.go index 1aaa2f5b0a..bce5daf671 100644 --- a/x/cronos/types/cronos.pb.go +++ b/x/cronos/types/cronos.pb.go @@ -31,6 +31,8 @@ type Params struct { CronosAdmin string `protobuf:"bytes,3,opt,name=cronos_admin,json=cronosAdmin,proto3" json:"cronos_admin,omitempty"` EnableAutoDeployment bool `protobuf:"varint,4,opt,name=enable_auto_deployment,json=enableAutoDeployment,proto3" json:"enable_auto_deployment,omitempty"` MaxCallbackGas uint64 `protobuf:"varint,5,opt,name=max_callback_gas,json=maxCallbackGas,proto3" json:"max_callback_gas,omitempty"` + // the authorized contract addresses for the SendCroToIbc hook; empty list disables the hook + CroBridgeContractAddresses []string `protobuf:"bytes,6,rep,name=cro_bridge_contract_addresses,json=croBridgeContractAddresses,proto3" json:"cro_bridge_contract_addresses,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -100,6 +102,13 @@ func (m *Params) GetMaxCallbackGas() uint64 { return 0 } +func (m *Params) GetCroBridgeContractAddresses() []string { + if m != nil { + return m.CroBridgeContractAddresses + } + return nil +} + // TokenMappingChangeProposal defines a proposal to change one token mapping. type TokenMappingChangeProposal struct { Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` @@ -205,36 +214,38 @@ func init() { func init() { proto.RegisterFile("cronos/cronos.proto", fileDescriptor_8bc54992a93db2d2) } var fileDescriptor_8bc54992a93db2d2 = []byte{ - // 449 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xb1, 0x6f, 0xd3, 0x40, - 0x14, 0xc6, 0x7d, 0x25, 0x35, 0xc9, 0xa5, 0x45, 0xe8, 0x88, 0x2a, 0x2b, 0x83, 0x63, 0x3c, 0x79, - 0xa0, 0x8d, 0x10, 0x4c, 0x99, 0x68, 0x53, 0xc1, 0x80, 0x90, 0x2a, 0xab, 0x13, 0x8b, 0xf5, 0x7c, - 0x39, 0x39, 0xa7, 0xfa, 0xee, 0x59, 0xe7, 0x8b, 0x14, 0xff, 0x07, 0x8c, 0x8c, 0x8c, 0xfd, 0x5b, - 0x98, 0x18, 0x3b, 0x32, 0x21, 0x94, 0xfc, 0x07, 0x8c, 0x4c, 0xc8, 0xbe, 0xb4, 0xb4, 0x43, 0x27, - 0xdf, 0xf7, 0xfb, 0x64, 0x7d, 0xef, 0x7b, 0x7a, 0xf4, 0x05, 0x37, 0xa8, 0xb1, 0x9e, 0xba, 0xcf, - 0x49, 0x65, 0xd0, 0x22, 0xf3, 0x9d, 0x1a, 0x8f, 0x0a, 0x2c, 0xb0, 0x43, 0xd3, 0xf6, 0xe5, 0xdc, - 0xf8, 0x2f, 0xa1, 0xfe, 0x05, 0x18, 0x50, 0x35, 0x7b, 0x4f, 0x0f, 0x65, 0xce, 0x33, 0x6e, 0x30, - 0x5b, 0x08, 0x8d, 0x2a, 0x20, 0x11, 0x49, 0x06, 0x67, 0xf1, 0x9f, 0x5f, 0x93, 0xb0, 0x01, 0x55, - 0xce, 0xe2, 0x07, 0xf6, 0x2b, 0x54, 0xd2, 0x0a, 0x55, 0xd9, 0x26, 0x4e, 0x87, 0x32, 0xe7, 0x73, - 0x83, 0xe7, 0x2d, 0x67, 0x13, 0xda, 0xca, 0xcc, 0x4a, 0x25, 0x70, 0x65, 0x83, 0xbd, 0x88, 0x24, - 0xbd, 0x94, 0xca, 0x9c, 0x5f, 0x3a, 0xc2, 0x5e, 0xd2, 0x03, 0x37, 0x53, 0x06, 0x0b, 0x25, 0x75, - 0xf0, 0xa4, 0xcd, 0x49, 0x87, 0x8e, 0x9d, 0xb6, 0x88, 0xbd, 0xa5, 0x47, 0x42, 0x43, 0x5e, 0x8a, - 0x0c, 0x56, 0xb6, 0x0d, 0xac, 0x4a, 0x6c, 0x94, 0xd0, 0x36, 0xe8, 0x45, 0x24, 0xe9, 0xa7, 0x23, - 0xe7, 0x9e, 0xae, 0x2c, 0x9e, 0xdf, 0x79, 0x2c, 0xa1, 0xcf, 0x15, 0xac, 0x33, 0x0e, 0x65, 0x99, - 0x03, 0xbf, 0xca, 0x0a, 0xa8, 0x83, 0xfd, 0x2e, 0xfe, 0x99, 0x82, 0xf5, 0x7c, 0x87, 0x3f, 0x40, - 0x3d, 0xeb, 0x7d, 0xbb, 0x9e, 0x78, 0xf1, 0x77, 0x42, 0xc7, 0x97, 0x78, 0x25, 0xf4, 0x27, 0xa8, - 0x2a, 0xa9, 0x8b, 0xf9, 0x12, 0x74, 0x21, 0x2e, 0x0c, 0x56, 0x58, 0x43, 0xc9, 0x46, 0x74, 0xdf, - 0x4a, 0x5b, 0x0a, 0xb7, 0x88, 0xd4, 0x09, 0x16, 0xd1, 0xe1, 0x42, 0xd4, 0xdc, 0xc8, 0xca, 0x4a, - 0xd4, 0x5d, 0xbd, 0x41, 0x7a, 0x1f, 0xb5, 0xff, 0xb9, 0x05, 0xba, 0x62, 0x4e, 0xb0, 0x31, 0xed, - 0x73, 0xd4, 0xd6, 0x00, 0x77, 0x25, 0x06, 0xe9, 0x9d, 0x66, 0x47, 0xd4, 0xaf, 0x1b, 0x95, 0x63, - 0xd9, 0x8d, 0x3b, 0x48, 0x77, 0x8a, 0x05, 0xf4, 0xe9, 0x42, 0x70, 0xa9, 0xa0, 0x0c, 0xfc, 0x88, - 0x24, 0x87, 0xe9, 0xad, 0x9c, 0xf5, 0xbf, 0x5c, 0x4f, 0xbc, 0xae, 0xc4, 0x3b, 0x7a, 0x70, 0xbf, - 0xc3, 0xff, 0x74, 0xf2, 0x58, 0xfa, 0xde, 0xc3, 0xf4, 0xb3, 0x8f, 0x3f, 0x36, 0x21, 0xb9, 0xd9, - 0x84, 0xe4, 0xf7, 0x26, 0x24, 0x5f, 0xb7, 0xa1, 0x77, 0xb3, 0x0d, 0xbd, 0x9f, 0xdb, 0xd0, 0xfb, - 0xfc, 0xba, 0x90, 0x76, 0xb9, 0xca, 0x4f, 0x38, 0xaa, 0x29, 0x37, 0x4d, 0x65, 0xf1, 0x18, 0x4d, - 0x71, 0xcc, 0x97, 0x20, 0xf5, 0xee, 0xca, 0xa6, 0xeb, 0xdb, 0x87, 0x6d, 0x2a, 0x51, 0xe7, 0x7e, - 0x77, 0x57, 0x6f, 0xfe, 0x05, 0x00, 0x00, 0xff, 0xff, 0x94, 0xe0, 0x49, 0x81, 0x8c, 0x02, 0x00, - 0x00, + // 488 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x52, 0xb1, 0x6e, 0xdb, 0x3c, + 0x18, 0xb4, 0x1c, 0x47, 0xbf, 0x4d, 0x27, 0x3f, 0x0a, 0xd6, 0x08, 0x04, 0x03, 0x95, 0x55, 0x4d, + 0x1a, 0x9a, 0x18, 0x45, 0x3b, 0x79, 0xaa, 0xed, 0xa0, 0x1d, 0x8a, 0x02, 0x01, 0x91, 0xa9, 0x8b, + 0x40, 0x51, 0x84, 0x4c, 0x44, 0xe4, 0x27, 0x90, 0x34, 0x60, 0xbd, 0x41, 0xc7, 0x8e, 0x1d, 0xf3, + 0x22, 0x5d, 0x3a, 0x75, 0xcc, 0xd8, 0xa9, 0x28, 0xec, 0x37, 0xe8, 0x13, 0x14, 0x12, 0xed, 0x34, + 0x19, 0x3a, 0x89, 0x77, 0xf7, 0x09, 0xc7, 0x3b, 0x7e, 0xe8, 0x29, 0xd3, 0xa0, 0xc0, 0x4c, 0xdd, + 0xe7, 0xa2, 0xd2, 0x60, 0x01, 0xfb, 0x0e, 0x8d, 0x47, 0x05, 0x14, 0xd0, 0x52, 0xd3, 0xe6, 0xe4, + 0xd4, 0xf8, 0x6b, 0x17, 0xf9, 0x57, 0x54, 0x53, 0x69, 0xf0, 0x5b, 0x74, 0x2a, 0x32, 0x96, 0x32, + 0x0d, 0x69, 0xce, 0x15, 0xc8, 0xc0, 0x8b, 0xbc, 0x64, 0xb0, 0x88, 0x7f, 0xff, 0x9c, 0x84, 0x35, + 0x95, 0xe5, 0x2c, 0x7e, 0x24, 0xbf, 0x00, 0x29, 0x2c, 0x97, 0x95, 0xad, 0x63, 0x32, 0x14, 0x19, + 0x5b, 0x6a, 0xb8, 0x6c, 0x78, 0x3c, 0x41, 0x0d, 0x4c, 0xad, 0x90, 0x1c, 0xd6, 0x36, 0xe8, 0x46, + 0x5e, 0xd2, 0x23, 0x48, 0x64, 0xec, 0xda, 0x31, 0xf8, 0x39, 0x3a, 0x71, 0x77, 0x4a, 0x69, 0x2e, + 0x85, 0x0a, 0x8e, 0x1a, 0x1f, 0x32, 0x74, 0xdc, 0xbc, 0xa1, 0xf0, 0x6b, 0x74, 0xc6, 0x15, 0xcd, + 0x4a, 0x9e, 0xd2, 0xb5, 0x6d, 0x0c, 0xab, 0x12, 0x6a, 0xc9, 0x95, 0x0d, 0x7a, 0x91, 0x97, 0xf4, + 0xc9, 0xc8, 0xa9, 0xf3, 0xb5, 0x85, 0xcb, 0x7b, 0x0d, 0x27, 0xe8, 0x89, 0xa4, 0x9b, 0x94, 0xd1, + 0xb2, 0xcc, 0x28, 0xbb, 0x49, 0x0b, 0x6a, 0x82, 0xe3, 0xd6, 0xfe, 0x7f, 0x49, 0x37, 0xcb, 0x3d, + 0xfd, 0x8e, 0x1a, 0x3c, 0x47, 0xcf, 0x9a, 0x20, 0x99, 0x16, 0x79, 0xc1, 0x53, 0x06, 0xca, 0x6a, + 0xca, 0x6c, 0x4a, 0xf3, 0x5c, 0x73, 0x63, 0xb8, 0x09, 0xfc, 0xe8, 0x28, 0x19, 0x90, 0x31, 0xd3, + 0xb0, 0x68, 0x67, 0x96, 0xfb, 0x91, 0xf9, 0x61, 0x62, 0xd6, 0xfb, 0x72, 0x3b, 0xe9, 0xc4, 0xdf, + 0x3c, 0x34, 0xbe, 0x86, 0x1b, 0xae, 0x3e, 0xd0, 0xaa, 0x12, 0xaa, 0x58, 0xae, 0xa8, 0x2a, 0xf8, + 0x95, 0x86, 0x0a, 0x0c, 0x2d, 0xf1, 0x08, 0x1d, 0x5b, 0x61, 0x4b, 0xee, 0xba, 0x24, 0x0e, 0xe0, + 0x08, 0x0d, 0x73, 0x6e, 0x98, 0x16, 0x95, 0x15, 0xa0, 0xda, 0x86, 0x06, 0xe4, 0x21, 0xd5, 0xfc, + 0xe7, 0xde, 0xc0, 0x75, 0xe3, 0x00, 0x1e, 0xa3, 0xfe, 0xe1, 0xaa, 0x6d, 0x0f, 0x03, 0x72, 0x8f, + 0xf1, 0x19, 0xf2, 0x4d, 0x2d, 0x33, 0x28, 0xdb, 0xc4, 0x03, 0xb2, 0x47, 0x38, 0x40, 0xff, 0xe5, + 0x9c, 0x09, 0x49, 0xcb, 0xc0, 0x8f, 0xbc, 0xe4, 0x94, 0x1c, 0xe0, 0xac, 0xff, 0xe9, 0x76, 0xd2, + 0x69, 0x43, 0xbc, 0x41, 0x27, 0x0f, 0x33, 0xfc, 0x75, 0xf7, 0xfe, 0xe5, 0xde, 0x7d, 0xec, 0xbe, + 0x78, 0xff, 0x7d, 0x1b, 0x7a, 0x77, 0xdb, 0xd0, 0xfb, 0xb5, 0x0d, 0xbd, 0xcf, 0xbb, 0xb0, 0x73, + 0xb7, 0x0b, 0x3b, 0x3f, 0x76, 0x61, 0xe7, 0xe3, 0xcb, 0x42, 0xd8, 0xd5, 0x3a, 0xbb, 0x60, 0x20, + 0xa7, 0x4c, 0xd7, 0x95, 0x85, 0x73, 0xd0, 0xc5, 0x39, 0x5b, 0x51, 0xa1, 0xf6, 0x8b, 0x3a, 0xdd, + 0x1c, 0x0e, 0xb6, 0xae, 0xb8, 0xc9, 0xfc, 0x76, 0x35, 0x5f, 0xfd, 0x09, 0x00, 0x00, 0xff, 0xff, + 0x88, 0x69, 0xed, 0xce, 0xcf, 0x02, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -257,6 +268,15 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.CroBridgeContractAddresses) > 0 { + for iNdEx := len(m.CroBridgeContractAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.CroBridgeContractAddresses[iNdEx]) + copy(dAtA[i:], m.CroBridgeContractAddresses[iNdEx]) + i = encodeVarintCronos(dAtA, i, uint64(len(m.CroBridgeContractAddresses[iNdEx]))) + i-- + dAtA[i] = 0x32 + } + } if m.MaxCallbackGas != 0 { i = encodeVarintCronos(dAtA, i, uint64(m.MaxCallbackGas)) i-- @@ -428,6 +448,12 @@ func (m *Params) Size() (n int) { if m.MaxCallbackGas != 0 { n += 1 + sovCronos(uint64(m.MaxCallbackGas)) } + if len(m.CroBridgeContractAddresses) > 0 { + for _, s := range m.CroBridgeContractAddresses { + l = len(s) + n += 1 + l + sovCronos(uint64(l)) + } + } return n } @@ -637,6 +663,38 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CroBridgeContractAddresses", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCronos + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCronos + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCronos + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CroBridgeContractAddresses = append(m.CroBridgeContractAddresses, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipCronos(dAtA[iNdEx:]) diff --git a/x/cronos/types/params.go b/x/cronos/types/params.go index dea732b8af..4ff596fc92 100644 --- a/x/cronos/types/params.go +++ b/x/cronos/types/params.go @@ -3,6 +3,7 @@ package types import ( "fmt" + "github.com/ethereum/go-ethereum/common" yaml "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" @@ -20,6 +21,8 @@ var ( KeyEnableAutoDeployment = []byte("EnableAutoDeployment") // KeyMaxCallbackGas is store's key for the MaxCallbackGas KeyMaxCallbackGas = []byte("MaxCallbackGas") + // KeyCroBridgeContractAddresses is store's key for the authorized CroBridge contract addresses + KeyCroBridgeContractAddresses = []byte("CroBridgeContractAddresses") ) const ( @@ -34,13 +37,14 @@ func ParamKeyTable() paramtypes.KeyTable { } // NewParams creates a new parameter configuration for the cronos module -func NewParams(ibcCroDenom string, ibcTimeout uint64, cronosAdmin string, enableAutoDeployment bool, maxCallbackGas uint64) Params { +func NewParams(ibcCroDenom string, ibcTimeout uint64, cronosAdmin string, enableAutoDeployment bool, maxCallbackGas uint64, croBridgeContractAddresses []string) Params { return Params{ - IbcCroDenom: ibcCroDenom, - IbcTimeout: ibcTimeout, - CronosAdmin: cronosAdmin, - EnableAutoDeployment: enableAutoDeployment, - MaxCallbackGas: maxCallbackGas, + IbcCroDenom: ibcCroDenom, + IbcTimeout: ibcTimeout, + CronosAdmin: cronosAdmin, + EnableAutoDeployment: enableAutoDeployment, + MaxCallbackGas: maxCallbackGas, + CroBridgeContractAddresses: croBridgeContractAddresses, } } @@ -71,6 +75,9 @@ func (p Params) Validate() error { if err := validateIsUint64(p.MaxCallbackGas); err != nil { return err } + if err := validateIsEvmAddresses(p.CroBridgeContractAddresses); err != nil { + return err + } return nil } @@ -88,6 +95,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyCronosAdmin, &p.CronosAdmin, validateIsAddress), paramtypes.NewParamSetPair(KeyEnableAutoDeployment, &p.EnableAutoDeployment, validateIsBool), paramtypes.NewParamSetPair(KeyMaxCallbackGas, &p.MaxCallbackGas, validateIsUint64), + paramtypes.NewParamSetPair(KeyCroBridgeContractAddresses, &p.CroBridgeContractAddresses, validateIsEvmAddresses), } } @@ -130,3 +138,16 @@ func validateIsBool(i interface{}) error { } return nil } + +func validateIsEvmAddresses(i interface{}) error { + addrs, ok := i.([]string) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + for _, addr := range addrs { + if !common.IsHexAddress(addr) || (common.HexToAddress(addr) == common.Address{}) { + return fmt.Errorf("invalid evm address: %s: must be a non-zero EVM hex address", addr) + } + } + return nil +}