diff --git a/CHANGELOG.md b/CHANGELOG.md index 43853ccf33..aa30e2041e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - (deps) [#1121](https://github.com/crypto-org-chain/cronos/pull/1121) Bump Cosmos-SDK to v0.47.5 and ibc-go to v7.2.0. - [cronos#1014](https://github.com/crypto-org-chain/cronos/pull/1014) Support stateful precompiled contract for relayer. - [cronos#1165](https://github.com/crypto-org-chain/cronos/pull/1165) Icaauth module is not adjusted correctly in ibc-go v7.2.0. +- [cronos#1163](https://github.com/crypto-org-chain/cronos/pull/1163) Support stateful precompiled contract for ica. - [cronos#837](https://github.com/crypto-org-chain/cronos/pull/837) Support stateful precompiled contract for bank. ### Bug Fixes diff --git a/app/app.go b/app/app.go index 872a370d24..37ae47cd2c 100644 --- a/app/app.go +++ b/app/app.go @@ -551,6 +551,7 @@ func New( []vm.PrecompiledContract{ cronosprecompiles.NewBankContract(app.BankKeeper, appCodec), cronosprecompiles.NewRelayerContract(app.IBCKeeper, appCodec), + cronosprecompiles.NewIcaContract(&app.ICAAuthKeeper, appCodec), }, allKeys, ) diff --git a/app/bench_test.go b/app/bench_test.go index d78ad6a802..99644ef256 100644 --- a/app/bench_test.go +++ b/app/bench_test.go @@ -68,7 +68,7 @@ func benchmarkERC20Transfer(b *testing.B, db dbm.DB) { ethSigner := ethtypes.LatestSignerForChainID(chainID) signTx := func(msg *evmtypes.MsgEthereumTx) ([]byte, error) { - msg.From = address.String() + msg.From = address.Bytes() if err := msg.Sign(ethSigner, signer); err != nil { return nil, err } diff --git a/go.mod b/go.mod index fd81a8153c..44135e458d 100644 --- a/go.mod +++ b/go.mod @@ -233,7 +233,7 @@ replace ( // TODO: remove it: https://github.com/cosmos/cosmos-sdk/issues/13134 github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.4.2 github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc1 - github.com/evmos/ethermint => github.com/crypto-org-chain/ethermint v0.6.1-0.20230921025237-ae144329ecaf + github.com/evmos/ethermint => github.com/crypto-org-chain/ethermint v0.6.1-0.20230925010909-716b0754a135 // Fix upstream GHSA-h395-qcrw-5vmq and GHSA-3vp4-m3rf-835h vulnerabilities. // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0 diff --git a/go.sum b/go.sum index 40bc958521..beee47a969 100644 --- a/go.sum +++ b/go.sum @@ -482,8 +482,8 @@ github.com/crypto-org-chain/cometbft-db v0.0.0-20230921030527-0d47d7537e32 h1:Vq github.com/crypto-org-chain/cometbft-db v0.0.0-20230921030527-0d47d7537e32/go.mod h1:V32HRAjDsAYLfAT90mk0O9UH+sE7P5apfiCmmmVLt3Q= github.com/crypto-org-chain/cosmos-sdk v0.46.0-beta2.0.20230905040840-b3af5590283b h1:d2GOFR3i3BjDlPsmJkp8Gsrt9LK2nq2IVEnE/rMv1Fo= github.com/crypto-org-chain/cosmos-sdk v0.46.0-beta2.0.20230905040840-b3af5590283b/go.mod h1:EHwCeN9IXonsjKcjpS12MqeStdZvIdxt3VYXhus3G3c= -github.com/crypto-org-chain/ethermint v0.6.1-0.20230921025237-ae144329ecaf h1:XvwFJ6kPHOYevfNjshq4n2nazvYzoSaQ8AjSYWSfUhI= -github.com/crypto-org-chain/ethermint v0.6.1-0.20230921025237-ae144329ecaf/go.mod h1:KtjU2MHMCTcLnAoS9C3U3f+vx4f9HHNQRcOlxXiVDxY= +github.com/crypto-org-chain/ethermint v0.6.1-0.20230925010909-716b0754a135 h1:hF+Xu71O4pKb8kvlGRO41qR9dqavoaqg4k1xOKZ0m9k= +github.com/crypto-org-chain/ethermint v0.6.1-0.20230925010909-716b0754a135/go.mod h1:KtjU2MHMCTcLnAoS9C3U3f+vx4f9HHNQRcOlxXiVDxY= github.com/crypto-org-chain/gravity-bridge/module/v2 v2.0.1-0.20230825054824-75403cd90c6e h1:rSTc35OBjjCBx47rHPWBCIHNGPbMnEj8f7fNcK2TjVI= github.com/crypto-org-chain/gravity-bridge/module/v2 v2.0.1-0.20230825054824-75403cd90c6e/go.mod h1:HBaDqlFjlaXJwVQtA7jHejyaA7xwjXI2o6pU/ccP3tE= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= diff --git a/gomod2nix.toml b/gomod2nix.toml index 01fd3bf28d..d132fee81a 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -213,8 +213,8 @@ schema = 3 hash = "sha256-GgcReGsIIuBE2TabDYqDO9sBGogdVr9RSh4arQzdPnE=" replaced = "github.com/evmos/go-ethereum" [mod."github.com/evmos/ethermint"] - version = "v0.6.1-0.20230921025237-ae144329ecaf" - hash = "sha256-ZDzwB65qROKNIB4Yv1i+5FTJoejeuRCcUzUacyuFBFw=" + version = "v0.6.1-0.20230925010909-716b0754a135" + hash = "sha256-I4NiYqyR3Cgs4QWrqod9ABCtpU0c5LVlyGr38GNjAxg=" replaced = "github.com/crypto-org-chain/ethermint" [mod."github.com/felixge/httpsnoop"] version = "v1.0.2" diff --git a/integration_tests/configs/ibc.jsonnet b/integration_tests/configs/ibc.jsonnet index f6e8b98a7c..b991cd7223 100644 --- a/integration_tests/configs/ibc.jsonnet +++ b/integration_tests/configs/ibc.jsonnet @@ -20,6 +20,11 @@ config { base_fee: '0', }, }, + icaauth: { + params: { + min_timeout_duration: '1ms', + }, + }, }, }, }, @@ -100,6 +105,7 @@ config { params: { allow_messages: [ '/cosmos.bank.v1beta1.MsgSend', + '/cosmos.staking.v1beta1.MsgDelegate', ], }, }, diff --git a/integration_tests/contracts/contracts/TestICA.sol b/integration_tests/contracts/contracts/TestICA.sol new file mode 100644 index 0000000000..c4c80ab023 --- /dev/null +++ b/integration_tests/contracts/contracts/TestICA.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import {IICAModule} from "./src/ICA.sol"; + +contract TestICA { + address constant icaContract = 0x0000000000000000000000000000000000000066; + IICAModule ica = IICAModule(icaContract); + address account; + uint64 lastAckSeq; + + function encodeRegister(string memory connectionID, string memory version) internal view returns (bytes memory) { + return abi.encodeWithSignature( + "registerAccount(string,string)", + connectionID, msg.sender, version + ); + } + + function callRegister(string memory connectionID, string memory version) public returns (bool) { + require(account == address(0) || account == msg.sender, "register fail"); + bool result = ica.registerAccount(connectionID, version); + require(result, "call failed"); + account = msg.sender; + } + + function getAccount() public view returns (address) { + return account; + } + + function delegateRegister(string memory connectionID, string memory version) public returns (bool) { + (bool result,) = icaContract.delegatecall(encodeRegister(connectionID, version)); + require(result, "call failed"); + return true; + } + + function staticRegister(string memory connectionID, string memory version) public returns (bool) { + (bool result,) = icaContract.staticcall(encodeRegister(connectionID, version)); + require(result, "call failed"); + return true; + } + + function encodeQueryAccount(string memory connectionID, address addr) internal view returns (bytes memory) { + return abi.encodeWithSignature( + "queryAccount(string,address)", + connectionID, addr + ); + } + + function callQueryAccount(string memory connectionID, address addr) public returns (string memory) { + return ica.queryAccount(connectionID, addr); + } + + function delegateQueryAccount(string memory connectionID, address addr) public returns (string memory) { + (bool result, bytes memory data) = icaContract.delegatecall(encodeQueryAccount(connectionID, addr)); + require(result, "call failed"); + return abi.decode(data, (string)); + } + + function staticQueryAccount(string memory connectionID, address addr) public returns (string memory) { + (bool result, bytes memory data) = icaContract.staticcall(encodeQueryAccount(connectionID, addr)); + require(result, "call failed"); + return abi.decode(data, (string)); + } + + function encodeSubmitMsgs(string memory connectionID, bytes memory data, uint256 timeout) internal view returns (bytes memory) { + return abi.encodeWithSignature( + "submitMsgs(string,bytes,uint256)", + connectionID, msg.sender, data, timeout + ); + } + + function callSubmitMsgs(string memory connectionID, bytes memory data, uint256 timeout) public returns (uint64) { + require(account == msg.sender, "not authorized"); + lastAckSeq = ica.submitMsgs(connectionID, data, timeout); + return lastAckSeq; + } + + function delegateSubmitMsgs(string memory connectionID, bytes memory data, uint256 timeout) public returns (uint64) { + (bool result, bytes memory data) = icaContract.delegatecall(encodeSubmitMsgs(connectionID, data, timeout)); + require(result, "call failed"); + lastAckSeq = abi.decode(data, (uint64)); + return lastAckSeq; + } + + function staticSubmitMsgs(string memory connectionID, bytes memory data, uint256 timeout) public returns (uint64) { + (bool result, bytes memory data) = icaContract.staticcall(encodeSubmitMsgs(connectionID, data, timeout)); + require(result, "call failed"); + lastAckSeq = abi.decode(data, (uint64)); + return lastAckSeq; + } + + function getLastAckSeq() public view returns (uint256) { + return lastAckSeq; + } +} \ No newline at end of file diff --git a/integration_tests/cosmoscli.py b/integration_tests/cosmoscli.py index a00e9b6b88..f98104f2aa 100644 --- a/integration_tests/cosmoscli.py +++ b/integration_tests/cosmoscli.py @@ -1062,10 +1062,10 @@ def set_delegate_keys(self, val_addr, acc_addr, eth_addr, signature, **kwargs): ) def query_gravity_params(self): - return json.loads(self.raw("query", "gravity", "params", home=self.data_dir)) + return self.query_params("gravity") - def query_evm_params(self): - return json.loads(self.raw("query", "evm", "params", home=self.data_dir)) + def query_params(self, module="cronos"): + return json.loads(self.raw("query", module, "params", home=self.data_dir)) def query_signer_set_txs(self): return json.loads( @@ -1275,7 +1275,7 @@ def icaauth_register_account(self, connid, **kwargs): rsp = self.event_query_tx_for(rsp["txhash"]) return rsp - def icaauth_submit_tx(self, connid, tx, **kwargs): + def icaauth_submit_tx(self, connid, tx, timeout_duration="1h", **kwargs): default_kwargs = { "home": self.data_dir, "node": self.node_rpc, @@ -1289,6 +1289,8 @@ def icaauth_submit_tx(self, connid, tx, **kwargs): "submit-tx", connid, tx, + "--timeout-duration" if timeout_duration else None, + timeout_duration if timeout_duration else None, "-y", **(default_kwargs | kwargs), ) @@ -1586,17 +1588,6 @@ def turn_bridge(self, enable, **kwargs): ) ) - def query_params(self): - "query cronos params" - return json.loads( - self.raw( - "query", - "cronos", - "params", - home=self.data_dir, - ) - ) - def evm_params(self, **kwargs): default_kwargs = { "node": self.node_rpc, diff --git a/integration_tests/ibc_utils.py b/integration_tests/ibc_utils.py index 78e203344b..68d62d55ec 100644 --- a/integration_tests/ibc_utils.py +++ b/integration_tests/ibc_utils.py @@ -597,6 +597,21 @@ def funds_ica(cli, adr): rsp = cli.transfer("signer2", adr, "1cro", gas_prices="1000000basecro") assert rsp["code"] == 0, rsp["raw_log"] wait_for_new_blocks(cli, 1) - + amt = 100000000 # check if the funds are received in interchain account - assert cli.balance(adr, denom="basecro") == 100000000 + assert cli.balance(adr, denom="basecro") == amt + return amt + + +def assert_channel_open_init(rsp): + assert rsp["code"] == 0, rsp["raw_log"] + port_id, channel_id = next( + ( + evt["attributes"][0]["value"], + evt["attributes"][1]["value"], + ) + for evt in rsp["events"] + if evt["type"] == "channel_open_init" + ) + print("port-id", port_id, "channel-id", channel_id) + return port_id, channel_id diff --git a/integration_tests/test_ibc_rly.py b/integration_tests/test_ibc_rly.py index d9800dfa01..5fc1f1f5c7 100644 --- a/integration_tests/test_ibc_rly.py +++ b/integration_tests/test_ibc_rly.py @@ -4,10 +4,8 @@ import subprocess import pytest -from eth_utils import abi, keccak, to_checksum_address +from eth_utils import keccak, to_checksum_address from pystarport import cluster -from web3._utils.contracts import abi_to_signature, find_matching_event_abi -from web3._utils.events import get_event_data from web3.datastructures import AttributeDict from .ibc_utils import ( @@ -24,14 +22,17 @@ CONTRACT_ABIS, bech32_to_eth, eth_to_bech32, + get_logs_since, + get_method_map, + get_topic_data, module_address, wait_for_fn, wait_for_new_blocks, ) CONTRACT = "0x0000000000000000000000000000000000000065" -method_map = None -contract_info = None +contract_info = json.loads(CONTRACT_ABIS["IRelayerModule"].read_text()) +method_map = get_method_map(contract_info) cronos_signer2 = ADDRS["signer2"] src_amount = 10 src_denom = "basecro" @@ -81,41 +82,6 @@ def rly_transfer(ibc): subprocess.run(cmd, check=True, shell=True) -def get_method_map(): - global contract_info - if contract_info is None: - contract_info = json.loads(CONTRACT_ABIS["IRelayerModule"].read_text()) - global method_map - if method_map is None: - method_map = {} - for item in contract_info: - event_abi = find_matching_event_abi(contract_info, item["name"]) - signature = abi_to_signature(event_abi) - key = f"0x{abi.event_signature_to_log_topic(signature).hex()}" - method_map[key] = signature - return method_map, contract_info - - -def get_topic_data(w3, log): - method_map, info = get_method_map() - method = method_map[log.topics[0].hex()] - name = method.split("(")[0] - event_abi = find_matching_event_abi(info, name) - event_data = get_event_data(w3.codec, event_abi, log) - return name, event_data.args - - -def get_logs(w3, start): - end = w3.eth.get_block_number() - return w3.eth.get_logs( - { - "fromBlock": start, - "toBlock": end, - "address": [CONTRACT], - } - ) - - def coin_received(receiver, amt, denom): return { "receiver": receiver, @@ -238,7 +204,7 @@ def check_balance_change(): wait_for_fn("balance change", check_balance_change) assert old_dst_balance + dst_amount == new_dst_balance - logs = get_logs(w3, start) + logs = get_logs_since(w3, CONTRACT, start) relayer0 = ibc.chainmain.cosmos_cli().address("relayer") relayer = to_checksum_address(bech32_to_eth(relayer0)) cronos_addr = module_address("cronos") @@ -253,7 +219,7 @@ def check_balance_change(): write_ack(relayer0, cronos_signer2, src_amount, src_denom), ] for i, log in enumerate(logs): - method_name, args = get_topic_data(w3, log) + method_name, args = get_topic_data(w3, method_map, contract_info, log) assert args == AttributeDict(expected[i]), [i, method_name] @@ -269,7 +235,7 @@ def test_ibc_incentivized_transfer(ibc): wait_for_new_blocks(cli, 1) start = w3.eth.get_block_number() amount = ibc_incentivized_transfer(ibc) - logs = get_logs(w3, start) + logs = get_logs_since(w3, CONTRACT, start) fee_denom = "ibcfee" fee = f"{src_amount}{fee_denom}" transfer_denom = "transfer/channel-0/basetcro" @@ -294,7 +260,7 @@ def test_ibc_incentivized_transfer(ibc): ] assert len(logs) == len(expected) for i, log in enumerate(logs): - method_name, args = get_topic_data(w3, log) + method_name, args = get_topic_data(w3, method_map, contract_info, log) assert args == AttributeDict(expected[i]), [i, method_name] @@ -322,13 +288,13 @@ def test_cronos_transfer_source_tokens(ibc): w3 = ibc.cronos.w3 start = w3.eth.get_block_number() amount, contract = cronos_transfer_source_tokens(ibc) - logs = get_logs(w3, start) + logs = get_logs_since(w3, CONTRACT, start) escrow = get_escrow_address(cli, channel) dst_adr = ibc.chainmain.cosmos_cli().address("signer2") expected = get_transfer_source_tokens_topics(dst_adr, amount, contract, escrow) assert len(logs) == len(expected) for i, log in enumerate(logs): - method_name, args = get_topic_data(w3, log) + method_name, args = get_topic_data(w3, method_map, contract_info, log) assert args == AttributeDict(expected[i]), [i, method_name] @@ -338,11 +304,11 @@ def test_cronos_transfer_source_tokens_with_proxy(ibc): w3 = ibc.cronos.w3 start = w3.eth.get_block_number() amount, contract = cronos_transfer_source_tokens_with_proxy(ibc) - logs = get_logs(w3, start) + logs = get_logs_since(w3, CONTRACT, start) escrow = get_escrow_address(cli, channel) dst_adr = ibc.chainmain.cosmos_cli().address("signer2") expected = get_transfer_source_tokens_topics(dst_adr, amount, contract, escrow) assert len(logs) == len(expected) for i, log in enumerate(logs): - method_name, args = get_topic_data(w3, log) + method_name, args = get_topic_data(w3, method_map, contract_info, log) assert args == AttributeDict(expected[i]), [i, method_name] diff --git a/integration_tests/test_ica.py b/integration_tests/test_ica.py index 3201a537fd..04c069810e 100644 --- a/integration_tests/test_ica.py +++ b/integration_tests/test_ica.py @@ -3,6 +3,7 @@ import pytest from .ibc_utils import ( + assert_channel_open_init, funds_ica, prepare_network, wait_for_check_channel_ready, @@ -28,17 +29,7 @@ def test_ica(ibc, tmp_path): rsp = cli_controller.icaauth_register_account( connid, from_="signer2", gas="400000", fees="100000000basetcro" ) - assert rsp["code"] == 0, rsp["raw_log"] - port_id, channel_id = next( - ( - evt["attributes"][0]["value"], - evt["attributes"][1]["value"], - ) - for evt in rsp["events"] - if evt["type"] == "channel_open_init" - ) - print("port-id", port_id, "channel-id", channel_id) - + _, channel_id = assert_channel_open_init(rsp) wait_for_check_channel_ready(cli_controller, connid, channel_id) print("query ica account") @@ -63,6 +54,7 @@ def test_ica(ibc, tmp_path): rsp = cli_controller.icaauth_submit_tx( connid, generated_tx, + timeout_duration="2h", from_="signer2", ) assert rsp["code"] == 0, rsp["raw_log"] diff --git a/integration_tests/test_ica_precompile.py b/integration_tests/test_ica_precompile.py new file mode 100644 index 0000000000..7aa08e714c --- /dev/null +++ b/integration_tests/test_ica_precompile.py @@ -0,0 +1,208 @@ +import base64 +import json + +import pytest +from web3.datastructures import AttributeDict + +from .ibc_utils import ( + funds_ica, + prepare_network, + wait_for_check_channel_ready, + wait_for_check_tx, +) +from .utils import ( + ADDRS, + CONTRACT_ABIS, + CONTRACTS, + KEYS, + deploy_contract, + eth_to_bech32, + get_logs_since, + get_method_map, + get_topic_data, + send_transaction, +) + +CONTRACT = "0x0000000000000000000000000000000000000066" +contract_info = json.loads(CONTRACT_ABIS["IICAModule"].read_text()) +method_map = get_method_map(contract_info) +connid = "connection-0" +timeout = 300000000000 +denom = "basecro" +keys = KEYS["signer2"] +validator = "validator" +amt = 1000 +amt1 = 100 + + +@pytest.fixture(scope="module") +def ibc(request, tmp_path_factory): + "prepare-network" + name = "ibc" + path = tmp_path_factory.mktemp(name) + network = prepare_network(path, name, incentivized=False, connection_only=True) + yield from network + + +def register_acc(cli, w3, register, query, data, addr, channel_id): + print("register ica account") + tx = register(connid, "").build_transaction(data) + receipt = send_transaction(w3, tx, keys) + assert receipt.status == 1 + owner = eth_to_bech32(addr) + wait_for_check_channel_ready(cli, connid, channel_id) + res = cli.ica_query_account(connid, owner) + ica_address = res["interchain_account_address"] + print("query ica account", ica_address) + res = query(connid, addr).call() + assert ica_address == res, res + return ica_address + + +def submit_msgs(ibc, func, data, ica_address, is_multi, seq): + cli_host = ibc.chainmain.cosmos_cli() + cli_controller = ibc.cronos.cosmos_cli() + w3 = ibc.cronos.w3 + to = cli_host.address(validator) + # generate msg send to host chain + msgs = [ + { + "@type": "/cosmos.bank.v1beta1.MsgSend", + "from_address": ica_address, + "to_address": to, + "amount": [{"denom": denom, "amount": f"{amt}"}], + } + ] + if is_multi: + to = cli_host.address(validator, bech="val") + # generate msg delegate to host chain + msgs.append( + { + "@type": "/cosmos.staking.v1beta1.MsgDelegate", + "delegator_address": ica_address, + "validator_address": to, + "amount": {"denom": denom, "amount": f"{amt1}"}, + } + ) + generated_packet = cli_controller.ica_generate_packet_data(json.dumps(msgs)) + num_txs = len(cli_host.query_all_txs(ica_address)["txs"]) + start = w3.eth.get_block_number() + str = base64.b64decode(generated_packet["data"]) + # submit transaction on host chain on behalf of interchain account + tx = func(connid, str, timeout).build_transaction(data) + receipt = send_transaction(w3, tx, keys) + assert receipt.status == 1 + logs = get_logs_since(w3, CONTRACT, start) + expected = [{"seq": seq}] + assert len(logs) == len(expected) + for i, log in enumerate(logs): + method_name, args = get_topic_data(w3, method_map, contract_info, log) + assert args == AttributeDict(expected[i]), [i, method_name] + wait_for_check_tx(cli_host, ica_address, num_txs) + return str + + +def test_call(ibc): + cli_host = ibc.chainmain.cosmos_cli() + cli_controller = ibc.cronos.cosmos_cli() + w3 = ibc.cronos.w3 + name = "signer2" + addr = ADDRS[name] + contract = w3.eth.contract(address=CONTRACT, abi=contract_info) + data = {"from": ADDRS[name], "gas": 200000} + ica_address = register_acc( + cli_controller, + w3, + contract.functions.registerAccount, + contract.functions.queryAccount, + data, + addr, + "channel-0", + ) + balance = funds_ica(cli_host, ica_address) + submit_msgs(ibc, contract.functions.submitMsgs, data, ica_address, False, 1) + balance -= amt + assert cli_host.balance(ica_address, denom=denom) == balance + submit_msgs(ibc, contract.functions.submitMsgs, data, ica_address, True, 2) + balance -= amt + balance -= amt1 + assert cli_host.balance(ica_address, denom=denom) == balance + + +def test_sc_call(ibc): + cli_host = ibc.chainmain.cosmos_cli() + cli_controller = ibc.cronos.cosmos_cli() + w3 = ibc.cronos.w3 + contract = w3.eth.contract(address=CONTRACT, abi=contract_info) + tcontract = deploy_contract(w3, CONTRACTS["TestICA"]) + addr = tcontract.address + name = "signer2" + signer = ADDRS[name] + keys = KEYS[name] + data = {"from": signer, "gas": 200000} + ica_address = register_acc( + cli_controller, + w3, + tcontract.functions.callRegister, + contract.functions.queryAccount, + data, + addr, + "channel-1", + ) + balance = funds_ica(cli_host, ica_address) + assert tcontract.caller.getAccount() == signer + assert tcontract.functions.callQueryAccount(connid, addr).call() == ica_address + + # register from another user should fail + name = "signer1" + data = {"from": ADDRS[name], "gas": 200000} + version = "" + tx = tcontract.functions.callRegister(connid, version).build_transaction(data) + res = send_transaction(w3, tx, KEYS[name]) + assert res.status == 0 + assert tcontract.caller.getAccount() == signer + + assert tcontract.functions.delegateQueryAccount(connid, addr).call() == ica_address + assert tcontract.functions.staticQueryAccount(connid, addr).call() == ica_address + + # readonly call should fail + def register_ro(func): + tx = func(connid, version).build_transaction(data) + assert send_transaction(w3, tx, keys).status == 0 + + register_ro(tcontract.functions.delegateRegister) + register_ro(tcontract.functions.staticRegister) + + # readonly call should fail + def submit_msgs_ro(func, str): + tx = func(connid, str, timeout).build_transaction(data) + assert send_transaction(w3, tx, keys).status == 0 + + seq = 1 + str = submit_msgs( + ibc, + tcontract.functions.callSubmitMsgs, + data, + ica_address, + False, + seq, + ) + submit_msgs_ro(tcontract.functions.delegateSubmitMsgs, str) + submit_msgs_ro(tcontract.functions.staticSubmitMsgs, str) + assert tcontract.caller.getLastAckSeq() == seq + balance -= amt + assert cli_host.balance(ica_address, denom=denom) == balance + seq = 2 + str = submit_msgs( + ibc, + tcontract.functions.callSubmitMsgs, + data, + ica_address, + True, + seq, + ) + submit_msgs_ro(tcontract.functions.delegateSubmitMsgs, str) + submit_msgs_ro(tcontract.functions.staticSubmitMsgs, str) + balance -= amt + balance -= amt1 + assert cli_host.balance(ica_address, denom=denom) == balance diff --git a/integration_tests/test_upgrade.py b/integration_tests/test_upgrade.py index 2ba22c74e3..02f6100250 100644 --- a/integration_tests/test_upgrade.py +++ b/integration_tests/test_upgrade.py @@ -184,6 +184,9 @@ def test_cosmovisor_upgrade(custom_cronos: Cronos, tmp_path_factory): } } + rsp = cli.query_params("icaauth") + assert rsp["params"]["min_timeout_duration"] == "3600s", rsp + # migrate to sdk v0.47 custom_cronos.supervisorctl("stop", "all") sdk_version = "v0.47" diff --git a/integration_tests/utils.py b/integration_tests/utils.py index 6a3b3f9ba6..9fd9a481b2 100644 --- a/integration_tests/utils.py +++ b/integration_tests/utils.py @@ -20,9 +20,11 @@ from dateutil.parser import isoparse from dotenv import load_dotenv from eth_account import Account -from eth_utils import to_checksum_address +from eth_utils import abi, to_checksum_address from hexbytes import HexBytes from pystarport import ledger +from web3._utils.contracts import abi_to_signature, find_matching_event_abi +from web3._utils.events import get_event_data from web3._utils.method_formatters import receipt_formatter from web3._utils.transactions import fill_nonce, fill_transaction_defaults from web3.datastructures import AttributeDict @@ -55,6 +57,7 @@ "TestMaliciousSupply": "TestMaliciousSupply.sol", "CosmosERC20": "CosmosToken.sol", "TestBank": "TestBank.sol", + "TestICA": "TestICA.sol", } @@ -81,6 +84,7 @@ def contract_path(name, filename): CONTRACT_ABIS = { "IRelayerModule": Path(__file__).parent.parent / "build/IRelayerModule.abi", + "IICAModule": Path(__file__).parent.parent / "build/IICAModule.abi", } @@ -681,3 +685,34 @@ def submit_any_proposal(cronos, tmp_path, event_query_tx=True): grant_detail = cli.query_grant(granter_addr, grantee_addr) assert grant_detail["granter"] == granter_addr assert grant_detail["grantee"] == grantee_addr + + +def get_method_map(contract_info): + method_map = {} + for item in contract_info: + if item["type"] != "event": + continue + event_abi = find_matching_event_abi(contract_info, item["name"]) + signature = abi_to_signature(event_abi) + key = f"0x{abi.event_signature_to_log_topic(signature).hex()}" + method_map[key] = signature + return method_map + + +def get_topic_data(w3, method_map, contract_info, log): + method = method_map[log.topics[0].hex()] + name = method.split("(")[0] + event_abi = find_matching_event_abi(contract_info, name) + event_data = get_event_data(w3.codec, event_abi, log) + return name, event_data.args + + +def get_logs_since(w3, addr, start): + end = w3.eth.get_block_number() + return w3.eth.get_logs( + { + "fromBlock": start, + "toBlock": end, + "address": [addr], + } + ) diff --git a/nix/default.nix b/nix/default.nix index 9893bbe5df..de060f0175 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -56,7 +56,7 @@ import sources.nixpkgs { name = "rly"; src = sources.relayer; subPackages = [ "." ]; - vendorSha256 = "sha256-Fd1vVVHEeVabsWpfI7yQfmC8T1z+dSDavxwmrKh9MmU="; + vendorSha256 = "sha256-IoaGLD3XKRmD61qcr/sPn3aWaa7zYAO9EbMiJFnF5BY="; doCheck = false; GOWORK = "off"; postInstall = '' diff --git a/nix/gen-binding-shell.nix b/nix/gen-binding-shell.nix index b469a08a56..2ac5711a47 100644 --- a/nix/gen-binding-shell.nix +++ b/nix/gen-binding-shell.nix @@ -5,6 +5,7 @@ in pkgs.mkShell { buildInputs = [ pkgs.go-ethereum + (renameExe pkgs.solc-static-versions.solc_0_6_8 "solc-0.6.8" "solc06") (renameExe pkgs.solc-static-versions.solc_0_8_21 "solc-0.8.21" "solc08") ]; } diff --git a/nix/sources.json b/nix/sources.json index af1af36a00..bf51bd3309 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -96,18 +96,6 @@ "url": "https://github.com/informalsystems/ibc-rs/archive/daad02843a091bbdb3dd608e5f4ce790895c8845.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, - "relayer": { - "branch": "master", - "description": "An IBC relayer for ibc-go", - "homepage": "https://github.com/crypto-org-chain/relayer", - "owner": "crypto-org-chain", - "repo": "relayer", - "rev": "6be13d112138244fc9dd4f80facd81baa2dac629", - "sha256": "sha256:02pbp0jksh3fvk6g4fqyqp56l15giajf2477898vjcaliqpvzrnr", - "type": "tarball", - "url": "https://github.com/crypto-org-chain/relayer/archive/6be13d112138244fc9dd4f80facd81baa2dac629.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - }, "niv": { "branch": "master", "description": "Easy dependency management for Nix projects", @@ -131,5 +119,17 @@ "type": "tarball", "url": "https://github.com/NixOS/nixpkgs/archive/90aa73fc8e1550b16d1ebdc436e48d9951f7989b.tar.gz", "url_template": "https://github.com///archive/.tar.gz" + }, + "relayer": { + "branch": "main", + "description": "An IBC relayer for ibc-go", + "homepage": "https://github.com/crypto-org-chain/relayer", + "owner": "crypto-org-chain", + "repo": "relayer", + "rev": "f202a264463e9d5829398f6be50bff990421b483", + "sha256": "08x4bhwglx12rp78gs4hzgp2cywzqwr7gghk1kxasmvy9z0qxp92", + "type": "tarball", + "url": "https://github.com/crypto-org-chain/relayer/archive/f202a264463e9d5829398f6be50bff990421b483.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" } } diff --git a/proto/icaauth/v1/tx.proto b/proto/icaauth/v1/tx.proto index 8044aed7de..5adec5b103 100644 --- a/proto/icaauth/v1/tx.proto +++ b/proto/icaauth/v1/tx.proto @@ -52,4 +52,6 @@ message MsgSubmitTx { } // MsgSubmitTxResponse defines the response message for MsgSubmitTx -message MsgSubmitTxResponse {} \ No newline at end of file +message MsgSubmitTxResponse { + uint64 sequence = 1; +} \ No newline at end of file diff --git a/scripts/gen-bindings-contracts b/scripts/gen-bindings-contracts index 096abb5797..52d629244b 100755 --- a/scripts/gen-bindings-contracts +++ b/scripts/gen-bindings-contracts @@ -3,8 +3,10 @@ solc08 --abi --bin x/cronos/events/bindings/src/CosmosTypes.sol -o build --overwrite solc08 --abi --bin x/cronos/events/bindings/src/Relayer.sol -o build --overwrite solc08 --abi --bin x/cronos/events/bindings/src/Bank.sol -o build --overwrite +solc08 --abi --bin x/cronos/events/bindings/src/ICA.sol -o build --overwrite abigen --pkg lib --abi build/CosmosTypes.abi --bin build/CosmosTypes.bin --out x/cronos/events/bindings/cosmos/lib/cosmos_types.abigen.go --type CosmosTypes abigen --pkg relayer --abi build/IRelayerModule.abi --bin build/IRelayerModule.bin --out x/cronos/events/bindings/cosmos/precompile/relayer/i_relayer_module.abigen.go --type RelayerModule abigen --pkg bank --abi build/IBankModule.abi --bin build/IBankModule.bin --out x/cronos/events/bindings/cosmos/precompile/bank/i_bank_module.abigen.go --type BankModule +abigen --pkg ica --abi build/IICAModule.abi --bin build/IICAModule.bin --out x/cronos/events/bindings/cosmos/precompile/ica/i_ica_module.abigen.go --type ICAModule diff --git a/x/cronos/events/bindings/cosmos/precompile/ica/i_ica_module.abigen.go b/x/cronos/events/bindings/cosmos/precompile/ica/i_ica_module.abigen.go new file mode 100644 index 0000000000..7f05447446 --- /dev/null +++ b/x/cronos/events/bindings/cosmos/precompile/ica/i_ica_module.abigen.go @@ -0,0 +1,387 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package ica + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription +) + +// ICAModuleMetaData contains all meta data concerning the ICAModule contract. +var ICAModuleMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"seq\",\"type\":\"uint64\"}],\"name\":\"SubmitMsgsResult\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"connectionID\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"queryAccount\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"connectionID\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"version\",\"type\":\"string\"}],\"name\":\"registerAccount\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"connectionID\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"timeout\",\"type\":\"uint256\"}],\"name\":\"submitMsgs\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]", +} + +// ICAModuleABI is the input ABI used to generate the binding from. +// Deprecated: Use ICAModuleMetaData.ABI instead. +var ICAModuleABI = ICAModuleMetaData.ABI + +// ICAModule is an auto generated Go binding around an Ethereum contract. +type ICAModule struct { + ICAModuleCaller // Read-only binding to the contract + ICAModuleTransactor // Write-only binding to the contract + ICAModuleFilterer // Log filterer for contract events +} + +// ICAModuleCaller is an auto generated read-only Go binding around an Ethereum contract. +type ICAModuleCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ICAModuleTransactor is an auto generated write-only Go binding around an Ethereum contract. +type ICAModuleTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ICAModuleFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type ICAModuleFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// ICAModuleSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type ICAModuleSession struct { + Contract *ICAModule // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ICAModuleCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type ICAModuleCallerSession struct { + Contract *ICAModuleCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// ICAModuleTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type ICAModuleTransactorSession struct { + Contract *ICAModuleTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// ICAModuleRaw is an auto generated low-level Go binding around an Ethereum contract. +type ICAModuleRaw struct { + Contract *ICAModule // Generic contract binding to access the raw methods on +} + +// ICAModuleCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type ICAModuleCallerRaw struct { + Contract *ICAModuleCaller // Generic read-only contract binding to access the raw methods on +} + +// ICAModuleTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type ICAModuleTransactorRaw struct { + Contract *ICAModuleTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewICAModule creates a new instance of ICAModule, bound to a specific deployed contract. +func NewICAModule(address common.Address, backend bind.ContractBackend) (*ICAModule, error) { + contract, err := bindICAModule(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &ICAModule{ICAModuleCaller: ICAModuleCaller{contract: contract}, ICAModuleTransactor: ICAModuleTransactor{contract: contract}, ICAModuleFilterer: ICAModuleFilterer{contract: contract}}, nil +} + +// NewICAModuleCaller creates a new read-only instance of ICAModule, bound to a specific deployed contract. +func NewICAModuleCaller(address common.Address, caller bind.ContractCaller) (*ICAModuleCaller, error) { + contract, err := bindICAModule(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &ICAModuleCaller{contract: contract}, nil +} + +// NewICAModuleTransactor creates a new write-only instance of ICAModule, bound to a specific deployed contract. +func NewICAModuleTransactor(address common.Address, transactor bind.ContractTransactor) (*ICAModuleTransactor, error) { + contract, err := bindICAModule(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &ICAModuleTransactor{contract: contract}, nil +} + +// NewICAModuleFilterer creates a new log filterer instance of ICAModule, bound to a specific deployed contract. +func NewICAModuleFilterer(address common.Address, filterer bind.ContractFilterer) (*ICAModuleFilterer, error) { + contract, err := bindICAModule(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &ICAModuleFilterer{contract: contract}, nil +} + +// bindICAModule binds a generic wrapper to an already deployed contract. +func bindICAModule(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := abi.JSON(strings.NewReader(ICAModuleABI)) + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ICAModule *ICAModuleRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ICAModule.Contract.ICAModuleCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ICAModule *ICAModuleRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ICAModule.Contract.ICAModuleTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ICAModule *ICAModuleRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ICAModule.Contract.ICAModuleTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_ICAModule *ICAModuleCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _ICAModule.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_ICAModule *ICAModuleTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _ICAModule.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_ICAModule *ICAModuleTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _ICAModule.Contract.contract.Transact(opts, method, params...) +} + +// QueryAccount is a free data retrieval call binding the contract method 0x15bf8a47. +// +// Solidity: function queryAccount(string connectionID, address addr) view returns(string) +func (_ICAModule *ICAModuleCaller) QueryAccount(opts *bind.CallOpts, connectionID string, addr common.Address) (string, error) { + var out []interface{} + err := _ICAModule.contract.Call(opts, &out, "queryAccount", connectionID, addr) + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// QueryAccount is a free data retrieval call binding the contract method 0x15bf8a47. +// +// Solidity: function queryAccount(string connectionID, address addr) view returns(string) +func (_ICAModule *ICAModuleSession) QueryAccount(connectionID string, addr common.Address) (string, error) { + return _ICAModule.Contract.QueryAccount(&_ICAModule.CallOpts, connectionID, addr) +} + +// QueryAccount is a free data retrieval call binding the contract method 0x15bf8a47. +// +// Solidity: function queryAccount(string connectionID, address addr) view returns(string) +func (_ICAModule *ICAModuleCallerSession) QueryAccount(connectionID string, addr common.Address) (string, error) { + return _ICAModule.Contract.QueryAccount(&_ICAModule.CallOpts, connectionID, addr) +} + +// RegisterAccount is a paid mutator transaction binding the contract method 0xddc7b6a7. +// +// Solidity: function registerAccount(string connectionID, string version) payable returns(bool) +func (_ICAModule *ICAModuleTransactor) RegisterAccount(opts *bind.TransactOpts, connectionID string, version string) (*types.Transaction, error) { + return _ICAModule.contract.Transact(opts, "registerAccount", connectionID, version) +} + +// RegisterAccount is a paid mutator transaction binding the contract method 0xddc7b6a7. +// +// Solidity: function registerAccount(string connectionID, string version) payable returns(bool) +func (_ICAModule *ICAModuleSession) RegisterAccount(connectionID string, version string) (*types.Transaction, error) { + return _ICAModule.Contract.RegisterAccount(&_ICAModule.TransactOpts, connectionID, version) +} + +// RegisterAccount is a paid mutator transaction binding the contract method 0xddc7b6a7. +// +// Solidity: function registerAccount(string connectionID, string version) payable returns(bool) +func (_ICAModule *ICAModuleTransactorSession) RegisterAccount(connectionID string, version string) (*types.Transaction, error) { + return _ICAModule.Contract.RegisterAccount(&_ICAModule.TransactOpts, connectionID, version) +} + +// SubmitMsgs is a paid mutator transaction binding the contract method 0x697bfa34. +// +// Solidity: function submitMsgs(string connectionID, bytes data, uint256 timeout) payable returns(uint64) +func (_ICAModule *ICAModuleTransactor) SubmitMsgs(opts *bind.TransactOpts, connectionID string, data []byte, timeout *big.Int) (*types.Transaction, error) { + return _ICAModule.contract.Transact(opts, "submitMsgs", connectionID, data, timeout) +} + +// SubmitMsgs is a paid mutator transaction binding the contract method 0x697bfa34. +// +// Solidity: function submitMsgs(string connectionID, bytes data, uint256 timeout) payable returns(uint64) +func (_ICAModule *ICAModuleSession) SubmitMsgs(connectionID string, data []byte, timeout *big.Int) (*types.Transaction, error) { + return _ICAModule.Contract.SubmitMsgs(&_ICAModule.TransactOpts, connectionID, data, timeout) +} + +// SubmitMsgs is a paid mutator transaction binding the contract method 0x697bfa34. +// +// Solidity: function submitMsgs(string connectionID, bytes data, uint256 timeout) payable returns(uint64) +func (_ICAModule *ICAModuleTransactorSession) SubmitMsgs(connectionID string, data []byte, timeout *big.Int) (*types.Transaction, error) { + return _ICAModule.Contract.SubmitMsgs(&_ICAModule.TransactOpts, connectionID, data, timeout) +} + +// ICAModuleSubmitMsgsResultIterator is returned from FilterSubmitMsgsResult and is used to iterate over the raw logs and unpacked data for SubmitMsgsResult events raised by the ICAModule contract. +type ICAModuleSubmitMsgsResultIterator struct { + Event *ICAModuleSubmitMsgsResult // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *ICAModuleSubmitMsgsResultIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(ICAModuleSubmitMsgsResult) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(ICAModuleSubmitMsgsResult) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *ICAModuleSubmitMsgsResultIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *ICAModuleSubmitMsgsResultIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// ICAModuleSubmitMsgsResult represents a SubmitMsgsResult event raised by the ICAModule contract. +type ICAModuleSubmitMsgsResult struct { + Seq uint64 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSubmitMsgsResult is a free log retrieval operation binding the contract event 0x9445c42aa80c009b1b0204bc10c31084e1262133ee7f838b51280832874afc1c. +// +// Solidity: event SubmitMsgsResult(uint64 seq) +func (_ICAModule *ICAModuleFilterer) FilterSubmitMsgsResult(opts *bind.FilterOpts) (*ICAModuleSubmitMsgsResultIterator, error) { + + logs, sub, err := _ICAModule.contract.FilterLogs(opts, "SubmitMsgsResult") + if err != nil { + return nil, err + } + return &ICAModuleSubmitMsgsResultIterator{contract: _ICAModule.contract, event: "SubmitMsgsResult", logs: logs, sub: sub}, nil +} + +// WatchSubmitMsgsResult is a free log subscription operation binding the contract event 0x9445c42aa80c009b1b0204bc10c31084e1262133ee7f838b51280832874afc1c. +// +// Solidity: event SubmitMsgsResult(uint64 seq) +func (_ICAModule *ICAModuleFilterer) WatchSubmitMsgsResult(opts *bind.WatchOpts, sink chan<- *ICAModuleSubmitMsgsResult) (event.Subscription, error) { + + logs, sub, err := _ICAModule.contract.WatchLogs(opts, "SubmitMsgsResult") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(ICAModuleSubmitMsgsResult) + if err := _ICAModule.contract.UnpackLog(event, "SubmitMsgsResult", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSubmitMsgsResult is a log parse operation binding the contract event 0x9445c42aa80c009b1b0204bc10c31084e1262133ee7f838b51280832874afc1c. +// +// Solidity: event SubmitMsgsResult(uint64 seq) +func (_ICAModule *ICAModuleFilterer) ParseSubmitMsgsResult(log types.Log) (*ICAModuleSubmitMsgsResult, error) { + event := new(ICAModuleSubmitMsgsResult) + if err := _ICAModule.contract.UnpackLog(event, "SubmitMsgsResult", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/x/cronos/events/bindings/src/ICA.sol b/x/cronos/events/bindings/src/ICA.sol new file mode 100644 index 0000000000..31f10530a7 --- /dev/null +++ b/x/cronos/events/bindings/src/ICA.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +interface IICAModule { + event SubmitMsgsResult(uint64 seq); + function registerAccount(string calldata connectionID, string calldata version) external payable returns (bool); + function queryAccount(string calldata connectionID, address addr) external view returns (string memory); + function submitMsgs(string calldata connectionID, bytes calldata data, uint256 timeout) external payable returns (uint64); +} diff --git a/x/cronos/events/decoders.go b/x/cronos/events/decoders.go index 4e722dc35b..936c666b74 100644 --- a/x/cronos/events/decoders.go +++ b/x/cronos/events/decoders.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "math/big" + "strconv" "strings" sdk "github.com/cosmos/cosmos-sdk/types" @@ -22,7 +23,20 @@ type ( ValueDecoders map[string]ValueDecoder ) -const intBase = 10 +func (d ValueDecoders) GetDecoder(name string) (ValueDecoder, bool) { + decoder, ok := d[name] + if !ok { + decoder, ok = d[""] + } + return decoder, ok +} + +const ( + // intBase is the base `int`s are parsed in, 10. + intBase = 10 + // int64Bits is the number of bits stored in a variabe of `int64` type. + int64Bits = 64 +) func AccAddressFromBech32(address string) (addr sdk.AccAddress, err error) { if len(strings.TrimSpace(address)) == 0 { @@ -113,6 +127,14 @@ func ReturnStringAsIs(attributeValue string, _ bool) ([]any, error) { return []any{attributeValue}, nil } +func ConvertUint64(attributeValue string, _ bool) ([]any, error) { + res, err := strconv.ParseUint(attributeValue, intBase, int64Bits) + if err != nil { + return nil, err + } + return []any{res}, err +} + func convertAddress(addrString string) (*common.Address, error) { cfg := sdk.GetConfig() var addr []byte diff --git a/x/cronos/events/event.go b/x/cronos/events/event.go index 524b36d5bd..0c146b95e2 100644 --- a/x/cronos/events/event.go +++ b/x/cronos/events/event.go @@ -46,7 +46,7 @@ func makeFilter( if !ok { return nil, fmt.Errorf("attribute %s not found", name) } - decode, ok := valueDecoders[name] + decode, ok := valueDecoders.GetDecoder(name) if !ok { return nil, fmt.Errorf("no decoder for %s", name) } diff --git a/x/cronos/events/events.go b/x/cronos/events/events.go index 6f00c16d3f..57da3426ff 100644 --- a/x/cronos/events/events.go +++ b/x/cronos/events/events.go @@ -5,46 +5,68 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ibcfeetypes "github.com/cosmos/ibc-go/v7/modules/apps/29-fee/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - ibctypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - generated "github.com/crypto-org-chain/cronos/v2/x/cronos/events/bindings/cosmos/precompile/relayer" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ica "github.com/crypto-org-chain/cronos/v2/x/cronos/events/bindings/cosmos/precompile/ica" + relayer "github.com/crypto-org-chain/cronos/v2/x/cronos/events/bindings/cosmos/precompile/relayer" + cronoseventstypes "github.com/crypto-org-chain/cronos/v2/x/cronos/events/types" "github.com/ethereum/go-ethereum/accounts/abi" ethtypes "github.com/ethereum/go-ethereum/core/types" ) var ( - IBCEvents map[string]*EventDescriptor - IBCValueDecoders = ValueDecoders{ - ibctypes.AttributeKeyDataHex: ConvertPacketData, - ibctypes.AttributeKeyConnection: ReturnStringAsIs, - ibctypes.AttributeKeyChannelOrdering: ReturnStringAsIs, - ibctypes.AttributeKeySrcPort: ReturnStringAsIs, - ibctypes.AttributeKeySrcChannel: ReturnStringAsIs, - ibctypes.AttributeKeyDstPort: ReturnStringAsIs, - ibctypes.AttributeKeyDstChannel: ReturnStringAsIs, - ibcfeetypes.AttributeKeyFee: ReturnStringAsIs, - transfertypes.AttributeKeyDenom: ReturnStringAsIs, - transfertypes.AttributeKeyAmount: ConvertAmount, - banktypes.AttributeKeyRecipient: ConvertAccAddressFromBech32, - banktypes.AttributeKeySpender: ConvertAccAddressFromBech32, - banktypes.AttributeKeyReceiver: ConvertAccAddressFromBech32, - banktypes.AttributeKeySender: ConvertAccAddressFromBech32, - banktypes.AttributeKeyMinter: ConvertAccAddressFromBech32, - banktypes.AttributeKeyBurner: ConvertAccAddressFromBech32, + RelayerEvents map[string]*EventDescriptor + IcaEvents map[string]*EventDescriptor + RelayerValueDecoders = ValueDecoders{ + channeltypes.AttributeKeyDataHex: ConvertPacketData, + transfertypes.AttributeKeyAmount: ConvertAmount, + banktypes.AttributeKeyRecipient: ConvertAccAddressFromBech32, + banktypes.AttributeKeySpender: ConvertAccAddressFromBech32, + banktypes.AttributeKeyReceiver: ConvertAccAddressFromBech32, + banktypes.AttributeKeySender: ConvertAccAddressFromBech32, + banktypes.AttributeKeyMinter: ConvertAccAddressFromBech32, + banktypes.AttributeKeyBurner: ConvertAccAddressFromBech32, + channeltypes.AttributeKeyConnection: ReturnStringAsIs, + channeltypes.AttributeKeyChannelOrdering: ReturnStringAsIs, + channeltypes.AttributeKeySrcPort: ReturnStringAsIs, + channeltypes.AttributeKeySrcChannel: ReturnStringAsIs, + channeltypes.AttributeKeyDstPort: ReturnStringAsIs, + channeltypes.AttributeKeyDstChannel: ReturnStringAsIs, + ibcfeetypes.AttributeKeyFee: ReturnStringAsIs, + transfertypes.AttributeKeyDenom: ReturnStringAsIs, + } + IcaValueDecoders = ValueDecoders{ + channeltypes.AttributeKeyChannelID: ReturnStringAsIs, + channeltypes.AttributeKeyPortID: ReturnStringAsIs, + cronoseventstypes.AttributeKeySeq: ConvertUint64, } ) func init() { - var ibcABI abi.ABI - if err := ibcABI.UnmarshalJSON([]byte(generated.RelayerModuleMetaData.ABI)); err != nil { + var relayerABI abi.ABI + if err := relayerABI.UnmarshalJSON([]byte(relayer.RelayerModuleMetaData.ABI)); err != nil { panic(err) } - IBCEvents = NewEventDescriptors(ibcABI) + RelayerEvents = NewEventDescriptors(relayerABI) + + var icaABI abi.ABI + if err := icaABI.UnmarshalJSON([]byte(ica.ICAModuleMetaData.ABI)); err != nil { + panic(err) + } + IcaEvents = NewEventDescriptors(icaABI) +} + +func RelayerConvertEvent(event sdk.Event) (*ethtypes.Log, error) { + desc, ok := RelayerEvents[event.Type] + if !ok { + return nil, nil + } + return desc.ConvertEvent(event.Attributes, RelayerValueDecoders) } -func ConvertEvent(event sdk.Event) (*ethtypes.Log, error) { - desc, ok := IBCEvents[event.Type] +func IcaConvertEvent(event sdk.Event) (*ethtypes.Log, error) { + desc, ok := IcaEvents[event.Type] if !ok { return nil, nil } - return desc.ConvertEvent(event.Attributes, IBCValueDecoders) + return desc.ConvertEvent(event.Attributes, IcaValueDecoders) } diff --git a/x/cronos/events/types/types.go b/x/cronos/events/types/types.go new file mode 100644 index 0000000000..66ace42d19 --- /dev/null +++ b/x/cronos/events/types/types.go @@ -0,0 +1,6 @@ +package types + +const ( + EventTypeSubmitMsgsResult = "submit_msgs_result" + AttributeKeySeq = "seq" +) diff --git a/x/cronos/keeper/grpc_query.go b/x/cronos/keeper/grpc_query.go index e2a5c00d8a..ad025cf544 100644 --- a/x/cronos/keeper/grpc_query.go +++ b/x/cronos/keeper/grpc_query.go @@ -79,14 +79,14 @@ func (k Keeper) ReplayBlock(goCtx context.Context, req *types.ReplayBlockRequest } // populate the `From` field - if _, err := msg.GetSender(chainID); err != nil { + if _, err := msg.GetSenderLegacy(chainID); err != nil { return nil, err } fees, err := evmkeeper.VerifyFee(txData, evmDenom, baseFee, homestead, istanbul, ctx.IsCheckTx()) if err != nil { return nil, errorsmod.Wrapf(err, "failed to verify the fees") } - if err := k.evmKeeper.DeductTxCostsFromUserBalance(ctx, fees, common.HexToAddress(msg.From)); err != nil { + if err := k.evmKeeper.DeductTxCostsFromUserBalance(ctx, fees, common.BytesToAddress(msg.From)); err != nil { return nil, err } diff --git a/x/cronos/keeper/precompiles/ica.go b/x/cronos/keeper/precompiles/ica.go new file mode 100644 index 0000000000..077627acb1 --- /dev/null +++ b/x/cronos/keeper/precompiles/ica.go @@ -0,0 +1,166 @@ +package precompiles + +import ( + "errors" + "fmt" + "math/big" + "time" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + cronosevents "github.com/crypto-org-chain/cronos/v2/x/cronos/events" + "github.com/crypto-org-chain/cronos/v2/x/cronos/events/bindings/cosmos/precompile/ica" + cronoseventstypes "github.com/crypto-org-chain/cronos/v2/x/cronos/events/types" + icaauthkeeper "github.com/crypto-org-chain/cronos/v2/x/icaauth/keeper" + "github.com/crypto-org-chain/cronos/v2/x/icaauth/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" +) + +// TODO: Replace this const with adjusted gas cost corresponding to input when executing precompile contract. +const ICAContractRequiredGas = 10000 + +var ( + icaABI abi.ABI + icaContractAddress = common.BytesToAddress([]byte{102}) +) + +func init() { + if err := icaABI.UnmarshalJSON([]byte(ica.ICAModuleMetaData.ABI)); err != nil { + panic(err) + } +} + +type IcaContract struct { + BaseContract + + cdc codec.Codec + icaauthKeeper *icaauthkeeper.Keeper +} + +func NewIcaContract(icaauthKeeper *icaauthkeeper.Keeper, cdc codec.Codec) vm.PrecompiledContract { + return &IcaContract{ + BaseContract: NewBaseContract(icaContractAddress), + cdc: cdc, + icaauthKeeper: icaauthKeeper, + } +} + +func (ic *IcaContract) Address() common.Address { + return icaContractAddress +} + +// RequiredGas calculates the contract gas use +func (ic *IcaContract) RequiredGas(input []byte) uint64 { + return ICAContractRequiredGas +} + +func (ic *IcaContract) IsStateful() bool { + return true +} + +func (ic *IcaContract) Run(evm *vm.EVM, contract *vm.Contract, readonly bool) ([]byte, error) { + // parse input + methodID := contract.Input[:4] + method, err := icaABI.MethodById(methodID) + if err != nil { + return nil, err + } + + stateDB := evm.StateDB.(ExtStateDB) + precompileAddr := ic.Address() + caller := contract.CallerAddress + owner := sdk.AccAddress(caller.Bytes()).String() + converter := cronosevents.IcaConvertEvent + var execErr error + switch method.Name { + case "registerAccount": + if readonly { + return nil, errors.New("the method is not readonly") + } + args, err := method.Inputs.Unpack(contract.Input[4:]) + if err != nil { + return nil, errors.New("fail to unpack input arguments") + } + connectionID := args[0].(string) + version := args[1].(string) + execErr = stateDB.ExecuteNativeAction(precompileAddr, converter, func(ctx sdk.Context) error { + _, err := ic.icaauthKeeper.RegisterAccount(ctx, &types.MsgRegisterAccount{ + Owner: owner, + ConnectionId: connectionID, + Version: version, + }) + return err + }) + if execErr != nil { + return nil, execErr + } + return method.Outputs.Pack(true) + case "queryAccount": + args, err := method.Inputs.Unpack(contract.Input[4:]) + if err != nil { + return nil, errors.New("fail to unpack input arguments") + } + connectionID := args[0].(string) + account := args[1].(common.Address) + owner := sdk.AccAddress(account.Bytes()).String() + icaAddress := "" + response, err := ic.icaauthKeeper.InterchainAccountAddress( + stateDB.CacheContext(), + &types.QueryInterchainAccountAddressRequest{ + Owner: owner, + ConnectionId: connectionID, + }) + if err != nil { + return nil, err + } + if response != nil { + icaAddress = response.InterchainAccountAddress + } + return method.Outputs.Pack(icaAddress) + case "submitMsgs": + if readonly { + return nil, errors.New("the method is not readonly") + } + args, err := method.Inputs.Unpack(contract.Input[4:]) + if err != nil { + return nil, errors.New("fail to unpack input arguments") + } + connectionID := args[0].(string) + data := args[1].([]byte) + timeout := args[2].(*big.Int) + icaMsgData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + } + timeoutDuration := time.Duration(timeout.Uint64()) + seq := uint64(0) + execErr = stateDB.ExecuteNativeAction(precompileAddr, converter, func(ctx sdk.Context) error { + response, err := ic.icaauthKeeper.SubmitTxWithArgs( + ctx, + owner, + connectionID, + timeoutDuration, + icaMsgData, + ) + if err == nil && response != nil { + seq = response.Sequence + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + cronoseventstypes.EventTypeSubmitMsgsResult, + sdk.NewAttribute(cronoseventstypes.AttributeKeySeq, fmt.Sprintf("%d", response.Sequence)), + ), + }) + } + return err + }) + if execErr != nil { + return nil, execErr + } + return method.Outputs.Pack(seq) + default: + return nil, errors.New("unknown method") + } +} diff --git a/x/cronos/keeper/precompiles/interface.go b/x/cronos/keeper/precompiles/interface.go index e3117589d1..cf14f2cddd 100644 --- a/x/cronos/keeper/precompiles/interface.go +++ b/x/cronos/keeper/precompiles/interface.go @@ -11,4 +11,5 @@ import ( type ExtStateDB interface { vm.StateDB ExecuteNativeAction(contract common.Address, converter statedb.EventConverter, action func(ctx sdk.Context) error) error + CacheContext() sdk.Context } diff --git a/x/cronos/keeper/precompiles/relayer.go b/x/cronos/keeper/precompiles/relayer.go index b6b59c9826..600fb8e176 100644 --- a/x/cronos/keeper/precompiles/relayer.go +++ b/x/cronos/keeper/precompiles/relayer.go @@ -9,9 +9,10 @@ import ( "github.com/ethereum/go-ethereum/core/vm" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + cronosevents "github.com/crypto-org-chain/cronos/v2/x/cronos/events" ) -// TODO adjust the gas cost +// TODO: Replace this const with adjusted gas cost corresponding to input when executing precompile contract. const RelayerContractRequiredGas = 10000 var RelayerContractAddress = common.BytesToAddress([]byte{101}) @@ -87,39 +88,40 @@ func (bc *RelayerContract) Run(evm *vm.EVM, contract *vm.Contract, readonly bool res []byte ) precompileAddr := bc.Address() + converter := cronosevents.RelayerConvertEvent switch prefix { case prefixCreateClient: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.CreateClient) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.CreateClient, converter) case prefixUpdateClient: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.UpdateClient) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.UpdateClient, converter) case prefixUpgradeClient: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.UpgradeClient) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.UpgradeClient, converter) case prefixSubmitMisbehaviour: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.SubmitMisbehaviour) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.SubmitMisbehaviour, converter) case prefixConnectionOpenInit: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenInit) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenInit, converter) case prefixConnectionOpenTry: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenTry) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenTry, converter) case prefixConnectionOpenAck: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenAck) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenAck, converter) case prefixConnectionOpenConfirm: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenConfirm) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ConnectionOpenConfirm, converter) case prefixChannelOpenInit: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenInit) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenInit, converter) case prefixChannelOpenTry: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenTry) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenTry, converter) case prefixChannelOpenAck: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenAck) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenAck, converter) case prefixChannelOpenConfirm: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenConfirm) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.ChannelOpenConfirm, converter) case prefixRecvPacket: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.RecvPacket) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.RecvPacket, converter) case prefixAcknowledgement: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.Acknowledgement) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.Acknowledgement, converter) case prefixTimeout: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.Timeout) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.Timeout, converter) case prefixTimeoutOnClose: - res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.TimeoutOnClose) + res, err = exec(bc.cdc, stateDB, contract.CallerAddress, precompileAddr, input, bc.ibcKeeper.TimeoutOnClose, converter) default: return nil, errors.New("unknown method") } diff --git a/x/cronos/keeper/precompiles/utils.go b/x/cronos/keeper/precompiles/utils.go index bc443d01b5..34c70ceb0d 100644 --- a/x/cronos/keeper/precompiles/utils.go +++ b/x/cronos/keeper/precompiles/utils.go @@ -7,8 +7,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - cronosevents "github.com/crypto-org-chain/cronos/v2/x/cronos/events" "github.com/ethereum/go-ethereum/common" + "github.com/evmos/ethermint/x/evm/statedb" ) type NativeMessage interface { @@ -27,6 +27,7 @@ func exec[Req any, PReq interface { contract common.Address, input []byte, action func(context.Context, PReq) (Resp, error), + converter statedb.EventConverter, ) ([]byte, error) { msg := PReq(new(Req)) if err := cdc.Unmarshal(input, msg); err != nil { @@ -42,7 +43,7 @@ func exec[Req any, PReq interface { } var res Resp - if err := stateDB.ExecuteNativeAction(contract, cronosevents.ConvertEvent, func(ctx sdk.Context) error { + if err := stateDB.ExecuteNativeAction(contract, converter, func(ctx sdk.Context) error { var err error res, err = action(ctx, msg) return err diff --git a/x/cronos/rpc/api.go b/x/cronos/rpc/api.go index eba64739c9..7ac7f00c3f 100644 --- a/x/cronos/rpc/api.go +++ b/x/cronos/rpc/api.go @@ -175,7 +175,7 @@ func (api *CronosAPI) GetTransactionReceiptsByBlock(blockNrOrHash rpctypes.Block status = hexutil.Uint(ethtypes.ReceiptStatusSuccessful) } - from, err := ethMsg.GetSender(api.chainIDEpoch) + from, err := ethMsg.GetSenderLegacy(api.chainIDEpoch) if err != nil { return nil, err } @@ -313,7 +313,7 @@ func (api *CronosAPI) ReplayBlock(blockNrOrHash rpctypes.BlockNumberOrHash, post status = hexutil.Uint(ethtypes.ReceiptStatusSuccessful) } - from, err := ethMsg.GetSender(api.chainIDEpoch) + from, err := ethMsg.GetSenderLegacy(api.chainIDEpoch) if err != nil { return nil, err } diff --git a/x/icaauth/keeper/grpc_query_interchain_account_address.go b/x/icaauth/keeper/grpc_query_interchain_account_address.go deleted file mode 100644 index a7e502cccd..0000000000 --- a/x/icaauth/keeper/grpc_query_interchain_account_address.go +++ /dev/null @@ -1,27 +0,0 @@ -package keeper - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/crypto-org-chain/cronos/v2/x/icaauth/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k Keeper) InterchainAccountAddress(goCtx context.Context, req *types.QueryInterchainAccountAddressRequest) (*types.QueryInterchainAccountAddressResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - ctx := sdk.UnwrapSDKContext(goCtx) - - icaAddress, err := k.GetInterchainAccountAddress(ctx, req.ConnectionId, req.Owner) - if err != nil { - return nil, err - } - - return &types.QueryInterchainAccountAddressResponse{ - InterchainAccountAddress: icaAddress, - }, nil -} diff --git a/x/icaauth/keeper/keeper.go b/x/icaauth/keeper/keeper.go index 56ca31bf48..5137efd79e 100644 --- a/x/icaauth/keeper/keeper.go +++ b/x/icaauth/keeper/keeper.go @@ -1,6 +1,7 @@ package keeper import ( + "context" "fmt" "time" @@ -10,7 +11,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - "github.com/cosmos/gogoproto/proto" icacontrollerkeeper "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/keeper" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" "github.com/crypto-org-chain/cronos/v2/x/icaauth/types" @@ -46,53 +46,72 @@ func NewKeeper( } } -// DoSubmitTx submits a transaction to the host chain on behalf of interchain account -func (k *Keeper) DoSubmitTx(ctx sdk.Context, connectionID, owner string, msgs []proto.Message, timeoutDuration time.Duration) error { - portID, err := icatypes.NewControllerPortID(owner) +// SubmitTx submits a transaction to the host chain on behalf of interchain account +func (k *Keeper) SubmitTx(goCtx context.Context, msg *types.MsgSubmitTx) (*types.MsgSubmitTxResponse, error) { + msgs, err := msg.GetMessages() if err != nil { - return err + return nil, err } data, err := icatypes.SerializeCosmosTx(k.cdc, msgs) if err != nil { - return err + return nil, err } packetData := icatypes.InterchainAccountPacketData{ Type: icatypes.EXECUTE_TX, Data: data, } + return k.SubmitTxWithArgs(goCtx, msg.Owner, msg.ConnectionId, *msg.TimeoutDuration, packetData) +} +func (k *Keeper) SubmitTxWithArgs(goCtx context.Context, owner, connectionId string, timeoutDuration time.Duration, packetData icatypes.InterchainAccountPacketData) (*types.MsgSubmitTxResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + portID, err := icatypes.NewControllerPortID(owner) + if err != nil { + return nil, err + } + minTimeoutDuration := k.MinTimeoutDuration(ctx) // timeoutDuration should be constraited by MinTimeoutDuration parameter. - timeoutTimestamp := ctx.BlockTime().Add(timeoutDuration).UnixNano() - - _, err = k.icaControllerKeeper.SendTx(ctx, nil, connectionID, portID, packetData, uint64(timeoutTimestamp)) //nolint:staticcheck + timeoutTimestamp := ctx.BlockTime().Add( + types.MsgSubmitTx{ + TimeoutDuration: &timeoutDuration, + }.CalculateTimeoutDuration(minTimeoutDuration)).UnixNano() + res, err := k.icaControllerKeeper.SendTx(ctx, nil, connectionId, portID, packetData, uint64(timeoutTimestamp)) //nolint:staticcheck if err != nil { - return err + return nil, err } - - return nil + return &types.MsgSubmitTxResponse{ + Sequence: res, + }, nil } -// RegisterInterchainAccount registers an interchain account with the given `connectionId` and `owner` on the host chain -func (k *Keeper) RegisterInterchainAccount(ctx sdk.Context, connectionID, owner, version string) error { - return k.icaControllerKeeper.RegisterInterchainAccount(ctx, connectionID, owner, version) +// RegisterAccount registers an interchain account with the given `connectionId` and `owner` on the host chain +func (k *Keeper) RegisterAccount(goCtx context.Context, msg *types.MsgRegisterAccount) (*types.MsgRegisterAccountResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if err := k.icaControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, msg.Version); err != nil { + return nil, err + } + return &types.MsgRegisterAccountResponse{}, nil } -// GetInterchainAccountAddress fetches the interchain account address for given `connectionId` and `owner` -func (k *Keeper) GetInterchainAccountAddress(ctx sdk.Context, connectionID, owner string) (string, error) { - portID, err := icatypes.NewControllerPortID(owner) +// InterchainAccountAddress fetches the interchain account address for given `connectionId` and `owner` +func (k Keeper) InterchainAccountAddress(goCtx context.Context, req *types.QueryInterchainAccountAddressRequest) (*types.QueryInterchainAccountAddressResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + portID, err := icatypes.NewControllerPortID(req.Owner) if err != nil { - return "", status.Errorf(codes.InvalidArgument, "invalid owner address: %s", err) + return nil, status.Errorf(codes.InvalidArgument, "invalid owner address: %s", err) } - icaAddress, found := k.icaControllerKeeper.GetInterchainAccountAddress(ctx, connectionID, portID) + icaAddress, found := k.icaControllerKeeper.GetInterchainAccountAddress(ctx, req.ConnectionId, portID) if !found { - return "", status.Errorf(codes.NotFound, "could not find account") + return nil, status.Errorf(codes.NotFound, "could not find account") } - return icaAddress, nil + return &types.QueryInterchainAccountAddressResponse{ + InterchainAccountAddress: icaAddress, + }, nil } // ClaimCapability claims the channel capability passed via the OnOpenChanInit callback diff --git a/x/icaauth/keeper/msg_server.go b/x/icaauth/keeper/msg_server.go index d01fce99a6..781d36dc18 100644 --- a/x/icaauth/keeper/msg_server.go +++ b/x/icaauth/keeper/msg_server.go @@ -14,4 +14,4 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer { return &msgServer{Keeper: keeper} } -var _ types.MsgServer = msgServer{} +var _ types.MsgServer = new(msgServer) diff --git a/x/icaauth/keeper/msg_server_register_account.go b/x/icaauth/keeper/msg_server_register_account.go deleted file mode 100644 index 45b1939d75..0000000000 --- a/x/icaauth/keeper/msg_server_register_account.go +++ /dev/null @@ -1,18 +0,0 @@ -package keeper - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/crypto-org-chain/cronos/v2/x/icaauth/types" -) - -func (k msgServer) RegisterAccount(goCtx context.Context, msg *types.MsgRegisterAccount) (*types.MsgRegisterAccountResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - if err := k.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.Owner, msg.Version); err != nil { - return nil, err - } - - return &types.MsgRegisterAccountResponse{}, nil -} diff --git a/x/icaauth/keeper/msg_server_submit_tx.go b/x/icaauth/keeper/msg_server_submit_tx.go deleted file mode 100644 index b0ceba4e6e..0000000000 --- a/x/icaauth/keeper/msg_server_submit_tx.go +++ /dev/null @@ -1,26 +0,0 @@ -package keeper - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/crypto-org-chain/cronos/v2/x/icaauth/types" -) - -func (k msgServer) SubmitTx(goCtx context.Context, msg *types.MsgSubmitTx) (*types.MsgSubmitTxResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - msgs, err := msg.GetMessages() - if err != nil { - return nil, err - } - - minTimeoutDuration := k.MinTimeoutDuration(ctx) - - err = k.DoSubmitTx(ctx, msg.ConnectionId, msg.Owner, msgs, msg.CalculateTimeoutDuration(minTimeoutDuration)) - if err != nil { - return nil, err - } - - return &types.MsgSubmitTxResponse{}, nil -} diff --git a/x/icaauth/types/tx.pb.go b/x/icaauth/types/tx.pb.go index 228e12ffad..24070483b3 100644 --- a/x/icaauth/types/tx.pb.go +++ b/x/icaauth/types/tx.pb.go @@ -212,6 +212,7 @@ func (m *MsgSubmitTx) GetTimeoutDuration() *time.Duration { // MsgSubmitTxResponse defines the response message for MsgSubmitTx type MsgSubmitTxResponse struct { + Sequence uint64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` } func (m *MsgSubmitTxResponse) Reset() { *m = MsgSubmitTxResponse{} } @@ -247,6 +248,13 @@ func (m *MsgSubmitTxResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgSubmitTxResponse proto.InternalMessageInfo +func (m *MsgSubmitTxResponse) GetSequence() uint64 { + if m != nil { + return m.Sequence + } + return 0 +} + func init() { proto.RegisterType((*MsgRegisterAccount)(nil), "icaauth.v1.MsgRegisterAccount") proto.RegisterType((*MsgRegisterAccountResponse)(nil), "icaauth.v1.MsgRegisterAccountResponse") @@ -257,36 +265,36 @@ func init() { func init() { proto.RegisterFile("icaauth/v1/tx.proto", fileDescriptor_09bf995a0c8f8b8c) } var fileDescriptor_09bf995a0c8f8b8c = []byte{ - // 449 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0x41, 0x8e, 0xd3, 0x30, - 0x14, 0x86, 0x6b, 0x5a, 0x18, 0x70, 0x41, 0x83, 0x32, 0x45, 0xa4, 0x11, 0x4a, 0xab, 0x2c, 0x50, - 0x37, 0xb5, 0x35, 0x45, 0xb3, 0x41, 0x62, 0x31, 0xd5, 0x6c, 0x40, 0xaa, 0x90, 0x02, 0x1b, 0xd8, - 0x54, 0xa9, 0x6b, 0x5c, 0x8b, 0x89, 0x5f, 0x65, 0x3b, 0xa5, 0x59, 0x73, 0x01, 0x96, 0x9c, 0x80, - 0x13, 0x70, 0x08, 0xc4, 0x6a, 0x96, 0xac, 0x00, 0xb5, 0xe2, 0x02, 0x9c, 0x00, 0x35, 0x89, 0x29, - 0xb4, 0x82, 0xdd, 0xec, 0xf2, 0xbf, 0xef, 0xf9, 0xcf, 0x7b, 0x7f, 0x62, 0x7c, 0x24, 0x59, 0x92, - 0x64, 0x76, 0x46, 0x17, 0xc7, 0xd4, 0x2e, 0xc9, 0x5c, 0x83, 0x05, 0x0f, 0x57, 0x45, 0xb2, 0x38, - 0x0e, 0xda, 0x0c, 0x4c, 0x0a, 0x66, 0x5c, 0x10, 0x5a, 0x8a, 0xb2, 0x2d, 0x68, 0x09, 0x10, 0x50, - 0xd6, 0x37, 0x4f, 0x55, 0x35, 0x14, 0x00, 0xe2, 0x9c, 0xd3, 0x42, 0x4d, 0xb2, 0x57, 0x74, 0x9a, - 0xe9, 0xc4, 0x4a, 0x50, 0x15, 0x6f, 0xef, 0xf2, 0x44, 0xe5, 0x25, 0x8a, 0xde, 0x22, 0xec, 0x8d, - 0x8c, 0x88, 0xb9, 0x90, 0xc6, 0x72, 0x7d, 0xca, 0x18, 0x64, 0xca, 0x7a, 0x2d, 0x7c, 0x15, 0xde, - 0x28, 0xae, 0x7d, 0xd4, 0x45, 0xbd, 0x1b, 0x71, 0x29, 0xbc, 0x47, 0xf8, 0x16, 0x03, 0xa5, 0x38, - 0xdb, 0x78, 0x8f, 0xe5, 0xd4, 0xbf, 0xb2, 0xa1, 0x43, 0xff, 0xe7, 0xd7, 0x4e, 0x2b, 0x4f, 0xd2, - 0xf3, 0x87, 0xd1, 0x5f, 0x38, 0x8a, 0x6f, 0x6e, 0xf5, 0xe3, 0xa9, 0xe7, 0xe3, 0x83, 0x05, 0xd7, - 0x46, 0x82, 0xf2, 0xeb, 0x85, 0xad, 0x93, 0xd1, 0x3d, 0x1c, 0xec, 0x0f, 0x11, 0x73, 0x33, 0x07, - 0x65, 0x78, 0xf4, 0x03, 0xe1, 0xe6, 0xc8, 0x88, 0x67, 0xd9, 0x24, 0x95, 0xf6, 0xf9, 0xf2, 0x72, - 0x86, 0x3b, 0xc1, 0x8d, 0xd4, 0x08, 0xe3, 0xd7, 0xbb, 0xf5, 0x5e, 0x73, 0xd0, 0x22, 0x65, 0x64, - 0xc4, 0x45, 0x46, 0x4e, 0x55, 0x3e, 0x6c, 0x7e, 0xfe, 0xd8, 0x3f, 0x30, 0xd3, 0xd7, 0x64, 0x33, - 0x6c, 0xd1, 0xee, 0x3d, 0xc1, 0xb7, 0xad, 0x4c, 0x39, 0x64, 0x76, 0xec, 0x42, 0xf7, 0x1b, 0x5d, - 0xd4, 0x6b, 0x0e, 0xda, 0x7b, 0x16, 0x67, 0x55, 0xc3, 0xb0, 0xf1, 0xfe, 0x5b, 0x07, 0xc5, 0x87, - 0xd5, 0x41, 0x57, 0x8e, 0xee, 0xe0, 0xa3, 0x3f, 0xd6, 0x74, 0xeb, 0x0f, 0x3e, 0x20, 0x5c, 0x1f, - 0x19, 0xe1, 0xbd, 0xc0, 0x87, 0xbb, 0x9f, 0x29, 0x24, 0xdb, 0xdf, 0x86, 0xec, 0x27, 0x18, 0xdc, - 0xff, 0x3f, 0x77, 0xaf, 0xf0, 0xce, 0xf0, 0xf5, 0xdf, 0xe9, 0xde, 0xdd, 0x39, 0xe3, 0x40, 0xd0, - 0xf9, 0x07, 0x70, 0x2e, 0xc3, 0xa7, 0x9f, 0x56, 0x21, 0xba, 0x58, 0x85, 0xe8, 0xfb, 0x2a, 0x44, - 0xef, 0xd6, 0x61, 0xed, 0x62, 0x1d, 0xd6, 0xbe, 0xac, 0xc3, 0xda, 0xcb, 0x13, 0x21, 0xed, 0x2c, - 0x9b, 0x10, 0x06, 0x29, 0x65, 0x3a, 0x9f, 0x5b, 0xe8, 0x83, 0x16, 0x7d, 0x36, 0x4b, 0xa4, 0xa2, - 0x4c, 0x83, 0x02, 0x43, 0x17, 0x03, 0xba, 0xa4, 0xee, 0x6a, 0xd8, 0x7c, 0xce, 0xcd, 0xe4, 0x5a, - 0x11, 0xdd, 0x83, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa7, 0xdd, 0x5f, 0x85, 0x32, 0x03, 0x00, - 0x00, + // 463 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0x3f, 0x8e, 0xd3, 0x40, + 0x14, 0xc6, 0x33, 0x24, 0xb0, 0xcb, 0x04, 0xb4, 0xc8, 0x1b, 0x09, 0xc7, 0x42, 0x4e, 0xe4, 0x02, + 0xa5, 0xc9, 0x8c, 0x12, 0xb4, 0x0d, 0x12, 0xc5, 0x46, 0xdb, 0x80, 0x14, 0x21, 0x19, 0x1a, 0x68, + 0x22, 0x67, 0x32, 0x4c, 0x46, 0xac, 0xe7, 0x05, 0xcf, 0x38, 0xc4, 0x35, 0x17, 0xa0, 0xe4, 0x04, + 0x9c, 0x80, 0x43, 0x20, 0xaa, 0x2d, 0xa9, 0x00, 0x25, 0xe2, 0x02, 0x9c, 0x00, 0xf9, 0xcf, 0x64, + 0x21, 0x11, 0x74, 0xdb, 0xf9, 0x7b, 0xbf, 0x37, 0x9f, 0xdf, 0xfb, 0xec, 0xc1, 0xc7, 0x92, 0x45, + 0x51, 0x6a, 0xe6, 0x74, 0x39, 0xa0, 0x66, 0x45, 0x16, 0x09, 0x18, 0x70, 0x70, 0x55, 0x24, 0xcb, + 0x81, 0xd7, 0x66, 0xa0, 0x63, 0xd0, 0x93, 0x82, 0xd0, 0x52, 0x94, 0x6d, 0x5e, 0x4b, 0x80, 0x80, + 0xb2, 0x9e, 0x3f, 0x55, 0x55, 0x5f, 0x00, 0x88, 0x73, 0x4e, 0x0b, 0x35, 0x4d, 0x5f, 0xd1, 0x59, + 0x9a, 0x44, 0x46, 0x82, 0xaa, 0x78, 0x7b, 0x97, 0x47, 0x2a, 0x2b, 0x51, 0xf0, 0x0e, 0x61, 0x67, + 0xac, 0x45, 0xc8, 0x85, 0xd4, 0x86, 0x27, 0xa7, 0x8c, 0x41, 0xaa, 0x8c, 0xd3, 0xc2, 0xd7, 0xe1, + 0xad, 0xe2, 0x89, 0x8b, 0xba, 0xa8, 0x77, 0x33, 0x2c, 0x85, 0xf3, 0x08, 0xdf, 0x66, 0xa0, 0x14, + 0x67, 0xb9, 0xf7, 0x44, 0xce, 0xdc, 0x6b, 0x39, 0x1d, 0xb9, 0xbf, 0xbe, 0x75, 0x5a, 0x59, 0x14, + 0x9f, 0x3f, 0x0c, 0xfe, 0xc2, 0x41, 0x78, 0xeb, 0x52, 0x3f, 0x9e, 0x39, 0x2e, 0x3e, 0x58, 0xf2, + 0x44, 0x4b, 0x50, 0x6e, 0xbd, 0xb0, 0xb5, 0x32, 0xb8, 0x87, 0xbd, 0xfd, 0x21, 0x42, 0xae, 0x17, + 0xa0, 0x34, 0x0f, 0x7e, 0x22, 0xdc, 0x1c, 0x6b, 0xf1, 0x2c, 0x9d, 0xc6, 0xd2, 0x3c, 0x5f, 0x5d, + 0xcd, 0x70, 0x27, 0xb8, 0x11, 0x6b, 0xa1, 0xdd, 0x7a, 0xb7, 0xde, 0x6b, 0x0e, 0x5b, 0xa4, 0x8c, + 0x8c, 0xd8, 0xc8, 0xc8, 0xa9, 0xca, 0x46, 0xcd, 0x2f, 0x9f, 0xfa, 0x07, 0x7a, 0xf6, 0x9a, 0xe4, + 0xc3, 0x16, 0xed, 0xce, 0x13, 0x7c, 0xc7, 0xc8, 0x98, 0x43, 0x6a, 0x26, 0x36, 0x74, 0xb7, 0xd1, + 0x45, 0xbd, 0xe6, 0xb0, 0xbd, 0x67, 0x71, 0x56, 0x35, 0x8c, 0x1a, 0x1f, 0xbe, 0x77, 0x50, 0x78, + 0x54, 0x1d, 0xb4, 0xe5, 0x60, 0x80, 0x8f, 0xff, 0x58, 0xd3, 0xae, 0xef, 0x78, 0xf8, 0x50, 0xf3, + 0x37, 0x29, 0x57, 0x8c, 0x17, 0x1b, 0x37, 0xc2, 0xad, 0x1e, 0x7e, 0x44, 0xb8, 0x3e, 0xd6, 0xc2, + 0x79, 0x81, 0x8f, 0x76, 0x3f, 0xa1, 0x4f, 0x2e, 0x7f, 0x29, 0xb2, 0x9f, 0xae, 0x77, 0xff, 0xff, + 0x7c, 0xfb, 0xfa, 0x33, 0x7c, 0xb8, 0x4d, 0xfe, 0xee, 0xce, 0x19, 0x0b, 0xbc, 0xce, 0x3f, 0x80, + 0x75, 0x19, 0x3d, 0xfd, 0xbc, 0xf6, 0xd1, 0xc5, 0xda, 0x47, 0x3f, 0xd6, 0x3e, 0x7a, 0xbf, 0xf1, + 0x6b, 0x17, 0x1b, 0xbf, 0xf6, 0x75, 0xe3, 0xd7, 0x5e, 0x9e, 0x08, 0x69, 0xe6, 0xe9, 0x94, 0x30, + 0x88, 0x29, 0x4b, 0xb2, 0x85, 0x81, 0x3e, 0x24, 0xa2, 0xcf, 0xe6, 0x91, 0x54, 0x94, 0x25, 0xa0, + 0x40, 0xd3, 0xe5, 0x90, 0xae, 0xa8, 0xbd, 0x36, 0x26, 0x5b, 0x70, 0x3d, 0xbd, 0x51, 0xc4, 0xfa, + 0xe0, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf3, 0xfc, 0xdd, 0xdc, 0x4e, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -561,6 +569,11 @@ func (m *MsgSubmitTxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Sequence != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -638,6 +651,9 @@ func (m *MsgSubmitTxResponse) Size() (n int) { } var l int _ = l + if m.Sequence != 0 { + n += 1 + sovTx(uint64(m.Sequence)) + } return n } @@ -1056,6 +1072,25 @@ func (m *MsgSubmitTxResponse) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: MsgSubmitTxResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) + } + m.Sequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:])