diff --git a/CHANGELOG.md b/CHANGELOG.md index fc3ecb5fc..cfc616c3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ - [\#730](https://github.com/cosmos/evm/pull/730) Fix panic if evm mempool not used. - [\#733](https://github.com/cosmos/evm/pull/733) Avoid rejecting tx with unsupported extension option for ExtensionOptionDynamicFeeTx. - [\#736](https://github.com/cosmos/evm/pull/736) Add InitEvmCoinInfo upgrade to avoid panic when denom is not registered. +- Add `stateDB` and `callFromPrecompile` parameters to internal EVM messages. +- Fixed an issue with events missing from final transaction result. ### IMPROVEMENTS diff --git a/Makefile b/Makefile index cda314b6e..0f85d784d 100644 --- a/Makefile +++ b/Makefile @@ -378,17 +378,17 @@ test-rpc-compat-stop: .PHONY: localnet-start localnet-stop localnet-build-env localnet-build-nodes test-rpc-compat test-rpc-compat-stop -test-system: build-v04 build +test-system: build-v05 build mkdir -p ./tests/systemtests/binaries/ cp $(BUILDDIR)/evmd ./tests/systemtests/binaries/ cd tests/systemtests/Counter && forge build $(MAKE) -C tests/systemtests test -build-v04: - mkdir -p ./tests/systemtests/binaries/v0.4 - git checkout v0.4.1 +build-v05: + mkdir -p ./tests/systemtests/binaries/v0.5 + git checkout v0.5.1 make build - cp $(BUILDDIR)/evmd ./tests/systemtests/binaries/v0.4 + cp $(BUILDDIR)/evmd ./tests/systemtests/binaries/v0.5 git checkout - mocks: diff --git a/README.md b/README.md index d6a56a487..401b89b95 100644 --- a/README.md +++ b/README.md @@ -1,139 +1,84 @@ - +# Confidential Security Hotfix -**Please note**: This repo is undergoing changes while the code is being audited and tested. For the time being we will -be making v0.x releases. Some breaking changes might occur. Cosmos Labs will only mark the Cosmos EVM repository as stable with a v1 -release after the audit, key stability features and benchmarking are completed. +⚠️ **This repository is confidential.** -**Visit the official documentation for Cosmos EVM**: [evm.cosmos.network](https://evm.cosmos.network/) +This repository contains a **private security hotfix for a critical Cosmos EVM vulnerability** that can lead to **fund loss and chain halts**. The issue is consensus-level, exploitable in practice, and has been locally reproduced. -## What is Cosmos EVM? +Details are intentionally limited during the private disclosure window. +Please **do not share, fork, or discuss publicly** until disclosure. -Cosmos EVM is a plug-and-play solution that adds EVM compatibility and customizability to your Cosmos SDK chain. Cosmos EVM equips Cosmos chains with complete Ethereum capabilities: Solidity smart contracts, Ethereum JSON-RPC, native support for the EVM wallet/token/user experience, and access to the entire Ethereum developer ecosystem. Its precompiles and extensions allow developers to leverage modules like [IBC](https://github.com/cosmos/ibc-go) with EVM and get native ERC-20 support for tokens on Cosmos. +Public disclosure is planned for **March 2nd**. -Cosmos EVM is customizable for your business use case, chain architecture, and performance needs. +Thank you for your continued dedication to maintaining a safe and secure ecosystem. +--- -## Integration +## Upgrade Guidance -Cosmos EVM can be integrated into your existing chain -or added during the development of your upcoming chain launch -by importing Cosmos EVM as a go module library. +To reduce the risk of premature disclosure, it is **strongly recommended** that this fix is deployed via **compiled binaries distributed directly to validators**, rather than public source changes, until the disclosure window closes. -### Robust defaults +Upgrades must be performed in a **coordinated fashion**. -Cosmos EVM’s modules come out of the box with defaults that enable rapid VM deployment. Integrating all available modules into a blockchain provides: +### Hotfix Tags -- Exposed JSON-RPC endpoints for connectivity with EVM tooling like wallets such as [MetaMask](https://metamask.io/) and [Rabby](https://rabby.io/), and block explorers like [Blockscout](https://docs.blockscout.com/). -- EVM extensions that allow functionality that is native to Cosmos SDK modules to be accessible from Solidity smart contracts [Solidity](https://docs.soliditylang.org/en/v0.8.26/) smart contracts. -- Use of any IBC asset in the EVM. +The following private tag is provided: -All modules can be controlled by on-chain governance. +- `v0.6.x-papyrus-hotfix` -### Extensive customizability +--- -Based on these robust defaults, the feature set is highly customizable: +## Applying the Hotfix -- **Permissioned EVM**- Implement customized access controls to either blacklist or whitelist individual addresses for calling and/or creating smart contracts on the network. -- **EVM Extensions** - Use custom EVM extensions to write custom business logic for your use case. -- **Single Token Representation v2 & ERC-20 Module** - The Single Token Representation v2 and our `x/erc20` module to aligns IBC and ERC-20 token representation to simplify and improve user experience. -- **EIP-1559 Fee Market Mechanism** - Customize fee structures and transaction surge management with the self-regulating fee market mechanism based on [EIP-1559 fee market](https://eips.ethereum.org/EIPS/eip-1559). -- **JSON-RPC Server** - There is full control over the exposed namespaces and [JSON-RPC server](https://cosmos-docs.mintlify.app/docs/api-reference/ethereum-json-rpc). Configurable parameters include custom timeouts for EVM calls or HTTP requests, maximum block gas, open connections, and more. -- **EIP-712 Signing** - Integrate the [EIP-712 signature](https://eips.ethereum.org/EIPS/eip-712) implementation to allow Cosmos SDK messages to be signed with EVM wallets like MetaMask. This supports structured data signing for arbitrary messages. -- **Custom Improvement Proposals (Opcodes)** - Any Cosmos EVM user is provided the opportunity to customize bits of their EVM opcodes and add new ones. Read more on [custom operations here](https://cosmos-docs.mintlify.app/docs/documentation/smart-contracts/custom-improvement-proposals#custom-improvement-proposals). +### 1. Update your Git config to use private repositories -## Compatibility with Ethereum +#### SSH Instructions -Is Cosmos EVM "Ethereum equivalent"? Ethereum-equivalence describes any EVM solution that is identical in transaction execution to the Ethereum client. On the other hand, Ethereum-compatible means that the EVM implementation can run every transaction that is valid on Ethereum, while also handling divergent transactions that are not valid on Ethereum. +First, configure your machine to use SSH for Git. More details can be found here: https://docs.github.com/en/authentication/connecting-to-github-with-ssh. -We describe Cosmos EVM as **forward-compatible** with Ethereum. It can run any valid smart contract from Ethereum and also implement new features that are not yet available on the standard Ethereum VM, thus moving the standard forward. - -## Getting started - -To run the example `evmd` chain, run the script using `./local_node.sh` -from the root folder of the repository. - -### Migrations - -We provide upgrade guides [here](./docs/migrations) for upgrading your chain from various Cosmos EVM versions. - -### Testing - -All test scripts are found in `Makefile` in the root of the repository. -Listed below are the commands for various tests: +To use SSH in `go mod` downloads, add these lines to `~/.gitconfig`: +```md +[url "ssh://git@github.com/"] + insteadOf = https://github.com/ +``` -#### Unit Testing -```bash -make test-unit -``` +#### HTTPS Instructions -#### Coverage Test +If you choose to use HTTPS, please follow the instructions here: https://go.dev/doc/faq#git_https. -This generates a code coverage file `filtered_coverage.txt` and prints out the -covered code percentage for the working files. -```bash -make test-unit-cover -``` +### 2. Update `go.mod` -#### Fuzz Testing +Add a `replace` directive pointing to this repository: -```bash -make test-fuzz +```go +replace github.com/cosmos/evm => github.com/cosmos/evm-sec-papyrus v0.6.x-papyrus-hotfix ``` -#### Solidity Tests +Upgrade Cosmos SDK to v0.53.6: -```bash -make test-solidity +```go +github.com/cosmos/cosmos-sdk v0.53.6 ``` -#### Benchmark Tests +Then, tidy using the `GOPRIVATE` variable: ```bash -make benchmark +GOPRIVATE=github.com/cosmos/evm-sec-papyrus go mod tidy ``` +--- -## Open-source License & Credits - -Cosmos EVM is fully open-source under the Apache 2.0 license. It is a fork of [evmOS](https://github.com/evmos/OS). The Interchain Foundation funded [evmOS developers](https://github.com/evmos/OS) Tharsis to open-source the original evmOS codebase. Tharsis and evmOS performed the foundational work for EVM compatibility and -interoperability in Cosmos. - -## Developer Community and Support - -The issue list of this repo is exclusively for bug reports and feature requests. We have active, helpful communities on Discord, Telegram, and Slack. - -**| Need Help? | Support & Community: [Discord](https://discord.com/invite/interchain) - [Telegram](https://t.me/CosmosOG) - [Talk to an Expert](https://cosmos.network/interest-form) - [Join the #Cosmos-tech Slack Channel](https://forms.gle/A8jawLgB8zuL1FN36) |** - - -## Maintainers -[Cosmos Labs](https://cosmoslabs.io/) maintains the core components of the stack: Cosmos SDK, CometBFT, IBC, Cosmos EVM, and various developer tools and frameworks. The detailed maintenance policy can be found [here](https://github.com/cosmos/security/blob/main/POLICY.md). In addition to developing and maintaining the Cosmos Stack, Cosmos Labs provides advisory and engineering services for blockchain solutions. [Get in touch with Cosmos Labs](https://www.cosmoslabs.io/contact). - -Cosmos Labs is a wholly-owned subsidiary of the [Interchain Foundation](https://interchain.io/), the Swiss nonprofit responsible for treasury management, funding public goods, and supporting governance for Cosmos. - -The Cosmos Stack is supported by a robust community of open-source contributors. - -## Contributing to Cosmos EVM - -We welcome open source contributions and discussions! For more on contributing, read the [guide](./CONTRIBUTING.md). - -### Key Contributors to Cosmos EVM +### 2. Build and Deploy -We would like to thank our key contributors at [B-Harvest](https://bharvest.io/) and -[Mantra](https://www.mantrachain.io/) for contributing to and helping us drive the development of Cosmos EVM. +For complete API-breaking changes and instructions, refer to the [migration docs](https://github.com/cosmos/evm-sec-papyrus/blob/release/v0.6.x/docs/migrations/v0.5.x_to_v0.6.0.md). -## Documentation and Resources +Rebuild your node binary using your standard process, distribute the compiled binary to validators, and perform a rolling upgrade. -### Documentation -Visit the official documentation for Cosmos EVM: [evm.cosmos.network](https://evm.cosmos.network/) +--- -### Cosmos Stack Libraries +## Notes -- [Cosmos SDK](http://github.com/cosmos/cosmos-sdk) - A framework for building - applications in Golang -- [The Inter-Blockchain Communication Protocol (IBC)](https://github.com/cosmos/ibc-go/) - A blockchain interoperability protocol that allows blockchains to transfer any type of data encoded in bytes. -- [CometBFT](https://github.com/cometbft/cometbft) - High-performance, 10k+ TPS configurable BFT consensus engine. +- Do not mirror this repository to public infrastructure +- Do not copy this repository to a public Github repository +- Do not reference this fix in public changelogs or releases before disclosure diff --git a/ante/cosmos/eip712.go b/ante/cosmos/eip712.go index e800cee0f..bdea0e7fa 100644 --- a/ante/cosmos/eip712.go +++ b/ante/cosmos/eip712.go @@ -25,7 +25,7 @@ import ( authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" ) -var evmCodec codec.ProtoCodecMarshaler +var evmCodec codec.Codec func init() { registry := codectypes.NewInterfaceRegistry() @@ -177,7 +177,7 @@ func VerifySignature( return errorsmod.Wrap(errortypes.ErrNoSignatures, "tx doesn't contain any msgs to verify signature") } - txBytes := legacytx.StdSignBytes( + txBytes := legacytx.StdSignBytes( //nolint:staticcheck // checking legacy type signerData.ChainID, signerData.AccountNumber, signerData.Sequence, diff --git a/ante/evm/fee_checker.go b/ante/evm/fee_checker.go index a31c1f013..a65d38551 100644 --- a/ante/evm/fee_checker.go +++ b/ante/evm/fee_checker.go @@ -93,7 +93,7 @@ func FeeChecker( } feeCoins := feeTx.GetFee() - feeAmtDec := sdkmath.LegacyNewDecFromInt(feeCoins.AmountOfNoDenomValidation(denom)) + feeAmtDec := sdkmath.LegacyNewDecFromInt(feeCoins.AmountOfNoDenomValidation(denom)) //nolint:staticcheck // checking legacy type feeCap := feeAmtDec.QuoInt(gas) if feeCap.LT(baseFee) { diff --git a/api/cosmos/evm/erc20/v1/erc20.pulsar.go b/api/cosmos/evm/erc20/v1/erc20.pulsar.go index 388117150..368e0ed52 100644 --- a/api/cosmos/evm/erc20/v1/erc20.pulsar.go +++ b/api/cosmos/evm/erc20/v1/erc20.pulsar.go @@ -20,6 +20,7 @@ var ( fd_TokenPair_denom protoreflect.FieldDescriptor fd_TokenPair_enabled protoreflect.FieldDescriptor fd_TokenPair_contract_owner protoreflect.FieldDescriptor + fd_TokenPair_owner_address protoreflect.FieldDescriptor ) func init() { @@ -29,6 +30,7 @@ func init() { fd_TokenPair_denom = md_TokenPair.Fields().ByName("denom") fd_TokenPair_enabled = md_TokenPair.Fields().ByName("enabled") fd_TokenPair_contract_owner = md_TokenPair.Fields().ByName("contract_owner") + fd_TokenPair_owner_address = md_TokenPair.Fields().ByName("owner_address") } var _ protoreflect.Message = (*fastReflection_TokenPair)(nil) @@ -120,6 +122,12 @@ func (x *fastReflection_TokenPair) Range(f func(protoreflect.FieldDescriptor, pr return } } + if x.OwnerAddress != "" { + value := protoreflect.ValueOfString(x.OwnerAddress) + if !f(fd_TokenPair_owner_address, value) { + return + } + } } // Has reports whether a field is populated. @@ -143,6 +151,8 @@ func (x *fastReflection_TokenPair) Has(fd protoreflect.FieldDescriptor) bool { return x.Enabled != false case "cosmos.evm.erc20.v1.TokenPair.contract_owner": return x.ContractOwner != 0 + case "cosmos.evm.erc20.v1.TokenPair.owner_address": + return x.OwnerAddress != "" default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.TokenPair")) @@ -167,6 +177,8 @@ func (x *fastReflection_TokenPair) Clear(fd protoreflect.FieldDescriptor) { x.Enabled = false case "cosmos.evm.erc20.v1.TokenPair.contract_owner": x.ContractOwner = 0 + case "cosmos.evm.erc20.v1.TokenPair.owner_address": + x.OwnerAddress = "" default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.TokenPair")) @@ -195,6 +207,9 @@ func (x *fastReflection_TokenPair) Get(descriptor protoreflect.FieldDescriptor) case "cosmos.evm.erc20.v1.TokenPair.contract_owner": value := x.ContractOwner return protoreflect.ValueOfEnum((protoreflect.EnumNumber)(value)) + case "cosmos.evm.erc20.v1.TokenPair.owner_address": + value := x.OwnerAddress + return protoreflect.ValueOfString(value) default: if descriptor.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.TokenPair")) @@ -223,6 +238,8 @@ func (x *fastReflection_TokenPair) Set(fd protoreflect.FieldDescriptor, value pr x.Enabled = value.Bool() case "cosmos.evm.erc20.v1.TokenPair.contract_owner": x.ContractOwner = (Owner)(value.Enum()) + case "cosmos.evm.erc20.v1.TokenPair.owner_address": + x.OwnerAddress = value.Interface().(string) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.TokenPair")) @@ -251,6 +268,8 @@ func (x *fastReflection_TokenPair) Mutable(fd protoreflect.FieldDescriptor) prot panic(fmt.Errorf("field enabled of message cosmos.evm.erc20.v1.TokenPair is not mutable")) case "cosmos.evm.erc20.v1.TokenPair.contract_owner": panic(fmt.Errorf("field contract_owner of message cosmos.evm.erc20.v1.TokenPair is not mutable")) + case "cosmos.evm.erc20.v1.TokenPair.owner_address": + panic(fmt.Errorf("field owner_address of message cosmos.evm.erc20.v1.TokenPair is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.TokenPair")) @@ -272,6 +291,8 @@ func (x *fastReflection_TokenPair) NewField(fd protoreflect.FieldDescriptor) pro return protoreflect.ValueOfBool(false) case "cosmos.evm.erc20.v1.TokenPair.contract_owner": return protoreflect.ValueOfEnum(0) + case "cosmos.evm.erc20.v1.TokenPair.owner_address": + return protoreflect.ValueOfString("") default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.TokenPair")) @@ -355,6 +376,10 @@ func (x *fastReflection_TokenPair) ProtoMethods() *protoiface.Methods { if x.ContractOwner != 0 { n += 1 + runtime.Sov(uint64(x.ContractOwner)) } + l = len(x.OwnerAddress) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } if x.unknownFields != nil { n += len(x.unknownFields) } @@ -384,6 +409,13 @@ func (x *fastReflection_TokenPair) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } + if len(x.OwnerAddress) > 0 { + i -= len(x.OwnerAddress) + copy(dAtA[i:], x.OwnerAddress) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.OwnerAddress))) + i-- + dAtA[i] = 0x2a + } if x.ContractOwner != 0 { i = runtime.EncodeVarint(dAtA, i, uint64(x.ContractOwner)) i-- @@ -565,6 +597,38 @@ func (x *fastReflection_TokenPair) ProtoMethods() *protoiface.Methods { break } } + case 5: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field OwnerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.OwnerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := runtime.Skip(dAtA[iNdEx:]) @@ -3566,6 +3630,9 @@ type TokenPair struct { // contract_owner is the an ENUM specifying the type of ERC20 owner (0 // invalid, 1 ModuleAccount, 2 external address) ContractOwner Owner `protobuf:"varint,4,opt,name=contract_owner,json=contractOwner,proto3,enum=cosmos.evm.erc20.v1.Owner" json:"contract_owner,omitempty"` + // owner_address is the address of the current owner of the token + // Only set if contract_owner is OWNER_MODULE + OwnerAddress string `protobuf:"bytes,5,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` } func (x *TokenPair) Reset() { @@ -3616,6 +3683,13 @@ func (x *TokenPair) GetContractOwner() Owner { return Owner_OWNER_UNSPECIFIED } +func (x *TokenPair) GetOwnerAddress() string { + if x != nil { + return x.OwnerAddress + } + return "" +} + // Allowance is a token allowance only for erc20 precompile type Allowance struct { state protoimpl.MessageState @@ -3905,7 +3979,7 @@ var file_cosmos_evm_erc20_v1_erc20_proto_rawDesc = []byte{ 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x1a, 0x1e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x62, 0x61, 0x6e, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x67, 0x6f, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa9, 0x01, 0x0a, + 0x6f, 0x2f, 0x67, 0x6f, 0x67, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xce, 0x01, 0x0a, 0x09, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x63, 0x32, 0x30, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x63, 0x32, 0x30, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, @@ -3916,64 +3990,67 @@ var file_cosmos_evm_erc20_v1_erc20_proto_rawDesc = []byte{ 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x4f, 0x77, 0x6e, - 0x65, 0x72, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x01, 0x22, 0x9b, 0x01, 0x0a, 0x09, 0x41, 0x6c, 0x6c, - 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x63, 0x32, 0x30, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, - 0x72, 0x63, 0x32, 0x30, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6f, - 0x77, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, - 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x33, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1d, 0xc8, 0xde, 0x1f, 0x00, - 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, - 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x95, 0x01, 0x0a, 0x14, 0x52, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, - 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, + 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x01, 0x22, 0x9b, 0x01, + 0x0a, 0x09, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, + 0x72, 0x63, 0x32, 0x30, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x63, 0x32, 0x30, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, + 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x12, 0x33, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x1d, 0xc8, 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x95, 0x01, 0x0a, 0x14, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x70, + 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, + 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x6e, 0x6b, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x04, 0xc8, + 0xde, 0x1f, 0x00, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x04, 0xe8, + 0xa0, 0x1f, 0x00, 0x22, 0x53, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3f, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x6e, 0x6b, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x08, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x53, - 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x3f, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, - 0x6e, 0x6b, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x22, 0x7d, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x45, - 0x52, 0x43, 0x32, 0x30, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, - 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x65, 0x72, - 0x63, 0x32, 0x30, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x3a, 0x04, 0xe8, 0xa0, - 0x1f, 0x00, 0x22, 0x73, 0x0a, 0x1d, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x50, 0x72, 0x6f, 0x70, 0x6f, - 0x73, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x01, 0x2a, 0x4a, 0x0a, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, - 0x12, 0x15, 0x0a, 0x11, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x4f, 0x57, 0x4e, 0x45, 0x52, - 0x5f, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x57, 0x4e, - 0x45, 0x52, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x10, 0x02, 0x1a, 0x04, 0x88, - 0xa3, 0x1e, 0x00, 0x42, 0xc2, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x42, - 0x0a, 0x45, 0x72, 0x63, 0x32, 0x30, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, - 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x72, 0x63, 0x32, 0x30, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, - 0x45, 0xaa, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x45, - 0x72, 0x63, 0x32, 0x30, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1f, - 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, - 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, - 0x02, 0x16, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x45, - 0x72, 0x63, 0x32, 0x30, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x7d, 0x0a, 0x15, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x45, 0x52, 0x43, 0x32, 0x30, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, + 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x65, 0x72, 0x63, + 0x32, 0x30, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x73, 0x0a, 0x1d, 0x54, 0x6f, 0x67, 0x67, 0x6c, + 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x3a, 0x04, 0xe8, 0xa0, 0x1f, 0x01, 0x2a, 0x4a, 0x0a, 0x05, + 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x15, 0x0a, 0x11, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x5f, 0x55, + 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, + 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x5f, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x12, + 0x0a, 0x0e, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x5f, 0x45, 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, + 0x10, 0x02, 0x1a, 0x04, 0x88, 0xa3, 0x1e, 0x00, 0x42, 0xc2, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, + 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, + 0x30, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x45, 0x72, 0x63, 0x32, 0x30, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, + 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x72, 0x63, 0x32, 0x30, 0x76, 0x31, + 0xa2, 0x02, 0x03, 0x43, 0x45, 0x45, 0xaa, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, + 0x45, 0x76, 0x6d, 0x2e, 0x45, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x43, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, + 0x56, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, + 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x16, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, + 0x76, 0x6d, 0x3a, 0x3a, 0x45, 0x72, 0x63, 0x32, 0x30, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/cosmos/evm/erc20/v1/query.pulsar.go b/api/cosmos/evm/erc20/v1/query.pulsar.go index 766fa21bb..af9491312 100644 --- a/api/cosmos/evm/erc20/v1/query.pulsar.go +++ b/api/cosmos/evm/erc20/v1/query.pulsar.go @@ -2670,6 +2670,846 @@ func (x *fastReflection_QueryParamsResponse) ProtoMethods() *protoiface.Methods } } +var ( + md_QueryOwnerAddressRequest protoreflect.MessageDescriptor + fd_QueryOwnerAddressRequest_contract_address protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_evm_erc20_v1_query_proto_init() + md_QueryOwnerAddressRequest = File_cosmos_evm_erc20_v1_query_proto.Messages().ByName("QueryOwnerAddressRequest") + fd_QueryOwnerAddressRequest_contract_address = md_QueryOwnerAddressRequest.Fields().ByName("contract_address") +} + +var _ protoreflect.Message = (*fastReflection_QueryOwnerAddressRequest)(nil) + +type fastReflection_QueryOwnerAddressRequest QueryOwnerAddressRequest + +func (x *QueryOwnerAddressRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryOwnerAddressRequest)(x) +} + +func (x *QueryOwnerAddressRequest) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_evm_erc20_v1_query_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryOwnerAddressRequest_messageType fastReflection_QueryOwnerAddressRequest_messageType +var _ protoreflect.MessageType = fastReflection_QueryOwnerAddressRequest_messageType{} + +type fastReflection_QueryOwnerAddressRequest_messageType struct{} + +func (x fastReflection_QueryOwnerAddressRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryOwnerAddressRequest)(nil) +} +func (x fastReflection_QueryOwnerAddressRequest_messageType) New() protoreflect.Message { + return new(fastReflection_QueryOwnerAddressRequest) +} +func (x fastReflection_QueryOwnerAddressRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryOwnerAddressRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryOwnerAddressRequest) Descriptor() protoreflect.MessageDescriptor { + return md_QueryOwnerAddressRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryOwnerAddressRequest) Type() protoreflect.MessageType { + return _fastReflection_QueryOwnerAddressRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryOwnerAddressRequest) New() protoreflect.Message { + return new(fastReflection_QueryOwnerAddressRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryOwnerAddressRequest) Interface() protoreflect.ProtoMessage { + return (*QueryOwnerAddressRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryOwnerAddressRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.ContractAddress != "" { + value := protoreflect.ValueOfString(x.ContractAddress) + if !f(fd_QueryOwnerAddressRequest_contract_address, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryOwnerAddressRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressRequest.contract_address": + return x.ContractAddress != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressRequest")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryOwnerAddressRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressRequest.contract_address": + x.ContractAddress = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressRequest")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryOwnerAddressRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressRequest.contract_address": + value := x.ContractAddress + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressRequest")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryOwnerAddressRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressRequest.contract_address": + x.ContractAddress = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressRequest")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryOwnerAddressRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressRequest.contract_address": + panic(fmt.Errorf("field contract_address of message cosmos.evm.erc20.v1.QueryOwnerAddressRequest is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressRequest")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryOwnerAddressRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressRequest.contract_address": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressRequest")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryOwnerAddressRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.evm.erc20.v1.QueryOwnerAddressRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryOwnerAddressRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryOwnerAddressRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryOwnerAddressRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryOwnerAddressRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryOwnerAddressRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.ContractAddress) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryOwnerAddressRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.ContractAddress) > 0 { + i -= len(x.ContractAddress) + copy(dAtA[i:], x.ContractAddress) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ContractAddress))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryOwnerAddressRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryOwnerAddressRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryOwnerAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_QueryOwnerAddressResponse protoreflect.MessageDescriptor + fd_QueryOwnerAddressResponse_owner_address protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_evm_erc20_v1_query_proto_init() + md_QueryOwnerAddressResponse = File_cosmos_evm_erc20_v1_query_proto.Messages().ByName("QueryOwnerAddressResponse") + fd_QueryOwnerAddressResponse_owner_address = md_QueryOwnerAddressResponse.Fields().ByName("owner_address") +} + +var _ protoreflect.Message = (*fastReflection_QueryOwnerAddressResponse)(nil) + +type fastReflection_QueryOwnerAddressResponse QueryOwnerAddressResponse + +func (x *QueryOwnerAddressResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryOwnerAddressResponse)(x) +} + +func (x *QueryOwnerAddressResponse) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_evm_erc20_v1_query_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryOwnerAddressResponse_messageType fastReflection_QueryOwnerAddressResponse_messageType +var _ protoreflect.MessageType = fastReflection_QueryOwnerAddressResponse_messageType{} + +type fastReflection_QueryOwnerAddressResponse_messageType struct{} + +func (x fastReflection_QueryOwnerAddressResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryOwnerAddressResponse)(nil) +} +func (x fastReflection_QueryOwnerAddressResponse_messageType) New() protoreflect.Message { + return new(fastReflection_QueryOwnerAddressResponse) +} +func (x fastReflection_QueryOwnerAddressResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryOwnerAddressResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryOwnerAddressResponse) Descriptor() protoreflect.MessageDescriptor { + return md_QueryOwnerAddressResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryOwnerAddressResponse) Type() protoreflect.MessageType { + return _fastReflection_QueryOwnerAddressResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryOwnerAddressResponse) New() protoreflect.Message { + return new(fastReflection_QueryOwnerAddressResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryOwnerAddressResponse) Interface() protoreflect.ProtoMessage { + return (*QueryOwnerAddressResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryOwnerAddressResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.OwnerAddress != "" { + value := protoreflect.ValueOfString(x.OwnerAddress) + if !f(fd_QueryOwnerAddressResponse_owner_address, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryOwnerAddressResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressResponse.owner_address": + return x.OwnerAddress != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryOwnerAddressResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressResponse.owner_address": + x.OwnerAddress = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryOwnerAddressResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressResponse.owner_address": + value := x.OwnerAddress + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryOwnerAddressResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressResponse.owner_address": + x.OwnerAddress = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryOwnerAddressResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressResponse.owner_address": + panic(fmt.Errorf("field owner_address of message cosmos.evm.erc20.v1.QueryOwnerAddressResponse is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryOwnerAddressResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.QueryOwnerAddressResponse.owner_address": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.QueryOwnerAddressResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.QueryOwnerAddressResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryOwnerAddressResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.evm.erc20.v1.QueryOwnerAddressResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryOwnerAddressResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryOwnerAddressResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryOwnerAddressResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryOwnerAddressResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryOwnerAddressResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.OwnerAddress) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryOwnerAddressResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.OwnerAddress) > 0 { + i -= len(x.OwnerAddress) + copy(dAtA[i:], x.OwnerAddress) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.OwnerAddress))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryOwnerAddressResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryOwnerAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryOwnerAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field OwnerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.OwnerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.0 @@ -2910,6 +3750,76 @@ func (x *QueryParamsResponse) GetParams() *Params { return nil } +type QueryOwnerAddressRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` +} + +func (x *QueryOwnerAddressRequest) Reset() { + *x = QueryOwnerAddressRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_evm_erc20_v1_query_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryOwnerAddressRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryOwnerAddressRequest) ProtoMessage() {} + +// Deprecated: Use QueryOwnerAddressRequest.ProtoReflect.Descriptor instead. +func (*QueryOwnerAddressRequest) Descriptor() ([]byte, []int) { + return file_cosmos_evm_erc20_v1_query_proto_rawDescGZIP(), []int{6} +} + +func (x *QueryOwnerAddressRequest) GetContractAddress() string { + if x != nil { + return x.ContractAddress + } + return "" +} + +type QueryOwnerAddressResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OwnerAddress string `protobuf:"bytes,1,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` +} + +func (x *QueryOwnerAddressResponse) Reset() { + *x = QueryOwnerAddressResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_evm_erc20_v1_query_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryOwnerAddressResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryOwnerAddressResponse) ProtoMessage() {} + +// Deprecated: Use QueryOwnerAddressResponse.ProtoReflect.Descriptor instead. +func (*QueryOwnerAddressResponse) Descriptor() ([]byte, []int) { + return file_cosmos_evm_erc20_v1_query_proto_rawDescGZIP(), []int{7} +} + +func (x *QueryOwnerAddressResponse) GetOwnerAddress() string { + if x != nil { + return x.OwnerAddress + } + return "" +} + var File_cosmos_evm_erc20_v1_query_proto protoreflect.FileDescriptor var file_cosmos_evm_erc20_v1_query_proto_rawDesc = []byte{ @@ -2961,47 +3871,66 @@ var file_cosmos_evm_erc20_v1_query_proto_rawDesc = []byte{ 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x09, 0xc8, 0xde, 0x1f, 0x00, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x32, 0xba, 0x03, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x91, 0x01, 0x0a, 0x0a, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, - 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x12, 0x99, - 0x01, 0x0a, 0x09, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2a, 0x2e, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, - 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x12, 0x2b, 0x2f, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, - 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2f, - 0x7b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x3d, 0x2a, 0x2a, 0x7d, 0x12, 0x80, 0x01, 0x0a, 0x06, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, + 0x22, 0x45, 0x0a, 0x18, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x40, 0x0a, 0x19, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6f, 0x77, 0x6e, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x32, 0xe4, 0x04, 0x0a, 0x05, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x12, 0x91, 0x01, 0x0a, 0x0a, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, + 0x72, 0x73, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, + 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, + 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x50, 0x61, 0x69, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x28, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, + 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x12, 0x99, 0x01, 0x0a, 0x09, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x50, 0x61, 0x69, 0x72, 0x12, 0x2a, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, + 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, + 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x12, 0x2b, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, + 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x5f, 0x70, 0x61, 0x69, 0x72, 0x73, 0x2f, 0x7b, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x3d, + 0x2a, 0x2a, 0x7d, 0x12, 0x80, 0x01, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x27, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, - 0x12, 0x1b, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, - 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0xc2, 0x01, - 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, - 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, - 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x72, - 0x63, 0x32, 0x30, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x45, 0xaa, 0x02, 0x13, 0x43, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x45, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x56, - 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, - 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, - 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x16, 0x43, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x45, 0x72, 0x63, 0x32, 0x30, 0x3a, 0x3a, - 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x2f, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0xa7, 0x01, 0x0a, 0x0c, 0x4f, 0x77, 0x6e, 0x65, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, + 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x38, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x32, 0x12, 0x30, + 0x2f, 0x65, 0x76, 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x2f, + 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2f, 0x7b, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, + 0x42, 0xc2, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, + 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, + 0x3b, 0x65, 0x72, 0x63, 0x32, 0x30, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x45, 0xaa, 0x02, + 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x45, 0x72, 0x63, 0x32, + 0x30, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, + 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, + 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x16, 0x43, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x45, 0x72, 0x63, 0x32, + 0x30, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3016,36 +3945,40 @@ func file_cosmos_evm_erc20_v1_query_proto_rawDescGZIP() []byte { return file_cosmos_evm_erc20_v1_query_proto_rawDescData } -var file_cosmos_evm_erc20_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_cosmos_evm_erc20_v1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 8) var file_cosmos_evm_erc20_v1_query_proto_goTypes = []interface{}{ - (*QueryTokenPairsRequest)(nil), // 0: cosmos.evm.erc20.v1.QueryTokenPairsRequest - (*QueryTokenPairsResponse)(nil), // 1: cosmos.evm.erc20.v1.QueryTokenPairsResponse - (*QueryTokenPairRequest)(nil), // 2: cosmos.evm.erc20.v1.QueryTokenPairRequest - (*QueryTokenPairResponse)(nil), // 3: cosmos.evm.erc20.v1.QueryTokenPairResponse - (*QueryParamsRequest)(nil), // 4: cosmos.evm.erc20.v1.QueryParamsRequest - (*QueryParamsResponse)(nil), // 5: cosmos.evm.erc20.v1.QueryParamsResponse - (*v1beta1.PageRequest)(nil), // 6: cosmos.base.query.v1beta1.PageRequest - (*TokenPair)(nil), // 7: cosmos.evm.erc20.v1.TokenPair - (*v1beta1.PageResponse)(nil), // 8: cosmos.base.query.v1beta1.PageResponse - (*Params)(nil), // 9: cosmos.evm.erc20.v1.Params + (*QueryTokenPairsRequest)(nil), // 0: cosmos.evm.erc20.v1.QueryTokenPairsRequest + (*QueryTokenPairsResponse)(nil), // 1: cosmos.evm.erc20.v1.QueryTokenPairsResponse + (*QueryTokenPairRequest)(nil), // 2: cosmos.evm.erc20.v1.QueryTokenPairRequest + (*QueryTokenPairResponse)(nil), // 3: cosmos.evm.erc20.v1.QueryTokenPairResponse + (*QueryParamsRequest)(nil), // 4: cosmos.evm.erc20.v1.QueryParamsRequest + (*QueryParamsResponse)(nil), // 5: cosmos.evm.erc20.v1.QueryParamsResponse + (*QueryOwnerAddressRequest)(nil), // 6: cosmos.evm.erc20.v1.QueryOwnerAddressRequest + (*QueryOwnerAddressResponse)(nil), // 7: cosmos.evm.erc20.v1.QueryOwnerAddressResponse + (*v1beta1.PageRequest)(nil), // 8: cosmos.base.query.v1beta1.PageRequest + (*TokenPair)(nil), // 9: cosmos.evm.erc20.v1.TokenPair + (*v1beta1.PageResponse)(nil), // 10: cosmos.base.query.v1beta1.PageResponse + (*Params)(nil), // 11: cosmos.evm.erc20.v1.Params } var file_cosmos_evm_erc20_v1_query_proto_depIdxs = []int32{ - 6, // 0: cosmos.evm.erc20.v1.QueryTokenPairsRequest.pagination:type_name -> cosmos.base.query.v1beta1.PageRequest - 7, // 1: cosmos.evm.erc20.v1.QueryTokenPairsResponse.token_pairs:type_name -> cosmos.evm.erc20.v1.TokenPair - 8, // 2: cosmos.evm.erc20.v1.QueryTokenPairsResponse.pagination:type_name -> cosmos.base.query.v1beta1.PageResponse - 7, // 3: cosmos.evm.erc20.v1.QueryTokenPairResponse.token_pair:type_name -> cosmos.evm.erc20.v1.TokenPair - 9, // 4: cosmos.evm.erc20.v1.QueryParamsResponse.params:type_name -> cosmos.evm.erc20.v1.Params - 0, // 5: cosmos.evm.erc20.v1.Query.TokenPairs:input_type -> cosmos.evm.erc20.v1.QueryTokenPairsRequest - 2, // 6: cosmos.evm.erc20.v1.Query.TokenPair:input_type -> cosmos.evm.erc20.v1.QueryTokenPairRequest - 4, // 7: cosmos.evm.erc20.v1.Query.Params:input_type -> cosmos.evm.erc20.v1.QueryParamsRequest - 1, // 8: cosmos.evm.erc20.v1.Query.TokenPairs:output_type -> cosmos.evm.erc20.v1.QueryTokenPairsResponse - 3, // 9: cosmos.evm.erc20.v1.Query.TokenPair:output_type -> cosmos.evm.erc20.v1.QueryTokenPairResponse - 5, // 10: cosmos.evm.erc20.v1.Query.Params:output_type -> cosmos.evm.erc20.v1.QueryParamsResponse - 8, // [8:11] is the sub-list for method output_type - 5, // [5:8] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 8, // 0: cosmos.evm.erc20.v1.QueryTokenPairsRequest.pagination:type_name -> cosmos.base.query.v1beta1.PageRequest + 9, // 1: cosmos.evm.erc20.v1.QueryTokenPairsResponse.token_pairs:type_name -> cosmos.evm.erc20.v1.TokenPair + 10, // 2: cosmos.evm.erc20.v1.QueryTokenPairsResponse.pagination:type_name -> cosmos.base.query.v1beta1.PageResponse + 9, // 3: cosmos.evm.erc20.v1.QueryTokenPairResponse.token_pair:type_name -> cosmos.evm.erc20.v1.TokenPair + 11, // 4: cosmos.evm.erc20.v1.QueryParamsResponse.params:type_name -> cosmos.evm.erc20.v1.Params + 0, // 5: cosmos.evm.erc20.v1.Query.TokenPairs:input_type -> cosmos.evm.erc20.v1.QueryTokenPairsRequest + 2, // 6: cosmos.evm.erc20.v1.Query.TokenPair:input_type -> cosmos.evm.erc20.v1.QueryTokenPairRequest + 4, // 7: cosmos.evm.erc20.v1.Query.Params:input_type -> cosmos.evm.erc20.v1.QueryParamsRequest + 6, // 8: cosmos.evm.erc20.v1.Query.OwnerAddress:input_type -> cosmos.evm.erc20.v1.QueryOwnerAddressRequest + 1, // 9: cosmos.evm.erc20.v1.Query.TokenPairs:output_type -> cosmos.evm.erc20.v1.QueryTokenPairsResponse + 3, // 10: cosmos.evm.erc20.v1.Query.TokenPair:output_type -> cosmos.evm.erc20.v1.QueryTokenPairResponse + 5, // 11: cosmos.evm.erc20.v1.Query.Params:output_type -> cosmos.evm.erc20.v1.QueryParamsResponse + 7, // 12: cosmos.evm.erc20.v1.Query.OwnerAddress:output_type -> cosmos.evm.erc20.v1.QueryOwnerAddressResponse + 9, // [9:13] is the sub-list for method output_type + 5, // [5:9] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_cosmos_evm_erc20_v1_query_proto_init() } @@ -3128,6 +4061,30 @@ func file_cosmos_evm_erc20_v1_query_proto_init() { return nil } } + file_cosmos_evm_erc20_v1_query_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryOwnerAddressRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_evm_erc20_v1_query_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryOwnerAddressResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -3135,7 +4092,7 @@ func file_cosmos_evm_erc20_v1_query_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_cosmos_evm_erc20_v1_query_proto_rawDesc, NumEnums: 0, - NumMessages: 6, + NumMessages: 8, NumExtensions: 0, NumServices: 1, }, diff --git a/api/cosmos/evm/erc20/v1/query_grpc.pb.go b/api/cosmos/evm/erc20/v1/query_grpc.pb.go index c31355491..0b8a70016 100644 --- a/api/cosmos/evm/erc20/v1/query_grpc.pb.go +++ b/api/cosmos/evm/erc20/v1/query_grpc.pb.go @@ -19,9 +19,10 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - Query_TokenPairs_FullMethodName = "/cosmos.evm.erc20.v1.Query/TokenPairs" - Query_TokenPair_FullMethodName = "/cosmos.evm.erc20.v1.Query/TokenPair" - Query_Params_FullMethodName = "/cosmos.evm.erc20.v1.Query/Params" + Query_TokenPairs_FullMethodName = "/cosmos.evm.erc20.v1.Query/TokenPairs" + Query_TokenPair_FullMethodName = "/cosmos.evm.erc20.v1.Query/TokenPair" + Query_Params_FullMethodName = "/cosmos.evm.erc20.v1.Query/Params" + Query_OwnerAddress_FullMethodName = "/cosmos.evm.erc20.v1.Query/OwnerAddress" ) // QueryClient is the client API for Query service. @@ -34,6 +35,8 @@ type QueryClient interface { TokenPair(ctx context.Context, in *QueryTokenPairRequest, opts ...grpc.CallOption) (*QueryTokenPairResponse, error) // Params retrieves the erc20 module params Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // OwnerAddress retrieves the owner address for a given ERC20 contract address + OwnerAddress(ctx context.Context, in *QueryOwnerAddressRequest, opts ...grpc.CallOption) (*QueryOwnerAddressResponse, error) } type queryClient struct { @@ -71,6 +74,15 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . return out, nil } +func (c *queryClient) OwnerAddress(ctx context.Context, in *QueryOwnerAddressRequest, opts ...grpc.CallOption) (*QueryOwnerAddressResponse, error) { + out := new(QueryOwnerAddressResponse) + err := c.cc.Invoke(ctx, Query_OwnerAddress_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. // All implementations must embed UnimplementedQueryServer // for forward compatibility @@ -81,6 +93,8 @@ type QueryServer interface { TokenPair(context.Context, *QueryTokenPairRequest) (*QueryTokenPairResponse, error) // Params retrieves the erc20 module params Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // OwnerAddress retrieves the owner address for a given ERC20 contract address + OwnerAddress(context.Context, *QueryOwnerAddressRequest) (*QueryOwnerAddressResponse, error) mustEmbedUnimplementedQueryServer() } @@ -97,6 +111,9 @@ func (UnimplementedQueryServer) TokenPair(context.Context, *QueryTokenPairReques func (UnimplementedQueryServer) Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") } +func (UnimplementedQueryServer) OwnerAddress(context.Context, *QueryOwnerAddressRequest) (*QueryOwnerAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OwnerAddress not implemented") +} func (UnimplementedQueryServer) mustEmbedUnimplementedQueryServer() {} // UnsafeQueryServer may be embedded to opt out of forward compatibility for this service. @@ -164,6 +181,24 @@ func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Query_OwnerAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryOwnerAddressRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).OwnerAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Query_OwnerAddress_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).OwnerAddress(ctx, req.(*QueryOwnerAddressRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Query_ServiceDesc is the grpc.ServiceDesc for Query service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -183,6 +218,10 @@ var Query_ServiceDesc = grpc.ServiceDesc{ MethodName: "Params", Handler: _Query_Params_Handler, }, + { + MethodName: "OwnerAddress", + Handler: _Query_OwnerAddress_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "cosmos/evm/erc20/v1/query.proto", diff --git a/api/cosmos/evm/erc20/v1/tx.pulsar.go b/api/cosmos/evm/erc20/v1/tx.pulsar.go index 0487e8734..651f3123f 100644 --- a/api/cosmos/evm/erc20/v1/tx.pulsar.go +++ b/api/cosmos/evm/erc20/v1/tx.pulsar.go @@ -4500,6 +4500,2782 @@ func (x *fastReflection_MsgToggleConversionResponse) ProtoMethods() *protoiface. } } +var ( + md_MsgTransferOwnership protoreflect.MessageDescriptor + fd_MsgTransferOwnership_authority protoreflect.FieldDescriptor + fd_MsgTransferOwnership_token protoreflect.FieldDescriptor + fd_MsgTransferOwnership_new_owner protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_evm_erc20_v1_tx_proto_init() + md_MsgTransferOwnership = File_cosmos_evm_erc20_v1_tx_proto.Messages().ByName("MsgTransferOwnership") + fd_MsgTransferOwnership_authority = md_MsgTransferOwnership.Fields().ByName("authority") + fd_MsgTransferOwnership_token = md_MsgTransferOwnership.Fields().ByName("token") + fd_MsgTransferOwnership_new_owner = md_MsgTransferOwnership.Fields().ByName("new_owner") +} + +var _ protoreflect.Message = (*fastReflection_MsgTransferOwnership)(nil) + +type fastReflection_MsgTransferOwnership MsgTransferOwnership + +func (x *MsgTransferOwnership) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgTransferOwnership)(x) +} + +func (x *MsgTransferOwnership) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgTransferOwnership_messageType fastReflection_MsgTransferOwnership_messageType +var _ protoreflect.MessageType = fastReflection_MsgTransferOwnership_messageType{} + +type fastReflection_MsgTransferOwnership_messageType struct{} + +func (x fastReflection_MsgTransferOwnership_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgTransferOwnership)(nil) +} +func (x fastReflection_MsgTransferOwnership_messageType) New() protoreflect.Message { + return new(fastReflection_MsgTransferOwnership) +} +func (x fastReflection_MsgTransferOwnership_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgTransferOwnership +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgTransferOwnership) Descriptor() protoreflect.MessageDescriptor { + return md_MsgTransferOwnership +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgTransferOwnership) Type() protoreflect.MessageType { + return _fastReflection_MsgTransferOwnership_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgTransferOwnership) New() protoreflect.Message { + return new(fastReflection_MsgTransferOwnership) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgTransferOwnership) Interface() protoreflect.ProtoMessage { + return (*MsgTransferOwnership)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgTransferOwnership) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Authority != "" { + value := protoreflect.ValueOfString(x.Authority) + if !f(fd_MsgTransferOwnership_authority, value) { + return + } + } + if x.Token != "" { + value := protoreflect.ValueOfString(x.Token) + if !f(fd_MsgTransferOwnership_token, value) { + return + } + } + if x.NewOwner != "" { + value := protoreflect.ValueOfString(x.NewOwner) + if !f(fd_MsgTransferOwnership_new_owner, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgTransferOwnership) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgTransferOwnership.authority": + return x.Authority != "" + case "cosmos.evm.erc20.v1.MsgTransferOwnership.token": + return x.Token != "" + case "cosmos.evm.erc20.v1.MsgTransferOwnership.new_owner": + return x.NewOwner != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnership")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnership does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgTransferOwnership) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgTransferOwnership.authority": + x.Authority = "" + case "cosmos.evm.erc20.v1.MsgTransferOwnership.token": + x.Token = "" + case "cosmos.evm.erc20.v1.MsgTransferOwnership.new_owner": + x.NewOwner = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnership")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnership does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgTransferOwnership) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.evm.erc20.v1.MsgTransferOwnership.authority": + value := x.Authority + return protoreflect.ValueOfString(value) + case "cosmos.evm.erc20.v1.MsgTransferOwnership.token": + value := x.Token + return protoreflect.ValueOfString(value) + case "cosmos.evm.erc20.v1.MsgTransferOwnership.new_owner": + value := x.NewOwner + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnership")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnership does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgTransferOwnership) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgTransferOwnership.authority": + x.Authority = value.Interface().(string) + case "cosmos.evm.erc20.v1.MsgTransferOwnership.token": + x.Token = value.Interface().(string) + case "cosmos.evm.erc20.v1.MsgTransferOwnership.new_owner": + x.NewOwner = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnership")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnership does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgTransferOwnership) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgTransferOwnership.authority": + panic(fmt.Errorf("field authority of message cosmos.evm.erc20.v1.MsgTransferOwnership is not mutable")) + case "cosmos.evm.erc20.v1.MsgTransferOwnership.token": + panic(fmt.Errorf("field token of message cosmos.evm.erc20.v1.MsgTransferOwnership is not mutable")) + case "cosmos.evm.erc20.v1.MsgTransferOwnership.new_owner": + panic(fmt.Errorf("field new_owner of message cosmos.evm.erc20.v1.MsgTransferOwnership is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnership")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnership does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgTransferOwnership) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgTransferOwnership.authority": + return protoreflect.ValueOfString("") + case "cosmos.evm.erc20.v1.MsgTransferOwnership.token": + return protoreflect.ValueOfString("") + case "cosmos.evm.erc20.v1.MsgTransferOwnership.new_owner": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnership")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnership does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgTransferOwnership) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.evm.erc20.v1.MsgTransferOwnership", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgTransferOwnership) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgTransferOwnership) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgTransferOwnership) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgTransferOwnership) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgTransferOwnership) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Authority) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Token) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.NewOwner) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgTransferOwnership) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.NewOwner) > 0 { + i -= len(x.NewOwner) + copy(dAtA[i:], x.NewOwner) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.NewOwner))) + i-- + dAtA[i] = 0x1a + } + if len(x.Token) > 0 { + i -= len(x.Token) + copy(dAtA[i:], x.Token) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Token))) + i-- + dAtA[i] = 0x12 + } + if len(x.Authority) > 0 { + i -= len(x.Authority) + copy(dAtA[i:], x.Authority) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Authority))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgTransferOwnership) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgTransferOwnership: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgTransferOwnership: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Token = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field NewOwner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.NewOwner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgTransferOwnershipResponse protoreflect.MessageDescriptor +) + +func init() { + file_cosmos_evm_erc20_v1_tx_proto_init() + md_MsgTransferOwnershipResponse = File_cosmos_evm_erc20_v1_tx_proto.Messages().ByName("MsgTransferOwnershipResponse") +} + +var _ protoreflect.Message = (*fastReflection_MsgTransferOwnershipResponse)(nil) + +type fastReflection_MsgTransferOwnershipResponse MsgTransferOwnershipResponse + +func (x *MsgTransferOwnershipResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgTransferOwnershipResponse)(x) +} + +func (x *MsgTransferOwnershipResponse) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgTransferOwnershipResponse_messageType fastReflection_MsgTransferOwnershipResponse_messageType +var _ protoreflect.MessageType = fastReflection_MsgTransferOwnershipResponse_messageType{} + +type fastReflection_MsgTransferOwnershipResponse_messageType struct{} + +func (x fastReflection_MsgTransferOwnershipResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgTransferOwnershipResponse)(nil) +} +func (x fastReflection_MsgTransferOwnershipResponse_messageType) New() protoreflect.Message { + return new(fastReflection_MsgTransferOwnershipResponse) +} +func (x fastReflection_MsgTransferOwnershipResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgTransferOwnershipResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgTransferOwnershipResponse) Descriptor() protoreflect.MessageDescriptor { + return md_MsgTransferOwnershipResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgTransferOwnershipResponse) Type() protoreflect.MessageType { + return _fastReflection_MsgTransferOwnershipResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgTransferOwnershipResponse) New() protoreflect.Message { + return new(fastReflection_MsgTransferOwnershipResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgTransferOwnershipResponse) Interface() protoreflect.ProtoMessage { + return (*MsgTransferOwnershipResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgTransferOwnershipResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgTransferOwnershipResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnershipResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnershipResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgTransferOwnershipResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnershipResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnershipResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgTransferOwnershipResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnershipResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnershipResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgTransferOwnershipResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnershipResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnershipResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgTransferOwnershipResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnershipResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnershipResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgTransferOwnershipResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgTransferOwnershipResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgTransferOwnershipResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgTransferOwnershipResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.evm.erc20.v1.MsgTransferOwnershipResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgTransferOwnershipResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgTransferOwnershipResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgTransferOwnershipResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgTransferOwnershipResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgTransferOwnershipResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgTransferOwnershipResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgTransferOwnershipResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgTransferOwnershipResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgTransferOwnershipResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgMint protoreflect.MessageDescriptor + fd_MsgMint_contract_address protoreflect.FieldDescriptor + fd_MsgMint_amount protoreflect.FieldDescriptor + fd_MsgMint_to protoreflect.FieldDescriptor + fd_MsgMint_sender protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_evm_erc20_v1_tx_proto_init() + md_MsgMint = File_cosmos_evm_erc20_v1_tx_proto.Messages().ByName("MsgMint") + fd_MsgMint_contract_address = md_MsgMint.Fields().ByName("contract_address") + fd_MsgMint_amount = md_MsgMint.Fields().ByName("amount") + fd_MsgMint_to = md_MsgMint.Fields().ByName("to") + fd_MsgMint_sender = md_MsgMint.Fields().ByName("sender") +} + +var _ protoreflect.Message = (*fastReflection_MsgMint)(nil) + +type fastReflection_MsgMint MsgMint + +func (x *MsgMint) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgMint)(x) +} + +func (x *MsgMint) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgMint_messageType fastReflection_MsgMint_messageType +var _ protoreflect.MessageType = fastReflection_MsgMint_messageType{} + +type fastReflection_MsgMint_messageType struct{} + +func (x fastReflection_MsgMint_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgMint)(nil) +} +func (x fastReflection_MsgMint_messageType) New() protoreflect.Message { + return new(fastReflection_MsgMint) +} +func (x fastReflection_MsgMint_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgMint +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgMint) Descriptor() protoreflect.MessageDescriptor { + return md_MsgMint +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgMint) Type() protoreflect.MessageType { + return _fastReflection_MsgMint_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgMint) New() protoreflect.Message { + return new(fastReflection_MsgMint) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgMint) Interface() protoreflect.ProtoMessage { + return (*MsgMint)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgMint) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.ContractAddress != "" { + value := protoreflect.ValueOfString(x.ContractAddress) + if !f(fd_MsgMint_contract_address, value) { + return + } + } + if x.Amount != "" { + value := protoreflect.ValueOfString(x.Amount) + if !f(fd_MsgMint_amount, value) { + return + } + } + if x.To != "" { + value := protoreflect.ValueOfString(x.To) + if !f(fd_MsgMint_to, value) { + return + } + } + if x.Sender != "" { + value := protoreflect.ValueOfString(x.Sender) + if !f(fd_MsgMint_sender, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgMint) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgMint.contract_address": + return x.ContractAddress != "" + case "cosmos.evm.erc20.v1.MsgMint.amount": + return x.Amount != "" + case "cosmos.evm.erc20.v1.MsgMint.to": + return x.To != "" + case "cosmos.evm.erc20.v1.MsgMint.sender": + return x.Sender != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMint")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMint does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgMint) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgMint.contract_address": + x.ContractAddress = "" + case "cosmos.evm.erc20.v1.MsgMint.amount": + x.Amount = "" + case "cosmos.evm.erc20.v1.MsgMint.to": + x.To = "" + case "cosmos.evm.erc20.v1.MsgMint.sender": + x.Sender = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMint")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMint does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgMint) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.evm.erc20.v1.MsgMint.contract_address": + value := x.ContractAddress + return protoreflect.ValueOfString(value) + case "cosmos.evm.erc20.v1.MsgMint.amount": + value := x.Amount + return protoreflect.ValueOfString(value) + case "cosmos.evm.erc20.v1.MsgMint.to": + value := x.To + return protoreflect.ValueOfString(value) + case "cosmos.evm.erc20.v1.MsgMint.sender": + value := x.Sender + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMint")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMint does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgMint) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgMint.contract_address": + x.ContractAddress = value.Interface().(string) + case "cosmos.evm.erc20.v1.MsgMint.amount": + x.Amount = value.Interface().(string) + case "cosmos.evm.erc20.v1.MsgMint.to": + x.To = value.Interface().(string) + case "cosmos.evm.erc20.v1.MsgMint.sender": + x.Sender = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMint")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMint does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgMint) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgMint.contract_address": + panic(fmt.Errorf("field contract_address of message cosmos.evm.erc20.v1.MsgMint is not mutable")) + case "cosmos.evm.erc20.v1.MsgMint.amount": + panic(fmt.Errorf("field amount of message cosmos.evm.erc20.v1.MsgMint is not mutable")) + case "cosmos.evm.erc20.v1.MsgMint.to": + panic(fmt.Errorf("field to of message cosmos.evm.erc20.v1.MsgMint is not mutable")) + case "cosmos.evm.erc20.v1.MsgMint.sender": + panic(fmt.Errorf("field sender of message cosmos.evm.erc20.v1.MsgMint is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMint")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMint does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgMint) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgMint.contract_address": + return protoreflect.ValueOfString("") + case "cosmos.evm.erc20.v1.MsgMint.amount": + return protoreflect.ValueOfString("") + case "cosmos.evm.erc20.v1.MsgMint.to": + return protoreflect.ValueOfString("") + case "cosmos.evm.erc20.v1.MsgMint.sender": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMint")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMint does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgMint) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.evm.erc20.v1.MsgMint", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgMint) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgMint) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgMint) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgMint) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgMint) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.ContractAddress) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Amount) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.To) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Sender) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgMint) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.Sender) > 0 { + i -= len(x.Sender) + copy(dAtA[i:], x.Sender) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Sender))) + i-- + dAtA[i] = 0x22 + } + if len(x.To) > 0 { + i -= len(x.To) + copy(dAtA[i:], x.To) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.To))) + i-- + dAtA[i] = 0x1a + } + if len(x.Amount) > 0 { + i -= len(x.Amount) + copy(dAtA[i:], x.Amount) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Amount))) + i-- + dAtA[i] = 0x12 + } + if len(x.ContractAddress) > 0 { + i -= len(x.ContractAddress) + copy(dAtA[i:], x.ContractAddress) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ContractAddress))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgMint) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgMint: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgMint: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Amount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgMintResponse protoreflect.MessageDescriptor +) + +func init() { + file_cosmos_evm_erc20_v1_tx_proto_init() + md_MsgMintResponse = File_cosmos_evm_erc20_v1_tx_proto.Messages().ByName("MsgMintResponse") +} + +var _ protoreflect.Message = (*fastReflection_MsgMintResponse)(nil) + +type fastReflection_MsgMintResponse MsgMintResponse + +func (x *MsgMintResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgMintResponse)(x) +} + +func (x *MsgMintResponse) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgMintResponse_messageType fastReflection_MsgMintResponse_messageType +var _ protoreflect.MessageType = fastReflection_MsgMintResponse_messageType{} + +type fastReflection_MsgMintResponse_messageType struct{} + +func (x fastReflection_MsgMintResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgMintResponse)(nil) +} +func (x fastReflection_MsgMintResponse_messageType) New() protoreflect.Message { + return new(fastReflection_MsgMintResponse) +} +func (x fastReflection_MsgMintResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgMintResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgMintResponse) Descriptor() protoreflect.MessageDescriptor { + return md_MsgMintResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgMintResponse) Type() protoreflect.MessageType { + return _fastReflection_MsgMintResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgMintResponse) New() protoreflect.Message { + return new(fastReflection_MsgMintResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgMintResponse) Interface() protoreflect.ProtoMessage { + return (*MsgMintResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgMintResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgMintResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMintResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMintResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgMintResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMintResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMintResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgMintResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMintResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMintResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgMintResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMintResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMintResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgMintResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMintResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMintResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgMintResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgMintResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgMintResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgMintResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.evm.erc20.v1.MsgMintResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgMintResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgMintResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgMintResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgMintResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgMintResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgMintResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgMintResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgMintResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgMintResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgBurn protoreflect.MessageDescriptor + fd_MsgBurn_contract_address protoreflect.FieldDescriptor + fd_MsgBurn_amount protoreflect.FieldDescriptor + fd_MsgBurn_sender protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_evm_erc20_v1_tx_proto_init() + md_MsgBurn = File_cosmos_evm_erc20_v1_tx_proto.Messages().ByName("MsgBurn") + fd_MsgBurn_contract_address = md_MsgBurn.Fields().ByName("contract_address") + fd_MsgBurn_amount = md_MsgBurn.Fields().ByName("amount") + fd_MsgBurn_sender = md_MsgBurn.Fields().ByName("sender") +} + +var _ protoreflect.Message = (*fastReflection_MsgBurn)(nil) + +type fastReflection_MsgBurn MsgBurn + +func (x *MsgBurn) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgBurn)(x) +} + +func (x *MsgBurn) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgBurn_messageType fastReflection_MsgBurn_messageType +var _ protoreflect.MessageType = fastReflection_MsgBurn_messageType{} + +type fastReflection_MsgBurn_messageType struct{} + +func (x fastReflection_MsgBurn_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgBurn)(nil) +} +func (x fastReflection_MsgBurn_messageType) New() protoreflect.Message { + return new(fastReflection_MsgBurn) +} +func (x fastReflection_MsgBurn_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgBurn +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgBurn) Descriptor() protoreflect.MessageDescriptor { + return md_MsgBurn +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgBurn) Type() protoreflect.MessageType { + return _fastReflection_MsgBurn_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgBurn) New() protoreflect.Message { + return new(fastReflection_MsgBurn) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgBurn) Interface() protoreflect.ProtoMessage { + return (*MsgBurn)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgBurn) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.ContractAddress != "" { + value := protoreflect.ValueOfString(x.ContractAddress) + if !f(fd_MsgBurn_contract_address, value) { + return + } + } + if x.Amount != "" { + value := protoreflect.ValueOfString(x.Amount) + if !f(fd_MsgBurn_amount, value) { + return + } + } + if x.Sender != "" { + value := protoreflect.ValueOfString(x.Sender) + if !f(fd_MsgBurn_sender, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgBurn) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgBurn.contract_address": + return x.ContractAddress != "" + case "cosmos.evm.erc20.v1.MsgBurn.amount": + return x.Amount != "" + case "cosmos.evm.erc20.v1.MsgBurn.sender": + return x.Sender != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurn")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurn does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgBurn) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgBurn.contract_address": + x.ContractAddress = "" + case "cosmos.evm.erc20.v1.MsgBurn.amount": + x.Amount = "" + case "cosmos.evm.erc20.v1.MsgBurn.sender": + x.Sender = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurn")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurn does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgBurn) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.evm.erc20.v1.MsgBurn.contract_address": + value := x.ContractAddress + return protoreflect.ValueOfString(value) + case "cosmos.evm.erc20.v1.MsgBurn.amount": + value := x.Amount + return protoreflect.ValueOfString(value) + case "cosmos.evm.erc20.v1.MsgBurn.sender": + value := x.Sender + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurn")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurn does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgBurn) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgBurn.contract_address": + x.ContractAddress = value.Interface().(string) + case "cosmos.evm.erc20.v1.MsgBurn.amount": + x.Amount = value.Interface().(string) + case "cosmos.evm.erc20.v1.MsgBurn.sender": + x.Sender = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurn")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurn does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgBurn) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgBurn.contract_address": + panic(fmt.Errorf("field contract_address of message cosmos.evm.erc20.v1.MsgBurn is not mutable")) + case "cosmos.evm.erc20.v1.MsgBurn.amount": + panic(fmt.Errorf("field amount of message cosmos.evm.erc20.v1.MsgBurn is not mutable")) + case "cosmos.evm.erc20.v1.MsgBurn.sender": + panic(fmt.Errorf("field sender of message cosmos.evm.erc20.v1.MsgBurn is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurn")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurn does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgBurn) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.evm.erc20.v1.MsgBurn.contract_address": + return protoreflect.ValueOfString("") + case "cosmos.evm.erc20.v1.MsgBurn.amount": + return protoreflect.ValueOfString("") + case "cosmos.evm.erc20.v1.MsgBurn.sender": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurn")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurn does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgBurn) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.evm.erc20.v1.MsgBurn", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgBurn) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgBurn) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgBurn) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgBurn) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgBurn) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.ContractAddress) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Amount) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + l = len(x.Sender) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgBurn) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.Sender) > 0 { + i -= len(x.Sender) + copy(dAtA[i:], x.Sender) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Sender))) + i-- + dAtA[i] = 0x1a + } + if len(x.Amount) > 0 { + i -= len(x.Amount) + copy(dAtA[i:], x.Amount) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Amount))) + i-- + dAtA[i] = 0x12 + } + if len(x.ContractAddress) > 0 { + i -= len(x.ContractAddress) + copy(dAtA[i:], x.ContractAddress) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ContractAddress))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgBurn) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgBurn: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgBurn: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Amount = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var ( + md_MsgBurnResponse protoreflect.MessageDescriptor +) + +func init() { + file_cosmos_evm_erc20_v1_tx_proto_init() + md_MsgBurnResponse = File_cosmos_evm_erc20_v1_tx_proto.Messages().ByName("MsgBurnResponse") +} + +var _ protoreflect.Message = (*fastReflection_MsgBurnResponse)(nil) + +type fastReflection_MsgBurnResponse MsgBurnResponse + +func (x *MsgBurnResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_MsgBurnResponse)(x) +} + +func (x *MsgBurnResponse) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_MsgBurnResponse_messageType fastReflection_MsgBurnResponse_messageType +var _ protoreflect.MessageType = fastReflection_MsgBurnResponse_messageType{} + +type fastReflection_MsgBurnResponse_messageType struct{} + +func (x fastReflection_MsgBurnResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_MsgBurnResponse)(nil) +} +func (x fastReflection_MsgBurnResponse_messageType) New() protoreflect.Message { + return new(fastReflection_MsgBurnResponse) +} +func (x fastReflection_MsgBurnResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_MsgBurnResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_MsgBurnResponse) Descriptor() protoreflect.MessageDescriptor { + return md_MsgBurnResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_MsgBurnResponse) Type() protoreflect.MessageType { + return _fastReflection_MsgBurnResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_MsgBurnResponse) New() protoreflect.Message { + return new(fastReflection_MsgBurnResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_MsgBurnResponse) Interface() protoreflect.ProtoMessage { + return (*MsgBurnResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_MsgBurnResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_MsgBurnResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurnResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurnResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgBurnResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurnResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurnResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_MsgBurnResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurnResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurnResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgBurnResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurnResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurnResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgBurnResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurnResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurnResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_MsgBurnResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.evm.erc20.v1.MsgBurnResponse")) + } + panic(fmt.Errorf("message cosmos.evm.erc20.v1.MsgBurnResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_MsgBurnResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.evm.erc20.v1.MsgBurnResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_MsgBurnResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_MsgBurnResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_MsgBurnResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_MsgBurnResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*MsgBurnResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*MsgBurnResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*MsgBurnResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgBurnResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: MsgBurnResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.0 @@ -4918,6 +7694,262 @@ func (*MsgToggleConversionResponse) Descriptor() ([]byte, []int) { return file_cosmos_evm_erc20_v1_tx_proto_rawDescGZIP(), []int{9} } +// MsgTransferOwnership defines a Msg to transfer the ownership of the ERC20 +// token pair to the new owner +type MsgTransferOwnership struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // token identifier can be either the hex contract address of the ERC20 or the + // Cosmos base denomination + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` + // new_owner is the hex address of the new owner + NewOwner string `protobuf:"bytes,3,opt,name=new_owner,json=newOwner,proto3" json:"new_owner,omitempty"` +} + +func (x *MsgTransferOwnership) Reset() { + *x = MsgTransferOwnership{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgTransferOwnership) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgTransferOwnership) ProtoMessage() {} + +// Deprecated: Use MsgTransferOwnership.ProtoReflect.Descriptor instead. +func (*MsgTransferOwnership) Descriptor() ([]byte, []int) { + return file_cosmos_evm_erc20_v1_tx_proto_rawDescGZIP(), []int{10} +} + +func (x *MsgTransferOwnership) GetAuthority() string { + if x != nil { + return x.Authority + } + return "" +} + +func (x *MsgTransferOwnership) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +func (x *MsgTransferOwnership) GetNewOwner() string { + if x != nil { + return x.NewOwner + } + return "" +} + +// MsgTransferOwnershipResponse returns no fields +type MsgTransferOwnershipResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MsgTransferOwnershipResponse) Reset() { + *x = MsgTransferOwnershipResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgTransferOwnershipResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgTransferOwnershipResponse) ProtoMessage() {} + +// Deprecated: Use MsgTransferOwnershipResponse.ProtoReflect.Descriptor instead. +func (*MsgTransferOwnershipResponse) Descriptor() ([]byte, []int) { + return file_cosmos_evm_erc20_v1_tx_proto_rawDescGZIP(), []int{11} +} + +// MsgMint defines a Msg to mint ERC20 tokens +type MsgMint struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // contract_address of an ERC20 token contract, that is registered in a token + // pair + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // amount of ERC20 tokens to mint + Amount string `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"` + // to is the address to mint the tokens to + To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"` + // sender is the address of the sender + Sender string `protobuf:"bytes,4,opt,name=sender,proto3" json:"sender,omitempty"` +} + +func (x *MsgMint) Reset() { + *x = MsgMint{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgMint) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgMint) ProtoMessage() {} + +// Deprecated: Use MsgMint.ProtoReflect.Descriptor instead. +func (*MsgMint) Descriptor() ([]byte, []int) { + return file_cosmos_evm_erc20_v1_tx_proto_rawDescGZIP(), []int{12} +} + +func (x *MsgMint) GetContractAddress() string { + if x != nil { + return x.ContractAddress + } + return "" +} + +func (x *MsgMint) GetAmount() string { + if x != nil { + return x.Amount + } + return "" +} + +func (x *MsgMint) GetTo() string { + if x != nil { + return x.To + } + return "" +} + +func (x *MsgMint) GetSender() string { + if x != nil { + return x.Sender + } + return "" +} + +type MsgMintResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MsgMintResponse) Reset() { + *x = MsgMintResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgMintResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgMintResponse) ProtoMessage() {} + +// Deprecated: Use MsgMintResponse.ProtoReflect.Descriptor instead. +func (*MsgMintResponse) Descriptor() ([]byte, []int) { + return file_cosmos_evm_erc20_v1_tx_proto_rawDescGZIP(), []int{13} +} + +// MsgBurn defines a Msg to burn ERC20 tokens +type MsgBurn struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // contract_address of an ERC20 token contract, that is registered in a token + // pair + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // amount of ERC20 tokens to burn + Amount string `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"` + // sender is the address of the sender + Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` +} + +func (x *MsgBurn) Reset() { + *x = MsgBurn{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgBurn) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgBurn) ProtoMessage() {} + +// Deprecated: Use MsgBurn.ProtoReflect.Descriptor instead. +func (*MsgBurn) Descriptor() ([]byte, []int) { + return file_cosmos_evm_erc20_v1_tx_proto_rawDescGZIP(), []int{14} +} + +func (x *MsgBurn) GetContractAddress() string { + if x != nil { + return x.ContractAddress + } + return "" +} + +func (x *MsgBurn) GetAmount() string { + if x != nil { + return x.Amount + } + return "" +} + +func (x *MsgBurn) GetSender() string { + if x != nil { + return x.Sender + } + return "" +} + +type MsgBurnResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *MsgBurnResponse) Reset() { + *x = MsgBurnResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_evm_erc20_v1_tx_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgBurnResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgBurnResponse) ProtoMessage() {} + +// Deprecated: Use MsgBurnResponse.ProtoReflect.Descriptor instead. +func (*MsgBurnResponse) Descriptor() ([]byte, []int) { + return file_cosmos_evm_erc20_v1_tx_proto_rawDescGZIP(), []int{15} +} + var File_cosmos_evm_erc20_v1_tx_proto protoreflect.FileDescriptor var file_cosmos_evm_erc20_v1_tx_proto_rawDesc = []byte{ @@ -5005,7 +8037,40 @@ var file_cosmos_evm_erc20_v1_tx_proto_rawDesc = []byte{ 0x4d, 0x73, 0x67, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x1d, 0x0a, 0x1b, 0x4d, 0x73, 0x67, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x32, 0xeb, 0x04, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x91, 0x01, 0x0a, 0x0c, 0x43, + 0x73, 0x65, 0x22, 0x91, 0x01, 0x0a, 0x14, 0x4d, 0x73, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x36, 0x0a, 0x09, 0x61, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, + 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x65, 0x77, + 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x65, + 0x77, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x3a, 0x0e, 0x82, 0xe7, 0xb0, 0x2a, 0x09, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x22, 0x1e, 0x0a, 0x1c, 0x4d, 0x73, 0x67, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa0, 0x01, 0x0a, 0x07, 0x4d, 0x73, 0x67, 0x4d, 0x69, + 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x35, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1d, 0xc8, + 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, + 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x6d, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x74, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, + 0xb0, 0x2a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x22, 0x11, 0x0a, 0x0f, 0x4d, 0x73, 0x67, + 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x90, 0x01, 0x0a, + 0x07, 0x4d, 0x73, 0x67, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x61, 0x63, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x35, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x1d, 0xc8, 0xde, 0x1f, 0x00, 0xda, 0xde, 0x1f, 0x15, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x6d, 0x61, 0x74, 0x68, 0x2e, 0x49, + 0x6e, 0x74, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x6e, 0x64, + 0x65, 0x72, 0x3a, 0x0b, 0x82, 0xe7, 0xb0, 0x2a, 0x06, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x22, + 0x11, 0x0a, 0x0f, 0x4d, 0x73, 0x67, 0x42, 0x75, 0x72, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x32, 0xca, 0x07, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x91, 0x01, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x45, 0x52, 0x43, 0x32, 0x30, 0x12, 0x24, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x45, 0x52, 0x43, 0x32, @@ -5043,20 +8108,42 @@ var file_cosmos_evm_erc20_v1_tx_proto_rawDesc = []byte{ 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x05, 0x80, 0xe7, 0xb0, 0x2a, 0x01, - 0x42, 0xbf, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, - 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x72, - 0x63, 0x32, 0x30, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x45, 0xaa, 0x02, 0x13, 0x43, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x45, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x56, - 0x31, 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, - 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, - 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x16, 0x43, 0x6f, 0x73, 0x6d, - 0x6f, 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x45, 0x72, 0x63, 0x32, 0x30, 0x3a, 0x3a, - 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x79, 0x0a, 0x19, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x4f, 0x77, 0x6e, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, + 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, + 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x70, 0x0a, 0x04, 0x4d, 0x69, 0x6e, 0x74, 0x12, 0x1c, 0x2e, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x4d, 0x69, 0x6e, 0x74, 0x1a, 0x24, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, + 0x2e, 0x4d, 0x73, 0x67, 0x4d, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x22, 0x1c, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x2f, 0x74, + 0x78, 0x2f, 0x6d, 0x69, 0x6e, 0x74, 0x12, 0x70, 0x0a, 0x04, 0x42, 0x75, 0x72, 0x6e, 0x12, 0x1c, + 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, + 0x30, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x42, 0x75, 0x72, 0x6e, 0x1a, 0x24, 0x2e, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x73, 0x67, 0x42, 0x75, 0x72, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x22, 0x1c, 0x2f, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2f, 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, + 0x2f, 0x74, 0x78, 0x2f, 0x62, 0x75, 0x72, 0x6e, 0x1a, 0x05, 0x80, 0xe7, 0xb0, 0x2a, 0x01, 0x42, + 0xbf, 0x01, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x65, + 0x76, 0x6d, 0x2e, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x76, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, + 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, + 0x65, 0x76, 0x6d, 0x2f, 0x65, 0x72, 0x63, 0x32, 0x30, 0x2f, 0x76, 0x31, 0x3b, 0x65, 0x72, 0x63, + 0x32, 0x30, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x43, 0x45, 0x45, 0xaa, 0x02, 0x13, 0x43, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x45, 0x76, 0x6d, 0x2e, 0x45, 0x72, 0x63, 0x32, 0x30, 0x2e, 0x56, 0x31, + 0xca, 0x02, 0x13, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, + 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1f, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, + 0x45, 0x76, 0x6d, 0x5c, 0x45, 0x72, 0x63, 0x32, 0x30, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x16, 0x43, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x3a, 0x3a, 0x45, 0x76, 0x6d, 0x3a, 0x3a, 0x45, 0x72, 0x63, 0x32, 0x30, 0x3a, 0x3a, 0x56, + 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -5071,36 +8158,48 @@ func file_cosmos_evm_erc20_v1_tx_proto_rawDescGZIP() []byte { return file_cosmos_evm_erc20_v1_tx_proto_rawDescData } -var file_cosmos_evm_erc20_v1_tx_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_cosmos_evm_erc20_v1_tx_proto_msgTypes = make([]protoimpl.MessageInfo, 16) var file_cosmos_evm_erc20_v1_tx_proto_goTypes = []interface{}{ - (*MsgConvertERC20)(nil), // 0: cosmos.evm.erc20.v1.MsgConvertERC20 - (*MsgConvertERC20Response)(nil), // 1: cosmos.evm.erc20.v1.MsgConvertERC20Response - (*MsgConvertCoin)(nil), // 2: cosmos.evm.erc20.v1.MsgConvertCoin - (*MsgConvertCoinResponse)(nil), // 3: cosmos.evm.erc20.v1.MsgConvertCoinResponse - (*MsgUpdateParams)(nil), // 4: cosmos.evm.erc20.v1.MsgUpdateParams - (*MsgUpdateParamsResponse)(nil), // 5: cosmos.evm.erc20.v1.MsgUpdateParamsResponse - (*MsgRegisterERC20)(nil), // 6: cosmos.evm.erc20.v1.MsgRegisterERC20 - (*MsgRegisterERC20Response)(nil), // 7: cosmos.evm.erc20.v1.MsgRegisterERC20Response - (*MsgToggleConversion)(nil), // 8: cosmos.evm.erc20.v1.MsgToggleConversion - (*MsgToggleConversionResponse)(nil), // 9: cosmos.evm.erc20.v1.MsgToggleConversionResponse - (*v1beta1.Coin)(nil), // 10: cosmos.base.v1beta1.Coin - (*Params)(nil), // 11: cosmos.evm.erc20.v1.Params + (*MsgConvertERC20)(nil), // 0: cosmos.evm.erc20.v1.MsgConvertERC20 + (*MsgConvertERC20Response)(nil), // 1: cosmos.evm.erc20.v1.MsgConvertERC20Response + (*MsgConvertCoin)(nil), // 2: cosmos.evm.erc20.v1.MsgConvertCoin + (*MsgConvertCoinResponse)(nil), // 3: cosmos.evm.erc20.v1.MsgConvertCoinResponse + (*MsgUpdateParams)(nil), // 4: cosmos.evm.erc20.v1.MsgUpdateParams + (*MsgUpdateParamsResponse)(nil), // 5: cosmos.evm.erc20.v1.MsgUpdateParamsResponse + (*MsgRegisterERC20)(nil), // 6: cosmos.evm.erc20.v1.MsgRegisterERC20 + (*MsgRegisterERC20Response)(nil), // 7: cosmos.evm.erc20.v1.MsgRegisterERC20Response + (*MsgToggleConversion)(nil), // 8: cosmos.evm.erc20.v1.MsgToggleConversion + (*MsgToggleConversionResponse)(nil), // 9: cosmos.evm.erc20.v1.MsgToggleConversionResponse + (*MsgTransferOwnership)(nil), // 10: cosmos.evm.erc20.v1.MsgTransferOwnership + (*MsgTransferOwnershipResponse)(nil), // 11: cosmos.evm.erc20.v1.MsgTransferOwnershipResponse + (*MsgMint)(nil), // 12: cosmos.evm.erc20.v1.MsgMint + (*MsgMintResponse)(nil), // 13: cosmos.evm.erc20.v1.MsgMintResponse + (*MsgBurn)(nil), // 14: cosmos.evm.erc20.v1.MsgBurn + (*MsgBurnResponse)(nil), // 15: cosmos.evm.erc20.v1.MsgBurnResponse + (*v1beta1.Coin)(nil), // 16: cosmos.base.v1beta1.Coin + (*Params)(nil), // 17: cosmos.evm.erc20.v1.Params } var file_cosmos_evm_erc20_v1_tx_proto_depIdxs = []int32{ - 10, // 0: cosmos.evm.erc20.v1.MsgConvertCoin.coin:type_name -> cosmos.base.v1beta1.Coin - 11, // 1: cosmos.evm.erc20.v1.MsgUpdateParams.params:type_name -> cosmos.evm.erc20.v1.Params + 16, // 0: cosmos.evm.erc20.v1.MsgConvertCoin.coin:type_name -> cosmos.base.v1beta1.Coin + 17, // 1: cosmos.evm.erc20.v1.MsgUpdateParams.params:type_name -> cosmos.evm.erc20.v1.Params 0, // 2: cosmos.evm.erc20.v1.Msg.ConvertERC20:input_type -> cosmos.evm.erc20.v1.MsgConvertERC20 2, // 3: cosmos.evm.erc20.v1.Msg.ConvertCoin:input_type -> cosmos.evm.erc20.v1.MsgConvertCoin 4, // 4: cosmos.evm.erc20.v1.Msg.UpdateParams:input_type -> cosmos.evm.erc20.v1.MsgUpdateParams 6, // 5: cosmos.evm.erc20.v1.Msg.RegisterERC20:input_type -> cosmos.evm.erc20.v1.MsgRegisterERC20 8, // 6: cosmos.evm.erc20.v1.Msg.ToggleConversion:input_type -> cosmos.evm.erc20.v1.MsgToggleConversion - 1, // 7: cosmos.evm.erc20.v1.Msg.ConvertERC20:output_type -> cosmos.evm.erc20.v1.MsgConvertERC20Response - 3, // 8: cosmos.evm.erc20.v1.Msg.ConvertCoin:output_type -> cosmos.evm.erc20.v1.MsgConvertCoinResponse - 5, // 9: cosmos.evm.erc20.v1.Msg.UpdateParams:output_type -> cosmos.evm.erc20.v1.MsgUpdateParamsResponse - 7, // 10: cosmos.evm.erc20.v1.Msg.RegisterERC20:output_type -> cosmos.evm.erc20.v1.MsgRegisterERC20Response - 9, // 11: cosmos.evm.erc20.v1.Msg.ToggleConversion:output_type -> cosmos.evm.erc20.v1.MsgToggleConversionResponse - 7, // [7:12] is the sub-list for method output_type - 2, // [2:7] is the sub-list for method input_type + 10, // 7: cosmos.evm.erc20.v1.Msg.TransferContractOwnership:input_type -> cosmos.evm.erc20.v1.MsgTransferOwnership + 12, // 8: cosmos.evm.erc20.v1.Msg.Mint:input_type -> cosmos.evm.erc20.v1.MsgMint + 14, // 9: cosmos.evm.erc20.v1.Msg.Burn:input_type -> cosmos.evm.erc20.v1.MsgBurn + 1, // 10: cosmos.evm.erc20.v1.Msg.ConvertERC20:output_type -> cosmos.evm.erc20.v1.MsgConvertERC20Response + 3, // 11: cosmos.evm.erc20.v1.Msg.ConvertCoin:output_type -> cosmos.evm.erc20.v1.MsgConvertCoinResponse + 5, // 12: cosmos.evm.erc20.v1.Msg.UpdateParams:output_type -> cosmos.evm.erc20.v1.MsgUpdateParamsResponse + 7, // 13: cosmos.evm.erc20.v1.Msg.RegisterERC20:output_type -> cosmos.evm.erc20.v1.MsgRegisterERC20Response + 9, // 14: cosmos.evm.erc20.v1.Msg.ToggleConversion:output_type -> cosmos.evm.erc20.v1.MsgToggleConversionResponse + 11, // 15: cosmos.evm.erc20.v1.Msg.TransferContractOwnership:output_type -> cosmos.evm.erc20.v1.MsgTransferOwnershipResponse + 13, // 16: cosmos.evm.erc20.v1.Msg.Mint:output_type -> cosmos.evm.erc20.v1.MsgMintResponse + 15, // 17: cosmos.evm.erc20.v1.Msg.Burn:output_type -> cosmos.evm.erc20.v1.MsgBurnResponse + 10, // [10:18] is the sub-list for method output_type + 2, // [2:10] is the sub-list for method input_type 2, // [2:2] is the sub-list for extension type_name 2, // [2:2] is the sub-list for extension extendee 0, // [0:2] is the sub-list for field type_name @@ -5233,6 +8332,78 @@ func file_cosmos_evm_erc20_v1_tx_proto_init() { return nil } } + file_cosmos_evm_erc20_v1_tx_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgTransferOwnership); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_evm_erc20_v1_tx_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgTransferOwnershipResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_evm_erc20_v1_tx_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgMint); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_evm_erc20_v1_tx_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgMintResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_evm_erc20_v1_tx_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgBurn); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_evm_erc20_v1_tx_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgBurnResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -5240,7 +8411,7 @@ func file_cosmos_evm_erc20_v1_tx_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_cosmos_evm_erc20_v1_tx_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 16, NumExtensions: 0, NumServices: 1, }, diff --git a/api/cosmos/evm/erc20/v1/tx_grpc.pb.go b/api/cosmos/evm/erc20/v1/tx_grpc.pb.go index b78f770e6..5244550c5 100644 --- a/api/cosmos/evm/erc20/v1/tx_grpc.pb.go +++ b/api/cosmos/evm/erc20/v1/tx_grpc.pb.go @@ -19,11 +19,14 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - Msg_ConvertERC20_FullMethodName = "/cosmos.evm.erc20.v1.Msg/ConvertERC20" - Msg_ConvertCoin_FullMethodName = "/cosmos.evm.erc20.v1.Msg/ConvertCoin" - Msg_UpdateParams_FullMethodName = "/cosmos.evm.erc20.v1.Msg/UpdateParams" - Msg_RegisterERC20_FullMethodName = "/cosmos.evm.erc20.v1.Msg/RegisterERC20" - Msg_ToggleConversion_FullMethodName = "/cosmos.evm.erc20.v1.Msg/ToggleConversion" + Msg_ConvertERC20_FullMethodName = "/cosmos.evm.erc20.v1.Msg/ConvertERC20" + Msg_ConvertCoin_FullMethodName = "/cosmos.evm.erc20.v1.Msg/ConvertCoin" + Msg_UpdateParams_FullMethodName = "/cosmos.evm.erc20.v1.Msg/UpdateParams" + Msg_RegisterERC20_FullMethodName = "/cosmos.evm.erc20.v1.Msg/RegisterERC20" + Msg_ToggleConversion_FullMethodName = "/cosmos.evm.erc20.v1.Msg/ToggleConversion" + Msg_TransferContractOwnership_FullMethodName = "/cosmos.evm.erc20.v1.Msg/TransferContractOwnership" + Msg_Mint_FullMethodName = "/cosmos.evm.erc20.v1.Msg/Mint" + Msg_Burn_FullMethodName = "/cosmos.evm.erc20.v1.Msg/Burn" ) // MsgClient is the client API for Msg service. @@ -48,6 +51,13 @@ type MsgClient interface { // token pair conversion. The authority is hard-coded to the Cosmos SDK x/gov // module account ToggleConversion(ctx context.Context, in *MsgToggleConversion, opts ...grpc.CallOption) (*MsgToggleConversionResponse, error) + // TransferContractOwnership defines a Msg to transfer the ownership of the + // ERC20 token pair to the new owner + TransferContractOwnership(ctx context.Context, in *MsgTransferOwnership, opts ...grpc.CallOption) (*MsgTransferOwnershipResponse, error) + // Mint mints ERC20 tokens + Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) + // Burn burns ERC20 tokens + Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) } type msgClient struct { @@ -103,6 +113,33 @@ func (c *msgClient) ToggleConversion(ctx context.Context, in *MsgToggleConversio return out, nil } +func (c *msgClient) TransferContractOwnership(ctx context.Context, in *MsgTransferOwnership, opts ...grpc.CallOption) (*MsgTransferOwnershipResponse, error) { + out := new(MsgTransferOwnershipResponse) + err := c.cc.Invoke(ctx, Msg_TransferContractOwnership_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) { + out := new(MsgMintResponse) + err := c.cc.Invoke(ctx, Msg_Mint_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) { + out := new(MsgBurnResponse) + err := c.cc.Invoke(ctx, Msg_Burn_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. // All implementations must embed UnimplementedMsgServer // for forward compatibility @@ -125,6 +162,13 @@ type MsgServer interface { // token pair conversion. The authority is hard-coded to the Cosmos SDK x/gov // module account ToggleConversion(context.Context, *MsgToggleConversion) (*MsgToggleConversionResponse, error) + // TransferContractOwnership defines a Msg to transfer the ownership of the + // ERC20 token pair to the new owner + TransferContractOwnership(context.Context, *MsgTransferOwnership) (*MsgTransferOwnershipResponse, error) + // Mint mints ERC20 tokens + Mint(context.Context, *MsgMint) (*MsgMintResponse, error) + // Burn burns ERC20 tokens + Burn(context.Context, *MsgBurn) (*MsgBurnResponse, error) mustEmbedUnimplementedMsgServer() } @@ -147,6 +191,15 @@ func (UnimplementedMsgServer) RegisterERC20(context.Context, *MsgRegisterERC20) func (UnimplementedMsgServer) ToggleConversion(context.Context, *MsgToggleConversion) (*MsgToggleConversionResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ToggleConversion not implemented") } +func (UnimplementedMsgServer) TransferContractOwnership(context.Context, *MsgTransferOwnership) (*MsgTransferOwnershipResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TransferContractOwnership not implemented") +} +func (UnimplementedMsgServer) Mint(context.Context, *MsgMint) (*MsgMintResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Mint not implemented") +} +func (UnimplementedMsgServer) Burn(context.Context, *MsgBurn) (*MsgBurnResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Burn not implemented") +} func (UnimplementedMsgServer) mustEmbedUnimplementedMsgServer() {} // UnsafeMsgServer may be embedded to opt out of forward compatibility for this service. @@ -250,6 +303,60 @@ func _Msg_ToggleConversion_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _Msg_TransferContractOwnership_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgTransferOwnership) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).TransferContractOwnership(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Msg_TransferContractOwnership_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).TransferContractOwnership(ctx, req.(*MsgTransferOwnership)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Mint_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgMint) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Mint(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Msg_Mint_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Mint(ctx, req.(*MsgMint)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Burn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgBurn) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Burn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Msg_Burn_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Burn(ctx, req.(*MsgBurn)) + } + return interceptor(ctx, in, info, handler) +} + // Msg_ServiceDesc is the grpc.ServiceDesc for Msg service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -277,6 +384,18 @@ var Msg_ServiceDesc = grpc.ServiceDesc{ MethodName: "ToggleConversion", Handler: _Msg_ToggleConversion_Handler, }, + { + MethodName: "TransferContractOwnership", + Handler: _Msg_TransferContractOwnership_Handler, + }, + { + MethodName: "Mint", + Handler: _Msg_Mint_Handler, + }, + { + MethodName: "Burn", + Handler: _Msg_Burn_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "cosmos/evm/erc20/v1/tx.proto", diff --git a/contracts/contract_creation_tester.go b/contracts/contract_creation_tester.go new file mode 100644 index 000000000..8732ea4a8 --- /dev/null +++ b/contracts/contract_creation_tester.go @@ -0,0 +1,10 @@ +package contracts + +import ( + contractutils "github.com/cosmos/evm/contracts/utils" + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +func LoadContractCreationTester() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("solidity/ContractCreationTester.json") +} diff --git a/contracts/erc20_with_native_transfers.go b/contracts/erc20_with_native_transfers.go new file mode 100644 index 000000000..9509af1e9 --- /dev/null +++ b/contracts/erc20_with_native_transfers.go @@ -0,0 +1,10 @@ +package contracts + +import ( + contractutils "github.com/cosmos/evm/contracts/utils" + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +func LoadERC20WithNativeTransfers() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("solidity/ERC20WithNativeTransfers.json") +} diff --git a/contracts/ics20_sequential_precompile_calls.go b/contracts/ics20_sequential_precompile_calls.go new file mode 100644 index 000000000..e25291bcf --- /dev/null +++ b/contracts/ics20_sequential_precompile_calls.go @@ -0,0 +1,10 @@ +package contracts + +import ( + contractutils "github.com/cosmos/evm/contracts/utils" + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +func LoadSequentialICS20Sender() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("solidity/SequentialICS20Sender.json") +} diff --git a/contracts/ics20_transfer_tester.go b/contracts/ics20_transfer_tester.go new file mode 100644 index 000000000..b89020089 --- /dev/null +++ b/contracts/ics20_transfer_tester.go @@ -0,0 +1,10 @@ +package contracts + +import ( + contractutils "github.com/cosmos/evm/contracts/utils" + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +func LoadICS20TransferTester() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("solidity/ICS20TransferTester.json") +} diff --git a/contracts/sequential_operations_tester.go b/contracts/sequential_operations_tester.go new file mode 100644 index 000000000..f3659e309 --- /dev/null +++ b/contracts/sequential_operations_tester.go @@ -0,0 +1,10 @@ +package contracts + +import ( + contractutils "github.com/cosmos/evm/contracts/utils" + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +func LoadSequentialOperationsTester() (evmtypes.CompiledContract, error) { + return contractutils.LoadContractFromJSONFile("solidity/SequentialOperationsTester.json") +} diff --git a/contracts/solidity/ContractCreationTester.json b/contracts/solidity/ContractCreationTester.json new file mode 100644 index 000000000..3b12708cc --- /dev/null +++ b/contracts/solidity/ContractCreationTester.json @@ -0,0 +1,282 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ContractCreationTester", + "sourceName": "solidity/ContractCreationTester.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "contractAddr", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "ContractCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "operation", + "type": "string" + }, + { + "indexed": false, + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "name": "OperationCompleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "ValueSent", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "creationValue", + "type": "uint256" + } + ], + "name": "createAndRevert", + "outputs": [ + { + "internalType": "contract SimpleReceiver", + "name": "", + "type": "address" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "createdContracts", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getCreatedContract", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getCreatedContractsCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "delegateAmount1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "creationValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "delegateAmount2", + "type": "uint256" + } + ], + "name": "scenario4_delegateCreateDelegate", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "delegateAmount1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "creationValue", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "delegateAmount2", + "type": "uint256" + } + ], + "name": "scenario5_delegateCreateRevertDelegate", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "creationValue1", + "type": "uint256" + }, + { + "internalType": "string", + "name": "validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "delegateAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "creationValue2", + "type": "uint256" + } + ], + "name": "scenario6_createRevertDelegateCreateRevert", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "creationValue", + "type": "uint256" + }, + { + "internalType": "string", + "name": "validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "delegateAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "sendAmount", + "type": "uint256" + } + ], + "name": "scenario7_createDelegateRevertSend", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "revertCreationValue", + "type": "uint256" + }, + { + "internalType": "string", + "name": "validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "delegateAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "successCreationValue", + "type": "uint256" + } + ], + "name": "scenario8_createRevertDelegateCreateSuccess", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x608080604052346100165761104a908161001c8239f35b600080fdfe60406080815260048036101561001f575b5050361561001d57600080fd5b005b600091823560e01c80630881139714610acd5780637a0aaa5b146108cd578381637d5b95391461079f578163aabf1086146105ba57508063b203934e1461059d578063c242737f1461051f578063c53e5ae314610470578063e71b671a146102765763edab9299146100915750610010565b829161009c36610c00565b8596919651946353266bbb60e01b9081875264e8d4a5100096879581806100cc60209b8c94048b30888501610c51565b038161080098895af1801561026c5761024f575b50875198600080516020610ff58339815191528a806100ff839d610cad565b0390a188516101f3808201908282106001600160401b0383111761023c578a9897969593898f969394818f94610182978391610de283398a815203019083f091826101fc5750505060808160068f9351918083528201526563726561746560d01b6060820152868b820152a15b8a51988997889687958652049130908501610c51565b03925af180156101f2576101c4575b5050516040808252600990820152683232b632b3b0ba329960b91b60608201526001602082015280608081015b0390a180f35b816101e392903d106101eb575b6101db8183610b28565b810190610c39565b503880610191565b503d6101d1565b83513d87823e3d90fd5b6001600160a01b0390921692600080516020610fd5833981519152929061022285610cd8565b51908152a28b8b518061023481610d15565b0390a161016c565b634e487b7160e01b8e526041855260248efd5b61026590883d8a116101eb576101db8183610b28565b50386100e0565b89513d8d823e3d90fd5b5061028036610bc6565b92919064e8d4a5100085519163c53e5ae360e01b83528488840152602094838680826024829886305af18c9281610441575b506103f257505050600080516020610ff58339815191528751806102d581610d85565b0390a15b6102f8875194859384936353266bbb60e01b85520490308b8501610c51565b0381896108005af180156103e8576103cb575b50825193600080516020610ff5833981519152858061032a8398610db7565b0390a18351906101f3808301918383106001600160401b038411176103b8575083918391610de2833988815203019083f080156101f2576001600160a01b031691600080516020610fd5833981519152919061038584610cd8565b8451908152a25160408082526007908201526631b932b0ba329960c91b60608201526001602082015280608081016101be565b634e487b7160e01b895260419052602488fd5b6103e190823d84116101eb576101db8183610b28565b503861030b565b84513d88823e3d90fd5b6001600160a01b0390911691600080516020610fd5833981519152919061041884610cd8565b8a51908152a2600080516020610ff583398151915287518061043981610d5c565b0390a16102d9565b610462919350823d8411610469575b61045a8183610b28565b810190610d3d565b91386102b2565b503d610450565b5082602036600319011261051c5781516101f3808201908282106001600160401b03831117610509576020918391610de283398481520301908435f0156104fe57815162461bcd60e51b8152602081850152602160248201527f496e74656e74696f6e616c20726576657274206166746572206372656174696f6044820152603760f91b6064820152608490fd5b9051903d90823e3d90fd5b634e487b7160e01b845260418652602484fd5b80fd5b5091903461059957602036600319011261059957803591548210156105605760208361054a84610afb565b905491519160018060a01b039160031b1c168152f35b606490602084519162461bcd60e51b83528201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152fd5b5080fd5b838234610599578160031936011261059957602091549051908152f35b9190506105c636610bc6565b90949291845164e8d4a5100063c53e5ae360e01b97888352858a84015260209583878082602482988d305af18a9281610780575b5061073157505050600080516020610ff583398151915288518061061d81610d85565b0390a15b610640885194859384936353266bbb60e01b85520490308d8501610c51565b0381876108005af180156107275761070a575b5080845196600080516020610ff58339815191528880610673839b610db7565b0390a18551968752860152818560248186305af1809584966106eb575b506106c557506080935060108351938085528401526f18dc99585d194c97dc995d995c9d195960821b6060840152820152a180f35b92936001600160a01b031692600080516020610fd5833981519152925061038584610cd8565b610703919650833d85116104695761045a8183610b28565b9438610690565b61072090833d85116101eb576101db8183610b28565b5038610653565b85513d86823e3d90fd5b6001600160a01b0390911691600080516020610fd5833981519152919061075784610cd8565b8b51908152a2600080516020610ff583398151915288518061077881610d5c565b0390a1610621565b610798919350823d84116104695761045a8183610b28565b91386105fa565b9290506107ab36610c00565b8596919651946353266bbb60e01b9081875264e8d4a5100096879581806107db60209b8c94048b30888501610c51565b038161080098895af1801561026c576108b0575b50875198600080516020610ff58339815191528a8061080e839d610cad565b0390a188516101f3808201908282106001600160401b0383111761023c57828e96959493928c92610de2833987815203019082f080156108a657899796959493926101829290916001600160a01b031690600080516020610fd5833981519152908a908e61087b85610cd8565b51908152a28b8b518061088d81610d15565b0390a18a51988997889687958652049130908501610c51565b8a513d86823e3d90fd5b6108c690883d8a116101eb576101db8183610b28565b50386107ef565b506108d736610bc6565b9094918451936101f3808601908682106001600160401b03831117610aba57908691610de28339898152602096879103019082f08015610ab0576001600160a01b03169291908390600080516020610fd583398151915290879061093a84610cd8565b8951908152a28464e8d4a51000875198600080516020610ff58339815191528a80610965839d610d15565b0390a1610987895194859384936353266bbb60e01b85520490308a8501610c51565b03818b6108005af19081610a93575b50610a7e5785608086518781526008888201526764656c656761746560c01b60608201528987820152a15b8680808084865af13d15610a79573d6109d981610b5f565b906109e688519283610b28565b815288863d92013e5b15610a42579183917ffb17d0033e42e6a76759d2c7c2795a304dfbba80679160ae60dc91aad4966e52869560019560809851908152a2835193808552840152631cd95b9960e21b6060840152820152a180f35b845162461bcd60e51b8152808401859052601160248201527015985b1d59481cd95b990819985a5b1959607a1b6044820152606490fd5b6109ef565b85855180610a8b81610db7565b0390a16109c1565b610aa990863d88116101eb576101db8183610b28565b5038610996565b86513d8a823e3d90fd5b634e487b7160e01b8a526041865260248afd5b509034610af7576020366003190112610af7573591805483101561051c575061054a602092610afb565b8280fd5b906000918254811015610b145782805260208320019190565b634e487b7160e01b83526032600452602483fd5b90601f801991011681019081106001600160401b03821117610b4957604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111610b4957601f01601f191660200190565b81601f82011215610bc157803590610b9182610b5f565b92610b9f6040519485610b28565b82845260208383010111610bc157816000926020809301838601378301015290565b600080fd5b906080600319830112610bc15760043591602435906001600160401b038211610bc157610bf591600401610b7a565b906044359060643590565b6080600319820112610bc157600435906001600160401b038211610bc157610c2a91600401610b7a565b90602435906044359060643590565b90816020910312610bc157518015158103610bc15790565b9392919060018060a01b03168452602060608186015281519182606087015260005b838110610c995750505060808160008260409488010152601f8019910116850101930152565b818101830151878201608001528201610c73565b9060408252600960408301526864656c65676174653160b81b60608301526001602060808401930152565b600054600160401b811015610b4957806001610cf79201600055610afb565b819291549060031b9160018060a01b03809116831b921b1916179055565b9060408252600660408301526563726561746560d01b60608301526001602060808401930152565b90816020910312610bc157516001600160a01b0381168103610bc15790565b906040825260076040830152666372656174653160c81b60608301526001602060808401930152565b9060408252601060408301526f18dc99585d194c57dc995d995c9d195960821b60608301526000602060808401930152565b9060408252600860408301526764656c656761746560c01b6060830152600160206080840193015256fe6080601f6101f338819003918201601f19168301916001600160401b038311848410176100e0578084926020946040528339810103126100db575180151581036100db57610096573360018060a01b03196001541617600155346000556040513481527fb263f5c1dda4b5b44a8d5658a105c64b6ec61c79463b79a1d0052a834d00fdc460203392a260405160fc90816100f78239f35b60405162461bcd60e51b815260206004820152601e60248201527f496e74656e74696f6e616c20636f6e7374727563746f722072657665727400006044820152606490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe60808060405260043610156040575b503615601957600080fd5b600054348101809111602a57600055005b634e487b7160e01b600052601160045260246000fd5b600090813560e01c90816302d05d3f14609f575080632096525514608457633fa4f24503600e57346081578060031936011260815760209054604051908152f35b80fd5b50346081578060031936011260815760209054604051908152f35b90503460c2578160031936011260c2576001546001600160a01b03168152602090f35b5080fdfea2646970667358221220d21dae735f8bd27e93e963f6caaa38336d387a65ef5055b60b5b67a5ea9bc79064736f6c634300081400331dc05c1d6a563dddb6c22082af72b54ec2f0207ceb55db5d13cdabc208f303a99f4d25774676d497fe3d8c1e43709b68b186fad01b05798c1410a178ff4ed7d0a2646970667358221220d240419af0d6f7c5730c6adddac161e3c233245911fa32bb94dbc84c12c08f3f64736f6c63430008140033", + "deployedBytecode": "0x60406080815260048036101561001f575b5050361561001d57600080fd5b005b600091823560e01c80630881139714610acd5780637a0aaa5b146108cd578381637d5b95391461079f578163aabf1086146105ba57508063b203934e1461059d578063c242737f1461051f578063c53e5ae314610470578063e71b671a146102765763edab9299146100915750610010565b829161009c36610c00565b8596919651946353266bbb60e01b9081875264e8d4a5100096879581806100cc60209b8c94048b30888501610c51565b038161080098895af1801561026c5761024f575b50875198600080516020610ff58339815191528a806100ff839d610cad565b0390a188516101f3808201908282106001600160401b0383111761023c578a9897969593898f969394818f94610182978391610de283398a815203019083f091826101fc5750505060808160068f9351918083528201526563726561746560d01b6060820152868b820152a15b8a51988997889687958652049130908501610c51565b03925af180156101f2576101c4575b5050516040808252600990820152683232b632b3b0ba329960b91b60608201526001602082015280608081015b0390a180f35b816101e392903d106101eb575b6101db8183610b28565b810190610c39565b503880610191565b503d6101d1565b83513d87823e3d90fd5b6001600160a01b0390921692600080516020610fd5833981519152929061022285610cd8565b51908152a28b8b518061023481610d15565b0390a161016c565b634e487b7160e01b8e526041855260248efd5b61026590883d8a116101eb576101db8183610b28565b50386100e0565b89513d8d823e3d90fd5b5061028036610bc6565b92919064e8d4a5100085519163c53e5ae360e01b83528488840152602094838680826024829886305af18c9281610441575b506103f257505050600080516020610ff58339815191528751806102d581610d85565b0390a15b6102f8875194859384936353266bbb60e01b85520490308b8501610c51565b0381896108005af180156103e8576103cb575b50825193600080516020610ff5833981519152858061032a8398610db7565b0390a18351906101f3808301918383106001600160401b038411176103b8575083918391610de2833988815203019083f080156101f2576001600160a01b031691600080516020610fd5833981519152919061038584610cd8565b8451908152a25160408082526007908201526631b932b0ba329960c91b60608201526001602082015280608081016101be565b634e487b7160e01b895260419052602488fd5b6103e190823d84116101eb576101db8183610b28565b503861030b565b84513d88823e3d90fd5b6001600160a01b0390911691600080516020610fd5833981519152919061041884610cd8565b8a51908152a2600080516020610ff583398151915287518061043981610d5c565b0390a16102d9565b610462919350823d8411610469575b61045a8183610b28565b810190610d3d565b91386102b2565b503d610450565b5082602036600319011261051c5781516101f3808201908282106001600160401b03831117610509576020918391610de283398481520301908435f0156104fe57815162461bcd60e51b8152602081850152602160248201527f496e74656e74696f6e616c20726576657274206166746572206372656174696f6044820152603760f91b6064820152608490fd5b9051903d90823e3d90fd5b634e487b7160e01b845260418652602484fd5b80fd5b5091903461059957602036600319011261059957803591548210156105605760208361054a84610afb565b905491519160018060a01b039160031b1c168152f35b606490602084519162461bcd60e51b83528201526013602482015272496e646578206f7574206f6620626f756e647360681b6044820152fd5b5080fd5b838234610599578160031936011261059957602091549051908152f35b9190506105c636610bc6565b90949291845164e8d4a5100063c53e5ae360e01b97888352858a84015260209583878082602482988d305af18a9281610780575b5061073157505050600080516020610ff583398151915288518061061d81610d85565b0390a15b610640885194859384936353266bbb60e01b85520490308d8501610c51565b0381876108005af180156107275761070a575b5080845196600080516020610ff58339815191528880610673839b610db7565b0390a18551968752860152818560248186305af1809584966106eb575b506106c557506080935060108351938085528401526f18dc99585d194c97dc995d995c9d195960821b6060840152820152a180f35b92936001600160a01b031692600080516020610fd5833981519152925061038584610cd8565b610703919650833d85116104695761045a8183610b28565b9438610690565b61072090833d85116101eb576101db8183610b28565b5038610653565b85513d86823e3d90fd5b6001600160a01b0390911691600080516020610fd5833981519152919061075784610cd8565b8b51908152a2600080516020610ff583398151915288518061077881610d5c565b0390a1610621565b610798919350823d84116104695761045a8183610b28565b91386105fa565b9290506107ab36610c00565b8596919651946353266bbb60e01b9081875264e8d4a5100096879581806107db60209b8c94048b30888501610c51565b038161080098895af1801561026c576108b0575b50875198600080516020610ff58339815191528a8061080e839d610cad565b0390a188516101f3808201908282106001600160401b0383111761023c57828e96959493928c92610de2833987815203019082f080156108a657899796959493926101829290916001600160a01b031690600080516020610fd5833981519152908a908e61087b85610cd8565b51908152a28b8b518061088d81610d15565b0390a18a51988997889687958652049130908501610c51565b8a513d86823e3d90fd5b6108c690883d8a116101eb576101db8183610b28565b50386107ef565b506108d736610bc6565b9094918451936101f3808601908682106001600160401b03831117610aba57908691610de28339898152602096879103019082f08015610ab0576001600160a01b03169291908390600080516020610fd583398151915290879061093a84610cd8565b8951908152a28464e8d4a51000875198600080516020610ff58339815191528a80610965839d610d15565b0390a1610987895194859384936353266bbb60e01b85520490308a8501610c51565b03818b6108005af19081610a93575b50610a7e5785608086518781526008888201526764656c656761746560c01b60608201528987820152a15b8680808084865af13d15610a79573d6109d981610b5f565b906109e688519283610b28565b815288863d92013e5b15610a42579183917ffb17d0033e42e6a76759d2c7c2795a304dfbba80679160ae60dc91aad4966e52869560019560809851908152a2835193808552840152631cd95b9960e21b6060840152820152a180f35b845162461bcd60e51b8152808401859052601160248201527015985b1d59481cd95b990819985a5b1959607a1b6044820152606490fd5b6109ef565b85855180610a8b81610db7565b0390a16109c1565b610aa990863d88116101eb576101db8183610b28565b5038610996565b86513d8a823e3d90fd5b634e487b7160e01b8a526041865260248afd5b509034610af7576020366003190112610af7573591805483101561051c575061054a602092610afb565b8280fd5b906000918254811015610b145782805260208320019190565b634e487b7160e01b83526032600452602483fd5b90601f801991011681019081106001600160401b03821117610b4957604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111610b4957601f01601f191660200190565b81601f82011215610bc157803590610b9182610b5f565b92610b9f6040519485610b28565b82845260208383010111610bc157816000926020809301838601378301015290565b600080fd5b906080600319830112610bc15760043591602435906001600160401b038211610bc157610bf591600401610b7a565b906044359060643590565b6080600319820112610bc157600435906001600160401b038211610bc157610c2a91600401610b7a565b90602435906044359060643590565b90816020910312610bc157518015158103610bc15790565b9392919060018060a01b03168452602060608186015281519182606087015260005b838110610c995750505060808160008260409488010152601f8019910116850101930152565b818101830151878201608001528201610c73565b9060408252600960408301526864656c65676174653160b81b60608301526001602060808401930152565b600054600160401b811015610b4957806001610cf79201600055610afb565b819291549060031b9160018060a01b03809116831b921b1916179055565b9060408252600660408301526563726561746560d01b60608301526001602060808401930152565b90816020910312610bc157516001600160a01b0381168103610bc15790565b906040825260076040830152666372656174653160c81b60608301526001602060808401930152565b9060408252601060408301526f18dc99585d194c57dc995d995c9d195960821b60608301526000602060808401930152565b9060408252600860408301526764656c656761746560c01b6060830152600160206080840193015256fe6080601f6101f338819003918201601f19168301916001600160401b038311848410176100e0578084926020946040528339810103126100db575180151581036100db57610096573360018060a01b03196001541617600155346000556040513481527fb263f5c1dda4b5b44a8d5658a105c64b6ec61c79463b79a1d0052a834d00fdc460203392a260405160fc90816100f78239f35b60405162461bcd60e51b815260206004820152601e60248201527f496e74656e74696f6e616c20636f6e7374727563746f722072657665727400006044820152606490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe60808060405260043610156040575b503615601957600080fd5b600054348101809111602a57600055005b634e487b7160e01b600052601160045260246000fd5b600090813560e01c90816302d05d3f14609f575080632096525514608457633fa4f24503600e57346081578060031936011260815760209054604051908152f35b80fd5b50346081578060031936011260815760209054604051908152f35b90503460c2578160031936011260c2576001546001600160a01b03168152602090f35b5080fdfea2646970667358221220d21dae735f8bd27e93e963f6caaa38336d387a65ef5055b60b5b67a5ea9bc79064736f6c634300081400331dc05c1d6a563dddb6c22082af72b54ec2f0207ceb55db5d13cdabc208f303a99f4d25774676d497fe3d8c1e43709b68b186fad01b05798c1410a178ff4ed7d0a2646970667358221220d240419af0d6f7c5730c6adddac161e3c233245911fa32bb94dbc84c12c08f3f64736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contracts/solidity/ContractCreationTester.sol b/contracts/solidity/ContractCreationTester.sol new file mode 100644 index 000000000..e59900625 --- /dev/null +++ b/contracts/solidity/ContractCreationTester.sol @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./precompiles/staking/StakingI.sol"; +import "./precompiles/common/Types.sol"; + +/** + * @dev Simple contract that can be created and receive value + */ +contract SimpleReceiver { + uint256 public value; + address public creator; + + event ReceiverCreated(address indexed creator, uint256 initialValue); + + constructor(bool shouldRevert) payable { + if (shouldRevert) { + revert("Intentional constructor revert"); + } + creator = msg.sender; + value = msg.value; + emit ReceiverCreated(msg.sender, msg.value); + } + + receive() external payable { + value += msg.value; + } + + function getValue() external view returns (uint256) { + return value; + } +} + +/** + * @dev Contract to test contract creation with precompile calls + * Tests scenarios 4-7 with various combinations of CREATE and precompile operations + */ +contract ContractCreationTester { + event OperationCompleted(string operation, bool success); + event ContractCreated(address indexed contractAddr, uint256 value); + event ValueSent(address indexed recipient, uint256 amount); + + address[] public createdContracts; + + /// @dev Helper function that creates a contract and then reverts + /// @dev Used for testing reverted contract creation scenarios + function createAndRevert(uint256 creationValue) public payable returns (SimpleReceiver) { + SimpleReceiver newContract = new SimpleReceiver{value: creationValue}(false); + revert("Intentional revert after creation"); + } + + /// @dev Scenario 4: Precompile -> Create Contract -> Precompile + function scenario4_delegateCreateDelegate( + string memory validatorAddr, + uint256 delegateAmount1, + uint256 creationValue, + uint256 delegateAmount2 + ) external payable { + // 1. Precompile call (delegate) - convert from wei to base denom + uint256 delegateAmount1BaseDenom = delegateAmount1 / 1e12; + STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmount1BaseDenom + ); + emit OperationCompleted("delegate1", true); + + // 2. Create another contract with value (shouldRevert = false) + SimpleReceiver newContract = new SimpleReceiver{value: creationValue}(false); + createdContracts.push(address(newContract)); + emit ContractCreated(address(newContract), creationValue); + emit OperationCompleted("create", true); + + // 3. Precompile call (delegate again) - convert from wei to base denom + uint256 delegateAmount2BaseDenom = delegateAmount2 / 1e12; + STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmount2BaseDenom + ); + emit OperationCompleted("delegate2", true); + } + + /// @dev Scenario 5: Precompile -> Create Contract (reverted & caught) -> Precompile + function scenario5_delegateCreateRevertDelegate( + string memory validatorAddr, + uint256 delegateAmount1, + uint256 creationValue, + uint256 delegateAmount2 + ) external payable { + // 1. Precompile call (delegate) - convert from wei to base denom + uint256 delegateAmount1BaseDenom = delegateAmount1 / 1e12; + STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmount1BaseDenom + ); + emit OperationCompleted("delegate1", true); + + // 2. Try to create contract (will revert if insufficient value, catch it) + try new SimpleReceiver{value: creationValue}(false) returns (SimpleReceiver newContract) { + createdContracts.push(address(newContract)); + emit ContractCreated(address(newContract), creationValue); + emit OperationCompleted("create", true); + } catch { + emit OperationCompleted("create", false); + } + + // 3. Precompile call (delegate again) - convert from wei to base denom + uint256 delegateAmount2BaseDenom = delegateAmount2 / 1e12; + STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmount2BaseDenom + ); + emit OperationCompleted("delegate2", true); + } + + /// @dev Scenario 6: Create+Revert (caught) -> Precompile -> Create+Revert (caught) + /// @dev Creates fail because the helper function reverts after creation, testing auto-flush with reverted creations + function scenario6_createRevertDelegateCreateRevert( + uint256 creationValue1, + string memory validatorAddr, + uint256 delegateAmount, + uint256 creationValue2 + ) external payable { + // 1. Try to create contract (will revert after creation, catch it) + try this.createAndRevert(creationValue1) returns (SimpleReceiver newContract1) { + // This won't execute because createAndRevert reverts + createdContracts.push(address(newContract1)); + emit ContractCreated(address(newContract1), creationValue1); + emit OperationCompleted("create1", true); + } catch { + emit OperationCompleted("create1_reverted", false); + } + + // 2. Precompile call - convert from wei to base denom + uint256 delegateAmountBaseDenom = delegateAmount / 1e12; + STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmountBaseDenom + ); + emit OperationCompleted("delegate", true); + + // 3. Try to create contract again (will revert after creation, catch it) + try this.createAndRevert(creationValue2) returns (SimpleReceiver newContract2) { + // This won't execute because createAndRevert reverts + createdContracts.push(address(newContract2)); + emit ContractCreated(address(newContract2), creationValue2); + emit OperationCompleted("create2", true); + } catch { + emit OperationCompleted("create2_reverted", false); + } + } + + /// @dev Scenario 7: Create+Send -> Precompile (reverted & caught) -> Send more + function scenario7_createDelegateRevertSend( + uint256 creationValue, + string memory validatorAddr, + uint256 delegateAmount, + uint256 sendAmount + ) external payable { + // 1. Create contract and send it value (shouldRevert = false) + SimpleReceiver newContract = new SimpleReceiver{value: creationValue}(false); + createdContracts.push(address(newContract)); + emit ContractCreated(address(newContract), creationValue); + emit OperationCompleted("create", true); + + // 2. Precompile call (delegate) - convert from wei to base denom, reverted and caught + uint256 delegateAmountBaseDenom = delegateAmount / 1e12; + try STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmountBaseDenom + ) { + emit OperationCompleted("delegate", true); + } catch { + emit OperationCompleted("delegate", false); + } + + // 3. Send more value to the created contract + (bool success, ) = address(newContract).call{value: sendAmount}(""); + require(success, "Value send failed"); + emit ValueSent(address(newContract), sendAmount); + emit OperationCompleted("send", true); + } + + /// @dev Scenario 8: Create+Revert (caught) -> Delegate -> Create+Success + /// @dev Tests that reverted creation doesn't prevent successful creation after delegation + function scenario8_createRevertDelegateCreateSuccess( + uint256 revertCreationValue, + string memory validatorAddr, + uint256 delegateAmount, + uint256 successCreationValue + ) external payable { + // 1. Try to create contract (will revert after creation, catch it) + try this.createAndRevert{value: revertCreationValue}(revertCreationValue) returns (SimpleReceiver newContract1) { + // This won't execute because createAndRevert reverts + createdContracts.push(address(newContract1)); + emit ContractCreated(address(newContract1), revertCreationValue); + emit OperationCompleted("create1", true); + } catch { + emit OperationCompleted("create1_reverted", false); + } + + // 2. Precompile call - convert from wei to base denom + uint256 delegateAmountBaseDenom = delegateAmount / 1e12; + STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmountBaseDenom + ); + emit OperationCompleted("delegate", true); + + // 3. Create contract successfully (shouldRevert = false) + SimpleReceiver newContract2 = new SimpleReceiver{value: successCreationValue}(false); + createdContracts.push(address(newContract2)); + emit ContractCreated(address(newContract2), successCreationValue); + emit OperationCompleted("create2", true); + } + + /// @dev Get count of created contracts + function getCreatedContractsCount() external view returns (uint256) { + return createdContracts.length; + } + + /// @dev Get created contract at index + function getCreatedContract(uint256 index) external view returns (address) { + require(index < createdContracts.length, "Index out of bounds"); + return createdContracts[index]; + } + + receive() external payable {} +} diff --git a/contracts/solidity/ERC20WithNativeTransfers.json b/contracts/solidity/ERC20WithNativeTransfers.json new file mode 100644 index 000000000..6d6ab695a --- /dev/null +++ b/contracts/solidity/ERC20WithNativeTransfers.json @@ -0,0 +1,813 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC20WithNativeTransfers", + "sourceName": "solidity/ERC20WithNativeTransfers.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "BeforeTransferHookTriggered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "available", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ContractBalanceCheck", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "DelegateCompleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "step", + "type": "uint256" + } + ], + "name": "NativeTransferCompleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MINTER_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_recipient1", + "type": "address" + }, + { + "internalType": "address", + "name": "_recipient2", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_transferAmount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "_validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "_delegateAmount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "_enableHook", + "type": "bool" + } + ], + "name": "configureHook", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "delegateAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "enableHook", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "getRoleMember", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleMemberCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "recipient1", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "recipient2", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "transferAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "validatorAddr", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x604060808152346200043857620027cc803803806200001e816200043d565b9283398101606082820312620004385781516001600160401b0391908281116200043857816200005091850162000463565b9160209182850151828111620004385786916200006f91870162000463565b9401519360ff8516809503620004385783518281116200034f576005918254916001968784811c941680156200042d575b878510146200032e578190601f94858111620003d9575b508790858311600114620003715760009262000365575b5050600019600383901b1c191690871b1783555b80519384116200034f576006548681811c9116801562000344575b868210146200032e578493838211620002d4575b5050849183116001146200026a576000926200025e575b5050600019600383901b1c191690831b176006555b60008052600081528360002033600052815260ff8460002054161562000221575b60008052818152620001743385600020620004d5565b507f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a680600052600082528460002033600052825260ff85600020541615620001e4575b60005252620001ca3383600020620004d5565b5060ff196007541617600755516122499081620005638239f35b806000526000825284600020336000528252846000208360ff19825416179055333382600080516020620027ac833981519152600080a4620001b7565b600080526000815283600020336000528152836000208260ff1982541617905533336000600080516020620027ac8339815191528180a46200015e565b01519050388062000128565b90859350601f198316916006600052856000209260005b87828210620002bd5750508411620002a3575b505050811b016006556200013d565b015160001960f88460031b161c1916905538808062000294565b838501518655899790950194938401930162000281565b90919293506006600052856000209084808701821c83019388881062000324575b9187968a93969594929601901c01915b82811062000314575062000111565b6000815586955088910162000305565b93508293620002f5565b634e487b7160e01b600052602260045260246000fd5b90607f1690620000fd565b634e487b7160e01b600052604160045260246000fd5b015190503880620000ce565b90899350601f1983169187600052896000209260005b8b828210620003c25750508411620003a8575b505050811b018355620000e2565b015160001960f88460031b161c191690553880806200039a565b8385015186558d9790950194938401930162000387565b909150856000528760002085808501881c8201928a861062000423575b918b918695949301891c01915b82811062000413575050620000b7565b600081558594508b910162000403565b92508192620003f6565b93607f1693620000a0565b600080fd5b6040519190601f01601f191682016001600160401b038111838210176200034f57604052565b919080601f84011215620004385782516001600160401b0381116200034f5760209062000499601f8201601f191683016200043d565b92818452828287010111620004385760005b818110620004c157508260009394955001015290565b8581018301518482018401528201620004ab565b919060018301600090828252806020526040822054156000146200055c57845494680100000000000000008610156200054857600186018082558610156200053457836040949596828552602085200155549382526020522055600190565b634e487b7160e01b83526032600452602483fd5b634e487b7160e01b83526041600452602483fd5b5092505056fe6080604081815260049182361015610022575b505050361561002057600080fd5b005b600092833560e01c91826301ffc9a714610fe3575081630688b13514610fba57816306fdde0314610f14578163095ea7b314610eea57816318160ddd14610ecc57816323b872dd14610e8f578163248a9ca314610e655781632f2ff15d14610db1578163313ce56714610d8f57816336568abe14610cfd5781633950935114610cad57816340c10f191461083e57816342966c6814610820578163504d27fd1461080157816370a08231146107c957816379cc6790146107995781639010d07c1461075857816391d148541461071257816395d89b41146106435781639f35c7e714610609578163a217fddf146105ee578163a457c2d714610546578163a9059cbb14610515578163aa3744bd146104e8578163b64bdb34146104c9578163ba84e217146104a5578163bd3fddd714610277578163ca15c8731461024f578163d539139314610214578163d547741f146101d2575063dd62ed3e146101875780610012565b346101ce57806003193601126101ce57806020926101a361109f565b6101ab6110ba565b6001600160a01b0391821683526003865283832091168252845220549051908152f35b5080fd5b9190503461021057806003193601126102105761020d913561020860016101f76110ba565b9383875286602052862001546111c7565b6114ef565b80f35b8280fd5b5050346101ce57816003193601126101ce57602090517f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68152f35b9050346102105760203660031901126102105760209282913581526001845220549051908152f35b839150346101ce5760c03660031901126101ce5761029361109f565b61029b6110ba565b9060643567ffffffffffffffff928382116104a157366023830112156104a157818501359384116104a1576024923684868501011161049d5760a4359586151580970361049957878052602098888a52808920338a528a5260ff818a2054161561046157505060078054610100600160a81b031916600892831b610100600160a81b031617905580546001600160a01b0319166001600160a01b0392909216919091179055604435600955600a54610352906110d0565b601f811161041d575b508495601f84116001146103b15750948495839495936103a4575b5050508160011b916000199060031b1c191617600a555b608435600b5560ff8019600c5416911617600c5580f35b0101359050848080610376565b91601f19841696600a87528387209387905b898210610403575050846001969798106103e7575b50505050811b01600a5561038d565b60001960f88660031b161c1992010135169055848080806103d8565b8060018497868395968901013581550196019201906103c3565b600a8652868620601f850160051c810191888610610457575b601f0160051c01905b81811061044c575061035b565b86815560010161043f565b9091508190610436565b5162461bcd60e51b8152908101899052601481860152734d75737420686176652061646d696e20726f6c6560601b6044820152606490fd5b8780fd5b8680fd5b8580fd5b5050346101ce57816003193601126101ce5760209060ff600c541690519015158152f35b5050346101ce57816003193601126101ce57602090600b549051908152f35b5050346101ce57816003193601126101ce57600754905160089190911c6001600160a01b03168152602090f35b5050346101ce57806003193601126101ce5760209061053f61053561109f565b6024359033611599565b5160018152f35b905082346105eb57826003193601126105eb5761056161109f565b918360243592338152600360205281812060018060a01b038616825260205220549082821061059a5760208561053f8585038733611a14565b608490602086519162461bcd60e51b8352820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152fd5b80fd5b5050346101ce57816003193601126101ce5751908152602090f35b5050346101ce57816003193601126101ce57805161063f916106358261062e8161110a565b038361118f565b5191829182611073565b0390f35b5050346101ce57816003193601126101ce5780519082600654610665816110d0565b808552906001908181169081156106ea5750600114610691575b5050506106358261063f94038361118f565b60068352602095507ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f5b8284106106d7575050508261063f94610635928201019461067f565b80548685018801529286019281016106bb565b61063f97506106359450602092508693915060ff191682840152151560051b8201019461067f565b9050346102105781600319360112610210578160209360ff926107336110ba565b903582528186528282206001600160a01b039091168252855220549151911615158152f35b9050346102105781600319360112610210576020926107839135815260018452826024359120611f7a565b905491519160018060a01b039160031b1c168152f35b5050346101ce573660031901126105eb5761020d6107b561109f565b602435906107c4823383611b16565b611bae565b5050346101ce5760203660031901126101ce5760209181906001600160a01b036107f161109f565b1681526002845220549051908152f35b5050346101ce57816003193601126101ce576020906009549051908152f35b8390346101ce5760203660031901126101ce5761020d903533611bae565b90503461021057816003193601126102105761085861109f565b906024928335917f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68652602093868552828720338852855260ff838820541615610c6c576001600160a01b03908116958615610c2b5760ff600c541680610c24575b80610c1c575b610900575b505091859391836108e6836000805160206121948339815191529654611576565b90558585526002835280852082815401905551908152a380f35b60008051602061213483398151915260608593999897959694965189815288878201528585820152a16009548015801580610bff575b610a6e575b5050869750600b969495965480151580610a5b575b610961575b508193959294506108c5565b909193809693955084518080936353266bbb60e01b8252308783015260608683015261098f6064830161110a565b90604483015203818b6108005af1908115610a51578891610a1b575b50156109e75750918391600080516020612194833981519152936000805160206121f48339815191528896600b548451908152a1949338610955565b60119085606494519362461bcd60e51b85528401528201527011195b1959d85d1a5bdb8819985a5b1959607a1b6044820152fd5b90508581813d8311610a4a575b610a32818361118f565b810103126104995751801515810361049957386109ab565b503d610a28565b84513d8a823e3d90fd5b50610a67600a546110d0565b1515610950565b8160011b908282046002141715610bed5747600080516020612154833981519152858051838152848a820152a110610ba25787808080938c60075460081c165af1610ab76120f3565b5015610b61576060878080808c60075460081c16600954908851908152818b820152600189820152600080516020612174833981519152968791a18d600854165af1610b016120f3565b5015610b3157606088996008999798995416600954855191825287820152600285820152a138809796959761093b565b825162461bcd60e51b8152808701869052601d818401526000805160206121d48339815191526044820152606490fd5b601c859185606494519362461bcd60e51b85528401528201527f4669727374206e6174697665207472616e73666572206661696c6564000000006044820152fd5b825162461bcd60e51b81528087018690526032818401526000805160206121b483398151915260448201527172206e6174697665207472616e736665727360701b6064820152608490fd5b634e487b7160e01b8952601187528289fd5b5060075460081c8a16151580610936575089600854161515610936565b5060016108c0565b50876108ba565b601f915085606494519362461bcd60e51b85528401528201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152fd5b50601d8585606494519362461bcd60e51b85528401528201527f4d7573742068617665206d696e74657220726f6c6520746f206d696e740000006044820152fd5b5050346101ce57806003193601126101ce5761053f602092610cf6610cd061109f565b338352600386528483206001600160a01b03821684528652918490205460243590611576565b9033611a14565b839150346101ce57826003193601126101ce57610d186110ba565b90336001600160a01b03831603610d34579061020d91356114ef565b608490602085519162461bcd60e51b8352820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152fd5b5050346101ce57816003193601126101ce5760209060ff600754169051908152f35b91905034610210578060031936011261021057610e1a9135906001610dd46110ba565b92808652602090868252610dec8385892001546111c7565b80875286825283872094838060a01b031694858852825260ff848820541615610e1e575b8652528320611f92565b5080f35b8087528682528387208588528252838720805460ff1916841790553385827f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8a80a4610e10565b90503461021057602036600319011261021057816020936001923581528085522001549051908152f35b5050346101ce5760603660031901126101ce5760209061053f610eb061109f565b610eb86110ba565b60443591610ec7833383611b16565b611599565b90503461021057826003193601126102105760209250549051908152f35b5050346101ce57806003193601126101ce5760209061053f610f0a61109f565b6024359033611a14565b5050346101ce57816003193601126101ce5780519082600554610f36816110d0565b808552906001908181169081156106ea5750600114610f61575050506106358261063f94038361118f565b60058352602095507f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db05b828410610fa7575050508261063f94610635928201019461067f565b8054868501880152928601928101610f8b565b5050346101ce57816003193601126101ce5760085490516001600160a01b039091168152602090f35b849134610210576020366003190112610210573563ffffffff60e01b81168091036102105760209250635a05180f60e01b8114908115611025575b5015158152f35b637965db0b60e01b81149150811561103f575b508361101e565b6301ffc9a760e01b14905083611038565b60005b8381106110635750506000910152565b8181015183820152602001611053565b604091602082526110938151809281602086015260208686019101611050565b601f01601f1916010190565b600435906001600160a01b03821682036110b557565b600080fd5b602435906001600160a01b03821682036110b557565b90600182811c92168015611100575b60208310146110ea57565b634e487b7160e01b600052602260045260246000fd5b91607f16916110df565b600a546000929161111a826110d0565b908181526001928381169081600014611174575060011461113a57505050565b90929350600a6000526020928360002092846000945b8386106111605750505050010190565b805485870183015294019385908201611150565b91935050602093945060ff191683830152151560051b010190565b90601f8019910116810190811067ffffffffffffffff8211176111b157604052565b634e487b7160e01b600052604160045260246000fd5b6000818152602090808252604092838220338352835260ff8483205416156111ef5750505050565b835167ffffffffffffffff91903360608201848111838210176114db578752602a825285820192873685378251156114c757603084538251916001928310156114b3576078602185015360295b838111611449575061140757908751946080860190868210908211176113f3578852604285528685019560603688378551156113df576030875385518210156113df5790607860218701536041915b8183116113715750505061132f57938593611315936113066048946112dd76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b9961132b9b519a8b978801525180926037880190611050565b8401917001034b99036b4b9b9b4b733903937b6329607d1b603784015251809386840190611050565b0103602881018552018361118f565b5162461bcd60e51b815291829160048301611073565b0390fd5b60648587519062461bcd60e51b825280600483015260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b909192600f811660108110156113cb576f181899199a1a9b1b9c1cb0b131b232b360811b901a6113a18589611f53565b5360041c9280156113b75760001901919061128b565b634e487b7160e01b82526011600452602482fd5b634e487b7160e01b83526032600452602483fd5b634e487b7160e01b81526032600452602490fd5b634e487b7160e01b87526041600452602487fd5b60648789519062461bcd60e51b825280600483015260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f8116601081101561149f576f181899199a1a9b1b9c1cb0b131b232b360811b901a6114778387611f53565b5360041c90801561148b576000190161123c565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b89526032600452602489fd5b634e487b7160e01b87526032600452602487fd5b634e487b7160e01b86526032600452602486fd5b634e487b7160e01b86526041600452602486fd5b90604061152c92600090808252816020528282209360018060a01b03169384835260205260ff838320541661152f575b8152600160205220612017565b50565b8082528160205282822084835260205282822060ff1981541690553384827ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b8580a461151f565b9190820180921161158357565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b03929083169182156119c15783169283156119705760ff600c541680611968575b80611960575b61166d575b5060008281526002602052604081205491808310611619576040828260008051602061219483398151915295876020965260028652038282205586815220818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b6040805191848352600080516020612134833981519152606060209488868201528685820152a16009548015801580611943575b6117c2575b505050600b54801515806117af575b6116c1575b50506115cc565b81516353266bbb60e01b815230600482015260606024820152906116e76064830161110a565b9060448301528382806000930381846108005af19182156117a3578192611769575b50501561173257906000805160206121f483398151915291600b549051908152a13880806116ba565b60649250519062461bcd60e51b82526004820152601160248201527011195b1959d85d1a5bdb8819985a5b1959607a1b6044820152fd5b9091508381813d831161179c575b611781818361118f565b810103126101ce57519081151582036105eb57503880611709565b503d611777565b508251903d90823e3d90fd5b506117bb600a546110d0565b15156116b5565b8160011b90828204600214171561158357476000805160206121548339815191528580518381528489820152a1106118f657600080808080948660075460081c165af161180d6120f3565b50156118b257908180806060948460075460081c16600954908851908152818a820152600189820152600080516020612174833981519152978891a185600854165af16118586120f3565b50156118805760609060085416600954845191825285820152600284820152a13880806116a6565b825162461bcd60e51b815260048101859052601d60248201526000805160206121d48339815191526044820152606490fd5b825162461bcd60e51b815260048101859052601c60248201527f4669727374206e6174697665207472616e73666572206661696c6564000000006044820152606490fd5b825162461bcd60e51b815260048101859052603260248201526000805160206121b483398151915260448201527172206e6174697665207472616e736665727360701b6064820152608490fd5b5060075460081c83161515806116a15750826008541615156116a1565b5060016115c7565b5060016115c1565b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b6001600160a01b03908116918215611ac55716918215611a755760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260038252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b9060018060a01b0380831660005260036020526040600020908216600052602052604060002054926000198403611b4e575b50505050565b808410611b6957611b60930391611a14565b38808080611b48565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b6001600160a01b03908116908115611f045760ff600c541680611efc575b80611ef4575b611c73575b5080600052600260205260406000205491808310611c235760208160008051602061219483398151915292600095858752600284520360408620558060045403600455604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608490fd5b6040805191838352600090600080516020612134833981519152606060209584878201528886820152a16009548015801580611ed7575b611d88575b505050600b549081151580611d75575b611ccc575b505050611bd7565b8383518080946353266bbb60e01b825230600483015260606024830152611cf56064830161110a565b9060448301520381846108005af19182156117a3578192611d3b575b50501561173257906000805160206121f483398151915291600b549051908152a138808080611cc4565b9091508381813d8311611d6e575b611d53818361118f565b810103126101ce57519081151582036105eb57503880611d11565b503d611d49565b50611d81600a546110d0565b1515611cbf565b8160011b908282046002141715611ec35747600080516020612154833981519152868051838152848a820152a110611e765782808080938560075460081c165af1611dd16120f3565b50156118b257808280808060609560075460081c16600954908951908152818b82015260018a820152600080516020612174833981519152978891a185600854165af1611e1c6120f3565b5015611e445760609060085416600954855191825286820152600285820152a1388080611caf565b835162461bcd60e51b815260048101869052601d60248201526000805160206121d48339815191526044820152606490fd5b835162461bcd60e51b815260048101869052603260248201526000805160206121b483398151915260448201527172206e6174697665207472616e736665727360701b6064820152608490fd5b634e487b7160e01b84526011600452602484fd5b5060075460081c8316151580611caa575082600854161515611caa565b506000611bd2565b506001611bcc565b60405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608490fd5b908151811015611f64570160200190565b634e487b7160e01b600052603260045260246000fd5b8054821015611f645760005260206000200190600090565b9190600183016000908282528060205260408220541560001461201157845494600160401b861015611ffd5783611fed611fd6886001604098999a01855584611f7a565b819391549060031b91821b91600019901b19161790565b9055549382526020522055600190565b634e487b7160e01b83526041600452602483fd5b50925050565b906001820190600092818452826020526040842054908115156000146120ec57600019918083018181116120d85782549084820191821161148b578082036120a3575b5050508054801561208f578201916120728383611f7a565b909182549160031b1b191690555582526020526040812055600190565b634e487b7160e01b86526031600452602486fd5b6120c36120b3611fd69386611f7a565b90549060031b1c92839286611f7a565b9055865284602052604086205538808061205a565b634e487b7160e01b87526011600452602487fd5b5050505090565b3d1561212e573d9067ffffffffffffffff82116111b15760405191612122601f8201601f19166020018461118f565b82523d6000602084013e565b60609056fef8c99ceb8ca6b64b60019ae7ba043e6753f3aeb6d4d6da4632448e2f0ce24c7f3d9cb59aaaabeafebf96f5927674f7bdb281620132fb370f5486016f4557699709374e11d36c216b990e8a6a68cb669a6233bad8bc3abc452666829b8cc0ea25ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef496e73756666696369656e7420636f6e74726163742062616c616e636520666f5365636f6e64206e6174697665207472616e73666572206661696c6564000000f6b9808ab5f93046dc92bff4d681788d48019c7bb71644624464cc99b51f15bda26469706673582212206f85743c29fd8dd3a29fe101738d8d381e61b9c12974b90b9c6a6ef6b201f19b64736f6c634300081400332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", + "deployedBytecode": "0x6080604081815260049182361015610022575b505050361561002057600080fd5b005b600092833560e01c91826301ffc9a714610fe3575081630688b13514610fba57816306fdde0314610f14578163095ea7b314610eea57816318160ddd14610ecc57816323b872dd14610e8f578163248a9ca314610e655781632f2ff15d14610db1578163313ce56714610d8f57816336568abe14610cfd5781633950935114610cad57816340c10f191461083e57816342966c6814610820578163504d27fd1461080157816370a08231146107c957816379cc6790146107995781639010d07c1461075857816391d148541461071257816395d89b41146106435781639f35c7e714610609578163a217fddf146105ee578163a457c2d714610546578163a9059cbb14610515578163aa3744bd146104e8578163b64bdb34146104c9578163ba84e217146104a5578163bd3fddd714610277578163ca15c8731461024f578163d539139314610214578163d547741f146101d2575063dd62ed3e146101875780610012565b346101ce57806003193601126101ce57806020926101a361109f565b6101ab6110ba565b6001600160a01b0391821683526003865283832091168252845220549051908152f35b5080fd5b9190503461021057806003193601126102105761020d913561020860016101f76110ba565b9383875286602052862001546111c7565b6114ef565b80f35b8280fd5b5050346101ce57816003193601126101ce57602090517f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68152f35b9050346102105760203660031901126102105760209282913581526001845220549051908152f35b839150346101ce5760c03660031901126101ce5761029361109f565b61029b6110ba565b9060643567ffffffffffffffff928382116104a157366023830112156104a157818501359384116104a1576024923684868501011161049d5760a4359586151580970361049957878052602098888a52808920338a528a5260ff818a2054161561046157505060078054610100600160a81b031916600892831b610100600160a81b031617905580546001600160a01b0319166001600160a01b0392909216919091179055604435600955600a54610352906110d0565b601f811161041d575b508495601f84116001146103b15750948495839495936103a4575b5050508160011b916000199060031b1c191617600a555b608435600b5560ff8019600c5416911617600c5580f35b0101359050848080610376565b91601f19841696600a87528387209387905b898210610403575050846001969798106103e7575b50505050811b01600a5561038d565b60001960f88660031b161c1992010135169055848080806103d8565b8060018497868395968901013581550196019201906103c3565b600a8652868620601f850160051c810191888610610457575b601f0160051c01905b81811061044c575061035b565b86815560010161043f565b9091508190610436565b5162461bcd60e51b8152908101899052601481860152734d75737420686176652061646d696e20726f6c6560601b6044820152606490fd5b8780fd5b8680fd5b8580fd5b5050346101ce57816003193601126101ce5760209060ff600c541690519015158152f35b5050346101ce57816003193601126101ce57602090600b549051908152f35b5050346101ce57816003193601126101ce57600754905160089190911c6001600160a01b03168152602090f35b5050346101ce57806003193601126101ce5760209061053f61053561109f565b6024359033611599565b5160018152f35b905082346105eb57826003193601126105eb5761056161109f565b918360243592338152600360205281812060018060a01b038616825260205220549082821061059a5760208561053f8585038733611a14565b608490602086519162461bcd60e51b8352820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152fd5b80fd5b5050346101ce57816003193601126101ce5751908152602090f35b5050346101ce57816003193601126101ce57805161063f916106358261062e8161110a565b038361118f565b5191829182611073565b0390f35b5050346101ce57816003193601126101ce5780519082600654610665816110d0565b808552906001908181169081156106ea5750600114610691575b5050506106358261063f94038361118f565b60068352602095507ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f5b8284106106d7575050508261063f94610635928201019461067f565b80548685018801529286019281016106bb565b61063f97506106359450602092508693915060ff191682840152151560051b8201019461067f565b9050346102105781600319360112610210578160209360ff926107336110ba565b903582528186528282206001600160a01b039091168252855220549151911615158152f35b9050346102105781600319360112610210576020926107839135815260018452826024359120611f7a565b905491519160018060a01b039160031b1c168152f35b5050346101ce573660031901126105eb5761020d6107b561109f565b602435906107c4823383611b16565b611bae565b5050346101ce5760203660031901126101ce5760209181906001600160a01b036107f161109f565b1681526002845220549051908152f35b5050346101ce57816003193601126101ce576020906009549051908152f35b8390346101ce5760203660031901126101ce5761020d903533611bae565b90503461021057816003193601126102105761085861109f565b906024928335917f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a68652602093868552828720338852855260ff838820541615610c6c576001600160a01b03908116958615610c2b5760ff600c541680610c24575b80610c1c575b610900575b505091859391836108e6836000805160206121948339815191529654611576565b90558585526002835280852082815401905551908152a380f35b60008051602061213483398151915260608593999897959694965189815288878201528585820152a16009548015801580610bff575b610a6e575b5050869750600b969495965480151580610a5b575b610961575b508193959294506108c5565b909193809693955084518080936353266bbb60e01b8252308783015260608683015261098f6064830161110a565b90604483015203818b6108005af1908115610a51578891610a1b575b50156109e75750918391600080516020612194833981519152936000805160206121f48339815191528896600b548451908152a1949338610955565b60119085606494519362461bcd60e51b85528401528201527011195b1959d85d1a5bdb8819985a5b1959607a1b6044820152fd5b90508581813d8311610a4a575b610a32818361118f565b810103126104995751801515810361049957386109ab565b503d610a28565b84513d8a823e3d90fd5b50610a67600a546110d0565b1515610950565b8160011b908282046002141715610bed5747600080516020612154833981519152858051838152848a820152a110610ba25787808080938c60075460081c165af1610ab76120f3565b5015610b61576060878080808c60075460081c16600954908851908152818b820152600189820152600080516020612174833981519152968791a18d600854165af1610b016120f3565b5015610b3157606088996008999798995416600954855191825287820152600285820152a138809796959761093b565b825162461bcd60e51b8152808701869052601d818401526000805160206121d48339815191526044820152606490fd5b601c859185606494519362461bcd60e51b85528401528201527f4669727374206e6174697665207472616e73666572206661696c6564000000006044820152fd5b825162461bcd60e51b81528087018690526032818401526000805160206121b483398151915260448201527172206e6174697665207472616e736665727360701b6064820152608490fd5b634e487b7160e01b8952601187528289fd5b5060075460081c8a16151580610936575089600854161515610936565b5060016108c0565b50876108ba565b601f915085606494519362461bcd60e51b85528401528201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152fd5b50601d8585606494519362461bcd60e51b85528401528201527f4d7573742068617665206d696e74657220726f6c6520746f206d696e740000006044820152fd5b5050346101ce57806003193601126101ce5761053f602092610cf6610cd061109f565b338352600386528483206001600160a01b03821684528652918490205460243590611576565b9033611a14565b839150346101ce57826003193601126101ce57610d186110ba565b90336001600160a01b03831603610d34579061020d91356114ef565b608490602085519162461bcd60e51b8352820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152fd5b5050346101ce57816003193601126101ce5760209060ff600754169051908152f35b91905034610210578060031936011261021057610e1a9135906001610dd46110ba565b92808652602090868252610dec8385892001546111c7565b80875286825283872094838060a01b031694858852825260ff848820541615610e1e575b8652528320611f92565b5080f35b8087528682528387208588528252838720805460ff1916841790553385827f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8a80a4610e10565b90503461021057602036600319011261021057816020936001923581528085522001549051908152f35b5050346101ce5760603660031901126101ce5760209061053f610eb061109f565b610eb86110ba565b60443591610ec7833383611b16565b611599565b90503461021057826003193601126102105760209250549051908152f35b5050346101ce57806003193601126101ce5760209061053f610f0a61109f565b6024359033611a14565b5050346101ce57816003193601126101ce5780519082600554610f36816110d0565b808552906001908181169081156106ea5750600114610f61575050506106358261063f94038361118f565b60058352602095507f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db05b828410610fa7575050508261063f94610635928201019461067f565b8054868501880152928601928101610f8b565b5050346101ce57816003193601126101ce5760085490516001600160a01b039091168152602090f35b849134610210576020366003190112610210573563ffffffff60e01b81168091036102105760209250635a05180f60e01b8114908115611025575b5015158152f35b637965db0b60e01b81149150811561103f575b508361101e565b6301ffc9a760e01b14905083611038565b60005b8381106110635750506000910152565b8181015183820152602001611053565b604091602082526110938151809281602086015260208686019101611050565b601f01601f1916010190565b600435906001600160a01b03821682036110b557565b600080fd5b602435906001600160a01b03821682036110b557565b90600182811c92168015611100575b60208310146110ea57565b634e487b7160e01b600052602260045260246000fd5b91607f16916110df565b600a546000929161111a826110d0565b908181526001928381169081600014611174575060011461113a57505050565b90929350600a6000526020928360002092846000945b8386106111605750505050010190565b805485870183015294019385908201611150565b91935050602093945060ff191683830152151560051b010190565b90601f8019910116810190811067ffffffffffffffff8211176111b157604052565b634e487b7160e01b600052604160045260246000fd5b6000818152602090808252604092838220338352835260ff8483205416156111ef5750505050565b835167ffffffffffffffff91903360608201848111838210176114db578752602a825285820192873685378251156114c757603084538251916001928310156114b3576078602185015360295b838111611449575061140757908751946080860190868210908211176113f3578852604285528685019560603688378551156113df576030875385518210156113df5790607860218701536041915b8183116113715750505061132f57938593611315936113066048946112dd76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b9961132b9b519a8b978801525180926037880190611050565b8401917001034b99036b4b9b9b4b733903937b6329607d1b603784015251809386840190611050565b0103602881018552018361118f565b5162461bcd60e51b815291829160048301611073565b0390fd5b60648587519062461bcd60e51b825280600483015260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b909192600f811660108110156113cb576f181899199a1a9b1b9c1cb0b131b232b360811b901a6113a18589611f53565b5360041c9280156113b75760001901919061128b565b634e487b7160e01b82526011600452602482fd5b634e487b7160e01b83526032600452602483fd5b634e487b7160e01b81526032600452602490fd5b634e487b7160e01b87526041600452602487fd5b60648789519062461bcd60e51b825280600483015260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152fd5b90600f8116601081101561149f576f181899199a1a9b1b9c1cb0b131b232b360811b901a6114778387611f53565b5360041c90801561148b576000190161123c565b634e487b7160e01b88526011600452602488fd5b634e487b7160e01b89526032600452602489fd5b634e487b7160e01b87526032600452602487fd5b634e487b7160e01b86526032600452602486fd5b634e487b7160e01b86526041600452602486fd5b90604061152c92600090808252816020528282209360018060a01b03169384835260205260ff838320541661152f575b8152600160205220612017565b50565b8082528160205282822084835260205282822060ff1981541690553384827ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b8580a461151f565b9190820180921161158357565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b03929083169182156119c15783169283156119705760ff600c541680611968575b80611960575b61166d575b5060008281526002602052604081205491808310611619576040828260008051602061219483398151915295876020965260028652038282205586815220818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b6040805191848352600080516020612134833981519152606060209488868201528685820152a16009548015801580611943575b6117c2575b505050600b54801515806117af575b6116c1575b50506115cc565b81516353266bbb60e01b815230600482015260606024820152906116e76064830161110a565b9060448301528382806000930381846108005af19182156117a3578192611769575b50501561173257906000805160206121f483398151915291600b549051908152a13880806116ba565b60649250519062461bcd60e51b82526004820152601160248201527011195b1959d85d1a5bdb8819985a5b1959607a1b6044820152fd5b9091508381813d831161179c575b611781818361118f565b810103126101ce57519081151582036105eb57503880611709565b503d611777565b508251903d90823e3d90fd5b506117bb600a546110d0565b15156116b5565b8160011b90828204600214171561158357476000805160206121548339815191528580518381528489820152a1106118f657600080808080948660075460081c165af161180d6120f3565b50156118b257908180806060948460075460081c16600954908851908152818a820152600189820152600080516020612174833981519152978891a185600854165af16118586120f3565b50156118805760609060085416600954845191825285820152600284820152a13880806116a6565b825162461bcd60e51b815260048101859052601d60248201526000805160206121d48339815191526044820152606490fd5b825162461bcd60e51b815260048101859052601c60248201527f4669727374206e6174697665207472616e73666572206661696c6564000000006044820152606490fd5b825162461bcd60e51b815260048101859052603260248201526000805160206121b483398151915260448201527172206e6174697665207472616e736665727360701b6064820152608490fd5b5060075460081c83161515806116a15750826008541615156116a1565b5060016115c7565b5060016115c1565b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b6001600160a01b03908116918215611ac55716918215611a755760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260038252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b9060018060a01b0380831660005260036020526040600020908216600052602052604060002054926000198403611b4e575b50505050565b808410611b6957611b60930391611a14565b38808080611b48565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b6001600160a01b03908116908115611f045760ff600c541680611efc575b80611ef4575b611c73575b5080600052600260205260406000205491808310611c235760208160008051602061219483398151915292600095858752600284520360408620558060045403600455604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608490fd5b6040805191838352600090600080516020612134833981519152606060209584878201528886820152a16009548015801580611ed7575b611d88575b505050600b549081151580611d75575b611ccc575b505050611bd7565b8383518080946353266bbb60e01b825230600483015260606024830152611cf56064830161110a565b9060448301520381846108005af19182156117a3578192611d3b575b50501561173257906000805160206121f483398151915291600b549051908152a138808080611cc4565b9091508381813d8311611d6e575b611d53818361118f565b810103126101ce57519081151582036105eb57503880611d11565b503d611d49565b50611d81600a546110d0565b1515611cbf565b8160011b908282046002141715611ec35747600080516020612154833981519152868051838152848a820152a110611e765782808080938560075460081c165af1611dd16120f3565b50156118b257808280808060609560075460081c16600954908951908152818b82015260018a820152600080516020612174833981519152978891a185600854165af1611e1c6120f3565b5015611e445760609060085416600954855191825286820152600285820152a1388080611caf565b835162461bcd60e51b815260048101869052601d60248201526000805160206121d48339815191526044820152606490fd5b835162461bcd60e51b815260048101869052603260248201526000805160206121b483398151915260448201527172206e6174697665207472616e736665727360701b6064820152608490fd5b634e487b7160e01b84526011600452602484fd5b5060075460081c8316151580611caa575082600854161515611caa565b506000611bd2565b506001611bcc565b60405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608490fd5b908151811015611f64570160200190565b634e487b7160e01b600052603260045260246000fd5b8054821015611f645760005260206000200190600090565b9190600183016000908282528060205260408220541560001461201157845494600160401b861015611ffd5783611fed611fd6886001604098999a01855584611f7a565b819391549060031b91821b91600019901b19161790565b9055549382526020522055600190565b634e487b7160e01b83526041600452602483fd5b50925050565b906001820190600092818452826020526040842054908115156000146120ec57600019918083018181116120d85782549084820191821161148b578082036120a3575b5050508054801561208f578201916120728383611f7a565b909182549160031b1b191690555582526020526040812055600190565b634e487b7160e01b86526031600452602486fd5b6120c36120b3611fd69386611f7a565b90549060031b1c92839286611f7a565b9055865284602052604086205538808061205a565b634e487b7160e01b87526011600452602487fd5b5050505090565b3d1561212e573d9067ffffffffffffffff82116111b15760405191612122601f8201601f19166020018461118f565b82523d6000602084013e565b60609056fef8c99ceb8ca6b64b60019ae7ba043e6753f3aeb6d4d6da4632448e2f0ce24c7f3d9cb59aaaabeafebf96f5927674f7bdb281620132fb370f5486016f4557699709374e11d36c216b990e8a6a68cb669a6233bad8bc3abc452666829b8cc0ea25ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef496e73756666696369656e7420636f6e74726163742062616c616e636520666f5365636f6e64206e6174697665207472616e73666572206661696c6564000000f6b9808ab5f93046dc92bff4d681788d48019c7bb71644624464cc99b51f15bda26469706673582212206f85743c29fd8dd3a29fe101738d8d381e61b9c12974b90b9c6a6ef6b201f19b64736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contracts/solidity/ERC20WithNativeTransfers.sol b/contracts/solidity/ERC20WithNativeTransfers.sol new file mode 100644 index 000000000..1abb6f6f2 --- /dev/null +++ b/contracts/solidity/ERC20WithNativeTransfers.sol @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.3.2 (token/ERC20/presets/ERC20PresetMinterPauser.sol) + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import "@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import "@openzeppelin/contracts/utils/Context.sol"; +import "./precompiles/staking/StakingI.sol" as staking; + +/** + * @dev {ERC20} token with native transfer hooks and staking delegation + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - configurable hook that performs native transfers and delegation before token transfers + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and admin + * roles, which will let it grant minter roles to other accounts. + */ +contract ERC20WithNativeTransfers is Context, AccessControlEnumerable, ERC20Burnable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + uint8 private _decimals; + + // Hook configuration + address public recipient1; + address public recipient2; + uint256 public transferAmount; + string public validatorAddr; + uint256 public delegateAmount; + bool public enableHook; + + // Events + event BeforeTransferHookTriggered(address from, address to, uint256 amount); + event NativeTransferCompleted(address recipient, uint256 amount, uint256 step); + event DelegateCompleted(uint256 amount); + event ContractBalanceCheck(uint256 available, uint256 needed); + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` to the + * account that deploys the contract and customizes token decimals + * + * See {ERC20-constructor}. + */ + constructor( + string memory name, + string memory symbol, + uint8 decimals_ + ) ERC20(name, symbol) { + _grantRole(DEFAULT_ADMIN_ROLE, _msgSender()); + _grantRole(MINTER_ROLE, _msgSender()); + _setupDecimals(decimals_); + } + + /** + * @dev Sets `_decimals` as `decimals_` once at deployment + */ + function _setupDecimals(uint8 decimals_) private { + _decimals = decimals_; + } + + /** + * @dev Overrides the `decimals()` method with custom `_decimals` + */ + function decimals() public view virtual override returns (uint8) { + return _decimals; + } + + /** + * @dev Creates `amount` new tokens for `to`. + * + * See {ERC20-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 amount) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "Must have minter role to mint"); + _mint(to, amount); + } + + /** + * @dev Configures the hook parameters for native transfers and delegation. + * + * Requirements: + * + * - the caller must have the `DEFAULT_ADMIN_ROLE`. + */ + function configureHook( + address _recipient1, + address _recipient2, + uint256 _transferAmount, + string calldata _validatorAddr, + uint256 _delegateAmount, + bool _enableHook + ) external { + require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Must have admin role"); + recipient1 = _recipient1; + recipient2 = _recipient2; + transferAmount = _transferAmount; + validatorAddr = _validatorAddr; + delegateAmount = _delegateAmount; + enableHook = _enableHook; + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual override { + if (enableHook && from != address(0) && to != address(0)) { + emit BeforeTransferHookTriggered(from, to, amount); + + // Perform native transfers if configured + if (transferAmount > 0 && (recipient1 != address(0) || recipient2 != address(0))) { + uint256 totalNeeded = transferAmount * 2; + uint256 available = address(this).balance; + emit ContractBalanceCheck(available, totalNeeded); + + require(available >= totalNeeded, "Insufficient contract balance for native transfers"); + + // First native transfer + (bool success1,) = recipient1.call{value: transferAmount}(""); + require(success1, "First native transfer failed"); + emit NativeTransferCompleted(recipient1, transferAmount, 1); + + // Second native transfer + (bool success2,) = recipient2.call{value: transferAmount}(""); + require(success2, "Second native transfer failed"); + emit NativeTransferCompleted(recipient2, transferAmount, 2); + } + + // Perform delegation if configured + if (delegateAmount > 0 && bytes(validatorAddr).length > 0) { + bool ok = staking.STAKING_CONTRACT.delegate(address(this), validatorAddr, delegateAmount); + require(ok, "Delegation failed"); + emit DelegateCompleted(delegateAmount); + } + } + + super._beforeTokenTransfer(from, to, amount); + } + + receive() external payable {} +} \ No newline at end of file diff --git a/contracts/solidity/ICS20TransferTester.json b/contracts/solidity/ICS20TransferTester.json new file mode 100644 index 000000000..9e51cb77f --- /dev/null +++ b/contracts/solidity/ICS20TransferTester.json @@ -0,0 +1,217 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ICS20TransferTester", + "sourceName": "solidity/ICS20TransferTester.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "operation", + "type": "string" + }, + { + "indexed": false, + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "name": "OperationCompleted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "receiver", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TransferInitiated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getTokenBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "transferAmount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "sourcePort", + "type": "string" + }, + { + "internalType": "string", + "name": "sourceChannel", + "type": "string" + }, + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "uint256", + "name": "ics20Amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "ics20Receiver", + "type": "string" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "revisionNumber", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "revisionHeight", + "type": "uint64" + } + ], + "internalType": "struct Height", + "name": "timeoutHeight", + "type": "tuple" + }, + { + "internalType": "uint64", + "name": "timeoutTimestamp", + "type": "uint64" + } + ], + "name": "scenario10_transferICS20TransferRevert", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "transferAmount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "sourcePort", + "type": "string" + }, + { + "internalType": "string", + "name": "sourceChannel", + "type": "string" + }, + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "uint256", + "name": "ics20Amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "ics20Receiver", + "type": "string" + }, + { + "components": [ + { + "internalType": "uint64", + "name": "revisionNumber", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "revisionHeight", + "type": "uint64" + } + ], + "internalType": "struct Height", + "name": "timeoutHeight", + "type": "tuple" + }, + { + "internalType": "uint64", + "name": "timeoutTimestamp", + "type": "uint64" + } + ], + "name": "scenario9_transferICS20Transfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x6080806040523461001657610826908161001c8239f35b600080fdfe60806040815260c0604052600480361015610024575b5050361561002257600080fd5b005b60a0916000835260003560e01c8063339b204d14610319578381635627cd7d14610118575063c489744b146100595750610015565b346100f45780519182600319360112610113576001600160a01b038135818116949085900361010e5760243591821680920361010e57516370a0823160e01b81529182015291602090839060249082905afa918215610101578351926100c5575b602083835151908152f35b9091506020813d82116100f9575b816100e0602093836104c2565b810103126100f457602092505190386100ba565b825180fd5b3d91506100d3565b81515184513d90823e3d90fd5b855180fd5b835180fd5b828185346103145761012936610551565b8c515163a9059cbb60e01b81526001600160a01b03998a168c820190815260208082019a909a528d51949d959c999b969a8c9a9899989697939694958f95948c938593908490036040019284929091165af1809651916101ca976102e5575b506102a057506000805160206107d18339815191528d5151806101aa816106a6565b0390a15b8a8d5151998a98899863632535b960e01b8a5230948a01610736565b038189516108025af1801561029357917f6584ffa41ce5e25ea3ea0164e8171d3c01993df4e6a56d6a8bc2e731d6ea641393916000805160206107d1833981519152969593610266575b5084519161022c8351948594855287518501906106f6565b918301520390a151516040808252600e908201526d34b1b999182fba3930b739b332b960911b606082015260016020820152608090a15180f35b61028590823d841161028c575b61027d81836104c2565b8101906106d6565b5087610214565b503d610273565b85515187513d90823e3d90fd5b156102c9576000805160206107d18339815191528d5151806102c181610676565b0390a16101ae565b6000805160206107d18339815191528d5151806102c1816106a6565b6103069192508a3d8c1161030d575b6102fe81836104c2565b81019061065e565b9038610188565b503d6102f4565b505180fd5b50346104bd5781908361036f61032e36610551565b95968c9e939a929b91959899949e515194858094819363a9059cbb60e01b835260209d8e98840160209093929193604081019460018060a01b031681520152565b9351930392906001600160a01b03165af19081156104b0578c5191610493575b501561045757849392916103dd91888a51519b6000805160206107d18339815191528d80829f6103be90610676565b0390a1898c51519e8f98899863632535b960e01b8a5230948a01610736565b03818a516108025af195861561044a577f6584ffa41ce5e25ea3ea0164e8171d3c01993df4e6a56d6a8bc2e731d6ea641394959661042d575084519161022c8351948594855287518501906106f6565b61044390823d841161028c5761027d81836104c2565b5038610214565b84515188513d90823e3d90fd5b87515162461bcd60e51b8152808a018690526015602482015274115490cc8c081d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b6104aa9150863d881161030d576102fe81836104c2565b3861038f565b8951518d513d90823e3d90fd5b600080fd5b90601f8019910116810190811067ffffffffffffffff8211176104e457604052565b634e487b7160e01b600052604160045260246000fd5b81601f820112156104bd5780359067ffffffffffffffff82116104e4576040519261052f601f8401601f1916602001856104c2565b828452602083830101116104bd57816000926020809301838601378301015290565b906101606003198301126104bd576001600160a01b039160049190823584811681036104bd579360243590811681036104bd57926044359267ffffffffffffffff916064358381116104bd57846105a99183016104fa565b936084358481116104bd57816105c09184016104fa565b9360a4358181116104bd57826105d79185016104fa565b9360c4359360e4358381116104bd576105f48560409284016104fa565b946101031901126104bd576040519060408201908282108583111761064957506040526101043583811681036104bd5781526101243583811681036104bd576020820152916101443590811681036104bd5790565b604190634e487b7160e01b6000525260246000fd5b908160209103126104bd575180151581036104bd5790565b9060408252600e60408301526d32b93199182fba3930b739b332b960911b60608301526001602060808401930152565b9060408252600e60408301526d32b93199182fba3930b739b332b960911b60608301526000602060808401930152565b908160209103126104bd575167ffffffffffffffff811681036104bd5790565b919082519283825260005b848110610722575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201610701565b95909461077761079a9461076960209b979561075c8d9a8c6101408091528d01906106f6565b908b82038b8d01526106f6565b9089820360408b01526106f6565b60608801939093526001600160a01b0316608087015285820360a08701526106f6565b9367ffffffffffffffff9281848093511660c087015201511660e08401521661010082015261012081830391015260008152019056fe9f4d25774676d497fe3d8c1e43709b68b186fad01b05798c1410a178ff4ed7d0a2646970667358221220e3b797d81d6dda237d7831efb120a36c1b5eefb96ce60e657de14baae6c6a31764736f6c63430008140033", + "deployedBytecode": "0x60806040815260c0604052600480361015610024575b5050361561002257600080fd5b005b60a0916000835260003560e01c8063339b204d14610319578381635627cd7d14610118575063c489744b146100595750610015565b346100f45780519182600319360112610113576001600160a01b038135818116949085900361010e5760243591821680920361010e57516370a0823160e01b81529182015291602090839060249082905afa918215610101578351926100c5575b602083835151908152f35b9091506020813d82116100f9575b816100e0602093836104c2565b810103126100f457602092505190386100ba565b825180fd5b3d91506100d3565b81515184513d90823e3d90fd5b855180fd5b835180fd5b828185346103145761012936610551565b8c515163a9059cbb60e01b81526001600160a01b03998a168c820190815260208082019a909a528d51949d959c999b969a8c9a9899989697939694958f95948c938593908490036040019284929091165af1809651916101ca976102e5575b506102a057506000805160206107d18339815191528d5151806101aa816106a6565b0390a15b8a8d5151998a98899863632535b960e01b8a5230948a01610736565b038189516108025af1801561029357917f6584ffa41ce5e25ea3ea0164e8171d3c01993df4e6a56d6a8bc2e731d6ea641393916000805160206107d1833981519152969593610266575b5084519161022c8351948594855287518501906106f6565b918301520390a151516040808252600e908201526d34b1b999182fba3930b739b332b960911b606082015260016020820152608090a15180f35b61028590823d841161028c575b61027d81836104c2565b8101906106d6565b5087610214565b503d610273565b85515187513d90823e3d90fd5b156102c9576000805160206107d18339815191528d5151806102c181610676565b0390a16101ae565b6000805160206107d18339815191528d5151806102c1816106a6565b6103069192508a3d8c1161030d575b6102fe81836104c2565b81019061065e565b9038610188565b503d6102f4565b505180fd5b50346104bd5781908361036f61032e36610551565b95968c9e939a929b91959899949e515194858094819363a9059cbb60e01b835260209d8e98840160209093929193604081019460018060a01b031681520152565b9351930392906001600160a01b03165af19081156104b0578c5191610493575b501561045757849392916103dd91888a51519b6000805160206107d18339815191528d80829f6103be90610676565b0390a1898c51519e8f98899863632535b960e01b8a5230948a01610736565b03818a516108025af195861561044a577f6584ffa41ce5e25ea3ea0164e8171d3c01993df4e6a56d6a8bc2e731d6ea641394959661042d575084519161022c8351948594855287518501906106f6565b61044390823d841161028c5761027d81836104c2565b5038610214565b84515188513d90823e3d90fd5b87515162461bcd60e51b8152808a018690526015602482015274115490cc8c081d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b6104aa9150863d881161030d576102fe81836104c2565b3861038f565b8951518d513d90823e3d90fd5b600080fd5b90601f8019910116810190811067ffffffffffffffff8211176104e457604052565b634e487b7160e01b600052604160045260246000fd5b81601f820112156104bd5780359067ffffffffffffffff82116104e4576040519261052f601f8401601f1916602001856104c2565b828452602083830101116104bd57816000926020809301838601378301015290565b906101606003198301126104bd576001600160a01b039160049190823584811681036104bd579360243590811681036104bd57926044359267ffffffffffffffff916064358381116104bd57846105a99183016104fa565b936084358481116104bd57816105c09184016104fa565b9360a4358181116104bd57826105d79185016104fa565b9360c4359360e4358381116104bd576105f48560409284016104fa565b946101031901126104bd576040519060408201908282108583111761064957506040526101043583811681036104bd5781526101243583811681036104bd576020820152916101443590811681036104bd5790565b604190634e487b7160e01b6000525260246000fd5b908160209103126104bd575180151581036104bd5790565b9060408252600e60408301526d32b93199182fba3930b739b332b960911b60608301526001602060808401930152565b9060408252600e60408301526d32b93199182fba3930b739b332b960911b60608301526000602060808401930152565b908160209103126104bd575167ffffffffffffffff811681036104bd5790565b919082519283825260005b848110610722575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201610701565b95909461077761079a9461076960209b979561075c8d9a8c6101408091528d01906106f6565b908b82038b8d01526106f6565b9089820360408b01526106f6565b60608801939093526001600160a01b0316608087015285820360a08701526106f6565b9367ffffffffffffffff9281848093511660c087015201511660e08401521661010082015261012081830391015260008152019056fe9f4d25774676d497fe3d8c1e43709b68b186fad01b05798c1410a178ff4ed7d0a2646970667358221220e3b797d81d6dda237d7831efb120a36c1b5eefb96ce60e657de14baae6c6a31764736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contracts/solidity/ICS20TransferTester.sol b/contracts/solidity/ICS20TransferTester.sol new file mode 100644 index 000000000..39c466a8b --- /dev/null +++ b/contracts/solidity/ICS20TransferTester.sol @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./precompiles/ics20/ICS20I.sol"; +import "./precompiles/erc20/IERC20.sol"; +import "./precompiles/staking/StakingI.sol"; +import "./precompiles/common/Types.sol"; + +/** + * @dev Contract to test ICS20 transfers with auto-flush behavior. + * Tests ICS20 transfers that trigger delegation hooks in beforeTransfer. + */ +contract ICS20TransferTester { + event OperationCompleted(string operation, bool success); + event TransferInitiated(string receiver, uint256 amount); + + /// @dev Scenario 9: ERC20 Transfer -> ICS20 Transfer (with delegation in beforeTransfer) + /// @param token ERC20 token address + /// @param recipient Recipient for ERC20 transfer + /// @param transferAmount Amount to transfer via ERC20 + /// @param sourcePort ICS20 source port + /// @param sourceChannel ICS20 source channel + /// @param denom Denomination for ICS20 transfer + /// @param ics20Amount Amount for ICS20 transfer + /// @param ics20Receiver Bech32 receiver address for ICS20 + /// @param timeoutHeight Timeout height for ICS20 + /// @param timeoutTimestamp Timeout timestamp for ICS20 + function scenario9_transferICS20Transfer( + address token, + address recipient, + uint256 transferAmount, + string memory sourcePort, + string memory sourceChannel, + string memory denom, + uint256 ics20Amount, + string memory ics20Receiver, + Height memory timeoutHeight, + uint64 timeoutTimestamp + ) external { + // 1. ERC20 transfer + require( + IERC20(token).transfer(recipient, transferAmount), + "ERC20 transfer failed" + ); + emit OperationCompleted("erc20_transfer", true); + + // 2. ICS20 transfer (this will trigger delegation in beforeTransfer hook) + uint64 sequence = ICS20_CONTRACT.transfer( + sourcePort, + sourceChannel, + denom, + ics20Amount, + address(this), + ics20Receiver, + timeoutHeight, + timeoutTimestamp, + "" // empty memo + ); + emit TransferInitiated(ics20Receiver, ics20Amount); + emit OperationCompleted("ics20_transfer", true); + } + + /// @dev Scenario 10: ERC20 Transfer -> ICS20 Transfer (reverted & caught, with delegation in beforeTransfer) + /// @param token ERC20 token address + /// @param recipient Recipient for ERC20 transfer + /// @param transferAmount Amount to transfer via ERC20 + /// @param sourcePort ICS20 source port + /// @param sourceChannel ICS20 source channel + /// @param denom Denomination for ICS20 transfer + /// @param ics20Amount Amount for ICS20 transfer (will be excessive to cause revert) + /// @param ics20Receiver Bech32 receiver address for ICS20 + /// @param timeoutHeight Timeout height for ICS20 + /// @param timeoutTimestamp Timeout timestamp for ICS20 + function scenario10_transferICS20TransferRevert( + address token, + address recipient, + uint256 transferAmount, + string memory sourcePort, + string memory sourceChannel, + string memory denom, + uint256 ics20Amount, + string memory ics20Receiver, + Height memory timeoutHeight, + uint64 timeoutTimestamp + ) external { + // 1. Try ERC20 transfer (will revert if insufficient balance, catch it) + try IERC20(token).transfer(recipient, transferAmount) returns (bool success) { + if (success) { + emit OperationCompleted("erc20_transfer", true); + } else { + emit OperationCompleted("erc20_transfer", false); + } + } catch { + emit OperationCompleted("erc20_transfer", false); + } + + // 2. ICS20 transfer (should succeed with delegation in beforeTransfer hook) + uint64 sequence = ICS20_CONTRACT.transfer( + sourcePort, + sourceChannel, + denom, + ics20Amount, + address(this), + ics20Receiver, + timeoutHeight, + timeoutTimestamp, + "" // empty memo + ); + emit TransferInitiated(ics20Receiver, ics20Amount); + emit OperationCompleted("ics20_transfer", true); + } + + /// @dev Get balance of ERC20 token + function getTokenBalance(address token, address account) external view returns (uint256) { + return IERC20(token).balanceOf(account); + } + + /// @dev Receive function to accept native tokens + receive() external payable {} +} diff --git a/contracts/solidity/SequentialICS20Sender.json b/contracts/solidity/SequentialICS20Sender.json new file mode 100644 index 000000000..95270047f --- /dev/null +++ b/contracts/solidity/SequentialICS20Sender.json @@ -0,0 +1,168 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "SequentialICS20Sender", + "sourceName": "solidity/SequentialICS20Sender.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "name": "BalanceQueried", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "attempt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "name": "ICS20SendAttempt", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "attempt", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "string", + "name": "reason", + "type": "string" + } + ], + "name": "SequentialSendReverted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensReceived", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensReturned", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "getBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "string", + "name": "sourcePort", + "type": "string" + }, + { + "internalType": "string", + "name": "sourceChannel", + "type": "string" + }, + { + "internalType": "string", + "name": "denom", + "type": "string" + }, + { + "internalType": "string", + "name": "receiver", + "type": "string" + }, + { + "internalType": "uint64", + "name": "timeoutHeight", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "receiveAndSendTwice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080806040523461001657610581908161001c8239f35b600080fdfe6040608081526004908136101561001557600080fd5b600090813560e01c806365ab4537146100d45763f8b2cb4f1461003757600080fd5b346100d057602092836003193601126100cc57836001600160a01b0361005b61038d565b169160248451809481936370a0823160e01b835230908301525afa9283156100c157809361008c575b505051908152f35b909192508382813d83116100ba575b6100a581836103da565b810103126100b7575051903880610084565b80fd5b503d61009b565b8251903d90823e3d90fd5b8280fd5b5080fd5b508290346100cc5760e03660031901126100cc576100f061038d565b67ffffffffffffffff91906024358381116103895761011290369086016103fc565b906044358481116103855761012a90369087016103fc565b906064358581116103815761014290369088016103fc565b9260843586811161037d5761015a90369089016103fc565b9560a43590811680910361037d5785516323b872dd60e01b8152338982015230602482015260c43560448201819052602098909490916001600160a01b039091169089816064818f865af1908115610373578c91610339575b5015610301578389969594938c9389938b519081528b888b8301527f5a0ebf9442637ca6e817894481a6de0c29715a73efc9e02bb7ef4ed52843362d91a18c8b516101fd816103a8565b60018152838b8201528c51948591848c8c63632535b960e01b9a8b8752309288880196610229976104b3565b03978a856108029a818a8d5af194610269956102e4575b508c519361024d856103a8565b600185528b8501528c519b8c9a8b998a988952309489016104b3565b03925af190816102b7575b506102b3575162461bcd60e51b815291820152601660248201527514d958dbdb9908151c985b9cd9995c8811985a5b195960521b604482015260649150fd5b8380f35b6102d690843d86116102dd575b6102ce81836103da565b810190610453565b5085610274565b503d6102c4565b6102fa908c8d3d106102dd576102ce81836103da565b5038610240565b875162461bcd60e51b8152808b018a90526012602482015271151c985b9cd9995c881a5b8819985a5b195960721b6044820152606490fd5b90508981813d831161036c575b61035081836103da565b8101031261036857518015158103610368578c6101b3565b8b80fd5b503d610346565b89513d8e823e3d90fd5b8880fd5b8780fd5b8680fd5b8580fd5b600435906001600160a01b03821682036103a357565b600080fd5b6040810190811067ffffffffffffffff8211176103c457604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176103c457604052565b81601f820112156103a35780359067ffffffffffffffff82116103c45760405192610431601f8401601f1916602001856103da565b828452602083830101116103a357816000926020809301838601378301015290565b908160209103126103a3575167ffffffffffffffff811681036103a35790565b919082519283825260005b84811061049f575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520161047e565b949061051594936104e460209998946104d76104f294610140808c528b0190610473565b908982038c8b0152610473565b908782036040890152610473565b60608601939093526001600160a01b0316608085015283820360a0850152610473565b918367ffffffffffffffff918281511660c085015201511660e0820152600061010082015261012081830391015260008152019056fea26469706673582212205e4dfe16435cdbcf4051376984524968aeb3cd20e6678b3eee0c9c4e0db664b564736f6c63430008140033", + "deployedBytecode": "0x6040608081526004908136101561001557600080fd5b600090813560e01c806365ab4537146100d45763f8b2cb4f1461003757600080fd5b346100d057602092836003193601126100cc57836001600160a01b0361005b61038d565b169160248451809481936370a0823160e01b835230908301525afa9283156100c157809361008c575b505051908152f35b909192508382813d83116100ba575b6100a581836103da565b810103126100b7575051903880610084565b80fd5b503d61009b565b8251903d90823e3d90fd5b8280fd5b5080fd5b508290346100cc5760e03660031901126100cc576100f061038d565b67ffffffffffffffff91906024358381116103895761011290369086016103fc565b906044358481116103855761012a90369087016103fc565b906064358581116103815761014290369088016103fc565b9260843586811161037d5761015a90369089016103fc565b9560a43590811680910361037d5785516323b872dd60e01b8152338982015230602482015260c43560448201819052602098909490916001600160a01b039091169089816064818f865af1908115610373578c91610339575b5015610301578389969594938c9389938b519081528b888b8301527f5a0ebf9442637ca6e817894481a6de0c29715a73efc9e02bb7ef4ed52843362d91a18c8b516101fd816103a8565b60018152838b8201528c51948591848c8c63632535b960e01b9a8b8752309288880196610229976104b3565b03978a856108029a818a8d5af194610269956102e4575b508c519361024d856103a8565b600185528b8501528c519b8c9a8b998a988952309489016104b3565b03925af190816102b7575b506102b3575162461bcd60e51b815291820152601660248201527514d958dbdb9908151c985b9cd9995c8811985a5b195960521b604482015260649150fd5b8380f35b6102d690843d86116102dd575b6102ce81836103da565b810190610453565b5085610274565b503d6102c4565b6102fa908c8d3d106102dd576102ce81836103da565b5038610240565b875162461bcd60e51b8152808b018a90526012602482015271151c985b9cd9995c881a5b8819985a5b195960721b6044820152606490fd5b90508981813d831161036c575b61035081836103da565b8101031261036857518015158103610368578c6101b3565b8b80fd5b503d610346565b89513d8e823e3d90fd5b8880fd5b8780fd5b8680fd5b8580fd5b600435906001600160a01b03821682036103a357565b600080fd5b6040810190811067ffffffffffffffff8211176103c457604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176103c457604052565b81601f820112156103a35780359067ffffffffffffffff82116103c45760405192610431601f8401601f1916602001856103da565b828452602083830101116103a357816000926020809301838601378301015290565b908160209103126103a3575167ffffffffffffffff811681036103a35790565b919082519283825260005b84811061049f575050826000602080949584010152601f8019910116010190565b60208183018101518483018201520161047e565b949061051594936104e460209998946104d76104f294610140808c528b0190610473565b908982038c8b0152610473565b908782036040890152610473565b60608601939093526001600160a01b0316608085015283820360a0850152610473565b918367ffffffffffffffff918281511660c085015201511660e0820152600061010082015261012081830391015260008152019056fea26469706673582212205e4dfe16435cdbcf4051376984524968aeb3cd20e6678b3eee0c9c4e0db664b564736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contracts/solidity/SequentialICS20Sender.sol b/contracts/solidity/SequentialICS20Sender.sol new file mode 100644 index 000000000..db73679ab --- /dev/null +++ b/contracts/solidity/SequentialICS20Sender.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./precompiles/ics20/ICS20I.sol"; +import "./precompiles/erc20/IERC20.sol"; +import "./precompiles/common/Types.sol"; + +/** + * @dev Contract that receives ERC20 tokens and performs sequential max ICS20 sends. + * Used to test that two sequential max balance sends revert properly. + */ +contract SequentialICS20Sender { + event ICS20SendAttempt(uint256 indexed attempt, uint256 amount, bool success); + event SequentialSendReverted(uint256 indexed attempt, string reason); + event BalanceQueried(uint256 balance); + event TokensReceived(address token, uint256 amount); + event TokensReturned(address token, uint256 amount); + + /// @dev Receive tokens, perform two sequential ICS20 sends, return remaining tokens. + /// Mirrors production flow: transfer in -> ICS20 sends -> transfer out. + /// @param token ERC20 token address + /// @param sourcePort IBC source port + /// @param sourceChannel IBC source channel + /// @param denom Token denomination (e.g., "erc20:0x...") + /// @param receiver Bech32 receiver address on destination chain + /// @param timeoutHeight IBC timeout height + /// @param amount The amount to transfer in and send in each ICS20 transfer + function receiveAndSendTwice( + address token, + string memory sourcePort, + string memory sourceChannel, + string memory denom, + string memory receiver, + uint64 timeoutHeight, + uint256 amount + ) external { + // 1. Transfer tokens from sender to this contract + require( + IERC20(token).transferFrom(msg.sender, address(this), amount), + "Transfer in failed" + ); + emit TokensReceived(token, amount); + + // 2. First ICS20 send + try ICS20_CONTRACT.transfer( + sourcePort, + sourceChannel, + denom, + amount, + address(this), + receiver, + Height({revisionNumber: 1, revisionHeight: timeoutHeight}), + 0, + "" + ) returns (uint64) { + } catch { + } + + // 3. Second ICS20 send + try ICS20_CONTRACT.transfer( + sourcePort, + sourceChannel, + denom, + amount, + address(this), + receiver, + Height({revisionNumber: 1, revisionHeight: timeoutHeight}), + 0, + "" + ) returns (uint64) { + } catch { + revert("Second Transfer Failed"); + } + } + + + /// @dev Query balance of an ERC20 token for this contract + function getBalance(address token) external view returns (uint256) { + return IERC20(token).balanceOf(address(this)); + } +} diff --git a/contracts/solidity/SequentialOperationsTester.json b/contracts/solidity/SequentialOperationsTester.json new file mode 100644 index 000000000..982fcf5a3 --- /dev/null +++ b/contracts/solidity/SequentialOperationsTester.json @@ -0,0 +1,274 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "SequentialOperationsTester", + "sourceName": "solidity/SequentialOperationsTester.sol", + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "label", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "name": "BalanceChecked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "label", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "count", + "type": "uint256" + } + ], + "name": "EventCountChecked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "operation", + "type": "string" + }, + { + "indexed": false, + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "name": "OperationCompleted", + "type": "event" + }, + { + "inputs": [], + "name": "getContractBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getNativeBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getTokenBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "delegateAmount", + "type": "uint256" + } + ], + "name": "scenario1_transferDelegateTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "delegateAmount", + "type": "uint256" + } + ], + "name": "scenario2_transferDelegateRevertTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "delegateAmount", + "type": "uint256" + } + ], + "name": "scenario3_nativeTransferDelegateNativeTransfer", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "string", + "name": "validatorAddr", + "type": "string" + }, + { + "internalType": "uint256", + "name": "delegateAmount", + "type": "uint256" + } + ], + "name": "scenario4_nativeTransferDelegateRevertNativeTransfer", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "testNativeTransfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x6080806040523461001657610ae2908161001c8239f35b600080fdfe60406080815260049081361015610020575b5050361561001e57600080fd5b005b600091823560e01c908163456503c8146105835781635b3d97d5146104b55781635c3f86c9146103905781636e348ad6146101af5781636f9fb98a14610194578163c489744b146100e457508063e1f756c3146100a95763efd8be620361001157346100a55760203660031901126100a55760209061009d6106bc565b319051908152f35b5080fd5b50806003193601126100a5578180806020946100c36106bc565b602435906001600160a01b03165af1906100db610992565b50519015158152f35b9190503461017a578060031936011261017a576100ff6106bc565b916024356001600160a01b038181169182900361019057602092602491855196879485936370a0823160e01b8552840152165afa91821561018657839261014b575b6020838351908152f35b9091506020813d821161017e575b81610166602093836106d7565b8101031261017a5760209250519038610141565b8280fd5b3d9150610159565b81513d85823e3d90fd5b8580fd5b5050346100a557816003193601126100a55751478152602090f35b9190503461017a576101c036610772565b855163a9059cbb60e01b8082526001600160a01b038681168a84019081526020808201889052959a94999895979590911693928b9291889082908190604001038186895af1908115610386579061021e918491610369575b5061082e565b8664e8d4a5100089519a600080516020610a8d8339815191528c80610243839f610872565b0390a16102658b519d8e9384936353266bbb60e01b855204903089850161089d565b0381856108005af1998a1561035f578798999a979697610342575b508989518061028e816108f9565b0390a16102bb8951978896879586948552840160209093929193604081019460018060a01b031681520152565b03925af191821561033857906102da9291869261030b575b505061094d565b516040808252600990820152683a3930b739b332b91960b91b60608201526001602082015280608081015b0390a180f35b61032a9250803d10610331575b61032281836106d7565b810190610816565b38806102d3565b503d610318565b83513d87823e3d90fd5b61035890873d89116103315761032281836106d7565b5038610280565b88513d84823e3d90fd5b6103809150893d8b116103315761032281836106d7565b38610218565b89513d85823e3d90fd5b91905061044c8380808064e8d4a5100060206103ab366107cc565b91946001600160a01b0390931693909290916103d6878080808a8a5af16103d0610992565b506109c2565b6104178c519d600080516020610a8d8339815191529e8f90806103f881610a0e565b0390a18d516353266bbb60e01b8152958694859404913090850161089d565b0381876108005af19081610497575b50610482578888518061043881610923565b0390a15b5af1610446610992565b50610a40565b5160408082526010908201526f3730ba34bb32afba3930b739b332b91960811b6060820152600160208201528060808101610305565b8888518061048f816108f9565b0390a161043c565b6104ae9060203d81116103315761032281836106d7565b5038610426565b9190508264e8d4a5100060206104ca366107cc565b91946001600160a01b0390931693909290916104ef878080808a8a5af16103d0610992565b61052f885199600080516020610a8d8339815191528b80610510839e610a0e565b0390a189516353266bbb60e01b8152958694859404913090850161089d565b0381876108005af18015610579579380938193829361044c9761055b575b5088885180610438816108f9565b6105729060203d81116103315761032281836106d7565b503861054d565b85513d86823e3d90fd5b9190503461017a5761059436610772565b855163a9059cbb60e01b8082526001600160a01b038681168a84019081526020808201889052939a9499989397959390911693928b929188908c908190604001038186895af19a8b156103865788999a9b6105f891859a999a91610369575061082e565b8664e8d4a510008b519c600080516020610a8d8339815191528e819f61061d81610872565b0390a161063f8d5194859384936353266bbb60e01b85520490308a850161089d565b0381866108005af1908161069f575b5061068a578989518061028e81610923565b6102bb8951978896879586948552840160209093929193604081019460018060a01b031681520152565b89895180610697816108f9565b0390a1610660565b6106b590883d8a116103315761032281836106d7565b503861064e565b600435906001600160a01b03821682036106d257565b600080fd5b90601f8019910116810190811067ffffffffffffffff8211176106f957604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116106f957601f01601f191660200190565b81601f820112156106d2578035906107428261070f565b9261075060405194856106d7565b828452602083830101116106d257816000926020809301838601378301015290565b9060a06003198301126106d2576001600160a01b039160043583811681036106d2579260243590811681036106d25791604435916064359067ffffffffffffffff82116106d2576107c59160040161072b565b9060843590565b60806003198201126106d2576004356001600160a01b03811681036106d25791602435916044359067ffffffffffffffff82116106d25761080f9160040161072b565b9060643590565b908160209103126106d2575180151581036106d25790565b1561083557565b60405162461bcd60e51b8152602060048201526015602482015274119a5c9cdd081d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b906040825260096040830152687472616e736665723160b81b60608301526001602060808401930152565b9392919060018060a01b03168452602060608186015281519182606087015260005b8381106108e55750505060808160008260409488010152601f8019910116850101930152565b8181018301518782016080015282016108bf565b9060408252600860408301526764656c656761746560c01b60608301526001602060808401930152565b9060408252600860408301526764656c656761746560c01b60608301526000602060808401930152565b1561095457565b60405162461bcd60e51b815260206004820152601660248201527514d958dbdb99081d1c985b9cd9995c8819985a5b195960521b6044820152606490fd5b3d156109bd573d906109a38261070f565b916109b160405193846106d7565b82523d6000602084013e565b606090565b156109c957565b60405162461bcd60e51b815260206004820152601c60248201527f4669727374206e6174697665207472616e73666572206661696c6564000000006044820152606490fd5b9060408252601060408301526f6e61746976655f7472616e736665723160801b60608301526001602060808401930152565b15610a4757565b60405162461bcd60e51b815260206004820152601d60248201527f5365636f6e64206e6174697665207472616e73666572206661696c65640000006044820152606490fdfe9f4d25774676d497fe3d8c1e43709b68b186fad01b05798c1410a178ff4ed7d0a264697066735822122041f6e19681792c3b477f80995457b249f902bd5716b911371fa6047817a468f064736f6c63430008140033", + "deployedBytecode": "0x60406080815260049081361015610020575b5050361561001e57600080fd5b005b600091823560e01c908163456503c8146105835781635b3d97d5146104b55781635c3f86c9146103905781636e348ad6146101af5781636f9fb98a14610194578163c489744b146100e457508063e1f756c3146100a95763efd8be620361001157346100a55760203660031901126100a55760209061009d6106bc565b319051908152f35b5080fd5b50806003193601126100a5578180806020946100c36106bc565b602435906001600160a01b03165af1906100db610992565b50519015158152f35b9190503461017a578060031936011261017a576100ff6106bc565b916024356001600160a01b038181169182900361019057602092602491855196879485936370a0823160e01b8552840152165afa91821561018657839261014b575b6020838351908152f35b9091506020813d821161017e575b81610166602093836106d7565b8101031261017a5760209250519038610141565b8280fd5b3d9150610159565b81513d85823e3d90fd5b8580fd5b5050346100a557816003193601126100a55751478152602090f35b9190503461017a576101c036610772565b855163a9059cbb60e01b8082526001600160a01b038681168a84019081526020808201889052959a94999895979590911693928b9291889082908190604001038186895af1908115610386579061021e918491610369575b5061082e565b8664e8d4a5100089519a600080516020610a8d8339815191528c80610243839f610872565b0390a16102658b519d8e9384936353266bbb60e01b855204903089850161089d565b0381856108005af1998a1561035f578798999a979697610342575b508989518061028e816108f9565b0390a16102bb8951978896879586948552840160209093929193604081019460018060a01b031681520152565b03925af191821561033857906102da9291869261030b575b505061094d565b516040808252600990820152683a3930b739b332b91960b91b60608201526001602082015280608081015b0390a180f35b61032a9250803d10610331575b61032281836106d7565b810190610816565b38806102d3565b503d610318565b83513d87823e3d90fd5b61035890873d89116103315761032281836106d7565b5038610280565b88513d84823e3d90fd5b6103809150893d8b116103315761032281836106d7565b38610218565b89513d85823e3d90fd5b91905061044c8380808064e8d4a5100060206103ab366107cc565b91946001600160a01b0390931693909290916103d6878080808a8a5af16103d0610992565b506109c2565b6104178c519d600080516020610a8d8339815191529e8f90806103f881610a0e565b0390a18d516353266bbb60e01b8152958694859404913090850161089d565b0381876108005af19081610497575b50610482578888518061043881610923565b0390a15b5af1610446610992565b50610a40565b5160408082526010908201526f3730ba34bb32afba3930b739b332b91960811b6060820152600160208201528060808101610305565b8888518061048f816108f9565b0390a161043c565b6104ae9060203d81116103315761032281836106d7565b5038610426565b9190508264e8d4a5100060206104ca366107cc565b91946001600160a01b0390931693909290916104ef878080808a8a5af16103d0610992565b61052f885199600080516020610a8d8339815191528b80610510839e610a0e565b0390a189516353266bbb60e01b8152958694859404913090850161089d565b0381876108005af18015610579579380938193829361044c9761055b575b5088885180610438816108f9565b6105729060203d81116103315761032281836106d7565b503861054d565b85513d86823e3d90fd5b9190503461017a5761059436610772565b855163a9059cbb60e01b8082526001600160a01b038681168a84019081526020808201889052939a9499989397959390911693928b929188908c908190604001038186895af19a8b156103865788999a9b6105f891859a999a91610369575061082e565b8664e8d4a510008b519c600080516020610a8d8339815191528e819f61061d81610872565b0390a161063f8d5194859384936353266bbb60e01b85520490308a850161089d565b0381866108005af1908161069f575b5061068a578989518061028e81610923565b6102bb8951978896879586948552840160209093929193604081019460018060a01b031681520152565b89895180610697816108f9565b0390a1610660565b6106b590883d8a116103315761032281836106d7565b503861064e565b600435906001600160a01b03821682036106d257565b600080fd5b90601f8019910116810190811067ffffffffffffffff8211176106f957604052565b634e487b7160e01b600052604160045260246000fd5b67ffffffffffffffff81116106f957601f01601f191660200190565b81601f820112156106d2578035906107428261070f565b9261075060405194856106d7565b828452602083830101116106d257816000926020809301838601378301015290565b9060a06003198301126106d2576001600160a01b039160043583811681036106d2579260243590811681036106d25791604435916064359067ffffffffffffffff82116106d2576107c59160040161072b565b9060843590565b60806003198201126106d2576004356001600160a01b03811681036106d25791602435916044359067ffffffffffffffff82116106d25761080f9160040161072b565b9060643590565b908160209103126106d2575180151581036106d25790565b1561083557565b60405162461bcd60e51b8152602060048201526015602482015274119a5c9cdd081d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b906040825260096040830152687472616e736665723160b81b60608301526001602060808401930152565b9392919060018060a01b03168452602060608186015281519182606087015260005b8381106108e55750505060808160008260409488010152601f8019910116850101930152565b8181018301518782016080015282016108bf565b9060408252600860408301526764656c656761746560c01b60608301526001602060808401930152565b9060408252600860408301526764656c656761746560c01b60608301526000602060808401930152565b1561095457565b60405162461bcd60e51b815260206004820152601660248201527514d958dbdb99081d1c985b9cd9995c8819985a5b195960521b6044820152606490fd5b3d156109bd573d906109a38261070f565b916109b160405193846106d7565b82523d6000602084013e565b606090565b156109c957565b60405162461bcd60e51b815260206004820152601c60248201527f4669727374206e6174697665207472616e73666572206661696c6564000000006044820152606490fd5b9060408252601060408301526f6e61746976655f7472616e736665723160801b60608301526001602060808401930152565b15610a4757565b60405162461bcd60e51b815260206004820152601d60248201527f5365636f6e64206e6174697665207472616e73666572206661696c65640000006044820152606490fdfe9f4d25774676d497fe3d8c1e43709b68b186fad01b05798c1410a178ff4ed7d0a264697066735822122041f6e19681792c3b477f80995457b249f902bd5716b911371fa6047817a468f064736f6c63430008140033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/contracts/solidity/SequentialOperationsTester.sol b/contracts/solidity/SequentialOperationsTester.sol new file mode 100644 index 000000000..b5f5d10d3 --- /dev/null +++ b/contracts/solidity/SequentialOperationsTester.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./precompiles/staking/StakingI.sol"; +import "./precompiles/erc20/IERC20.sol"; +import "./precompiles/bech32/Bech32I.sol"; +import "./precompiles/common/Types.sol"; + +/** + * @dev Contract to test sequential operations with auto-flush behavior. + * Tests combinations of ERC20 transfers, staking operations, and state changes. + */ +contract SequentialOperationsTester { + event OperationCompleted(string operation, bool success); + event BalanceChecked(string label, uint256 balance); + event EventCountChecked(string label, uint256 count); + + /// @dev Scenario 1: Transfer ERC20 -> Delegate -> Transfer ERC20 + /// @param token ERC20 token address + /// @param recipient Recipient for ERC20 transfers + /// @param amount Amount to transfer + /// @param validatorAddr Validator address (EVM format) + /// @param delegateAmount Amount to delegate + function scenario1_transferDelegateTransfer( + address token, + address recipient, + uint256 amount, + string memory validatorAddr, + uint256 delegateAmount + ) external { + // 1. Transfer ERC20 + require( + IERC20(token).transfer(recipient, amount), + "First transfer failed" + ); + emit OperationCompleted("transfer1", true); + + // 2. Staking delegate - convert from wei (18 decimals) to base denom (6 decimals) + uint256 delegateAmountBaseDenom = delegateAmount / 1e12; + STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmountBaseDenom + ); + emit OperationCompleted("delegate", true); + + // 3. Transfer ERC20 again + require( + IERC20(token).transfer(recipient, amount), + "Second transfer failed" + ); + emit OperationCompleted("transfer2", true); + } + + /// @dev Scenario 2: Transfer ERC20 -> Delegate (reverted & caught) -> Transfer ERC20 + /// @param token ERC20 token address + /// @param recipient Recipient for ERC20 transfers + /// @param amount Amount to transfer + /// @param validatorAddr Validator address (EVM format) + /// @param delegateAmount Amount to delegate (will revert) + function scenario2_transferDelegateRevertTransfer( + address token, + address recipient, + uint256 amount, + string memory validatorAddr, + uint256 delegateAmount + ) external { + // 1. Transfer ERC20 + require( + IERC20(token).transfer(recipient, amount), + "First transfer failed" + ); + emit OperationCompleted("transfer1", true); + + // 2. Try to delegate (will revert, catch it) + uint256 delegateAmountBaseDenom = delegateAmount / 1e12; + try STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmountBaseDenom + ) { + emit OperationCompleted("delegate", true); + } catch { + emit OperationCompleted("delegate", false); + } + + // 3. Transfer ERC20 again + require( + IERC20(token).transfer(recipient, amount), + "Second transfer failed" + ); + emit OperationCompleted("transfer2", true); + } + + /// @dev Scenario 3: Native transfer -> Delegate -> Native transfer + /// @param recipient Recipient for native transfers + /// @param amount Amount of native tokens to transfer (in wei) + /// @param validatorAddr Validator address + /// @param delegateAmount Amount to delegate (in wei, will be converted to base denom) + function scenario3_nativeTransferDelegateNativeTransfer( + address payable recipient, + uint256 amount, + string memory validatorAddr, + uint256 delegateAmount + ) external payable { + // 1. Transfer native tokens + (bool success1, ) = recipient.call{value: amount}(""); + require(success1, "First native transfer failed"); + emit OperationCompleted("native_transfer1", true); + + // 2. Staking delegate - convert from wei (18 decimals) to base denom (6 decimals) + uint256 delegateAmountBaseDenom = delegateAmount / 1e12; + STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmountBaseDenom + ); + emit OperationCompleted("delegate", true); + + // 3. Transfer native tokens again + (bool success2, ) = recipient.call{value: amount}(""); + require(success2, "Second native transfer failed"); + emit OperationCompleted("native_transfer2", true); + } + + /// @dev Scenario 4: Native transfer -> Delegate (reverted & caught) -> Native transfer + /// @param recipient Recipient for native transfers + /// @param amount Amount of native tokens to transfer (in wei) + /// @param validatorAddr Validator address + /// @param delegateAmount Amount to delegate (in wei, will be converted to base denom, will revert) + function scenario4_nativeTransferDelegateRevertNativeTransfer( + address payable recipient, + uint256 amount, + string memory validatorAddr, + uint256 delegateAmount + ) external payable { + // 1. Transfer native tokens + (bool success1, ) = recipient.call{value: amount}(""); + require(success1, "First native transfer failed"); + emit OperationCompleted("native_transfer1", true); + + // 2. Try to delegate - convert from wei (18 decimals) to base denom (6 decimals) + uint256 delegateAmountBaseDenom = delegateAmount / 1e12; + try STAKING_CONTRACT.delegate( + address(this), + validatorAddr, + delegateAmountBaseDenom + ) { + emit OperationCompleted("delegate", true); + } catch { + emit OperationCompleted("delegate", false); + } + + // 3. Transfer native tokens again + (bool success2, ) = recipient.call{value: amount}(""); + require(success2, "Second native transfer failed"); + emit OperationCompleted("native_transfer2", true); + } + + /// @dev Get balance of ERC20 token + function getTokenBalance(address token, address account) external view returns (uint256) { + return IERC20(token).balanceOf(account); + } + + /// @dev Get native balance + function getNativeBalance(address account) external view returns (uint256) { + return account.balance; + } + + /// @dev Test function to check contract balance + function getContractBalance() external view returns (uint256) { + return address(this).balance; + } + + /// @dev Simple native transfer test + function testNativeTransfer(address payable recipient, uint256 amount) external payable returns (bool) { + (bool success, ) = recipient.call{value: amount}(""); + return success; + } + + /// @dev Receive function to accept native tokens + receive() external payable {} +} diff --git a/contracts/solidity/eips/testdata/Counter.sol b/contracts/solidity/eips/testdata/Counter.sol new file mode 100644 index 000000000..30ba0869f --- /dev/null +++ b/contracts/solidity/eips/testdata/Counter.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +pragma solidity >=0.7.0 <0.9.0; + +contract Counter { + uint256 public counter = 1; + + function increment() external { + counter++; + } + + function decrement() external { + counter--; + } +} diff --git a/contracts/solidity/eips/testdata/CounterFactory.sol b/contracts/solidity/eips/testdata/CounterFactory.sol new file mode 100644 index 000000000..7b64412d2 --- /dev/null +++ b/contracts/solidity/eips/testdata/CounterFactory.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: LGPL-3.0-only + +pragma solidity >=0.7.0 <0.9.0; + +import "./Counter.sol"; + +contract Counterfactory { + Counter public counterInstance; + + constructor() { + counterInstance = new Counter(); + } + + function incrementCounter() public { + counterInstance.increment(); + } + + function decrementCounter() public { + counterInstance.decrement(); + } + + function getCounterValue() public view returns (uint256) { + return counterInstance.counter(); + } +} diff --git a/crypto/ethsecp256k1/keys.pb.go b/crypto/ethsecp256k1/keys.pb.go index 90f1bbd22..9207a7ad3 100644 --- a/crypto/ethsecp256k1/keys.pb.go +++ b/crypto/ethsecp256k1/keys.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cosmos/evm/crypto/v1/ethsecp256k1/keys.proto +// source: ethermint/crypto/v1/ethsecp256k1/keys.proto package ethsecp256k1 @@ -34,7 +34,7 @@ type PubKey struct { func (m *PubKey) Reset() { *m = PubKey{} } func (*PubKey) ProtoMessage() {} func (*PubKey) Descriptor() ([]byte, []int) { - return fileDescriptor_3033ac433209de5f, []int{0} + return fileDescriptor_0c10cadcf35beb64, []int{0} } func (m *PubKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -81,7 +81,7 @@ func (m *PrivKey) Reset() { *m = PrivKey{} } func (m *PrivKey) String() string { return proto.CompactTextString(m) } func (*PrivKey) ProtoMessage() {} func (*PrivKey) Descriptor() ([]byte, []int) { - return fileDescriptor_3033ac433209de5f, []int{1} + return fileDescriptor_0c10cadcf35beb64, []int{1} } func (m *PrivKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -118,29 +118,29 @@ func (m *PrivKey) GetKey() []byte { } func init() { - proto.RegisterType((*PubKey)(nil), "cosmos.evm.crypto.v1.ethsecp256k1.PubKey") - proto.RegisterType((*PrivKey)(nil), "cosmos.evm.crypto.v1.ethsecp256k1.PrivKey") + proto.RegisterType((*PubKey)(nil), "ethermint.crypto.v1.ethsecp256k1.PubKey") + proto.RegisterType((*PrivKey)(nil), "ethermint.crypto.v1.ethsecp256k1.PrivKey") } func init() { - proto.RegisterFile("cosmos/evm/crypto/v1/ethsecp256k1/keys.proto", fileDescriptor_3033ac433209de5f) + proto.RegisterFile("ethermint/crypto/v1/ethsecp256k1/keys.proto", fileDescriptor_0c10cadcf35beb64) } -var fileDescriptor_3033ac433209de5f = []byte{ - // 193 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x49, 0xce, 0x2f, 0xce, - 0xcd, 0x2f, 0xd6, 0x4f, 0x2d, 0xcb, 0xd5, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x33, - 0xd4, 0x4f, 0x2d, 0xc9, 0x28, 0x4e, 0x4d, 0x2e, 0x30, 0x32, 0x35, 0xcb, 0x36, 0xd4, 0xcf, 0x4e, - 0xad, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x52, 0x84, 0xa8, 0xd6, 0x4b, 0x2d, 0xcb, - 0xd5, 0x83, 0xa8, 0xd6, 0x2b, 0x33, 0xd4, 0x43, 0x56, 0x2d, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, - 0x56, 0xad, 0x0f, 0x62, 0x41, 0x34, 0x2a, 0x29, 0x70, 0xb1, 0x05, 0x94, 0x26, 0x79, 0xa7, 0x56, - 0x0a, 0x09, 0x70, 0x31, 0x67, 0xa7, 0x56, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x04, 0x81, 0x98, - 0x56, 0x2c, 0x33, 0x16, 0xc8, 0x33, 0x28, 0x49, 0x73, 0xb1, 0x07, 0x14, 0x65, 0x96, 0x61, 0x55, - 0xe2, 0xe4, 0x7c, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, - 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x9a, 0xe9, 0x99, - 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x98, 0x5e, 0x41, 0x76, 0x59, 0x12, 0x1b, - 0xd8, 0x29, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x77, 0x7e, 0xb9, 0x2e, 0xf3, 0x00, 0x00, - 0x00, +var fileDescriptor_0c10cadcf35beb64 = []byte{ + // 198 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4e, 0x2d, 0xc9, 0x48, + 0x2d, 0xca, 0xcd, 0xcc, 0x2b, 0xd1, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x33, 0xd4, + 0x4f, 0x2d, 0xc9, 0x28, 0x4e, 0x4d, 0x2e, 0x30, 0x32, 0x35, 0xcb, 0x36, 0xd4, 0xcf, 0x4e, 0xad, + 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x52, 0x80, 0x2b, 0xd6, 0x83, 0x28, 0xd6, 0x2b, + 0x33, 0xd4, 0x43, 0x56, 0x2c, 0x25, 0x92, 0x9e, 0x9f, 0x9e, 0x0f, 0x56, 0xac, 0x0f, 0x62, 0x41, + 0xf4, 0x29, 0x29, 0x70, 0xb1, 0x05, 0x94, 0x26, 0x79, 0xa7, 0x56, 0x0a, 0x09, 0x70, 0x31, 0x67, + 0xa7, 0x56, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0xf0, 0x04, 0x81, 0x98, 0x56, 0x2c, 0x33, 0x16, 0xc8, + 0x33, 0x28, 0x49, 0x73, 0xb1, 0x07, 0x14, 0x65, 0x96, 0x61, 0x55, 0xe2, 0xe4, 0x7c, 0xe2, 0x91, + 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, + 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x9a, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, + 0xc9, 0xf9, 0xb9, 0xfa, 0xc9, 0xf9, 0xc5, 0xb9, 0xf9, 0xc5, 0xfa, 0xa9, 0x65, 0xb9, 0x30, 0x9f, + 0x20, 0xbb, 0x2c, 0x89, 0x0d, 0xec, 0x14, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3c, 0xae, + 0xea, 0xae, 0xf1, 0x00, 0x00, 0x00, } func (m *PubKey) Marshal() (dAtA []byte, err error) { diff --git a/docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md b/docs/migrations/v0.4.0_to_v0.5.0.md similarity index 100% rename from docs/migrations/v0.4.0_to_v0.5.0_UNRELEASED.md rename to docs/migrations/v0.4.0_to_v0.5.0.md diff --git a/docs/migrations/v0.5.x_to_v0.6.0.md b/docs/migrations/v0.5.x_to_v0.6.0.md new file mode 100644 index 000000000..8be4ef323 --- /dev/null +++ b/docs/migrations/v0.5.x_to_v0.6.0.md @@ -0,0 +1,496 @@ +# Cosmos EVM v0.5.x → v0.6.0 Migration + +## 0) Prep + +- Create a branch: `git switch -c upgrade/evm-v0.6`. +- Ensure a clean build + tests green pre-upgrade. +- Snapshot your current params/genesis for comparison later. + +--- + +## 1) Dependency bumps (go.mod) + +- Bump `github.com/cosmos/evm` to v0.6.0 +- Bump `github.com/cosmos/cosmos-sdk` to v0.53.6 +- Run: + +```bash +go mod tidy +``` + +--- + +## 2) App Wiring Changes + +### IBC Transfer Module + +v0.6.0 removes the custom IBC transfer keeper override and now uses the official IBC-Go transfer keeper directly. +This means that **ERC20 conversions via Cosmos IBC transfer transactions are not possible**. These are now only +handled in the ICS20 precompile, and any ERC20 transfer must be initiated through there. + +**Changes required in `app.go`:** + +1. **Update imports** - Replace custom transfer imports with official IBC-Go imports: + +```diff +- import ( +- "github.com/cosmos/evm/x/ibc/transfer" +- transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" +- transferv2 "github.com/cosmos/evm/x/ibc/transfer/v2" +- ibctransfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" +- ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" +- ) ++ import ( ++ transfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" ++ transferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" ++ ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" ++ transferv2 "github.com/cosmos/ibc-go/v10/modules/apps/transfer/v2" ++ ) +``` + +2. **Update TransferKeeper initialization** - Remove ERC20 keeper parameter: + +```diff + app.TransferKeeper = transferkeeper.NewKeeper( + appCodec, + runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]), ++ nil, // ICS4Wrapper param + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.ChannelKeeper, + app.MsgServiceRouter(), + app.AccountKeeper, + app.BankKeeper, +- app.Erc20Keeper, // Remove: no longer passed to transfer keeper + authAddr, + ) +``` + +3. **Update module registration** - Use official transfer module: + +```diff + app.BasicModuleManager = module.NewBasicManager( + // ... other modules +- ibctransfertypes.ModuleName: transfer.AppModuleBasic{AppModuleBasic: &ibctransfer.AppModuleBasic{}}, ++ ibctransfertypes.ModuleName: transfer.AppModuleBasic{}, + ) +``` + +4. **Update ICS20 precompile wiring** - Pass ERC20 keeper to ICS20 precompile: + +```diff + precompiletypes.DefaultStaticPrecompiles( + *app.StakingKeeper, + app.DistrKeeper, + app.PreciseBankKeeper, + &app.Erc20Keeper, + &app.TransferKeeper, + app.IBCKeeper.ChannelKeeper, + app.GovKeeper, + app.SlashingKeeper, + appCodec, + ) +``` + +The ICS20 precompile now takes the ERC20 keeper as a parameter (instead of the transfer keeper receiving it). +This allows the precompile to handle ERC20 conversions directly. + +--- + +## 3) Breaking API Changes + +### StateDB Requirements + +v0.6.0 introduces significant changes to event tracking and state management. All EVM execution functions now +require an explicit `stateDB` parameter and a `callFromPrecompile` flag to properly handle event management +and state transitions. + +**NOTE:** The only function calls affected are `CallEVM`, `CallEVMWithData`, `ApplyMessage`, and`ApplyMessageWithConfig`. +These are typically used in common precompiles and logic that calls back into the EVM from the SDK. If your project +does not use these functions, then no steps need to be taken for the upgrade. + +#### Advanced Changes + +The following functions have updated signatures: + +##### `CallEVM` + +**Before (v0.5.x):** +```go +func (k Keeper) CallEVM( + ctx sdk.Context, + abi abi.ABI, + from, contract common.Address, + commit bool, + gasCap *big.Int, + method string, + args ...interface{}, +) (*types.MsgEthereumTxResponse, error) +``` + +**After (v0.6.0):** +```go +func (k Keeper) CallEVM( + ctx sdk.Context, + stateDB *statedb.StateDB, + abi abi.ABI, + from, contract common.Address, + commit bool, + callFromPrecompile bool, + gasCap *big.Int, + method string, + args ...interface{}, +) (*types.MsgEthereumTxResponse, error) +``` + +##### `CallEVMWithData` + +**Before (v0.5.x):** +```go +func (k Keeper) CallEVMWithData( + ctx sdk.Context, + from common.Address, + contract *common.Address, + data []byte, + commit bool, + gasCap *big.Int, +) (*types.MsgEthereumTxResponse, error) +``` + +**After (v0.6.0):** +```go +func (k Keeper) CallEVMWithData( + ctx sdk.Context, + stateDB *statedb.StateDB, + from common.Address, + contract *common.Address, + data []byte, + commit bool, + callFromPrecompile bool, + gasCap *big.Int, +) (*types.MsgEthereumTxResponse, error) +``` + +##### `ApplyMessage` + +**Before (v0.5.x):** +```go +func (k *Keeper) ApplyMessage( + ctx sdk.Context, + msg core.Message, + tracer *tracing.Hooks, + commit bool, + internal bool, +) (*types.MsgEthereumTxResponse, error) +``` + +**After (v0.6.0):** +```go +func (k *Keeper) ApplyMessage( + ctx sdk.Context, + stateDB *statedb.StateDB, + msg core.Message, + tracer *tracing.Hooks, + commit bool, + callFromPrecompile bool, + internal bool, +) (*types.MsgEthereumTxResponse, error) +``` + +##### `ApplyMessageWithConfig` + +**Before (v0.5.x):** +```go +func (k *Keeper) ApplyMessageWithConfig( + ctx sdk.Context, + msg core.Message, + tracer *tracing.Hooks, + commit bool, + cfg *statedb.EVMConfig, + txConfig statedb.TxConfig, + internal bool, + overrides *rpctypes.StateOverride, +) (*types.MsgEthereumTxResponse, error) +``` + +**After (v0.6.0):** +```go +func (k *Keeper) ApplyMessageWithConfig( + ctx sdk.Context, + stateDB *statedb.StateDB, + msg core.Message, + tracer *tracing.Hooks, + commit bool, + callFromPrecompile bool, + cfg *statedb.EVMConfig, + txConfig statedb.TxConfig, + internal bool, + overrides *rpctypes.StateOverride, +) (*types.MsgEthereumTxResponse, error) +``` + +### Migration Steps + +#### For Non-Precompile Contexts + +If you're calling EVM functions from **outside** a precompile (e.g., from a module keeper, message server, or query handler): + +1. Create a new `stateDB` before calling EVM functions +2. Pass `false` for the `callFromPrecompile` parameter + +**Example:** + +```go +import ( + "github.com/cosmos/evm/x/vm/statedb" +) + +// Before (v0.5.x) +res, err := k.evmKeeper.CallEVM( + ctx, + abi, + from, + contract, + false, // commit + nil, // gasCap + "balanceOf", + account, +) + +// After (v0.6.0) +stateDB := statedb.New(ctx, k.evmKeeper, statedb.NewEmptyTxConfig()) +res, err := k.evmKeeper.CallEVM( + ctx, + stateDB, + abi, + from, + contract, + false, // commit + false, // callFromPrecompile + nil, // gasCap + "balanceOf", + account, +) +``` + +#### For Precompile Contexts + +If you're calling EVM functions from **within** a precompile: + +1. **Reuse the existing `stateDB`** from your precompile context (do not create a new one) +2. Pass `true` for the `callFromPrecompile` parameter +3. The existing `stateDB` is typically available as a parameter in your precompile function + +**Example:** + +```go +// In your precompile's Run() method, you'll have access to stateDB +func (p *MyPrecompile) Run( + evm *vm.EVM, + contract *vm.Contract, + readOnly bool, +) ([]byte, error) { + stateDB := evm.StateDB.(*statedb.StateDB) + + // Use the existing stateDB and set callFromPrecompile=true + res, err := p.evmKeeper.CallEVM( + ctx, + stateDB, // reuse existing stateDB + abi, + from, + contract, + true, // commit (will flush to cache context) + true, // callFromPrecompile + nil, // gasCap + "transfer", + recipient, + amount, + ) +} +``` + +### Important Notes + +- **Never pass `nil` for `stateDB`**: This will return `ErrNilStateDB` error +- **Commit behavior in precompiles**: When `commit=true` and `callFromPrecompile=true`, the state changes +are flushed to the cache context rather than fully committed. This prevents collapsing the cache stack in +nested call scenarios. + +### EVMKeeper Interface Changes + +If you implement or mock the `EVMKeeper` interface, update your implementation: + +```go +type EVMKeeper interface { + // Updated signatures + ApplyMessage( + ctx sdk.Context, + stateDB *statedb.StateDB, + msg core.Message, + tracer *tracing.Hooks, + commit, callFromPrecompile, internal bool, + ) (*evmtypes.MsgEthereumTxResponse, error) + + CallEVM( + ctx sdk.Context, + stateDB *statedb.StateDB, + abi abi.ABI, + from, contract common.Address, + commit, callFromPrecompile bool, + gasCap *big.Int, + method string, + args ...interface{}, + ) (*evmtypes.MsgEthereumTxResponse, error) + + CallEVMWithData( + ctx sdk.Context, + stateDB *statedb.StateDB, + from common.Address, + contract *common.Address, + data []byte, + commit bool, + callFromPrecompile bool, + gasCap *big.Int, + ) (*evmtypes.MsgEthereumTxResponse, error) + + // ... other methods +} +``` + +--- + +## 4) ERC20 Keeper Interface Changes + +The `ERC20Keeper` interface has new methods: + +```go +type ERC20Keeper interface { + // ... existing methods + + // New methods in v0.6.0 + IsERC20Enabled(ctx sdk.Context) bool + GetTokenPairID(ctx sdk.Context, token string) []byte + ConvertERC20IntoCoinsForNativeToken( + ctx sdk.Context, + stateDB *statedb.StateDB, + contract ethcommon.Address, + amount math.Int, + receiver sdk.AccAddress, + sender ethcommon.Address, + commit bool, + callFromPrecompile bool, + ) (*erc20types.MsgConvertERC20Response, error) +} +``` + +If you implement this interface, add these methods to your implementation. + +--- + +## 5) Error Handling + +A new error type has been added: + +```go +var ErrNilStateDB = errorsmod.Register(ModuleName, codeErrNilStateDB, "stateDB cannot be nil") +``` + +This error is returned when `nil` is passed as the `stateDB` parameter to EVM functions. + +--- + +## 6) Build & Tests + +```bash +go build ./... +go test ./... +``` + +### Testing Checklist + +After migration, verify: +- [ ] All EVM calls pass a valid `stateDB` +- [ ] Non-precompile calls use `callFromPrecompile=false` +- [ ] Precompile calls reuse existing `stateDB` and use `callFromPrecompile=true` +- [ ] Event emission works correctly in both success and revert scenarios +- [ ] State changes are properly committed or reverted + +--- + +## Common Migration Examples + +### Example 1: Module Keeper Query + +```go +// Before (v0.5.x) +func (k Keeper) QueryBalance(ctx sdk.Context, addr common.Address) (*big.Int, error) { + res, err := k.evmKeeper.CallEVM( + ctx, erc20ABI, moduleAddr, contract, false, nil, "balanceOf", addr, + ) + // ... +} + +// After (v0.6.0) +func (k Keeper) QueryBalance(ctx sdk.Context, addr common.Address) (*big.Int, error) { + stateDB := statedb.New(ctx, k.evmKeeper, statedb.NewEmptyTxConfig()) + res, err := k.evmKeeper.CallEVM( + ctx, stateDB, erc20ABI, moduleAddr, contract, false, false, nil, "balanceOf", addr, + ) + // ... +} +``` + +### Example 2: Message Server Transaction + +```go +// Before (v0.5.x) +func (ms msgServer) ConvertCoin(goCtx context.Context, msg *types.MsgConvertCoin) (*types.MsgConvertCoinResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + // ... + res, err := ms.evmKeeper.CallEVMWithData( + ctx, moduleAddr, &contract, data, true, nil, + ) + // ... +} + +// After (v0.6.0) +func (ms msgServer) ConvertCoin(goCtx context.Context, msg *types.MsgConvertCoin) (*types.MsgConvertCoinResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + // ... + stateDB := statedb.New(ctx, ms.evmKeeper, statedb.NewEmptyTxConfig()) + res, err := ms.evmKeeper.CallEVMWithData( + ctx, stateDB, moduleAddr, &contract, data, true, false, nil, + ) + // ... +} +``` + +### Example 3: Precompile Internal Call + +```go +// Before (v0.5.x) +func (p *StakingPrecompile) delegate( + ctx sdk.Context, + evm *vm.EVM, + // ... +) ([]byte, error) { + // ... delegate logic ... + res, err := p.evmKeeper.CallEVM( + ctx, delegationABI, from, contract, true, nil, "afterDelegate", + ) + // ... +} + +// After (v0.6.0) +func (p *StakingPrecompile) delegate( + ctx sdk.Context, + evm *vm.EVM, + stateDB *statedb.StateDB, // typically passed from Run() + // ... +) ([]byte, error) { + // ... delegate logic ... + res, err := p.evmKeeper.CallEVM( + ctx, stateDB, delegationABI, from, contract, true, true, nil, "afterDelegate", + ) + // ... +} +``` \ No newline at end of file diff --git a/ethereum/eip712/codec.go b/ethereum/eip712/codec.go index f8a6391f3..04da97406 100644 --- a/ethereum/eip712/codec.go +++ b/ethereum/eip712/codec.go @@ -2,6 +2,7 @@ package eip712 import ( antetypes "github.com/cosmos/evm/ante/types" + legacytypes "github.com/cosmos/evm/rpc/types/legacy" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdktypes "github.com/cosmos/cosmos-sdk/types" @@ -27,4 +28,26 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { &ExtensionOptionsWeb3Tx{}, &antetypes.ExtensionOptionDynamicFeeTx{}, ) + + // Register the TxData interface for legacy ethermint transaction types. + // These are needed to decode pre-v9 upgrade transactions that use ethermint.evm.v1 proto package. + // The proto types are registered in evm/rpc/types/legacy/tx.pb.go via init(). + registry.RegisterInterface( + "ethermint.evm.v1.TxData", + (*legacytypes.TxData)(nil), + &legacytypes.LegacyTx{}, + &legacytypes.AccessListTx{}, + &legacytypes.DynamicFeeTx{}, + ) + + registry.RegisterImplementations( + (*sdktypes.Msg)(nil), + &legacytypes.MsgEthereumTx{}, + &legacytypes.MsgUpdateParams{}, + ) + + registry.RegisterImplementations( + (*tx.TxExtensionOptionI)(nil), + &legacytypes.ExtensionOptionsEthereumTx{}, + ) } diff --git a/ethereum/eip712/encoding.go b/ethereum/eip712/encoding.go index 5292fa4e4..c4cfa9899 100644 --- a/ethereum/eip712/encoding.go +++ b/ethereum/eip712/encoding.go @@ -14,7 +14,7 @@ import ( ) var ( - protoCodec codec.ProtoCodecMarshaler + protoCodec codec.Codec aminoCodec *codec.LegacyAmino eip155ChainID uint64 ) @@ -166,7 +166,7 @@ func decodeProtobufSignDoc(signDocBytes []byte) (apitypes.TypedData, error) { } // WrapTxToTypedData expects the payload as an Amino Sign Doc - signBytes := legacytx.StdSignBytes( + signBytes := legacytx.StdSignBytes( //nolint:staticcheck // check against deprecated type signDoc.ChainId, signDoc.AccountNumber, signerInfo.Sequence, diff --git a/ethereum/eip712/encoding_legacy.go b/ethereum/eip712/encoding_legacy.go index d0efecf50..760bf4813 100644 --- a/ethereum/eip712/encoding_legacy.go +++ b/ethereum/eip712/encoding_legacy.go @@ -175,7 +175,7 @@ func legacyDecodeProtobufSignDoc(signDocBytes []byte, eip155ChainID uint64) (api } // WrapTxToTypedData expects the payload as an Amino Sign Doc - signBytes := legacytx.StdSignBytes( + signBytes := legacytx.StdSignBytes( //nolint:staticcheck // checking legacy type signDoc.ChainId, signDoc.AccountNumber, signerInfo.Sequence, diff --git a/evmd/app.go b/evmd/app.go index f07b0a471..43dfe3e75 100644 --- a/evmd/app.go +++ b/evmd/app.go @@ -37,9 +37,6 @@ import ( feemarkettypes "github.com/cosmos/evm/x/feemarket/types" ibccallbackskeeper "github.com/cosmos/evm/x/ibc/callbacks/keeper" - "github.com/cosmos/evm/x/ibc/transfer" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" - transferv2 "github.com/cosmos/evm/x/ibc/transfer/v2" "github.com/cosmos/evm/x/precisebank" precisebankkeeper "github.com/cosmos/evm/x/precisebank/keeper" precisebanktypes "github.com/cosmos/evm/x/precisebank/types" @@ -48,8 +45,10 @@ import ( evmtypes "github.com/cosmos/evm/x/vm/types" "github.com/cosmos/gogoproto/proto" ibccallbacks "github.com/cosmos/ibc-go/v10/modules/apps/callbacks" - ibctransfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" + transfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" + transferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + transferv2 "github.com/cosmos/ibc-go/v10/modules/apps/transfer/v2" ibc "github.com/cosmos/ibc-go/v10/modules/core" porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" ibcapi "github.com/cosmos/ibc-go/v10/modules/core/api" @@ -405,7 +404,7 @@ func NewExampleApp( app.GovKeeper = *govKeeper.SetHooks( govtypes.NewMultiGovHooks( - // register the governance hooks + // register the governance hooks ), ) @@ -483,12 +482,12 @@ func NewExampleApp( app.TransferKeeper = transferkeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]), + nil, app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, app.MsgServiceRouter(), app.AccountKeeper, app.BankKeeper, - app.Erc20Keeper, // Add ERC20 Keeper for ERC20 transfers authAddr, ) app.TransferKeeper.SetAddressCodec(evmaddress.NewEvmCodec(sdk.GetConfig().GetBech32AccountAddrPrefix())) @@ -585,7 +584,7 @@ func NewExampleApp( genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), stakingtypes.ModuleName: staking.AppModuleBasic{}, govtypes.ModuleName: gov.NewAppModuleBasic(nil), - ibctransfertypes.ModuleName: transfer.AppModuleBasic{AppModuleBasic: &ibctransfer.AppModuleBasic{}}, + ibctransfertypes.ModuleName: transfer.AppModuleBasic{}, }, ) app.BasicModuleManager.RegisterLegacyAminoCodec(legacyAmino) diff --git a/evmd/go.mod b/evmd/go.mod index bcd83b1be..f12d11cd7 100644 --- a/evmd/go.mod +++ b/evmd/go.mod @@ -14,9 +14,9 @@ require ( cosmossdk.io/x/evidence v0.2.0 cosmossdk.io/x/feegrant v0.2.0 cosmossdk.io/x/upgrade v0.2.0 - github.com/cometbft/cometbft v0.38.19 + github.com/cometbft/cometbft v0.38.21 github.com/cosmos/cosmos-db v1.1.3 - github.com/cosmos/cosmos-sdk v0.53.5-0.20251030204916-768cb210885c + github.com/cosmos/cosmos-sdk v0.53.6 github.com/cosmos/evm v0.2.0 github.com/cosmos/gogoproto v1.7.2 github.com/cosmos/ibc-go/v10 v10.3.1-0.20250909102629-ed3b125c7b6f @@ -26,7 +26,7 @@ require ( github.com/spf13/cast v1.10.0 github.com/spf13/cobra v1.10.1 github.com/spf13/pflag v1.0.10 - github.com/spf13/viper v1.20.1 + github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 golang.org/x/sync v0.16.0 google.golang.org/grpc v1.75.0 @@ -87,7 +87,7 @@ require ( github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.2.2 // indirect github.com/cosmos/ics23/go v0.11.0 // indirect - github.com/cosmos/ledger-cosmos-go v0.16.0 // indirect + github.com/cosmos/ledger-cosmos-go v1.0.0 // indirect github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect github.com/creachadair/atomicfile v0.3.7 // indirect @@ -207,11 +207,11 @@ require ( github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/rs/zerolog v1.34.0 // indirect - github.com/sagikazarmark/locafero v0.9.0 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.14.0 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect @@ -249,6 +249,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.17.0 // indirect golang.org/x/crypto v0.41.0 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect diff --git a/evmd/go.sum b/evmd/go.sum index 13d5f5d2d..d9a64a027 100644 --- a/evmd/go.sum +++ b/evmd/go.sum @@ -835,8 +835,8 @@ github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.19 h1:vNdtCkvhuwUlrcLPAyigV7lQpmmo+tAq8CsB8gZjEYw= -github.com/cometbft/cometbft v0.38.19/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= +github.com/cometbft/cometbft v0.38.21 h1:qcIJSH9LiwU5s6ZgKR5eRbsLNucbubfraDs5bzgjtOI= +github.com/cometbft/cometbft v0.38.21/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ= github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ= github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= @@ -853,8 +853,8 @@ github.com/cosmos/cosmos-db v1.1.3 h1:7QNT77+vkefostcKkhrzDK9uoIEryzFrU9eoMeaQOP github.com/cosmos/cosmos-db v1.1.3/go.mod h1:kN+wGsnwUJZYn8Sy5Q2O0vCYA99MJllkKASbs6Unb9U= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/cosmos-sdk v0.53.5-0.20251030204916-768cb210885c h1:HMVLvm0q3ahGvsyExkSCBcmvcdItMpTxAh4jllL4rJ4= -github.com/cosmos/cosmos-sdk v0.53.5-0.20251030204916-768cb210885c/go.mod h1:nifazrMGFjpmOuaVIZBQ8akQc160imzySYFEA8A7tus= +github.com/cosmos/cosmos-sdk v0.53.6 h1:aJeInld7rbsHtH1qLHu2aZJF9t40mGlqp3ylBLDT0HI= +github.com/cosmos/cosmos-sdk v0.53.6/go.mod h1:N6YuprhAabInbT3YGumGDKONbvPX5dNro7RjHvkQoKE= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/go-ethereum v1.16.2-cosmos-1 h1:QIaIS6HIdPSBdTvpFhxswhMLUJgcr4irbd2o9ZKldAI= @@ -872,8 +872,8 @@ github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5Rtn github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= -github.com/cosmos/ledger-cosmos-go v0.16.0 h1:YKlWPG9NnGZIEUb2bEfZ6zhON1CHlNTg0QKRRGcNEd0= -github.com/cosmos/ledger-cosmos-go v0.16.0/go.mod h1:WrM2xEa8koYoH2DgeIuZXNarF7FGuZl3mrIOnp3Dp0o= +github.com/cosmos/ledger-cosmos-go v1.0.0 h1:jNKW89nPf0vR0EkjHG8Zz16h6p3zqwYEOxlHArwgYtw= +github.com/cosmos/ledger-cosmos-go v1.0.0/go.mod h1:mGaw2wDOf+Z6SfRJsMGxU9DIrBa4du0MAiPlpPhLAOE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -1614,8 +1614,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= -github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= @@ -1633,14 +1633,14 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= -github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= @@ -1651,8 +1651,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1802,8 +1802,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= -go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= diff --git a/evmd/tests/ibc/autoflush_test.go b/evmd/tests/ibc/autoflush_test.go new file mode 100644 index 000000000..f0abbe057 --- /dev/null +++ b/evmd/tests/ibc/autoflush_test.go @@ -0,0 +1,967 @@ +package ibc + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/evm/contracts" + "github.com/cosmos/evm/evmd" + "github.com/cosmos/evm/evmd/tests/integration" + "github.com/cosmos/evm/testutil" + evmibctesting "github.com/cosmos/evm/testutil/ibc" + testutiltypes "github.com/cosmos/evm/testutil/types" + erc20types "github.com/cosmos/evm/x/erc20/types" + evmtypes "github.com/cosmos/evm/x/vm/types" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Test constants +const ( + AutoFlushInitialTokenAmount int64 = 1_000_000_000_000_000_000 // 1 token with 18 decimals + AutoFlushDelegationAmount int64 = 100_000_000_000_000_000 // 0.1 token for delegation + AutoFlushTransferAmount int64 = 50_000_000_000_000_000 // 0.05 token for transfers + AutoFlushNativeAmount int64 = 1_000_000_000_000_000_000 // 1 native token (larger to avoid fractional issues) + AutoFlushSenderIndex = 1 +) + +// Test suite for auto-flush behavior with various operation combinations +type AutoFlushTestSuite struct { + suite.Suite + + coordinator *evmibctesting.Coordinator + chain *evmibctesting.TestChain +} + +func (suite *AutoFlushTestSuite) SetupTest() { + suite.coordinator = evmibctesting.NewCoordinator(suite.T(), 1, 0, integration.SetupEvmd) + suite.chain = suite.coordinator.GetChain(evmibctesting.GetEvmChainID(1)) +} + +func TestAutoFlushTestSuite(t *testing.T) { + suite.Run(t, new(AutoFlushTestSuite)) +} + +// Helper: Deploy and setup ERC20 token +func (suite *AutoFlushTestSuite) deployAndRegisterERC20(name, symbol string) (common.Address, evmtypes.CompiledContract) { + evmApp := suite.chain.App.(*evmd.EVMD) + + // Deploy ERC20 + erc20ContractData := contracts.ERC20MinterBurnerDecimalsContract + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: erc20ContractData, + ConstructorArgs: []interface{}{name, symbol, uint8(18)}, + } + + erc20Addr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + // Register ERC20 + _, err = evmApp.Erc20Keeper.RegisterERC20(suite.chain.GetContext(), &erc20types.MsgRegisterERC20{ + Signer: evmApp.AccountKeeper.GetModuleAddress("gov").String(), + Erc20Addresses: []string{erc20Addr.Hex()}, + }) + suite.Require().NoError(err) + suite.chain.NextBlock() + + return erc20Addr, erc20ContractData +} + +// Helper: Get validator address +func (suite *AutoFlushTestSuite) getValidatorAddress() string { + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + vals, err := evmApp.StakingKeeper.GetAllValidators(ctx) + suite.Require().NoError(err) + suite.Require().Greater(len(vals), 0, "no validators found") + + return vals[0].OperatorAddress +} + +// Helper: Mint tokens to address +func (suite *AutoFlushTestSuite) mintTokens(tokenAddr common.Address, erc20Data evmtypes.CompiledContract, recipient common.Address, amount *big.Int) { + evmApp := suite.chain.App.(*evmd.EVMD) + deployerAddr := common.BytesToAddress(suite.chain.SenderPrivKey.PubKey().Address().Bytes()) + + stateDB := testutil.NewStateDB(suite.chain.GetContext(), evmApp.EVMKeeper) + _, err := evmApp.GetEVMKeeper().CallEVM( + suite.chain.GetContext(), + stateDB, + erc20Data.ABI, + deployerAddr, + tokenAddr, + true, + false, + nil, + "mint", + recipient, + amount, + ) + suite.Require().NoError(err) + suite.chain.NextBlock() +} + +// Helper: Fund contract with native tokens +func (suite *AutoFlushTestSuite) fundContractNative(contractAddr sdk.AccAddress, amount sdkmath.Int) { + evmApp := suite.chain.App.(*evmd.EVMD) + bondDenom, err := evmApp.StakingKeeper.BondDenom(suite.chain.GetContext()) + suite.Require().NoError(err) + + coins := sdk.NewCoins(sdk.NewCoin(bondDenom, amount)) + err = evmApp.GetBankKeeper().MintCoins(suite.chain.GetContext(), "mint", coins) + suite.Require().NoError(err) + + err = evmApp.GetBankKeeper().SendCoinsFromModuleToAccount( + suite.chain.GetContext(), + "mint", + contractAddr, + coins, + ) + suite.Require().NoError(err) + suite.chain.NextBlock() +} + +// Helper: Count events and print them +func (suite *AutoFlushTestSuite) countEvents(ctx sdk.Context) int { + return len(ctx.EventManager().Events()) +} + + +// Helper: Check balances and events +func (suite *AutoFlushTestSuite) verifyState( + label string, + expectedEventCount int, + expectedBalances map[common.Address]map[common.Address]*big.Int, // tokenAddr -> holderAddr -> balance + expectedNativeBalances map[string]sdkmath.Int, // bech32 address -> balance + expectedAccountsCreated int, +) { + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + // Check event count + actualEventCount := suite.countEvents(ctx) + suite.Require().Equal(expectedEventCount, actualEventCount, + "%s: event count mismatch - expected %d, got %d", label, expectedEventCount, actualEventCount) + + // Check ERC20 balances + for tokenAddr, holders := range expectedBalances { + tokenPairID := evmApp.Erc20Keeper.GetTokenPairID(ctx, "erc20:"+tokenAddr.Hex()) + tokenPair, found := evmApp.Erc20Keeper.GetTokenPair(ctx, tokenPairID) + suite.Require().True(found, "%s: token pair not found for %s", label, tokenAddr.Hex()) + + erc20Data := contracts.ERC20MinterBurnerDecimalsContract + for holderAddr, expectedBal := range holders { + actualBal := evmApp.GetErc20Keeper().BalanceOf(ctx, erc20Data.ABI, tokenPair.GetERC20Contract(), holderAddr) + suite.Require().Equal(expectedBal.String(), actualBal.String(), + "%s: ERC20 balance mismatch for %s holding %s", label, holderAddr.Hex(), tokenAddr.Hex()) + } + } + + // Check native balances + for addrStr, expectedBal := range expectedNativeBalances { + bondDenom, err := evmApp.StakingKeeper.BondDenom(ctx) + suite.Require().NoError(err) + + addr, err := sdk.AccAddressFromBech32(addrStr) + suite.Require().NoError(err) + + actualBal := evmApp.GetBankKeeper().GetBalance(ctx, addr, bondDenom) + suite.Require().Equal(expectedBal.String(), actualBal.Amount.String(), + "%s: native balance mismatch for %s", label, addrStr) + } + + // TODO: Check account creation count if needed + _ = expectedAccountsCreated +} + +// Scenario 1: Transfer ERC20 -> Delegate -> Transfer ERC20 +func (suite *AutoFlushTestSuite) TestScenario1_TransferDelegateTransfer() { + suite.SetupTest() + + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + // Deploy test contract + contractData, err := contracts.LoadSequentialOperationsTester() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + contractAddrSDK := sdk.AccAddress(contractAddr.Bytes()) + + // Deploy and register ERC20 + tokenAddr, erc20Data := suite.deployAndRegisterERC20("TestToken", "TT") + + // Mint tokens to contract + suite.mintTokens(tokenAddr, erc20Data, contractAddr, big.NewInt(AutoFlushInitialTokenAmount)) + + // Fund contract with native tokens for delegation + suite.fundContractNative(contractAddrSDK, sdkmath.NewInt(AutoFlushDelegationAmount*2)) + + // Get recipient and validator + senderAccount := suite.chain.SenderAccounts[AutoFlushSenderIndex] + recipientAddr := common.BytesToAddress(senderAccount.SenderAccount.GetAddress().Bytes()) + validatorAddr := suite.getValidatorAddress() + + // Get balances before + ctx = suite.chain.GetContext() + contractBalBefore := evmApp.GetErc20Keeper().BalanceOf(ctx, erc20Data.ABI, tokenAddr, contractAddr) + recipientBalBefore := evmApp.GetErc20Keeper().BalanceOf(ctx, erc20Data.ABI, tokenAddr, recipientAddr) + + // Pack the call data + callData, err := contractData.ABI.Pack( + "scenario1_transferDelegateTransfer", + tokenAddr, + recipientAddr, + big.NewInt(AutoFlushTransferAmount), + validatorAddr, + big.NewInt(AutoFlushDelegationAmount), + ) + suite.Require().NoError(err) + + // Execute via SendEvmTx to get proper event tracking + res, _, _, err := suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + big.NewInt(0), + callData, + 0, + ) + suite.Require().NoError(err) + + // Get balances after + ctx = suite.chain.GetContext() + contractBalAfter := evmApp.GetErc20Keeper().BalanceOf(ctx, erc20Data.ABI, tokenAddr, contractAddr) + recipientBalAfter := evmApp.GetErc20Keeper().BalanceOf(ctx, erc20Data.ABI, tokenAddr, recipientAddr) + + expectedDelta := new(big.Int).Mul(big.NewInt(AutoFlushTransferAmount), big.NewInt(2)) + actualDelta := new(big.Int).Sub(contractBalBefore, contractBalAfter) + + // Verify balances + suite.Require().Equal(expectedDelta.String(), actualDelta.String(), "transfer amount mismatch") + suite.Require().Equal( + new(big.Int).Mul(big.NewInt(AutoFlushTransferAmount), big.NewInt(2)).String(), + new(big.Int).Sub(recipientBalAfter, recipientBalBefore).String(), + "recipient should receive 2x transfer amount", + ) + + // Verify delegation occurred + delegations, err := evmApp.StakingKeeper.GetAllDelegatorDelegations(ctx, contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(len(delegations), 1, "should have at 1 delegation") + bondedTokens, err := evmApp.StakingKeeper.GetDelegatorBonded(suite.chain.GetContext(), contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(AutoFlushDelegationAmount/1_000_000_000_000, bondedTokens.Int64()) + + suite.Require().Equal(DelegationEventCount+EVMEventCount, len(res.Events)) // 8 events, no gas token transfer +} + +// Scenario 2: Transfer ERC20 -> Delegate (reverted & caught) -> Transfer ERC20 +func (suite *AutoFlushTestSuite) TestScenario2_TransferDelegateRevertTransfer() { + suite.SetupTest() + + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + // Deploy test contract + contractData, err := contracts.LoadSequentialOperationsTester() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + // Deploy and register ERC20 + tokenAddr, erc20Data := suite.deployAndRegisterERC20("TestToken2", "TT2") + + // Mint tokens to contract + suite.mintTokens(tokenAddr, erc20Data, contractAddr, big.NewInt(AutoFlushInitialTokenAmount)) + + // Get recipient and validator + senderAccount := suite.chain.SenderAccounts[AutoFlushSenderIndex] + recipientAddr := common.BytesToAddress(senderAccount.SenderAccount.GetAddress().Bytes()) + validatorAddr := suite.getValidatorAddress() + + // Get balances before + ctx = suite.chain.GetContext() + contractBalBefore := evmApp.GetErc20Keeper().BalanceOf(ctx, erc20Data.ABI, tokenAddr, contractAddr) + recipientBalBefore := evmApp.GetErc20Keeper().BalanceOf(ctx, erc20Data.ABI, tokenAddr, recipientAddr) + + // Pack the call data with excessive delegation amount (will revert and be caught) + excessiveAmount := new(big.Int).Mul(big.NewInt(AutoFlushDelegationAmount), big.NewInt(1000)) + callData, err := contractData.ABI.Pack( + "scenario2_transferDelegateRevertTransfer", + tokenAddr, + recipientAddr, + big.NewInt(AutoFlushTransferAmount), + validatorAddr, + excessiveAmount, // Will fail - insufficient balance + ) + suite.Require().NoError(err) + + // Execute via SendEvmTx to get proper event tracking + res, _, _, err := suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + big.NewInt(0), + callData, + 0, + ) + suite.Require().NoError(err) + + // Get balances after + ctx = suite.chain.GetContext() + contractBalAfter := evmApp.GetErc20Keeper().BalanceOf(ctx, erc20Data.ABI, tokenAddr, contractAddr) + recipientBalAfter := evmApp.GetErc20Keeper().BalanceOf(ctx, erc20Data.ABI, tokenAddr, recipientAddr) + + expectedDelta := new(big.Int).Mul(big.NewInt(AutoFlushTransferAmount), big.NewInt(2)) + actualDelta := new(big.Int).Sub(contractBalBefore, contractBalAfter) + + // Verify balances - both transfers should succeed even though delegate failed + suite.Require().Equal(expectedDelta.String(), actualDelta.String(), "transfer amount mismatch") + suite.Require().Equal( + new(big.Int).Mul(big.NewInt(AutoFlushTransferAmount), big.NewInt(2)).String(), + new(big.Int).Sub(recipientBalAfter, recipientBalBefore).String(), + "recipient should receive 2x transfer amount", + ) + + // Verify NO delegation occurred (it was reverted) + contractAddrSDK := sdk.AccAddress(contractAddr.Bytes()) + delegations, err := evmApp.StakingKeeper.GetAllDelegatorDelegations(ctx, contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(0, len(delegations), "should have no delegations since it reverted") + bondedTokens, err := evmApp.StakingKeeper.GetDelegatorBonded(suite.chain.GetContext(), contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(int64(0), bondedTokens.Int64()) + + suite.Require().Equal(EVMEventCount, len(res.Events)) +} + +// Scenario 3: Native transfer -> Delegate -> Native transfer +func (suite *AutoFlushTestSuite) TestScenario3_NativeTransferDelegateNativeTransfer() { + suite.SetupTest() + + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + // Deploy test contract + contractData, err := contracts.LoadSequentialOperationsTester() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + contractAddrSDK := sdk.AccAddress(contractAddr.Bytes()) + senderAccount := suite.chain.SenderAccounts[AutoFlushSenderIndex] + + // Fund contract via bank module for all operations (both native transfers and delegation) + // Convert from wei (18 decimals) to aatom (6 decimals) by dividing by 1e12 + totalAmountWei := AutoFlushNativeAmount*2 + AutoFlushDelegationAmount + totalAmountAatom := sdkmath.NewInt(int64(totalAmountWei / 1_000_000_000_000)) + suite.fundContractNative(contractAddrSDK, totalAmountAatom) + + // Get recipient and validator + recipientAddr := common.BytesToAddress(senderAccount.SenderAccount.GetAddress().Bytes()) + recipientAddrSDK := senderAccount.SenderAccount.GetAddress() + validatorAddr := suite.getValidatorAddress() + + // Get balances before + ctx = suite.chain.GetContext() + bondDenom, err := evmApp.StakingKeeper.BondDenom(ctx) + suite.Require().NoError(err) + + contractBalBefore := evmApp.GetBankKeeper().GetBalance(ctx, contractAddrSDK, bondDenom) + recipientBalBefore := evmApp.GetBankKeeper().GetBalance(ctx, recipientAddrSDK, bondDenom) + + // Pack the call data + callData, err := contractData.ABI.Pack( + "scenario3_nativeTransferDelegateNativeTransfer", + recipientAddr, + big.NewInt(AutoFlushNativeAmount), + validatorAddr, + big.NewInt(AutoFlushDelegationAmount), + ) + suite.Require().NoError(err) + + // Execute via SendEvmTx to get proper event tracking + res, _, _, err := suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + big.NewInt(0), + callData, + 0, + ) + suite.Require().NoError(err) + + // Get balances after + ctx = suite.chain.GetContext() + contractBalAfter := evmApp.GetBankKeeper().GetBalance(ctx, contractAddrSDK, bondDenom) + recipientBalAfter := evmApp.GetBankKeeper().GetBalance(ctx, recipientAddrSDK, bondDenom) + + // Bank balances are in Cosmos units (6 decimals), EVM amounts are in wei (18 decimals) + // Conversion: 1e18 wei = 1e6 aatom (divide by 1e12) + conversionFactor := sdkmath.NewInt(1_000_000_000_000) // 1e12 + + // Verify balances - contract should lose 2x native transfer + delegation (in bank units) + expectedContractDeltaWei := sdkmath.NewInt(AutoFlushNativeAmount*2 + AutoFlushDelegationAmount) + expectedContractDelta := expectedContractDeltaWei.Quo(conversionFactor) + actualContractDelta := contractBalBefore.Amount.Sub(contractBalAfter.Amount) + + // Verify recipient received 2x native amount (in bank units) + expectedRecipientDeltaWei := sdkmath.NewInt(AutoFlushNativeAmount * 2) + expectedRecipientDelta := expectedRecipientDeltaWei.Quo(conversionFactor) + actualRecipientDelta := recipientBalAfter.Amount.Sub(recipientBalBefore.Amount) + + suite.Require().Equal(expectedContractDelta.String(), actualContractDelta.String(), "contract balance delta mismatch") + suite.Require().Equal(expectedRecipientDelta.String(), actualRecipientDelta.String(), "recipient should receive 2x native amount") + + // Verify delegation occurred + delegations, err := evmApp.StakingKeeper.GetAllDelegatorDelegations(ctx, contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(len(delegations), 1, "should have 1 delegation") + bondedTokens, err := evmApp.StakingKeeper.GetDelegatorBonded(suite.chain.GetContext(), contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(AutoFlushDelegationAmount/conversionFactor.Int64(), bondedTokens.Int64()) + + suite.Require().Equal(PreciseBankMintEventCount+PreciseBankBurnEventCount+DelegationEventCount+PreciseBankMintEventCount+PreciseBankBurnEventCount+EVMEventCount, len(res.Events)) +} + +// Scenario 4: Native transfer -> Delegate (reverted & caught) -> Native transfer +func (suite *AutoFlushTestSuite) TestScenario4_NativeTransferDelegateRevertNativeTransfer() { + suite.SetupTest() + + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + // Deploy test contract + contractData, err := contracts.LoadSequentialOperationsTester() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + contractAddrSDK := sdk.AccAddress(contractAddr.Bytes()) + + // Fund contract with native tokens for transfers via direct EVM transfer + senderAccount := suite.chain.SenderAccounts[AutoFlushSenderIndex] + nativeTransferValue := big.NewInt(AutoFlushNativeAmount * 2) // 2x transfers + _, _, _, err = suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + nativeTransferValue, + nil, // no data, just value transfer + 0, + ) + suite.Require().NoError(err) + suite.chain.NextBlock() + + // Get recipient and validator + recipientAddr := common.BytesToAddress(senderAccount.SenderAccount.GetAddress().Bytes()) + recipientAddrSDK := senderAccount.SenderAccount.GetAddress() + validatorAddr := suite.getValidatorAddress() + + // Get balances before + bondDenom, err := evmApp.StakingKeeper.BondDenom(ctx) + suite.Require().NoError(err) + + contractBalBefore := evmApp.GetBankKeeper().GetBalance(ctx, contractAddrSDK, bondDenom) + recipientBalBefore := evmApp.GetBankKeeper().GetBalance(ctx, recipientAddrSDK, bondDenom) + + // Pack the call data with excessive delegation amount (will revert and be caught) + excessiveAmount := new(big.Int).Mul(big.NewInt(AutoFlushDelegationAmount), big.NewInt(1000)) + callData, err := contractData.ABI.Pack( + "scenario4_nativeTransferDelegateRevertNativeTransfer", + recipientAddr, + big.NewInt(AutoFlushNativeAmount), + validatorAddr, + excessiveAmount, // Will fail - insufficient balance + ) + suite.Require().NoError(err) + + // Execute via SendEvmTx to get proper event tracking + res, _, _, err := suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + big.NewInt(0), + callData, + 0, + ) + suite.Require().NoError(err) + + // Get balances after + ctx = suite.chain.GetContext() + contractBalAfter := evmApp.GetBankKeeper().GetBalance(ctx, contractAddrSDK, bondDenom) + recipientBalAfter := evmApp.GetBankKeeper().GetBalance(ctx, recipientAddrSDK, bondDenom) + + // Bank balances are in Cosmos units (6 decimals), EVM amounts are in wei (18 decimals) + // Conversion: 1e18 wei = 1e6 aatom (divide by 1e12) + conversionFactor := sdkmath.NewInt(1_000_000_000_000) // 1e12 + + // Verify balances - contract should lose only 2x native transfer (delegation reverted, in bank units) + expectedContractDeltaWei := sdkmath.NewInt(AutoFlushNativeAmount * 2) + expectedContractDelta := expectedContractDeltaWei.Quo(conversionFactor) + actualContractDelta := contractBalBefore.Amount.Sub(contractBalAfter.Amount) + + // Verify recipient received 2x native amount (in bank units) + expectedRecipientDeltaWei := sdkmath.NewInt(AutoFlushNativeAmount * 2) + expectedRecipientDelta := expectedRecipientDeltaWei.Quo(conversionFactor) + actualRecipientDelta := recipientBalAfter.Amount.Sub(recipientBalBefore.Amount) + + suite.Require().Equal(expectedContractDelta.String(), actualContractDelta.String(), "contract balance delta mismatch") + suite.Require().Equal(expectedRecipientDelta.String(), actualRecipientDelta.String(), "recipient should receive 2x native amount") + + // Verify NO delegation occurred (it was reverted) + delegations, err := evmApp.StakingKeeper.GetAllDelegatorDelegations(ctx, contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(0, len(delegations), "should have no delegations since it reverted") + bondedTokens, err := evmApp.StakingKeeper.GetDelegatorBonded(suite.chain.GetContext(), contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(int64(0), bondedTokens.Int64()) + + suite.Require().Equal(PreciseBankBurnEventCount+PreciseBankBurnEventCount+EVMEventCount, len(res.Events)) // no delegation in middle, so we bundle the two events transfer events into one +} + +// Scenario 5: Delegate -> Create Contract -> Delegate +func (suite *AutoFlushTestSuite) TestScenario5_DelegateCreateDelegate() { + suite.SetupTest() + + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + // Deploy test contract + contractData, err := contracts.LoadContractCreationTester() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + contractAddrSDK := sdk.AccAddress(contractAddr.Bytes()) + + // Fund contract for delegations via bank module + delegationAmountAatom := sdkmath.NewInt(int64(AutoFlushDelegationAmount * 2)) + suite.fundContractNative(contractAddrSDK, delegationAmountAatom) + + // Get validator + senderAccount := suite.chain.SenderAccounts[AutoFlushSenderIndex] + validatorAddr := suite.getValidatorAddress() + + // Value to send when creating the contract + creationValue := big.NewInt(AutoFlushNativeAmount) + + // Pack the call data + callData, err := contractData.ABI.Pack( + "scenario4_delegateCreateDelegate", + validatorAddr, + big.NewInt(AutoFlushDelegationAmount), + big.NewInt(1).Quo(creationValue, big.NewInt(10)), + big.NewInt(AutoFlushDelegationAmount), + ) + suite.Require().NoError(err) + + // Execute via SendEvmTx with value for contract creation + res, _, _, err := suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + creationValue, // Send value for the new contract creation + callData, + 0, + ) + suite.Require().NoError(err) + + // Verify 1 delegations occurred + delegations, err := evmApp.StakingKeeper.GetAllDelegatorDelegations(ctx, contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(1, len(delegations), "should have 1 delegation") + bondedTokens, err := evmApp.StakingKeeper.GetDelegatorBonded(suite.chain.GetContext(), contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(AutoFlushDelegationAmount*2/1_000_000_000_000, bondedTokens.Int64()) + + suite.Require().Equal(PreciseBankMintEventCount+PreciseBankBurnEventCount+DelegationEventCount+PreciseBankMintEventCount+PreciseBankBurnEventCount+DelegationEventCount+WithdrawalNoTokensEventCount+EVMEventCount, len(res.Events)) +} + +// Scenario 6: Delegate -> Create Contract (reverted & caught) -> Delegate +func (suite *AutoFlushTestSuite) TestScenario6_DelegateCreateRevertDelegate() { + suite.SetupTest() + + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + // Deploy test contract + contractData, err := contracts.LoadContractCreationTester() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + contractAddrSDK := sdk.AccAddress(contractAddr.Bytes()) + + // Fund contract for delegations via bank module + delegationAmountAatom := sdkmath.NewInt(int64(AutoFlushDelegationAmount * 2)) + suite.fundContractNative(contractAddrSDK, delegationAmountAatom.QuoRaw(1_000_000_000_000)) + + // Get validator + senderAccount := suite.chain.SenderAccounts[AutoFlushSenderIndex] + validatorAddr := suite.getValidatorAddress() + + // Excessive value that will cause contract creation to fail + excessiveValue := new(big.Int).Mul(big.NewInt(AutoFlushNativeAmount), big.NewInt(1000)) + + // Pack the call data + callData, err := contractData.ABI.Pack( + "scenario5_delegateCreateRevertDelegate", + validatorAddr, + big.NewInt(AutoFlushDelegationAmount), + excessiveValue, // Will fail - insufficient value + big.NewInt(AutoFlushDelegationAmount), + ) + suite.Require().NoError(err) + + // Execute via SendEvmTx + res, _, _, err := suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + big.NewInt(0), + callData, + 0, + ) + suite.Require().NoError(err) + + // Verify 1 delegation occurred + delegations, err := evmApp.StakingKeeper.GetAllDelegatorDelegations(ctx, contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(1, len(delegations), "should have 1 delegation") + bondedTokens, err := evmApp.StakingKeeper.GetDelegatorBonded(suite.chain.GetContext(), contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(AutoFlushDelegationAmount*2/1_000_000_000_000, bondedTokens.Int64()) + + suite.Require().Equal(DelegationEventCount+DelegationEventCount+WithdrawalNoTokensEventCount+EVMEventCount, len(res.Events)) +} + +// Scenario 7: Create+Revert (caught) -> Delegate -> Create+Revert (caught) +func (suite *AutoFlushTestSuite) TestScenario7_CreateRevertDelegateCreateRevert() { + suite.SetupTest() + + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + // Deploy test contract + contractData, err := contracts.LoadContractCreationTester() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + contractAddrSDK := sdk.AccAddress(contractAddr.Bytes()) + senderAccount := suite.chain.SenderAccounts[AutoFlushSenderIndex] + + // Fund contract for delegation via bank module + delegationAmountAatom := sdkmath.NewInt(int64(AutoFlushDelegationAmount)) + suite.fundContractNative(contractAddrSDK, delegationAmountAatom) + + // Fund contract with some EVM balance for contract creations (even though they revert) + // This is needed because the contract needs balance to create sub-contracts + fundingAmount := big.NewInt(AutoFlushNativeAmount) + _, _, _, err = suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + fundingAmount, + nil, + 0, + ) + suite.Require().NoError(err) + suite.chain.NextBlock() + + // Get validator + validatorAddr := suite.getValidatorAddress() + + // Values for contract creations (use 0 to avoid balance issues with reverts) + creationValue1 := big.NewInt(0) + creationValue2 := big.NewInt(0) + + // Pack the call data + callData, err := contractData.ABI.Pack( + "scenario6_createRevertDelegateCreateRevert", + creationValue1, + validatorAddr, + big.NewInt(AutoFlushDelegationAmount), + creationValue2, + ) + suite.Require().NoError(err) + + // Execute via SendEvmTx (no value needed since contract creations use 0 and revert) + res, _, _, err := suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + big.NewInt(0), + callData, + 0, + ) + suite.Require().NoError(err) + + // Verify 1 delegation occurred + delegations, err := evmApp.StakingKeeper.GetAllDelegatorDelegations(ctx, contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(1, len(delegations), "should have 1 delegation") + bondedTokens, err := evmApp.StakingKeeper.GetDelegatorBonded(suite.chain.GetContext(), contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(AutoFlushDelegationAmount/1_000_000_000_000, bondedTokens.Int64()) + + suite.Require().Equal(DelegationEventCount+EVMEventCount, len(res.Events)) +} + +// Scenario 8: Create+Send -> Delegate (reverted & caught) -> Send more +func (suite *AutoFlushTestSuite) TestScenario8_CreateDelegateRevertSend() { + suite.SetupTest() + + evmApp := suite.chain.App.(*evmd.EVMD) + ctx := suite.chain.GetContext() + + // Deploy test contract + contractData, err := contracts.LoadContractCreationTester() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + // Get validator + senderAccount := suite.chain.SenderAccounts[AutoFlushSenderIndex] + validatorAddr := suite.getValidatorAddress() + + // Values for operations + creationValue := big.NewInt(AutoFlushNativeAmount) + sendAmount := big.NewInt(AutoFlushNativeAmount / 2) + excessiveDelegateAmount := new(big.Int).Mul(big.NewInt(AutoFlushDelegationAmount), big.NewInt(1000)) + + // Pack the call data + callData, err := contractData.ABI.Pack( + "scenario7_createDelegateRevertSend", + creationValue, + validatorAddr, + excessiveDelegateAmount, // Will fail - insufficient balance + sendAmount, + ) + suite.Require().NoError(err) + + // Execute via SendEvmTx with value for contract creation and sends + totalValue := new(big.Int).Add(creationValue, sendAmount) + res, _, _, err := suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + totalValue, + callData, + 0, + ) + suite.Require().NoError(err) + + // Verify NO delegation occurred (it was reverted) + contractAddrSDK := sdk.AccAddress(contractAddr.Bytes()) + delegations, err := evmApp.StakingKeeper.GetAllDelegatorDelegations(ctx, contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(0, len(delegations), "should have no delegations since it reverted") + + suite.Require().Equal(PreciseBankMintEventCount+PreciseBankBurnEventCount+EVMEventCount, len(res.Events)) +} + +// Scenario 9: Create+Revert (caught) -> Delegate -> Create+Success +func (suite *AutoFlushTestSuite) TestScenario9_CreateRevertDelegateCreateSuccess() { + suite.SetupTest() + + evmApp := suite.chain.App.(*evmd.EVMD) + + // Deploy test contract + contractData, err := contracts.LoadContractCreationTester() + suite.Require().NoError(err) + + deploymentData := testutiltypes.ContractDeploymentData{ + Contract: contractData, + ConstructorArgs: []interface{}{}, + } + + contractAddr, err := DeployContract(suite.T(), suite.chain, deploymentData) + suite.chain.NextBlock() + suite.Require().NoError(err) + + contractAddrSDK := sdk.AccAddress(contractAddr.Bytes()) + senderAccount := suite.chain.SenderAccounts[AutoFlushSenderIndex] + + // Fund contract for delegation via bank module + delegationAmountAatom := sdkmath.NewInt(int64(AutoFlushDelegationAmount / 1_000_000_000_000)) + suite.fundContractNative(contractAddrSDK, delegationAmountAatom) + + // Fund contract with EVM balance for contract creations + // Need enough for the successful creation (reverted one returns the value) + fundingAmount := big.NewInt(AutoFlushNativeAmount * 2) // Extra buffer + _, _, _, err = suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + fundingAmount, + nil, + 0, + ) + suite.Require().NoError(err) + suite.chain.NextBlock() + + // Get validator + validatorAddr := suite.getValidatorAddress() + + // Values for operations + revertCreationValue := big.NewInt(AutoFlushNativeAmount / 2) + successCreationValue := big.NewInt(AutoFlushNativeAmount / 2) + + // Get balances before + ctx := suite.chain.GetContext() + bondDenom, err := evmApp.StakingKeeper.BondDenom(ctx) + suite.Require().NoError(err) + contractBalBefore := evmApp.GetBankKeeper().GetBalance(ctx, contractAddrSDK, bondDenom) + + // Pack the call data + callData, err := contractData.ABI.Pack( + "scenario8_createRevertDelegateCreateSuccess", + revertCreationValue, + validatorAddr, + big.NewInt(AutoFlushDelegationAmount), + successCreationValue, + ) + suite.Require().NoError(err) + + // Execute via SendEvmTx + res, _, _, err := suite.chain.SendEvmTx( + senderAccount, + AutoFlushSenderIndex, + contractAddr, + big.NewInt(0), + callData, + 0, + ) + suite.Require().NoError(err) + + // Verify final state + ctx = suite.chain.GetContext() + + // Check delegation occurred + delegations, err := evmApp.StakingKeeper.GetAllDelegatorDelegations(ctx, contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(1, len(delegations), "should have 1 delegation") + bondedTokens, err := evmApp.StakingKeeper.GetDelegatorBonded(suite.chain.GetContext(), contractAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(AutoFlushDelegationAmount/1_000_000_000_000, bondedTokens.Int64()) + + // Check created contracts count + stateDB := testutil.NewStateDB(ctx, evmApp.EVMKeeper) + + countResult, err := evmApp.GetEVMKeeper().CallEVM( + ctx, + stateDB, + contractData.ABI, + contractAddr, + contractAddr, + true, + false, + nil, + "getCreatedContractsCount", + ) + suite.Require().NoError(err) + + var createdCount *big.Int + err = contractData.ABI.UnpackIntoInterface(&createdCount, "getCreatedContractsCount", countResult.Ret) + suite.Require().NoError(err) + suite.Require().Equal(int64(1), createdCount.Int64(), "should have 1 created contract (reverted one doesn't count)") + + // Get the created contract address + addrResult, err := evmApp.GetEVMKeeper().CallEVM( + ctx, + stateDB, + contractData.ABI, + contractAddr, + contractAddr, + true, + false, + nil, + "getCreatedContract", + big.NewInt(0), + ) + suite.Require().NoError(err) + + var createdContractAddr common.Address + err = contractData.ABI.UnpackIntoInterface(&createdContractAddr, "getCreatedContract", addrResult.Ret) + suite.Require().NoError(err) + + // Check the created contract's balance + createdContractBalance := stateDB.GetBalance(createdContractAddr) + suite.Require().Equal(successCreationValue.String(), createdContractBalance.String(), + "created contract should have the creation value") + + // Check main contract's bank balance decreased by delegation + created contract value + contractBalAfter := evmApp.GetBankKeeper().GetBalance(ctx, contractAddrSDK, bondDenom) + // Delta = delegation amount + successful creation value (reverted creation returns the value) + expectedDelta := sdkmath.NewInt((AutoFlushDelegationAmount + successCreationValue.Int64()) / 1_000_000_000_000) + actualDelta := contractBalBefore.Amount.Sub(contractBalAfter.Amount) + suite.Require().Equal(expectedDelta.String(), actualDelta.String(), "bank balance should decrease by delegation + creation value") + + suite.Require().Equal(DelegationEventCount+PreciseBankMintEventCount+PreciseBankBurnEventCount+EVMEventCount, len(res.Events)) +} diff --git a/evmd/tests/ibc/helper.go b/evmd/tests/ibc/helper.go index b7df90579..f9232f2a3 100644 --- a/evmd/tests/ibc/helper.go +++ b/evmd/tests/ibc/helper.go @@ -2,9 +2,11 @@ package ibc import ( "errors" + "fmt" "math/big" "testing" + abci "github.com/cometbft/cometbft/abci/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -14,15 +16,28 @@ import ( evmibctesting "github.com/cosmos/evm/testutil/ibc" testutiltypes "github.com/cosmos/evm/testutil/types" erc20types "github.com/cosmos/evm/x/erc20/types" + "github.com/cosmos/evm/x/vm/statedb" + "github.com/cosmos/evm/x/vm/types" ibctesting "github.com/cosmos/ibc-go/v10/testing" errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) +// Event count constants for test assertions +const ( + PreciseBankMintEventCount = 9 // Native transfer with mint operation + PreciseBankBurnEventCount = 9 // Native transfer with burn operation + DelegationEventCount = 3 // Staking delegation events + EVMEventCount = 5 // EVM transaction wrapper events + WithdrawalNoTokensEventCount = 1 // Withdrawal with no tokens + ICS20WithConversionEventCount = 15 // ERC20 conversion (7) + IBC packet (8) +) + // NativeErc20Info holds details about a deployed ERC20 token. type NativeErc20Info struct { Denom string @@ -40,7 +55,8 @@ func SetupNativeErc20(t *testing.T, chain *evmibctesting.TestChain, senderAcc ev evmApp := chain.App.(evm.EvmApp) // Deploy new ERC20 contract with default metadata - contractAddr, err := evmApp.GetErc20Keeper().DeployERC20Contract(evmCtx, banktypes.Metadata{ + stateDB := statedb.New(chain.GetContext(), chain.App.(evm.EvmApp).GetEVMKeeper(), statedb.NewEmptyTxConfig()) + contractAddr, err := DeployERC20Contract(evmCtx, stateDB, evmApp.GetAccountKeeper(), evmApp.GetEVMKeeper(), banktypes.Metadata{ DenomUnits: []*banktypes.DenomUnit{ {Denom: "example", Exponent: 18}, }, @@ -67,12 +83,15 @@ func SetupNativeErc20(t *testing.T, chain *evmibctesting.TestChain, senderAcc ev sendAmt := ibctesting.DefaultCoinAmount senderAddr := senderAcc.SenderAccount.GetAddress() + stateDB = statedb.New(evmCtx, evmApp.GetEVMKeeper(), statedb.NewEmptyTxConfig()) _, err = evmApp.GetEVMKeeper().CallEVM( evmCtx, + stateDB, contractAbi, erc20types.ModuleAddress, contractAddr, true, + false, nil, "mint", common.BytesToAddress(senderAddr), @@ -116,10 +135,69 @@ func DeployContract(t *testing.T, chain *evmibctesting.TestChain, deploymentData data := deploymentData.Contract.Bin data = append(data, ctorArgs...) - _, err = chain.App.(evm.EvmApp).GetEVMKeeper().CallEVMWithData(chain.GetContext(), from, nil, data, true, nil) + stateDB := statedb.New(chain.GetContext(), chain.App.(evm.EvmApp).GetEVMKeeper(), statedb.NewEmptyTxConfig()) + + _, err = chain.App.(evm.EvmApp).GetEVMKeeper().CallEVMWithData(chain.GetContext(), stateDB, from, nil, data, true, false, nil) if err != nil { return common.Address{}, errorsmod.Wrapf(err, "failed to deploy contract") } return crypto.CreateAddress(from, account.Nonce), nil } + +// DeployERC20Contract creates and deploys an ERC20 contract on the EVM with the +// erc20 module account as owner. +func DeployERC20Contract( + ctx sdk.Context, + stateDB *statedb.StateDB, + accountKeeper erc20types.AccountKeeper, + evmKeeper erc20types.EVMKeeper, + coinMetadata banktypes.Metadata, +) (common.Address, error) { + decimals := uint8(0) + if len(coinMetadata.DenomUnits) > 0 { + decimalsIdx := len(coinMetadata.DenomUnits) - 1 + decimals = uint8(coinMetadata.DenomUnits[decimalsIdx].Exponent) //#nosec G115 // exponent will not exceed uint8 + } + ctorArgs, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack( + "", + coinMetadata.Name, + coinMetadata.Symbol, + decimals, + ) + if err != nil { + return common.Address{}, errorsmod.Wrapf(types.ErrABIPack, "coin metadata is invalid %s: %s", coinMetadata.Name, err.Error()) + } + + data := make([]byte, len(contracts.ERC20MinterBurnerDecimalsContract.Bin)+len(ctorArgs)) + copy(data[:len(contracts.ERC20MinterBurnerDecimalsContract.Bin)], contracts.ERC20MinterBurnerDecimalsContract.Bin) + copy(data[len(contracts.ERC20MinterBurnerDecimalsContract.Bin):], ctorArgs) + + nonce, err := accountKeeper.GetSequence(ctx, erc20types.ModuleAddress.Bytes()) + if err != nil { + return common.Address{}, err + } + + contractAddr := crypto.CreateAddress(erc20types.ModuleAddress, nonce) + _, err = evmKeeper.CallEVMWithData(ctx, stateDB, erc20types.ModuleAddress, nil, data, true, false, nil) + if err != nil { + return common.Address{}, errorsmod.Wrapf(err, "failed to deploy contract for %s", coinMetadata.Name) + } + + return contractAddr, nil +} + +// PrintEvents prints all events with their attributes for debugging +func PrintEvents(label string, events []abci.Event) { + fmt.Printf("\n========== Events for %s ==========\n", label) + fmt.Printf("Total Event Count: %d\n\n", len(events)) + + for i, event := range events { + fmt.Printf("[%d] Type: %s\n", i, event.Type) + for _, attr := range event.Attributes { + fmt.Printf(" %s: %s\n", attr.Key, attr.Value) + } + fmt.Println() + } + fmt.Printf("========================================\n\n") +} diff --git a/evmd/tests/ibc/ibc_middleware_test.go b/evmd/tests/ibc/ibc_middleware_test.go index b930641dd..7a607544c 100644 --- a/evmd/tests/ibc/ibc_middleware_test.go +++ b/evmd/tests/ibc/ibc_middleware_test.go @@ -15,6 +15,7 @@ import ( "github.com/cosmos/evm/evmd" "github.com/cosmos/evm/evmd/tests/integration" "github.com/cosmos/evm/ibc" + ics20precompile "github.com/cosmos/evm/precompiles/ics20" "github.com/cosmos/evm/testutil" evmibctesting "github.com/cosmos/evm/testutil/ibc" testutiltypes "github.com/cosmos/evm/testutil/types" @@ -23,6 +24,7 @@ import ( "github.com/cosmos/evm/x/erc20/types" ibctestutil "github.com/cosmos/evm/x/ibc/callbacks/testutil" callbacktypes "github.com/cosmos/evm/x/ibc/callbacks/types" + "github.com/cosmos/evm/x/vm/statedb" evmtypes "github.com/cosmos/evm/x/vm/types" ibctransfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" @@ -45,7 +47,8 @@ type MiddlewareTestSuite struct { evmChainA *evmibctesting.TestChain chainB *evmibctesting.TestChain - path *evmibctesting.Path + path *evmibctesting.Path + evmChainAPrecompile *ics20precompile.Precompile } // SetupTest initializes the coordinator and test chains before each test. @@ -65,6 +68,80 @@ func (suite *MiddlewareTestSuite) SetupTest() { // ensure the channel is found to verify proper setup _, found := suite.evmChainA.App.GetIBCKeeper().ChannelKeeper.GetChannel(suite.evmChainA.GetContext(), suite.path.EndpointA.ChannelConfig.PortID, suite.path.EndpointA.ChannelID) suite.Require().True(found) + + // Setup ICS20 precompile for evmChainA + evmAppA := suite.evmChainA.App.(*evmd.EVMD) + suite.evmChainAPrecompile = ics20precompile.NewPrecompile( + evmAppA.BankKeeper, + *evmAppA.StakingKeeper, + evmAppA.TransferKeeper, + evmAppA.IBCKeeper.ChannelKeeper, + evmAppA.Erc20Keeper, + ) +} + +// transferViaPrecompile sends an IBC transfer using the ICS20 precompile. +// This is required for native ERC20 tokens. +func (suite *MiddlewareTestSuite) transferViaPrecompile( + ctx sdk.Context, + sourcePort, sourceChannel string, + token sdk.Coin, + sender, receiver string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + memo string, +) (uint64, error) { + evmApp := suite.evmChainA.App.(*evmd.EVMD) + + // Convert sender to address type + senderAddr := sdk.MustAccAddressFromBech32(sender) + senderEthAddr := common.BytesToAddress(senderAddr) + + // Create timeoutHeight struct matching the ABI + type Height struct { + RevisionNumber uint64 + RevisionHeight uint64 + } + timeoutHeightStruct := Height{ + RevisionNumber: timeoutHeight.RevisionNumber, + RevisionHeight: timeoutHeight.RevisionHeight, + } + + // Call the precompile through the EVM with correct parameter order and types + // ABI order: sourcePort, sourceChannel, denom, amount, sender (address), receiver, timeoutHeight (struct), timeoutTimestamp, memo + stateDB := statedb.New(suite.evmChainA.GetContext(), evmApp.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + res, err := evmApp.EVMKeeper.CallEVM( + ctx, + stateDB, + ics20precompile.ABI, + senderEthAddr, + common.HexToAddress(ics20precompile.PrecompileAddress), + true, + false, + nil, + "transfer", + sourcePort, + sourceChannel, + token.Denom, + token.Amount.BigInt(), + senderEthAddr, + receiver, + timeoutHeightStruct, + timeoutTimestamp, + memo, + ) + if err != nil { + return 0, err + } + + // Unpack the sequence from the result + var sequence uint64 + err = ics20precompile.ABI.UnpackIntoInterface(&sequence, "transfer", res.Ret) + if err != nil { + return 0, err + } + + return sequence, nil } func TestMiddlewareTestSuite(t *testing.T) { @@ -617,17 +694,22 @@ func (suite *MiddlewareTestSuite) TestOnRecvPacketNativeErc20() { senderEthAddr := nativeErc20.Account sender := sdk.AccAddress(senderEthAddr.Bytes()) - // Transfer half the initial balance out + // Transfer half the initial balance out using the precompile // Sender transfers 50 out (escrowed) - msg := transfertypes.NewMsgTransfer( - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, + _, err := suite.transferViaPrecompile( + evmCtx, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, sdk.NewCoin(nativeErc20.Denom, sendAmt), - sender.String(), chainBAccount.String(), - timeoutHeight, 0, "", + sender.String(), + chainBAccount.String(), + timeoutHeight, + 0, + "", ) - - _, err := suite.evmChainA.SendMsgs(msg) suite.Require().NoError(err) // message committed + suite.evmChainA.NextBlock() + evmCtx = suite.evmChainA.GetContext() // Balance after transfer should be initial balance - sendAmt balAfterTransfer := evmApp.Erc20Keeper.BalanceOf(evmCtx, nativeErc20.ContractAbi, nativeErc20.ContractAddr, senderEthAddr) @@ -1211,19 +1293,21 @@ func (suite *MiddlewareTestSuite) TestOnAcknowledgementPacketWithCallback() { ack, receiver, ) + stateDB := statedb.New(suite.evmChainA.GetContext(), evmApp.GetEVMKeeper(), statedb.NewEmptyTxConfig()) // Validate results if tc.expError == "" { suite.Require().NoError(err, "Expected success but got error") - // Verify callback execution by checking counter increment if strings.Contains(tc.memo(), "src_callback") { counterRes, err := evmApp.EVMKeeper.CallEVM( ctxA, + stateDB, contractData.ABI, common.BytesToAddress(suite.evmChainA.SenderAccount.GetAddress()), contractAddr, false, + false, big.NewInt(100000), "getCounter", ) @@ -1250,10 +1334,12 @@ func (suite *MiddlewareTestSuite) TestOnAcknowledgementPacketWithCallback() { counterRes, err := evmApp.EVMKeeper.CallEVM( ctxA, + stateDB, contractData.ABI, common.BytesToAddress(suite.evmChainA.SenderAccount.GetAddress()), contractAddr, false, + false, big.NewInt(100000), "getCounter", ) @@ -1483,13 +1569,6 @@ func (suite *MiddlewareTestSuite) TestOnAcknowledgementPacketNativeErc20() { sender := sdk.AccAddress(senderEthAddr.Bytes()) receiver := suite.chainB.SenderAccount.GetAddress() - // Send the native erc20 token from evmChainA to chainB. - msg := transfertypes.NewMsgTransfer( - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - sdk.NewCoin(nativeErc20.Denom, sendAmt), sender.String(), receiver.String(), - timeoutHeight, 0, "", - ) - escrowAddr := transfertypes.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) // checkEscrow is a check function to ensure the native erc20 token is escrowed. checkEscrow := func() { @@ -1512,8 +1591,21 @@ func (suite *MiddlewareTestSuite) TestOnAcknowledgementPacketNativeErc20() { suite.Require().Equal(nativeErc20.InitialBal.String(), erc20BalAfterIbcTransfer.String()) } - _, err := suite.evmChainA.SendMsgs(msg) + // Send the native erc20 token from evmChainA to chainB using the precompile. + _, err := suite.transferViaPrecompile( + evmCtx, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + sdk.NewCoin(nativeErc20.Denom, sendAmt), + sender.String(), + receiver.String(), + timeoutHeight, + 0, + "", + ) suite.Require().NoError(err) // message committed + suite.evmChainA.NextBlock() + evmCtx = suite.evmChainA.GetContext() checkEscrow() transferStack, ok := suite.evmChainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) @@ -2012,6 +2104,7 @@ func (suite *MiddlewareTestSuite) TestOnTimeoutPacketWithCallback() { receiver, ) balAfterTimeout := evmApp.BankKeeper.GetBalance(ctxA, sender, bondDenom) + stateDB := statedb.New(suite.evmChainA.GetContext(), evmApp.GetEVMKeeper(), statedb.NewEmptyTxConfig()) // Validate results if tc.expError == "" { @@ -2023,10 +2116,12 @@ func (suite *MiddlewareTestSuite) TestOnTimeoutPacketWithCallback() { if strings.Contains(tc.memo(), "src_callback") { counterRes, err := evmApp.EVMKeeper.CallEVM( ctxA, + stateDB, contractData.ABI, common.BytesToAddress(suite.evmChainA.SenderAccount.GetAddress()), contractAddr, false, + false, big.NewInt(100000), "getCounter", ) @@ -2055,10 +2150,12 @@ func (suite *MiddlewareTestSuite) TestOnTimeoutPacketWithCallback() { if strings.Contains(tc.memo(), "src_callback") && strings.Contains(tc.expError, "ABCI code") { counterRes, err := evmApp.EVMKeeper.CallEVM( ctxA, + stateDB, contractData.ABI, common.BytesToAddress(suite.evmChainA.SenderAccount.GetAddress()), contractAddr, false, + false, big.NewInt(100000), "getCounter", ) @@ -2130,12 +2227,6 @@ func (suite *MiddlewareTestSuite) TestOnTimeoutPacketNativeErc20() { sender := sdk.AccAddress(senderEthAddr.Bytes()) receiver := suite.chainB.SenderAccount.GetAddress() - msg := transfertypes.NewMsgTransfer( - path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, - sdk.NewCoin(nativeErc20.Denom, sendAmt), sender.String(), receiver.String(), - timeoutHeight, 0, "", - ) - escrowAddr := transfertypes.GetEscrowAddress(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) // checkEscrow is a check function to ensure the native erc20 token is escrowed. checkEscrow := func() { @@ -2157,8 +2248,22 @@ func (suite *MiddlewareTestSuite) TestOnTimeoutPacketNativeErc20() { erc20BalAfterIbcTransfer := evmApp.Erc20Keeper.BalanceOf(evmCtx, nativeErc20.ContractAbi, nativeErc20.ContractAddr, senderEthAddr) suite.Require().Equal(nativeErc20.InitialBal.String(), erc20BalAfterIbcTransfer.String()) } - _, err := suite.evmChainA.SendMsgs(msg) + + // Send the native erc20 token from evmChainA to chainB using the precompile. + _, err := suite.transferViaPrecompile( + evmCtx, + path.EndpointA.ChannelConfig.PortID, + path.EndpointA.ChannelID, + sdk.NewCoin(nativeErc20.Denom, sendAmt), + sender.String(), + receiver.String(), + timeoutHeight, + 0, + "", + ) suite.Require().NoError(err) // message committed + suite.evmChainA.NextBlock() + evmCtx = suite.evmChainA.GetContext() checkEscrow() transferStack, ok := suite.evmChainA.App.GetIBCKeeper().PortKeeper.Route(transfertypes.ModuleName) diff --git a/evmd/tests/ibc/ics20_erc20_conversion_test.go b/evmd/tests/ibc/ics20_erc20_conversion_test.go new file mode 100644 index 000000000..886f088d1 --- /dev/null +++ b/evmd/tests/ibc/ics20_erc20_conversion_test.go @@ -0,0 +1,500 @@ +package ibc + +import ( + "fmt" + "math/big" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/evm/evmd" + "github.com/cosmos/evm/evmd/tests/integration" + "github.com/cosmos/evm/precompiles/ics20" + evmibctesting "github.com/cosmos/evm/testutil/ibc" + erc20types "github.com/cosmos/evm/x/erc20/types" + transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" + + sdkmath "cosmossdk.io/math" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +type ICS20ERC20ConversionTestSuite struct { + suite.Suite + + coordinator *evmibctesting.Coordinator + + chainA *evmibctesting.TestChain + chainAPrecompile *ics20.Precompile + chainB *evmibctesting.TestChain + chainBPrecompile *ics20.Precompile +} + +func (suite *ICS20ERC20ConversionTestSuite) SetupTest() { + suite.coordinator = evmibctesting.NewCoordinator(suite.T(), 2, 0, integration.SetupEvmd) + suite.chainA = suite.coordinator.GetChain(evmibctesting.GetEvmChainID(1)) + suite.chainB = suite.coordinator.GetChain(evmibctesting.GetEvmChainID(2)) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + suite.chainAPrecompile = ics20.NewPrecompile( + evmAppA.BankKeeper, + *evmAppA.StakingKeeper, + evmAppA.TransferKeeper, + evmAppA.IBCKeeper.ChannelKeeper, + evmAppA.Erc20Keeper, + ) + evmAppB := suite.chainB.App.(*evmd.EVMD) + suite.chainBPrecompile = ics20.NewPrecompile( + evmAppB.BankKeeper, + *evmAppB.StakingKeeper, + evmAppB.TransferKeeper, + evmAppB.IBCKeeper.ChannelKeeper, + evmAppB.Erc20Keeper, + ) +} + +func TestICS20ERC20ConversionTestSuite(t *testing.T) { + suite.Run(t, new(ICS20ERC20ConversionTestSuite)) +} + +// TestTransferWithERC20Conversion tests IBC transfers with ERC20 token conversion +func (suite *ICS20ERC20ConversionTestSuite) TestTransferWithERC20Conversion() { + var ( + denom string + amount sdkmath.Int + sender common.Address + nativeErc20 *NativeErc20Info + path *evmibctesting.Path + ) + + receiver := suite.chainB.SenderAccount.GetAddress().String() + timeoutHeight := clienttypes.NewHeight(1, 110) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "pass - no token pair", + func() { + evmAppA := suite.chainA.App.(*evmd.EVMD) + var err error + denom, err = evmAppA.StakingKeeper.BondDenom(suite.chainA.GetContext()) + suite.Require().NoError(err) + amount = sdkmath.NewInt(10) + sender = common.BytesToAddress(suite.chainA.SenderAccount.GetAddress().Bytes()) + }, + true, + }, + { + "no-op - disabled erc20 by params - sufficient sdk.Coins balance", + func() { + // Deploy and mint ERC20 + nativeErc20 = SetupNativeErc20(suite.T(), suite.chainA, suite.chainA.SenderAccounts[0]) + denom = nativeErc20.Denom + amount = sdkmath.NewInt(nativeErc20.InitialBal.Int64()) + + // Convert ERC20 to coins + evmAppA := suite.chainA.App.(*evmd.EVMD) + _, err := evmAppA.Erc20Keeper.ConvertERC20(suite.chainA.GetContext(), &erc20types.MsgConvertERC20{ + ContractAddress: nativeErc20.ContractAddr.Hex(), + Amount: amount, + Receiver: suite.chainA.SenderAccount.GetAddress().String(), + Sender: nativeErc20.Account.Hex(), + }) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Disable ERC20 + params := evmAppA.Erc20Keeper.GetParams(suite.chainA.GetContext()) + params.EnableErc20 = false + err = evmAppA.Erc20Keeper.SetParams(suite.chainA.GetContext(), params) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + sender = nativeErc20.Account + }, + true, + }, + { + "error - disabled erc20 by params - insufficient sdk.Coins balance", + func() { + // Deploy and mint ERC20 but don't convert + nativeErc20 = SetupNativeErc20(suite.T(), suite.chainA, suite.chainA.SenderAccounts[0]) + denom = nativeErc20.Denom + amount = sdkmath.NewInt(nativeErc20.InitialBal.Int64()) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + ctx := suite.chainA.GetContext() + + // No conversion to IBC coin, so the balance is insufficient + suite.Require().EqualValues( + evmAppA.BankKeeper.GetBalance(ctx, suite.chainA.SenderAccount.GetAddress(), denom).Amount, + sdkmath.ZeroInt(), + "Bank balance should be zero since we didn't convert", + ) + + // Disable ERC20 without converting + params := evmAppA.Erc20Keeper.GetParams(ctx) + params.EnableErc20 = false + err := evmAppA.Erc20Keeper.SetParams(ctx, params) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + sender = nativeErc20.Account + }, + false, + }, + { + "error - pair not registered", + func() { + denom = "unregistered" + amount = sdkmath.NewInt(10) + sender = common.BytesToAddress(suite.chainA.SenderAccount.GetAddress().Bytes()) + }, + false, + }, + { + "no-op - pair is disabled", + func() { + // Deploy and mint ERC20 + nativeErc20 = SetupNativeErc20(suite.T(), suite.chainA, suite.chainA.SenderAccounts[0]) + denom = nativeErc20.Denom + amount = sdkmath.NewInt(nativeErc20.InitialBal.Int64()) + + // Convert to coins first + evmAppA := suite.chainA.App.(*evmd.EVMD) + _, err := evmAppA.Erc20Keeper.ConvertERC20(suite.chainA.GetContext(), &erc20types.MsgConvertERC20{ + ContractAddress: nativeErc20.ContractAddr.Hex(), + Amount: amount, + Receiver: suite.chainA.SenderAccount.GetAddress().String(), + Sender: nativeErc20.Account.Hex(), + }) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Disable the token pair + govAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() + _, err = evmAppA.Erc20Keeper.ToggleConversion(suite.chainA.GetContext(), &erc20types.MsgToggleConversion{ + Token: denom, + Authority: govAddr, + }) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + sender = nativeErc20.Account + }, + true, + }, + { + "pass - has enough balance in erc20 - need to convert", + func() { + // Deploy and mint ERC20 but don't convert - transfer should auto-convert + nativeErc20 = SetupNativeErc20(suite.T(), suite.chainA, suite.chainA.SenderAccounts[0]) + denom = nativeErc20.Denom + amount = sdkmath.NewInt(nativeErc20.InitialBal.Int64()) + + // Verify denom format is correct + suite.Require().Equal( + erc20types.CreateDenom(nativeErc20.ContractAddr.String()), + denom, + "Denom should match the ERC20 contract address format", + ) + + sender = nativeErc20.Account + }, + true, + }, + { + "pass - has enough balance in coins", + func() { + // Deploy and mint ERC20 + nativeErc20 = SetupNativeErc20(suite.T(), suite.chainA, suite.chainA.SenderAccounts[0]) + denom = nativeErc20.Denom + amount = sdkmath.NewInt(nativeErc20.InitialBal.Int64()) + + // Convert to coins + evmAppA := suite.chainA.App.(*evmd.EVMD) + _, err := evmAppA.Erc20Keeper.ConvertERC20(suite.chainA.GetContext(), &erc20types.MsgConvertERC20{ + ContractAddress: nativeErc20.ContractAddr.Hex(), + Amount: amount, + Receiver: suite.chainA.SenderAccount.GetAddress().String(), + Sender: nativeErc20.Account.Hex(), + }) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + sender = nativeErc20.Account + }, + true, + }, + { + "error - fail conversion - no balance in erc20", + func() { + // Deploy and register ERC20 but don't mint + nativeErc20 = SetupNativeErc20(suite.T(), suite.chainA, suite.chainA.SenderAccounts[0]) + denom = nativeErc20.Denom + // Request more than minted + amount = sdkmath.NewInt(nativeErc20.InitialBal.Int64() * 2) + sender = nativeErc20.Account + }, + false, + }, + { + "pass - verify correct prefix trimming for ERC20 native tokens", + func() { + // Deploy and mint ERC20 + nativeErc20 = SetupNativeErc20(suite.T(), suite.chainA, suite.chainA.SenderAccounts[0]) + denom = nativeErc20.Denom + amount = sdkmath.NewInt(nativeErc20.InitialBal.Int64()) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + ctx := suite.chainA.GetContext() + + // Create a denom with erc20: prefix + erc20Denom := erc20types.CreateDenom(nativeErc20.ContractAddr.String()) + suite.Require().Equal(erc20types.Erc20NativeCoinDenomPrefix+nativeErc20.ContractAddr.String(), erc20Denom) + + // Verify that GetTokenPairID works correctly with the contract address (hex string) + pairIDFromAddress := evmAppA.Erc20Keeper.GetTokenPairID(ctx, nativeErc20.ContractAddr.String()) + suite.Require().NotEmpty(pairIDFromAddress) + + // Verify that GetTokenPairID works correctly with the full denom + pairIDFromDenom := evmAppA.Erc20Keeper.GetTokenPairID(ctx, erc20Denom) + suite.Require().NotEmpty(pairIDFromDenom) + + // Both should return the same pair ID + suite.Require().Equal(pairIDFromAddress, pairIDFromDenom) + + sender = nativeErc20.Account + }, + true, + }, + { + "no-op - fail transfer", + func() { + evmAppA := suite.chainA.App.(*evmd.EVMD) + ctx := suite.chainA.GetContext() + senderAcc := suite.chainA.SenderAccount.GetAddress() + + // Create a fake IBC voucher denom (IBC-transferred token) + denom = "ibc/DF63978F803A2E27CA5CC9B7631654CCF0BBC788B3B7F0A10200508E37C70992" + + // Register it as an ERC20 extension + _, err := evmAppA.Erc20Keeper.RegisterERC20Extension(ctx, denom) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Verify the pair exists + pairID := evmAppA.Erc20Keeper.GetTokenPairID(ctx, denom) + suite.Require().NotEmpty(pairID, "Token pair should be registered") + + pair, found := evmAppA.Erc20Keeper.GetTokenPair(ctx, pairID) + suite.Require().True(found) + suite.Require().Equal(pair.Denom, denom) + + // Try to transfer without having any balance (should fail) + amount = sdkmath.NewInt(10) + sender = common.BytesToAddress(senderAcc) + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() + + // Setup IBC path + path = evmibctesting.NewTransferPath(suite.chainA, suite.chainB) + path.Setup() + + // Run test-specific setup + tc.malleate() + + // Call precompile transfer + data, err := suite.chainAPrecompile.ABI.Pack( + "transfer", + transfertypes.PortID, + path.EndpointA.ChannelID, + denom, + amount.BigInt(), + sender, + receiver, + timeoutHeight, + uint64(0), + "", + ) + suite.Require().NoError(err) + + res, _, _, err := suite.chainA.SendEvmTx( + suite.chainA.SenderAccounts[0], + 0, + suite.chainAPrecompile.Address(), + big.NewInt(0), + data, + 0, + ) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(uint32(0), res.Code, res.Log) + } else { + suite.Require().Error(err) + } + }) + } +} + +// TestPrefixTrimming specifically tests that the erc20: prefix is correctly handled +func (suite *ICS20ERC20ConversionTestSuite) TestPrefixTrimming() { + var ( + denom string + amount sdkmath.Int + sender common.Address + nativeErc20 *NativeErc20Info + path *evmibctesting.Path + ) + + receiver := suite.chainB.SenderAccount.GetAddress().String() + timeoutHeight := clienttypes.NewHeight(1, 110) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "pass - correct prefix trimming erc20:", + func() { + nativeErc20 = SetupNativeErc20(suite.T(), suite.chainA, suite.chainA.SenderAccounts[0]) + denom = nativeErc20.Denom + amount = sdkmath.NewInt(nativeErc20.InitialBal.Int64()) + + // Verify the denom has the correct prefix + suite.Require().Contains(denom, erc20types.Erc20NativeCoinDenomPrefix) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + ctx := suite.chainA.GetContext() + + // TEST: Verify that the prefix trimming works correctly + // The Transfer method should trim "erc20:" prefix to get the hex address + expectedTrimmed := strings.TrimPrefix(denom, erc20types.Erc20NativeCoinDenomPrefix) + suite.Require().Equal(nativeErc20.ContractAddr.String(), expectedTrimmed, + "Correct: Trimming 'erc20:' yields the contract address") + + // TEST: Verify that incorrect prefix trimming would fail + // If we incorrectly trim "erc20/" instead of "erc20:", we'd get the wrong string + incorrectTrimmed := strings.TrimPrefix(denom, erc20types.ModuleName+"/") + suite.Require().NotEqual(nativeErc20.ContractAddr.String(), incorrectTrimmed, + "Bug: Trimming 'erc20/' does not yield the contract address") + suite.Require().Equal(denom, incorrectTrimmed, + "Since 'erc20/' is not in the string, TrimPrefix returns it unchanged") + + // Verify that GetTokenPairID works correctly with the contract address (hex string) + pairIDFromAddress := evmAppA.Erc20Keeper.GetTokenPairID(ctx, nativeErc20.ContractAddr.String()) + suite.Require().NotEmpty(pairIDFromAddress) + + // Verify that GetTokenPairID works correctly with the full denom + pairIDFromDenom := evmAppA.Erc20Keeper.GetTokenPairID(ctx, denom) + suite.Require().NotEmpty(pairIDFromDenom) + + // Both should return the same pair ID + suite.Require().Equal(pairIDFromAddress, pairIDFromDenom) + + sender = nativeErc20.Account + }, + true, + }, + { + "pass - demonstrate bug impact", + func() { + nativeErc20 = SetupNativeErc20(suite.T(), suite.chainA, suite.chainA.SenderAccounts[0]) + denom = nativeErc20.Denom + amount = sdkmath.NewInt(nativeErc20.InitialBal.Int64()) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + ctx := suite.chainA.GetContext() + + // Demonstrate the bug's impact: incorrect vs correct prefix trimming + // The denom format is "erc20:0x1234..." where "erc20:" is the prefix + + // CORRECT trimming: trim "erc20:" to get the hex address + correctTrimmed := strings.TrimPrefix(denom, erc20types.Erc20NativeCoinDenomPrefix) + suite.Require().Equal(nativeErc20.ContractAddr.String(), correctTrimmed, + "Trimming 'erc20:' should yield the contract address") + + // INCORRECT trimming: trim "erc20/" instead (the bug) + // This doesn't match the actual prefix, so TrimPrefix returns the string unchanged + incorrectTrimmed := strings.TrimPrefix(denom, erc20types.ModuleName+"/") + suite.Require().Equal(denom, incorrectTrimmed, + "Trimming 'erc20/' should not change the string since prefix is 'erc20:'") + suite.Require().NotEqual(nativeErc20.ContractAddr.String(), incorrectTrimmed, + "Incorrect trimming does not yield the contract address") + + // Demonstrate why the bug wasn't caught earlier: + // Both lookups work due to dual mapping in the keeper + // The keeper maps both "0x1234..." and "erc20:0x1234..." to the same pair + pairIDFromCorrect := evmAppA.Erc20Keeper.GetTokenPairID(ctx, correctTrimmed) // "0x1234..." + pairIDFromIncorrect := evmAppA.Erc20Keeper.GetTokenPairID(ctx, incorrectTrimmed) // "erc20:0x1234..." + + suite.Require().NotEmpty(pairIDFromCorrect) + suite.Require().NotEmpty(pairIDFromIncorrect) + suite.Require().Equal(pairIDFromCorrect, pairIDFromIncorrect, + "Both lookups succeed due to dual mapping, masking the prefix bug") + + sender = nativeErc20.Account + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() + + // Setup IBC path + path = evmibctesting.NewTransferPath(suite.chainA, suite.chainB) + path.Setup() + + // Run test-specific setup + tc.malleate() + + // Call precompile transfer + data, err := suite.chainAPrecompile.ABI.Pack( + "transfer", + transfertypes.PortID, + path.EndpointA.ChannelID, + denom, + amount.BigInt(), + sender, + receiver, + timeoutHeight, + uint64(0), + "", + ) + suite.Require().NoError(err) + + res, _, _, err := suite.chainA.SendEvmTx( + suite.chainA.SenderAccounts[0], + 0, + suite.chainAPrecompile.Address(), + big.NewInt(0), + data, + 0, + ) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(uint32(0), res.Code, res.Log) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/evmd/tests/ibc/ics20_precompile_transfer_test.go b/evmd/tests/ibc/ics20_precompile_transfer_test.go index fcb1df32c..c7a70c6c8 100644 --- a/evmd/tests/ibc/ics20_precompile_transfer_test.go +++ b/evmd/tests/ibc/ics20_precompile_transfer_test.go @@ -13,12 +13,14 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/stretchr/testify/suite" + "github.com/cosmos/evm" "github.com/cosmos/evm/evmd" "github.com/cosmos/evm/evmd/tests/integration" "github.com/cosmos/evm/precompiles/ics20" chainutil "github.com/cosmos/evm/testutil" evmibctesting "github.com/cosmos/evm/testutil/ibc" evmante "github.com/cosmos/evm/x/vm/ante" + "github.com/cosmos/evm/x/vm/statedb" transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" @@ -51,6 +53,7 @@ func (suite *ICS20TransferTestSuite) SetupTest() { *evmAppA.StakingKeeper, evmAppA.TransferKeeper, evmAppA.IBCKeeper.ChannelKeeper, + evmAppA.Erc20Keeper, ) evmAppB := suite.chainB.App.(*evmd.EVMD) suite.chainBPrecompile = ics20.NewPrecompile( @@ -58,6 +61,7 @@ func (suite *ICS20TransferTestSuite) SetupTest() { *evmAppB.StakingKeeper, evmAppB.TransferKeeper, evmAppB.IBCKeeper.ChannelKeeper, + evmAppB.Erc20Keeper, ) } @@ -229,12 +233,15 @@ func (suite *ICS20TransferTestSuite) TestHandleMsgTransfer() { // denoms query method chainBAddr := common.BytesToAddress(suite.chainB.SenderAccount.GetAddress().Bytes()) ctxB := evmante.BuildEvmExecutionCtx(suite.chainB.GetContext()) + stateDB := statedb.New(ctxB, suite.chainB.App.(evm.EvmApp).GetEVMKeeper(), statedb.NewEmptyTxConfig()) evmRes, err := evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomsMethod, query.PageRequest{ @@ -254,10 +261,12 @@ func (suite *ICS20TransferTestSuite) TestHandleMsgTransfer() { // denom query method with result evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomMethod, chainBDenom.Hash().String(), @@ -271,10 +280,12 @@ func (suite *ICS20TransferTestSuite) TestHandleMsgTransfer() { // denom query method not exists case evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomMethod, "0000000000000000000000000000000000000000000000000000000000000000", @@ -288,10 +299,12 @@ func (suite *ICS20TransferTestSuite) TestHandleMsgTransfer() { // denom query method invalid error case evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomMethod, "INVALID-DENOM-HASH", @@ -305,10 +318,12 @@ func (suite *ICS20TransferTestSuite) TestHandleMsgTransfer() { // denomHash query method evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomHashMethod, chainBDenom.Path(), @@ -322,10 +337,12 @@ func (suite *ICS20TransferTestSuite) TestHandleMsgTransfer() { // denomHash query method not exists case evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomHashMethod, "transfer/channel-0/erc20:not-exists-case", @@ -338,10 +355,12 @@ func (suite *ICS20TransferTestSuite) TestHandleMsgTransfer() { // denomHash query method invalid error case evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomHashMethod, "", diff --git a/evmd/tests/ibc/ics20_recursive_precompile_calls_test.go b/evmd/tests/ibc/ics20_recursive_precompile_calls_test.go index 7af6ebeea..cc86d2231 100644 --- a/evmd/tests/ibc/ics20_recursive_precompile_calls_test.go +++ b/evmd/tests/ibc/ics20_recursive_precompile_calls_test.go @@ -6,34 +6,32 @@ package ibc import ( - "fmt" "math/big" "testing" - distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" - distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/evm/utils" - - "github.com/cosmos/evm/contracts" - testutiltypes "github.com/cosmos/evm/testutil/types" - erc20types "github.com/cosmos/evm/x/erc20/types" - evmtypes "github.com/cosmos/evm/x/vm/types" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/suite" + "github.com/cosmos/evm/contracts" "github.com/cosmos/evm/evmd" "github.com/cosmos/evm/evmd/tests/integration" "github.com/cosmos/evm/precompiles/ics20" evmibctesting "github.com/cosmos/evm/testutil/ibc" + testutiltypes "github.com/cosmos/evm/testutil/types" + "github.com/cosmos/evm/utils" + erc20types "github.com/cosmos/evm/x/erc20/types" + "github.com/cosmos/evm/x/vm/statedb" + evmtypes "github.com/cosmos/evm/x/vm/types" transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // Test constants @@ -71,6 +69,7 @@ type stakingRewards struct { RewardAmt sdkmath.Int } + func (suite *ICS20RecursivePrecompileCallsTestSuite) prepareStakingRewards(ctx sdk.Context, stkRs ...stakingRewards) (sdk.Context, error) { for _, r := range stkRs { // set distribution module account balance which pays out the rewards @@ -153,12 +152,15 @@ func (suite *ICS20RecursivePrecompileCallsTestSuite) setupContractForTesting( suite.Require().NoError(err, "sending native tokens to contract should succeed") // Mint ERC20 tokens + stateDB := statedb.New(suite.chainA.GetContext(), evmAppA.GetEVMKeeper(), statedb.NewEmptyTxConfig()) _, err = evmAppA.GetEVMKeeper().CallEVM( suite.chainA.GetContext(), + stateDB, contractData.ABI, deployerAddr, contractAddr, true, + false, nil, "mint", senderEVMAddr, @@ -171,12 +173,15 @@ func (suite *ICS20RecursivePrecompileCallsTestSuite) setupContractForTesting( vals, err := evmAppA.StakingKeeper.GetAllValidators(suite.chainA.GetContext()) suite.Require().NoError(err) + stateDB = statedb.New(suite.chainA.GetContext(), evmAppA.GetEVMKeeper(), statedb.NewEmptyTxConfig()) _, err = evmAppA.GetEVMKeeper().CallEVM( ctxA, + stateDB, contractData.ABI, deployerAddr, contractAddr, true, + false, nil, "delegate", vals[0].OperatorAddress, @@ -220,12 +225,13 @@ func (suite *ICS20RecursivePrecompileCallsTestSuite) SetupTest() { *evmAppA.StakingKeeper, evmAppA.TransferKeeper, evmAppA.IBCKeeper.ChannelKeeper, + evmAppA.Erc20Keeper, ) bondDenom, err := evmAppA.StakingKeeper.BondDenom(suite.chainA.GetContext()) suite.Require().NoError(err) evmAppA.Erc20Keeper.GetTokenPair(suite.chainA.GetContext(), evmAppA.Erc20Keeper.GetTokenPairID(suite.chainA.GetContext(), bondDenom)) - //evmAppA.Erc20Keeper.SetNativePrecompile(suite.chainA.GetContext(), werc20.Address()) + // evmAppA.Erc20Keeper.SetNativePrecompile(suite.chainA.GetContext(), werc20.Address()) avail := evmAppA.Erc20Keeper.IsNativePrecompileAvailable(suite.chainA.GetContext(), common.HexToAddress("0xD4949664cD82660AaE99bEdc034a0deA8A0bd517")) suite.Require().True(avail) @@ -236,6 +242,7 @@ func (suite *ICS20RecursivePrecompileCallsTestSuite) SetupTest() { *evmAppB.StakingKeeper, evmAppB.TransferKeeper, evmAppB.IBCKeeper.ChannelKeeper, + evmAppB.Erc20Keeper, ) } @@ -343,7 +350,7 @@ func (suite *ICS20RecursivePrecompileCallsTestSuite) TestHandleMsgTransfer() { suite.Require().NoError(err) contractBondDenomBalance := evmAppA.BankKeeper.GetBalance(suite.chainA.GetContext(), nativeErc20.ContractAddr.Bytes(), bondDenom) - suite.Require().Equal(contractBondDenomBalance.Amount, sdkmath.NewInt(50)) + suite.Require().Equal(sdkmath.NewInt(50), contractBondDenomBalance.Amount) // Check distribution rewards after transfer afterRewards, err := querier.DelegationRewards(suite.chainA.GetContext(), &distrtypes.QueryDelegationRewardsRequest{ @@ -429,7 +436,6 @@ func (suite *ICS20RecursivePrecompileCallsTestSuite) TestHandleMsgTransfer() { suite.Require().NoError(err) eventAmount := len(res.Events) - fmt.Println(res.Events) tc.postCheck(querier, vals[0].OperatorAddress, eventAmount) @@ -452,7 +458,7 @@ func (suite *ICS20RecursivePrecompileCallsTestSuite) TestHandleMsgTransfer() { relayerBalance := GetBalance(relayerAddr) // relay send - pathAToB.EndpointA.Chain.SenderAccount = evmAppA.AccountKeeper.GetAccount(suite.chainA.GetContext(), relayerAddr) //update account in the path as the sequence recorded in that object is out of date + pathAToB.EndpointA.Chain.SenderAccount = evmAppA.AccountKeeper.GetAccount(suite.chainA.GetContext(), relayerAddr) // update account in the path as the sequence recorded in that object is out of date err = pathAToB.RelayPacket(packet) suite.Require().NoError(err) // relay committed @@ -491,6 +497,444 @@ func (suite *ICS20RecursivePrecompileCallsTestSuite) TestHandleMsgTransfer() { } } +// TestContractICS20TransferWithDelegationHook tests a contract calling ICS20 transfer +// on an ERC20 token that has a delegation in the beforeTransfer hook +// Contract -> ICS20 Start -> ERC20 -> Delegate -> ICS20 End +func (suite *ICS20RecursivePrecompileCallsTestSuite) TestContractICS20TransferWithDelegationHook() { + suite.SetupTest() // reset + + pathAToB := evmibctesting.NewTransferPath(suite.chainA, suite.chainB) + pathAToB.Setup() + + senderAccount := suite.chainA.SenderAccounts[SenderIndex] + + // Deploy ICS20TransferTester contract + testerData, err := contracts.LoadICS20TransferTester() + suite.Require().NoError(err) + + testerDeploymentData := testutiltypes.ContractDeploymentData{ + Contract: testerData, + ConstructorArgs: []interface{}{}, + } + + testerAddr, err := DeployContract(suite.T(), suite.chainA, testerDeploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + + // Deploy regular ERC20 token (no hooks) for dummy transfer + regularTokenData := contracts.ERC20MinterBurnerDecimalsContract + + regularTokenDeploymentData := testutiltypes.ContractDeploymentData{ + Contract: regularTokenData, + ConstructorArgs: []interface{}{"DummyToken", "DT", uint8(18)}, + } + + regularTokenAddr, err := DeployContract(suite.T(), suite.chainA, regularTokenDeploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + + // Deploy ERC20WithNativeTransfers contract + hookTokenData, err := contracts.LoadERC20WithNativeTransfers() + suite.Require().NoError(err) + + hookTokenDeploymentData := testutiltypes.ContractDeploymentData{ + Contract: hookTokenData, + ConstructorArgs: []interface{}{"HookToken", "HT", uint8(18)}, + } + + hookTokenAddr, err := DeployContract(suite.T(), suite.chainA, hookTokenDeploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + ctxA := suite.chainA.GetContext() + + // Register both ERC20 contracts + _, err = evmAppA.Erc20Keeper.RegisterERC20(ctxA, &erc20types.MsgRegisterERC20{ + Signer: evmAppA.AccountKeeper.GetModuleAddress("gov").String(), + Erc20Addresses: []string{hookTokenAddr.Hex()}, + }) + suite.Require().NoError(err, "registering hook token should succeed") + suite.chainA.NextBlock() + + // Mint tokens to tester contract using CallEVM (setup function) + hookTokenAmount := big.NewInt(InitialTokenAmount) + mintData, err := hookTokenData.ABI.Pack("mint", testerAddr, hookTokenAmount) + suite.Require().NoError(err) + + stateDB := statedb.New(ctxA, evmAppA.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + deployer := common.BytesToAddress(suite.chainA.SenderPrivKey.PubKey().Address().Bytes()) + _, err = evmAppA.GetEVMKeeper().CallEVMWithData(ctxA, stateDB, deployer, &hookTokenAddr, mintData, true, false, nil) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Mint regular tokens to tester for the dummy transfer + regularTokenAmount := big.NewInt(1000) + ctxA = suite.chainA.GetContext() + stateDB = statedb.New(ctxA, evmAppA.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + _, err = evmAppA.GetEVMKeeper().CallEVM( + ctxA, + stateDB, + regularTokenData.ABI, + deployer, + regularTokenAddr, + true, + false, + nil, + "mint", + testerAddr, + regularTokenAmount, + ) + suite.Require().NoError(err, "mint regular tokens to tester should succeed") + suite.chainA.NextBlock() + + // Configure hook to perform delegation + bondDenom, err := evmAppA.StakingKeeper.BondDenom(ctxA) + suite.Require().NoError(err) + + vals, err := evmAppA.StakingKeeper.GetAllValidators(ctxA) + suite.Require().NoError(err) + validatorAddr := vals[0].OperatorAddress + + // Fund hook token contract with native tokens for delegation using EVM transaction + hookTokenAddrSDK := sdk.AccAddress(hookTokenAddr.Bytes()) + delegationAmountSDK := sdkmath.NewInt(DelegationAmount / 1_000_000_000_000) // Convert from wei to base denom + // Fund exact amount: delegation + 2 native transfers (1 aatom each, no rounding with 1e12 wei) + fundAmountAatom := delegationAmountSDK.AddRaw(2) // +2 for two 1 aatom native transfers + + // Convert aatom to wei for EVM transaction: aatom * 1e12 = wei + fundAmountWei := new(big.Int).Mul(fundAmountAatom.BigInt(), big.NewInt(1_000_000_000_000)) + + // Send EVM transaction with value to fund the contract (updates both bank module and StateDB) + _, _, _, err = suite.chainA.SendEvmTx( + senderAccount, + 0, // senderAccIdx + hookTokenAddr, // to (not pointer) + fundAmountWei, + []byte{}, // empty calldata + 0, // gasLimit (0 = auto) + ) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Configure hook parameters + recipient1 := common.BytesToAddress(senderAccount.SenderAccount.GetAddress().Bytes()) + recipient2 := recipient1 + transferAmount := big.NewInt(1_000_000_000_000) // 1e12 wei = exactly 1 aatom (no rounding) + delegateAmount := big.NewInt(DelegationAmount / 1_000_000_000_000) // Already in base denom + + configData, err := hookTokenData.ABI.Pack( + "configureHook", + recipient1, + recipient2, + transferAmount, + validatorAddr, + delegateAmount, + true, // enable hook + ) + suite.Require().NoError(err) + + // Use CallEVM for configuration (setup function) + ctxA = suite.chainA.GetContext() + stateDB = statedb.New(ctxA, evmAppA.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + _, err = evmAppA.GetEVMKeeper().CallEVMWithData(ctxA, stateDB, deployer, &hookTokenAddr, configData, true, false, nil) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Setup transfer parameters + timeoutHeight := clienttypes.NewHeight(1, TimeoutHeight) + hookTokenDenom := "erc20:" + hookTokenAddr.Hex() + transferTokenAmount := sdkmath.NewIntFromBigInt(big.NewInt(InitialTokenAmount / 2)) + + // Get balances before + ctxA = suite.chainA.GetContext() + testerHookBalBefore := evmAppA.Erc20Keeper.BalanceOf(ctxA, hookTokenData.ABI, hookTokenAddr, testerAddr) + hookTokenNativeBalBefore := evmAppA.GetBankKeeper().GetBalance(ctxA, hookTokenAddrSDK, bondDenom) + recipientAddrSDK := senderAccount.SenderAccount.GetAddress() + recipientNativeBalBefore := evmAppA.GetBankKeeper().GetBalance(ctxA, recipientAddrSDK, bondDenom) + + // Call scenario9_transferICS20Transfer from tester contract + callData, err := testerData.ABI.Pack( + "scenario9_transferICS20Transfer", + regularTokenAddr, // token (regular token without hooks) + recipient1, // recipient for dummy transfer + big.NewInt(100), // transferAmount (dummy transfer to avoid triggering hookToken hook) + pathAToB.EndpointA.ChannelConfig.PortID, // sourcePort + pathAToB.EndpointA.ChannelID, // sourceChannel + hookTokenDenom, // denom + transferTokenAmount.BigInt(), // ics20Amount + suite.chainB.SenderAccount.GetAddress().String(), // ics20Receiver + timeoutHeight, // timeoutHeight + uint64(0), // timeoutTimestamp + ) + suite.Require().NoError(err) + + // Execute transaction + res, _, _, err := suite.chainA.SendEvmTx(senderAccount, SenderIndex, testerAddr, big.NewInt(0), callData, 0) + suite.Require().NoError(err) + + // Get balances after + ctxA = suite.chainA.GetContext() + testerHookBalAfter := evmAppA.Erc20Keeper.BalanceOf(ctxA, hookTokenData.ABI, hookTokenAddr, testerAddr) + hookTokenNativeBalAfter := evmAppA.GetBankKeeper().GetBalance(ctxA, hookTokenAddrSDK, bondDenom) + recipientNativeBalAfter := evmAppA.GetBankKeeper().GetBalance(ctxA, recipientAddrSDK, bondDenom) + + // Verify ERC20 balance changes + expectedERC20Delta := transferTokenAmount.BigInt() + actualERC20Delta := new(big.Int).Sub(testerHookBalBefore, testerHookBalAfter) + suite.Require().Equal(expectedERC20Delta.String(), actualERC20Delta.String(), "hook token should be transferred via ICS20") + + // Verify native balance changes + // Hook contract should lose: delegation (1e6 aatom) + 2 native transfers (1 aatom each) = 1_000_002 aatom + conversionFactor := int64(1_000_000_000_000) // 1e12 wei to aatom conversion + expectedDelegationAatom := DelegationAmount / conversionFactor + expectedTransferAatom := int64(2) // 2 transfers of 1e12 wei each = 2 aatom total + expectedHookNativeDelta := sdkmath.NewInt(expectedDelegationAatom + expectedTransferAatom) + actualHookNativeDelta := hookTokenNativeBalBefore.Amount.Sub(hookTokenNativeBalAfter.Amount) + suite.Require().Equal(expectedHookNativeDelta.String(), actualHookNativeDelta.String(), + "hook token contract should lose delegation + 2 native transfers") + + // Recipient should receive 2 native transfers (2 aatom) + expectedRecipientDelta := sdkmath.NewInt(expectedTransferAatom) + actualRecipientDelta := recipientNativeBalAfter.Amount.Sub(recipientNativeBalBefore.Amount) + suite.Require().Equal(expectedRecipientDelta.String(), actualRecipientDelta.String(), + "recipient should receive 2 native transfers") + + // Verify delegation occurred + delegations, err := evmAppA.StakingKeeper.GetAllDelegatorDelegations(ctxA, hookTokenAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(1, len(delegations), "should have 1 delegation from beforeTransfer hook") + + // Verify total bonded amount + bondedTokens, err := evmAppA.StakingKeeper.GetDelegatorBonded(ctxA, hookTokenAddrSDK) + suite.Require().NoError(err) + expectedBondedAmount := DelegationAmount / 1_000_000_000_000 // Convert wei to base denom + suite.Require().Equal(int64(expectedBondedAmount), bondedTokens.Int64(), + "bonded tokens should equal delegation amount") + + // Verify event count + suite.Require().Equal(PreciseBankMintEventCount+PreciseBankBurnEventCount+DelegationEventCount+ICS20WithConversionEventCount+EVMEventCount, len(res.Events), "should have 41 events") +} + +// TestContractICS20TransferRevertWithDelegationHook tests a contract with reverted ERC20 transfer +// followed by ICS20 transfer on an ERC20 token that has a delegation in the beforeTransfer hook +func (suite *ICS20RecursivePrecompileCallsTestSuite) TestContractICS20TransferRevertWithDelegationHook() { + suite.SetupTest() // reset + + pathAToB := evmibctesting.NewTransferPath(suite.chainA, suite.chainB) + pathAToB.Setup() + + senderAccount := suite.chainA.SenderAccounts[SenderIndex] + + // Deploy ICS20TransferTester contract + testerData, err := contracts.LoadICS20TransferTester() + suite.Require().NoError(err) + + testerDeploymentData := testutiltypes.ContractDeploymentData{ + Contract: testerData, + ConstructorArgs: []interface{}{}, + } + + testerAddr, err := DeployContract(suite.T(), suite.chainA, testerDeploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + + // Deploy regular ERC20 token for the first transfer (that will revert) + regularTokenData := contracts.ERC20MinterBurnerDecimalsContract + + regularTokenDeploymentData := testutiltypes.ContractDeploymentData{ + Contract: regularTokenData, + ConstructorArgs: []interface{}{"RegularToken", "RT", uint8(18)}, + } + + regularTokenAddr, err := DeployContract(suite.T(), suite.chainA, regularTokenDeploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + + // Deploy ERC20WithNativeTransfers contract + hookTokenData, err := contracts.LoadERC20WithNativeTransfers() + suite.Require().NoError(err) + + hookTokenDeploymentData := testutiltypes.ContractDeploymentData{ + Contract: hookTokenData, + ConstructorArgs: []interface{}{"HookToken", "HT", uint8(18)}, + } + + hookTokenAddr, err := DeployContract(suite.T(), suite.chainA, hookTokenDeploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + ctxA := suite.chainA.GetContext() + + // Get deployer address for CallEVM + deployer := common.BytesToAddress(suite.chainA.SenderPrivKey.PubKey().Address().Bytes()) + + // Register both ERC20 contracts + _, err = evmAppA.Erc20Keeper.RegisterERC20(ctxA, &erc20types.MsgRegisterERC20{ + Signer: evmAppA.AccountKeeper.GetModuleAddress("gov").String(), + Erc20Addresses: []string{regularTokenAddr.Hex(), hookTokenAddr.Hex()}, + }) + suite.Require().NoError(err, "registering tokens should succeed") + suite.chainA.NextBlock() + + // Mint only a small amount of regular tokens to tester using CallEVM (setup function) + regularTokenAmount := big.NewInt(1000) + mintRegularData, err := regularTokenData.ABI.Pack("mint", testerAddr, regularTokenAmount) + suite.Require().NoError(err) + + stateDB := statedb.New(ctxA, evmAppA.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + _, err = evmAppA.GetEVMKeeper().CallEVMWithData(ctxA, stateDB, deployer, ®ularTokenAddr, mintRegularData, true, false, nil) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Mint tokens to tester contract (hook token) using CallEVM (setup function) + hookTokenAmount := big.NewInt(InitialTokenAmount) + mintHookData, err := hookTokenData.ABI.Pack("mint", testerAddr, hookTokenAmount) + suite.Require().NoError(err) + + ctxA = suite.chainA.GetContext() + stateDB = statedb.New(ctxA, evmAppA.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + _, err = evmAppA.GetEVMKeeper().CallEVMWithData(ctxA, stateDB, deployer, &hookTokenAddr, mintHookData, true, false, nil) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + vals, err := evmAppA.StakingKeeper.GetAllValidators(ctxA) + suite.Require().NoError(err) + validatorAddr := vals[0].OperatorAddress + + // Fund hook token contract with native tokens for delegation using EVM transaction + hookTokenAddrSDK := sdk.AccAddress(hookTokenAddr.Bytes()) + delegationAmountSDK := sdkmath.NewInt(DelegationAmount / 1_000_000_000_000) // Convert from wei to base denom + // Fund exact amount: delegation + 2 native transfers (1 aatom each, no rounding with 1e12 wei) + fundAmountAatom := delegationAmountSDK.AddRaw(2) // +2 for two 1 aatom native transfers + + // Convert aatom to wei for EVM transaction: aatom * 1e12 = wei + fundAmountWei := new(big.Int).Mul(fundAmountAatom.BigInt(), big.NewInt(1_000_000_000_000)) + + // Send EVM transaction with value to fund the contract (updates both bank module and StateDB) + _, _, _, err = suite.chainA.SendEvmTx( + senderAccount, + 0, // senderAccIdx + hookTokenAddr, // to (not pointer) + fundAmountWei, + []byte{}, // empty calldata + 0, // gasLimit (0 = auto) + ) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Configure hook parameters + recipient1 := common.BytesToAddress(senderAccount.SenderAccount.GetAddress().Bytes()) + recipient2 := recipient1 + transferAmount := big.NewInt(1_000_000_000_000) // 1e12 wei = exactly 1 aatom (no rounding) + delegateAmount := big.NewInt(DelegationAmount / 1_000_000_000_000) // Already in base denom + + configData, err := hookTokenData.ABI.Pack( + "configureHook", + recipient1, + recipient2, + transferAmount, + validatorAddr, + delegateAmount, + true, // enable hook + ) + suite.Require().NoError(err) + + // Use CallEVM for configuration (setup function) + ctxA = suite.chainA.GetContext() + stateDB = statedb.New(ctxA, evmAppA.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + _, err = evmAppA.GetEVMKeeper().CallEVMWithData(ctxA, stateDB, deployer, &hookTokenAddr, configData, true, false, nil) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Setup transfer parameters + timeoutHeight := clienttypes.NewHeight(1, TimeoutHeight) + hookTokenDenom := "erc20:" + hookTokenAddr.Hex() + transferTokenAmount := sdkmath.NewIntFromBigInt(big.NewInt(InitialTokenAmount / 2)) + + // Get balances before + ctxA = suite.chainA.GetContext() + bondDenom, err := evmAppA.StakingKeeper.BondDenom(ctxA) + suite.Require().NoError(err) + regularTokenBalBefore := evmAppA.Erc20Keeper.BalanceOf(ctxA, regularTokenData.ABI, regularTokenAddr, testerAddr) + testerHookBalBefore := evmAppA.Erc20Keeper.BalanceOf(ctxA, hookTokenData.ABI, hookTokenAddr, testerAddr) + hookTokenNativeBalBefore := evmAppA.GetBankKeeper().GetBalance(ctxA, hookTokenAddrSDK, bondDenom) + recipientAddrSDK := senderAccount.SenderAccount.GetAddress() + recipientNativeBalBefore := evmAppA.GetBankKeeper().GetBalance(ctxA, recipientAddrSDK, bondDenom) + + // Call scenario10_transferICS20TransferRevert from tester contract + // First transfer will revert due to excessive amount + excessiveAmount := big.NewInt(1000000) // More than the minted amount + callData, err := testerData.ABI.Pack( + "scenario10_transferICS20TransferRevert", + regularTokenAddr, // token (will revert) + recipient1, // recipient + excessiveAmount, // excessive transferAmount (will revert) + pathAToB.EndpointA.ChannelConfig.PortID, // sourcePort + pathAToB.EndpointA.ChannelID, // sourceChannel + hookTokenDenom, // denom + transferTokenAmount.BigInt(), // ics20Amount + suite.chainB.SenderAccount.GetAddress().String(), // ics20Receiver + timeoutHeight, // timeoutHeight + uint64(0), // timeoutTimestamp + ) + suite.Require().NoError(err) + + // Execute contract call + res, _, _, err := suite.chainA.SendEvmTx(senderAccount, SenderIndex, testerAddr, big.NewInt(0), callData, 0) + suite.Require().NoError(err) + + // Get balances after + ctxA = suite.chainA.GetContext() + regularTokenBalAfter := evmAppA.Erc20Keeper.BalanceOf(ctxA, regularTokenData.ABI, regularTokenAddr, testerAddr) + testerHookBalAfter := evmAppA.Erc20Keeper.BalanceOf(ctxA, hookTokenData.ABI, hookTokenAddr, testerAddr) + hookTokenNativeBalAfter := evmAppA.GetBankKeeper().GetBalance(ctxA, hookTokenAddrSDK, bondDenom) + recipientNativeBalAfter := evmAppA.GetBankKeeper().GetBalance(ctxA, recipientAddrSDK, bondDenom) + + // Verify regular token balance unchanged (transfer reverted) + suite.Require().Equal(regularTokenBalBefore.String(), regularTokenBalAfter.String(), + "regular token balance should be unchanged since transfer reverted") + + // Verify hook token balance changed (ICS20 transfer succeeded) + expectedERC20Delta := transferTokenAmount.BigInt() + actualERC20Delta := new(big.Int).Sub(testerHookBalBefore, testerHookBalAfter) + suite.Require().Equal(expectedERC20Delta.String(), actualERC20Delta.String(), + "hook token should be transferred via ICS20") + + // Verify native balance changes + // Hook contract should lose: delegation (1e6 aatom) + 2 native transfers (1 aatom each) = 1_000_002 aatom + conversionFactor := int64(1_000_000_000_000) // 1e12 wei to aatom conversion + expectedDelegationAatom := DelegationAmount / conversionFactor + expectedTransferAatom := int64(2) // 2 transfers of 1e12 wei each = 2 aatom total + expectedHookNativeDelta := sdkmath.NewInt(expectedDelegationAatom + expectedTransferAatom) + actualHookNativeDelta := hookTokenNativeBalBefore.Amount.Sub(hookTokenNativeBalAfter.Amount) + suite.Require().Equal(expectedHookNativeDelta.String(), actualHookNativeDelta.String(), + "hook token contract should lose delegation + 2 native transfers") + + // Recipient should receive 2 native transfers (2 aatom) + expectedRecipientDelta := sdkmath.NewInt(expectedTransferAatom) + actualRecipientDelta := recipientNativeBalAfter.Amount.Sub(recipientNativeBalBefore.Amount) + suite.Require().Equal(expectedRecipientDelta.String(), actualRecipientDelta.String(), + "recipient should receive 2 native transfers") + + // Verify delegation occurred (from beforeTransfer hook) + delegations, err := evmAppA.StakingKeeper.GetAllDelegatorDelegations(ctxA, hookTokenAddrSDK) + suite.Require().NoError(err) + suite.Require().Equal(1, len(delegations), "should have 1 delegation from beforeTransfer hook") + + // Verify total bonded amount + bondedTokens, err := evmAppA.StakingKeeper.GetDelegatorBonded(ctxA, hookTokenAddrSDK) + suite.Require().NoError(err) + expectedBondedAmount := DelegationAmount / 1_000_000_000_000 // Convert wei to base denom + suite.Require().Equal(int64(expectedBondedAmount), bondedTokens.Int64(), + "bonded tokens should equal delegation amount") + + // Verify event count + suite.Require().Equal(PreciseBankMintEventCount+PreciseBankBurnEventCount+DelegationEventCount+ICS20WithConversionEventCount+EVMEventCount, len(res.Events), "should have 41 events") + +} + func TestICS20RecursivePrecompileCallsTestSuite(t *testing.T) { suite.Run(t, new(ICS20RecursivePrecompileCallsTestSuite)) } diff --git a/evmd/tests/ibc/ics20_sequential_precompile_calls_test.go b/evmd/tests/ibc/ics20_sequential_precompile_calls_test.go new file mode 100644 index 000000000..105026f43 --- /dev/null +++ b/evmd/tests/ibc/ics20_sequential_precompile_calls_test.go @@ -0,0 +1,199 @@ +package ibc + +import ( + "fmt" + "github.com/cosmos/evm/testutil" + "math/big" + "testing" + + "github.com/cosmos/evm/contracts" + testutiltypes "github.com/cosmos/evm/testutil/types" + erc20types "github.com/cosmos/evm/x/erc20/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/evm/evmd" + "github.com/cosmos/evm/evmd/tests/integration" + "github.com/cosmos/evm/precompiles/ics20" + evmibctesting "github.com/cosmos/evm/testutil/ibc" +) + +// Test constants for sequential ICS20 sends +const ( + SeqICS20InitialTokenAmount = 1_000_000_000_000_000_000 // 1 token with 18 decimals + SeqICS20SenderIndex = 1 + SeqICS20TimeoutHeight = 110 +) + +// Test suite for ICS20 sequential max sends +type ICS20SequentialPrecompileCallsTestSuite struct { + suite.Suite + + coordinator *evmibctesting.Coordinator + + chainA *evmibctesting.TestChain + chainAPrecompile *ics20.Precompile + chainB *evmibctesting.TestChain + chainBPrecompile *ics20.Precompile +} + +func (suite *ICS20SequentialPrecompileCallsTestSuite) SetupTest() { + suite.coordinator = evmibctesting.NewCoordinator(suite.T(), 2, 0, integration.SetupEvmd) + suite.chainA = suite.coordinator.GetChain(evmibctesting.GetEvmChainID(1)) + suite.chainB = suite.coordinator.GetChain(evmibctesting.GetEvmChainID(2)) + + evmAppA := suite.chainA.App.(*evmd.EVMD) + suite.chainAPrecompile = ics20.NewPrecompile( + evmAppA.BankKeeper, + *evmAppA.StakingKeeper, + evmAppA.TransferKeeper, + evmAppA.IBCKeeper.ChannelKeeper, + evmAppA.Erc20Keeper, + ) + bondDenom, err := evmAppA.StakingKeeper.BondDenom(suite.chainA.GetContext()) + suite.Require().NoError(err) + + evmAppA.Erc20Keeper.GetTokenPair(suite.chainA.GetContext(), evmAppA.Erc20Keeper.GetTokenPairID(suite.chainA.GetContext(), bondDenom)) + + avail := evmAppA.Erc20Keeper.IsNativePrecompileAvailable(suite.chainA.GetContext(), common.HexToAddress("0xD4949664cD82660AaE99bEdc034a0deA8A0bd517")) + suite.Require().True(avail) + + evmAppB := suite.chainB.App.(*evmd.EVMD) + suite.chainBPrecompile = ics20.NewPrecompile( + evmAppB.BankKeeper, + *evmAppB.StakingKeeper, + evmAppB.TransferKeeper, + evmAppB.IBCKeeper.ChannelKeeper, + evmAppB.Erc20Keeper, + ) +} + +// TestReceiveAndSendTwice tests the production flow: transfer tokens in -> ICS20 sends -> transfer out +// This mirrors the actual transaction pattern seen on-chain. +func (suite *ICS20SequentialPrecompileCallsTestSuite) TestReceiveAndSendTwice() { + suite.SetupTest() + + pathAToB := evmibctesting.NewTransferPath(suite.chainA, suite.chainB) + pathAToB.Setup() + + evmAppA := suite.chainA.App.(*evmd.EVMD) + // Deployer has MINTER_ROLE - use it for minting + deployerAddr := common.BytesToAddress(suite.chainA.SenderPrivKey.PubKey().Address().Bytes()) + // Use a different account for the actual test tx + senderAccount := suite.chainA.SenderAccounts[SeqICS20SenderIndex] + senderAddr := common.BytesToAddress(senderAccount.SenderAccount.GetAddress().Bytes()) + + // 1. Deploy ERC20 contract + erc20ContractData := contracts.ERC20MinterBurnerDecimalsContract + erc20DeploymentData := testutiltypes.ContractDeploymentData{ + Contract: erc20ContractData, + ConstructorArgs: []interface{}{"TestToken", "TT", uint8(18)}, + } + erc20Addr, err := DeployContract(suite.T(), suite.chainA, erc20DeploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + fmt.Printf("ERC20 contract deployed at: %s\n", erc20Addr.Hex()) + + // 2. Register the ERC20 + _, err = evmAppA.Erc20Keeper.RegisterERC20(suite.chainA.GetContext(), &erc20types.MsgRegisterERC20{ + Signer: evmAppA.AccountKeeper.GetModuleAddress("gov").String(), + Erc20Addresses: []string{erc20Addr.Hex()}, + }) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // 3. Deploy the Sender contract + senderContractData, err := contracts.LoadSequentialICS20Sender() + suite.Require().NoError(err) + senderDeploymentData := testutiltypes.ContractDeploymentData{ + Contract: senderContractData, + ConstructorArgs: []interface{}{}, + } + contractAddr, err := DeployContract(suite.T(), suite.chainA, senderDeploymentData) + suite.chainA.NextBlock() + suite.Require().NoError(err) + fmt.Printf("Sender contract deployed at: %s\n", contractAddr.Hex()) + + // 4. Mint ERC20 tokens to the test sender using deployer (who has MINTER_ROLE) + mintStateDB := testutil.NewStateDB(suite.chainA.GetContext(), evmAppA.EVMKeeper) + _, err = evmAppA.GetEVMKeeper().CallEVM(suite.chainA.GetContext(), mintStateDB, erc20ContractData.ABI, deployerAddr, erc20Addr, true, false, nil, "mint", senderAddr, big.NewInt(SeqICS20InitialTokenAmount)) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Verify minted balance + senderBal := evmAppA.GetErc20Keeper().BalanceOf(suite.chainA.GetContext(), erc20ContractData.ABI, erc20Addr, senderAddr) + suite.Require().Equal(big.NewInt(SeqICS20InitialTokenAmount), senderBal) + fmt.Printf("Sender balance before: %s\n", senderBal.String()) + + // 5. Approve the contract to spend tokens (called by sender) + approveStateDB := testutil.NewStateDB(suite.chainA.GetContext(), evmAppA.EVMKeeper) + _, err = evmAppA.GetEVMKeeper().CallEVM(suite.chainA.GetContext(), approveStateDB, erc20ContractData.ABI, senderAddr, erc20Addr, true, false, nil, "approve", contractAddr, big.NewInt(SeqICS20InitialTokenAmount*2)) + suite.Require().NoError(err) + suite.chainA.NextBlock() + + // Get balances before + senderBalBefore := evmAppA.GetErc20Keeper().BalanceOf(suite.chainA.GetContext(), erc20ContractData.ABI, erc20Addr, senderAddr) + contractBalBefore := evmAppA.GetErc20Keeper().BalanceOf(suite.chainA.GetContext(), erc20ContractData.ABI, erc20Addr, contractAddr) + fmt.Printf("Before tx - Sender: %s, Contract: %s\n", senderBalBefore.String(), contractBalBefore.String()) + + // 6. Call receiveAndSendTwice - this should: + // - Transfer tokens from sender to contract + // - Attempt first ICS20 send (should succeed) + // - Attempt second ICS20 send (should fail - no balance) + // - Revert and return tokens + denom := "erc20:" + erc20Addr.Hex() + data, err := senderContractData.ABI.Pack( + "receiveAndSendTwice", + erc20Addr, + pathAToB.EndpointA.ChannelConfig.PortID, + pathAToB.EndpointA.ChannelID, + denom, + suite.chainB.SenderAccount.GetAddress().String(), + uint64(SeqICS20TimeoutHeight), + big.NewInt(SeqICS20InitialTokenAmount), + ) + suite.Require().NoError(err) + + res, _, _, err := suite.chainA.SendEvmTx(senderAccount, SeqICS20SenderIndex, contractAddr, big.NewInt(0), data, 0) + + // Log events + if res != nil { + fmt.Printf("Total events: %d\n", len(res.Events)) + for i, event := range res.Events { + fmt.Printf("Event %d: type=%s\n", i, event.Type) + for _, attr := range event.Attributes { + fmt.Printf(" %s: %s\n", attr.Key, attr.Value) + } + } + } + + // Check for revert + hasRevertEvent := false + if res != nil { + for _, event := range res.Events { + if event.Type == "ethereum_tx" { + for _, attr := range event.Attributes { + if attr.Key == "ethereumTxFailed" { + hasRevertEvent = true + fmt.Printf("Found revert: %s\n", attr.Value) + } + } + } + } + } + + // Get balances after + senderBalAfter := evmAppA.GetErc20Keeper().BalanceOf(suite.chainA.GetContext(), erc20ContractData.ABI, erc20Addr, senderAddr) + contractBalAfter := evmAppA.GetErc20Keeper().BalanceOf(suite.chainA.GetContext(), erc20ContractData.ABI, erc20Addr, contractAddr) + fmt.Printf("After tx - Sender: %s, Contract: %s\n", senderBalAfter.String(), contractBalAfter.String()) + + // The second ICS20 send should have failed, causing a revert + // Sender balance should be unchanged (tokens returned on revert) + suite.Require().True(hasRevertEvent || err != nil, "expected transaction to revert on second ICS20 send") + suite.Require().Equal(senderBalBefore.String(), senderBalAfter.String(), "sender balance should be unchanged after revert") + suite.Require().Equal(contractBalBefore.String(), contractBalAfter.String(), "contract balance should be unchanged after revert") +} + +func TestICS20SequentialPrecompileCallsTestSuite(t *testing.T) { + suite.Run(t, new(ICS20SequentialPrecompileCallsTestSuite)) +} diff --git a/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go b/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go index 27c7c4565..01421ddb7 100644 --- a/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go +++ b/evmd/tests/ibc/v2_ics20_precompile_transfer_test.go @@ -14,12 +14,14 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/stretchr/testify/suite" + "github.com/cosmos/evm" "github.com/cosmos/evm/evmd" "github.com/cosmos/evm/evmd/tests/integration" "github.com/cosmos/evm/precompiles/ics20" chainutil "github.com/cosmos/evm/testutil" evmibctesting "github.com/cosmos/evm/testutil/ibc" evmante "github.com/cosmos/evm/x/vm/ante" + "github.com/cosmos/evm/x/vm/statedb" transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" @@ -52,6 +54,7 @@ func (suite *ICS20TransferV2TestSuite) SetupTest() { *evmAppA.StakingKeeper, evmAppA.TransferKeeper, evmAppA.IBCKeeper.ChannelKeeper, + evmAppA.Erc20Keeper, ) evmAppB := suite.chainB.App.(*evmd.EVMD) suite.chainBPrecompile = ics20.NewPrecompile( @@ -59,6 +62,7 @@ func (suite *ICS20TransferV2TestSuite) SetupTest() { *evmAppB.StakingKeeper, evmAppB.TransferKeeper, evmAppB.IBCKeeper.ChannelKeeper, + evmAppB.Erc20Keeper, ) } @@ -235,12 +239,15 @@ func (suite *ICS20TransferV2TestSuite) TestHandleMsgTransfer() { // denoms query method chainBAddr := common.BytesToAddress(suite.chainB.SenderAccount.GetAddress().Bytes()) ctxB := evmante.BuildEvmExecutionCtx(suite.chainB.GetContext()) + stateDB := statedb.New(ctxB, suite.chainB.App.(evm.EvmApp).GetEVMKeeper(), statedb.NewEmptyTxConfig()) evmRes, err := evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomsMethod, query.PageRequest{ @@ -260,10 +267,12 @@ func (suite *ICS20TransferV2TestSuite) TestHandleMsgTransfer() { // denom query method evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomMethod, chainBDenom.Hash().String(), @@ -277,10 +286,12 @@ func (suite *ICS20TransferV2TestSuite) TestHandleMsgTransfer() { // denom query method not exists case evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomMethod, "0000000000000000000000000000000000000000000000000000000000000000", @@ -294,10 +305,12 @@ func (suite *ICS20TransferV2TestSuite) TestHandleMsgTransfer() { // denom query method invalid error case evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomMethod, "INVALID-DENOM-HASH", @@ -310,10 +323,12 @@ func (suite *ICS20TransferV2TestSuite) TestHandleMsgTransfer() { // denomHash query method evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomHashMethod, chainBDenom.Path(), @@ -327,10 +342,12 @@ func (suite *ICS20TransferV2TestSuite) TestHandleMsgTransfer() { // denomHash query method not exists case evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomHashMethod, "transfer/channel-0/erc20:not-exists-case", @@ -343,10 +360,12 @@ func (suite *ICS20TransferV2TestSuite) TestHandleMsgTransfer() { // denomHash query method invalid error case evmRes, err = evmAppB.EVMKeeper.CallEVM( ctxB, + stateDB, suite.chainBPrecompile.ABI, chainBAddr, suite.chainBPrecompile.Address(), false, + false, nil, ics20.DenomHashMethod, "", diff --git a/evmd/tests/integration/balance_handler/helper.go b/evmd/tests/integration/balance_handler/helper.go index 85c6a0a6c..3d9c8e75f 100644 --- a/evmd/tests/integration/balance_handler/helper.go +++ b/evmd/tests/integration/balance_handler/helper.go @@ -7,11 +7,12 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - errorsmod "cosmossdk.io/errors" - "github.com/cosmos/evm" - testutiltypes "github.com/cosmos/evm/testutil/types" evmibctesting "github.com/cosmos/evm/testutil/ibc" + testutiltypes "github.com/cosmos/evm/testutil/types" + "github.com/cosmos/evm/x/vm/statedb" + + errorsmod "cosmossdk.io/errors" ) // DeployContract deploys a contract to the test chain @@ -32,8 +33,9 @@ func DeployContract(t *testing.T, chain *evmibctesting.TestChain, deploymentData data := deploymentData.Contract.Bin data = append(data, ctorArgs...) + stateDB := statedb.New(chain.GetContext(), chain.App.(evm.EvmApp).GetEVMKeeper(), statedb.NewEmptyTxConfig()) - _, err = chain.App.(evm.EvmApp).GetEVMKeeper().CallEVMWithData(chain.GetContext(), from, nil, data, true, nil) + _, err = chain.App.(evm.EvmApp).GetEVMKeeper().CallEVMWithData(chain.GetContext(), stateDB, from, nil, data, true, false, nil) if err != nil { return common.Address{}, errorsmod.Wrapf(err, "failed to deploy contract") } diff --git a/evmd/tests/testdata/debug/debug.go b/evmd/tests/testdata/debug/debug.go index 0cc02bfac..f7a476f16 100644 --- a/evmd/tests/testdata/debug/debug.go +++ b/evmd/tests/testdata/debug/debug.go @@ -9,9 +9,12 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/vm" + cmn "github.com/cosmos/evm/precompiles/common" + "github.com/cosmos/evm/x/vm/statedb" + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" - cmn "github.com/cosmos/evm/precompiles/common" ) // Precompile defines a debugging precompile for use in testing. @@ -66,7 +69,12 @@ func (p Precompile) Call0(ctx sdk.Context, stateDB vm.StateDB, contract *vm.Cont caller := contract.Caller() fmt.Printf("Execute debug precompile %s, %p\n", caller.String(), p.BalanceHandlerFactory) - rsp, err := p.evmKeeper.CallEVMWithData(ctx, p.Address(), &caller, data, true, nil) + stateDBExp := stateDB.(*statedb.StateDB) + // Note: when called from within a precompile context, we do not set + // commit to true. Doing so will collapse the cache stack and subsequent + // reversions will panic. + rsp, err := p.evmKeeper.CallEVMWithData(ctx, stateDBExp, p.Address(), &caller, data, true, true, nil) + fmt.Println("callback response:", rsp.Ret, err) if err != nil { return nil, err diff --git a/evmd/tests/testdata/debug/interface.go b/evmd/tests/testdata/debug/interface.go index 2fc70e75a..70fb9e56f 100644 --- a/evmd/tests/testdata/debug/interface.go +++ b/evmd/tests/testdata/debug/interface.go @@ -2,6 +2,7 @@ package debug import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/evm/x/vm/statedb" evmtypes "github.com/cosmos/evm/x/vm/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -9,13 +10,15 @@ import ( ) type EVMKeeper interface { - CallEVM(ctx sdk.Context, abi abi.ABI, from, contract common.Address, commit bool, gasCap *big.Int, method string, args ...interface{}) (*evmtypes.MsgEthereumTxResponse, error) + CallEVM(ctx sdk.Context, stateDB *statedb.StateDB, abi abi.ABI, from, contract common.Address, commit bool, callFromPrecompile bool, gasCap *big.Int, method string, args ...interface{}) (*evmtypes.MsgEthereumTxResponse, error) CallEVMWithData( ctx sdk.Context, + stateDB *statedb.StateDB, from common.Address, contract *common.Address, data []byte, commit bool, + callFromPrecompile bool, gasCap *big.Int, ) (*evmtypes.MsgEthereumTxResponse, error) } diff --git a/evmd/upgrades.go b/evmd/upgrades.go index 272428f6b..69f279e9f 100644 --- a/evmd/upgrades.go +++ b/evmd/upgrades.go @@ -3,9 +3,6 @@ package evmd import ( "context" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/evm/x/vm/types" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" @@ -19,7 +16,7 @@ import ( // NOTE: This upgrade defines a reference implementation of what an upgrade // could look like when an application is migrating from EVMD version // v0.4.0 to v0.5.x -const UpgradeName = "v0.4.0-to-v0.5.0" +const UpgradeName = "v0.5.0-to-v0.6.0" func (app EVMD) RegisterUpgradeHandlers() { app.UpgradeKeeper.SetUpgradeHandler( @@ -27,43 +24,6 @@ func (app EVMD) RegisterUpgradeHandlers() { func(ctx context.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) sdkCtx.Logger().Debug("this is a debug level message to test that verbose logging mode has properly been enabled during a chain upgrade") - - app.BankKeeper.SetDenomMetaData(ctx, banktypes.Metadata{ - Description: "Example description", - DenomUnits: []*banktypes.DenomUnit{ - { - Denom: "atest", - Exponent: 0, - Aliases: nil, - }, - { - Denom: "test", - Exponent: 18, - Aliases: nil, - }, - }, - Base: "atest", - Display: "test", - Name: "Test Token", - Symbol: "TEST", - URI: "example_uri", - URIHash: "example_uri_hash", - }) - - // (Required for NON-18 denom chains *only) - // Update EVM params to add Extended denom options - // Ensure that this corresponds to the EVM denom - // (tyically the bond denom) - evmParams := app.EVMKeeper.GetParams(sdkCtx) - evmParams.ExtendedDenomOptions = &types.ExtendedDenomOptions{ExtendedDenom: "atest"} - err := app.EVMKeeper.SetParams(sdkCtx, evmParams) - if err != nil { - return nil, err - } - // Initialize EvmCoinInfo in the module store - if err := app.EVMKeeper.InitEvmCoinInfo(sdkCtx); err != nil { - return nil, err - } return app.ModuleManager.RunMigrations(ctx, app.Configurator(), fromVM) }, ) diff --git a/go.mod b/go.mod index ff50080b1..71d0fae5d 100644 --- a/go.mod +++ b/go.mod @@ -17,14 +17,14 @@ require ( cosmossdk.io/x/upgrade v0.2.0 github.com/btcsuite/btcd v0.24.2 github.com/btcsuite/btcd/btcutil v1.1.6 - github.com/cometbft/cometbft v0.38.19 + github.com/cometbft/cometbft v0.38.21 github.com/cosmos/cosmos-db v1.1.3 github.com/cosmos/cosmos-proto v1.0.0-beta.5 - github.com/cosmos/cosmos-sdk v0.53.5-0.20251030204916-768cb210885c + github.com/cosmos/cosmos-sdk v0.53.6 github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/gogoproto v1.7.2 github.com/cosmos/ibc-go/v10 v10.3.1-0.20250909102629-ed3b125c7b6f - github.com/cosmos/ledger-cosmos-go v0.16.0 + github.com/cosmos/ledger-cosmos-go v1.0.0 github.com/creachadair/tomledit v0.0.28 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/ethereum/go-ethereum v1.15.11 @@ -43,7 +43,7 @@ require ( github.com/rs/cors v1.11.1 github.com/spf13/cast v1.10.0 github.com/spf13/cobra v1.10.1 - github.com/spf13/viper v1.20.1 + github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/gjson v1.18.0 github.com/tidwall/sjson v1.2.5 @@ -213,11 +213,11 @@ require ( github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/zerolog v1.34.0 // indirect - github.com/sagikazarmark/locafero v0.9.0 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.14.0 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/stretchr/objx v0.5.2 // indirect @@ -251,6 +251,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.17.0 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect golang.org/x/oauth2 v0.30.0 // indirect diff --git a/go.sum b/go.sum index 35d99b611..5d5959beb 100644 --- a/go.sum +++ b/go.sum @@ -832,8 +832,8 @@ github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.19 h1:vNdtCkvhuwUlrcLPAyigV7lQpmmo+tAq8CsB8gZjEYw= -github.com/cometbft/cometbft v0.38.19/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= +github.com/cometbft/cometbft v0.38.21 h1:qcIJSH9LiwU5s6ZgKR5eRbsLNucbubfraDs5bzgjtOI= +github.com/cometbft/cometbft v0.38.21/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ= github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ= github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= @@ -850,8 +850,8 @@ github.com/cosmos/cosmos-db v1.1.3 h1:7QNT77+vkefostcKkhrzDK9uoIEryzFrU9eoMeaQOP github.com/cosmos/cosmos-db v1.1.3/go.mod h1:kN+wGsnwUJZYn8Sy5Q2O0vCYA99MJllkKASbs6Unb9U= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/cosmos-sdk v0.53.5-0.20251030204916-768cb210885c h1:HMVLvm0q3ahGvsyExkSCBcmvcdItMpTxAh4jllL4rJ4= -github.com/cosmos/cosmos-sdk v0.53.5-0.20251030204916-768cb210885c/go.mod h1:nifazrMGFjpmOuaVIZBQ8akQc160imzySYFEA8A7tus= +github.com/cosmos/cosmos-sdk v0.53.6 h1:aJeInld7rbsHtH1qLHu2aZJF9t40mGlqp3ylBLDT0HI= +github.com/cosmos/cosmos-sdk v0.53.6/go.mod h1:N6YuprhAabInbT3YGumGDKONbvPX5dNro7RjHvkQoKE= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/go-ethereum v1.16.2-cosmos-1 h1:QIaIS6HIdPSBdTvpFhxswhMLUJgcr4irbd2o9ZKldAI= @@ -869,8 +869,8 @@ github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5Rtn github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= -github.com/cosmos/ledger-cosmos-go v0.16.0 h1:YKlWPG9NnGZIEUb2bEfZ6zhON1CHlNTg0QKRRGcNEd0= -github.com/cosmos/ledger-cosmos-go v0.16.0/go.mod h1:WrM2xEa8koYoH2DgeIuZXNarF7FGuZl3mrIOnp3Dp0o= +github.com/cosmos/ledger-cosmos-go v1.0.0 h1:jNKW89nPf0vR0EkjHG8Zz16h6p3zqwYEOxlHArwgYtw= +github.com/cosmos/ledger-cosmos-go v1.0.0/go.mod h1:mGaw2wDOf+Z6SfRJsMGxU9DIrBa4du0MAiPlpPhLAOE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -1599,8 +1599,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= -github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= @@ -1618,14 +1618,14 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= -github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= @@ -1636,8 +1636,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1787,8 +1787,8 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= -go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= diff --git a/interfaces.go b/interfaces.go index ecebf7e16..98429f004 100644 --- a/interfaces.go +++ b/interfaces.go @@ -6,9 +6,9 @@ import ( erc20keeper "github.com/cosmos/evm/x/erc20/keeper" feemarketkeeper "github.com/cosmos/evm/x/feemarket/keeper" "github.com/cosmos/evm/x/ibc/callbacks/keeper" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" precisebankkeeper "github.com/cosmos/evm/x/precisebank/keeper" evmkeeper "github.com/cosmos/evm/x/vm/keeper" + transferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" ibctesting "github.com/cosmos/ibc-go/v10/testing" storetypes "cosmossdk.io/store/types" diff --git a/local_node.sh b/local_node.sh index a7e410825..096b72d9c 100755 --- a/local_node.sh +++ b/local_node.sh @@ -245,7 +245,7 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then jq '.app_state["evm"]["params"]["evm_denom"]="atest"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state.erc20.native_precompiles=["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" - jq '.app_state.erc20.token_pairs=[{contract_owner:1,erc20_address:"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",denom:"atest",enabled:true}]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + jq '.app_state.erc20.token_pairs=[{contract_owner:1,erc20_address:"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",denom:"atest",enabled:true,"owner_address":"cosmos1cml96vmptgw99syqrrz8az79xer2pcgp95srxm"}]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.consensus.params.block.max_gas="10000000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" diff --git a/mempool/blockchain_test.go b/mempool/blockchain_test.go index 6e076867c..1aff786f4 100644 --- a/mempool/blockchain_test.go +++ b/mempool/blockchain_test.go @@ -29,7 +29,8 @@ func createMockContext() sdk.Context { return sdk.Context{}. WithBlockTime(time.Now()). WithBlockHeader(cmtproto.Header{AppHash: []byte("00000000000000000000000000000000")}). - WithBlockHeight(1) + WithBlockHeight(1). + WithEventManager(sdk.NewEventManager()) } // TestBlockchainRaceCondition tests concurrent access to NotifyNewBlock and StateAt diff --git a/precompiles/common/balance_handler.go b/precompiles/common/balance_handler.go index 92f182763..54aa248fb 100644 --- a/precompiles/common/balance_handler.go +++ b/precompiles/common/balance_handler.go @@ -54,7 +54,6 @@ func (bh *BalanceHandler) BeforeBalanceChange(ctx sdk.Context) { // NOTES: Balance change events involving BlockedAddresses are bypassed. // Native balances are handled separately to prevent cases where a bank coin transfer // initiated by a precompile is unintentionally overwritten by balance changes from within a contract. - // Typically, accounts registered as BlockedAddresses in app.go—such as module accounts—are not expected to receive coins. // However, in modules like precisebank, it is common to borrow and repay integer balances // from the module account to support fractional balance handling. @@ -68,7 +67,14 @@ func (bh *BalanceHandler) BeforeBalanceChange(ctx sdk.Context) { func (bh *BalanceHandler) AfterBalanceChange(ctx sdk.Context, stateDB *statedb.StateDB) error { events := ctx.EventManager().Events() - for _, event := range events[bh.prevEventsLen:] { + for i, event := range events[bh.prevEventsLen:] { + eventIdx := bh.prevEventsLen + i + + // Skip events already processed by flushing before the precompile was called. + if stateDB.IsEventProcessed(eventIdx) { + continue + } + switch event.Type { case banktypes.EventTypeCoinSpent: spenderAddr, err := ParseAddress(event, banktypes.AttributeKeySpender) @@ -131,6 +137,7 @@ func (bh *BalanceHandler) AfterBalanceChange(ctx sdk.Context, stateDB *statedb.S } default: + // Non-balance events are already marked as processed above continue } } diff --git a/precompiles/common/interfaces.go b/precompiles/common/interfaces.go index e69e11d39..fb6ebdb1b 100644 --- a/precompiles/common/interfaces.go +++ b/precompiles/common/interfaces.go @@ -6,10 +6,13 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" erc20types "github.com/cosmos/evm/x/erc20/types" + "github.com/cosmos/evm/x/vm/statedb" ibctypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" connectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" @@ -62,4 +65,7 @@ type ERC20Keeper interface { GetCoinAddress(ctx sdk.Context, denom string) (ethcommon.Address, error) GetERC20Map(ctx sdk.Context, erc20 ethcommon.Address) []byte GetTokenPair(ctx sdk.Context, id []byte) (erc20types.TokenPair, bool) + IsERC20Enabled(ctx sdk.Context) bool + GetTokenPairID(ctx sdk.Context, token string) []byte + ConvertERC20IntoCoinsForNativeToken(ctx sdk.Context, stateDB *statedb.StateDB, contract ethcommon.Address, amount math.Int, receiver sdk.AccAddress, sender ethcommon.Address, commit bool, callFromPrecompile bool) (*erc20types.MsgConvertERC20Response, error) } diff --git a/precompiles/common/precompile.go b/precompiles/common/precompile.go index 1554fe1b3..242d525b3 100644 --- a/precompiles/common/precompile.go +++ b/precompiles/common/precompile.go @@ -69,17 +69,16 @@ func (p Precompile) runNativeAction(evm *vm.EVM, contract *vm.Contract, action N // take a snapshot of the current state before any changes // to be able to revert the changes snapshot := stateDB.MultiStoreSnapshot() - events := ctx.EventManager().Events() // add precompileCall entry on the stateDB journal // this allows to revert the changes within an evm tx - if err := stateDB.AddPrecompileFn(snapshot, events); err != nil { + if err := stateDB.AddPrecompileFn(snapshot); err != nil { return nil, err } // commit the current changes in the cache ctx // to get the updated state for the precompile call - if err := stateDB.CommitWithCacheCtx(); err != nil { + if err := stateDB.FlushToCacheCtx(); err != nil { return nil, err } diff --git a/precompiles/erc20/IERC20Burnable.sol b/precompiles/erc20/IERC20Burnable.sol new file mode 100644 index 000000000..d139bc039 --- /dev/null +++ b/precompiles/erc20/IERC20Burnable.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IERC20.sol"; + +/** + * @dev Extension of {ERC20} that allows token holders to destroy both their own + * tokens and those that they have an allowance for, in a way that can be + * recognized off-chain (via event analysis). + */ +interface IERC20Burnable is IERC20 { + /** + * @dev Destroys `amount` tokens from the caller. + * + * See {ERC20-_burn}. + */ + function burn(uint256 amount) external; + + /** + * @dev Destroys `amount` tokens from `from`. + * + * See {ERC20-_burn} and {ERC20-allowance}. + * + */ + function burn(address from, uint256 amount) external; + + /** + * @dev Destroys a `value` amount of tokens from `account`, deducting from + * the caller's allowance. + * + * See {ERC20-_burn} and {ERC20-allowance}. + * + * Requirements: + * + * - the caller must have allowance for ``accounts``'s tokens of at least + * `value`. + */ + function burnFrom(address account, uint256 value) external; +} diff --git a/precompiles/erc20/IERC20Metadata.sol b/precompiles/erc20/IERC20Metadata.sol index 982bc39eb..862207cc3 100644 --- a/precompiles/erc20/IERC20Metadata.sol +++ b/precompiles/erc20/IERC20Metadata.sol @@ -4,13 +4,16 @@ pragma solidity ^0.8.0; import "./IERC20.sol"; +import "./IERC20Mintable.sol"; +import "./IERC20Burnable.sol"; +import "./IOwnable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ -interface IERC20Metadata is IERC20 { +interface IERC20Metadata is IERC20, IERC20Mintable, IERC20Burnable, IOwnable { /** * @dev Returns the name of the token. */ diff --git a/precompiles/erc20/IERC20Mintable.sol b/precompiles/erc20/IERC20Mintable.sol new file mode 100644 index 000000000..1a1816ce4 --- /dev/null +++ b/precompiles/erc20/IERC20Mintable.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IERC20.sol"; + +interface IERC20Mintable is IERC20 { + + function mint(address account, uint256 amount) external returns (bool); +} diff --git a/precompiles/erc20/IOwnable.sol b/precompiles/erc20/IOwnable.sol new file mode 100644 index 000000000..0f7aa97ac --- /dev/null +++ b/precompiles/erc20/IOwnable.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is set to the address provided by the deployer. This can + * later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +interface IOwnable { + /** + * @dev The caller account is not authorized to perform an operation. + */ + error OwnableUnauthorizedAccount(address account); + + /** + * @dev The owner is not a valid owner account. (eg. `address(0)`) + */ + error OwnableInvalidOwner(address owner); + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Returns the address of the current owner. + */ + function owner() external view returns (address); + + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) external; +} diff --git a/precompiles/erc20/abi.json b/precompiles/erc20/abi.json index ebb8c03b0..9443662f8 100644 --- a/precompiles/erc20/abi.json +++ b/precompiles/erc20/abi.json @@ -28,6 +28,25 @@ "name": "Approval", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -224,6 +243,99 @@ ], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" } ], "bytecode": "0x", diff --git a/precompiles/erc20/erc20.go b/precompiles/erc20/erc20.go index 12121b7c4..6220ac3f7 100644 --- a/precompiles/erc20/erc20.go +++ b/precompiles/erc20/erc20.go @@ -27,15 +27,17 @@ const ( // The results can be inspected here: // https://github.com/evmos/evmos/blob/malte/erc20-gas-tests/precompiles/erc20/plot_gas_values.ipynb - GasTransfer = 9_000 - GasTransferFrom = 30_500 - GasApprove = 8_100 - GasName = 3_421 - GasSymbol = 3_464 - GasDecimals = 427 - GasTotalSupply = 2_480 - GasBalanceOf = 2_870 - GasAllowance = 3_225 + GasTransfer = 9_000 + GasTransferFrom = 30_500 + GasApprove = 8_100 + GasName = 3_421 + GasSymbol = 3_464 + GasDecimals = 427 + GasTotalSupply = 2_480 + GasBalanceOf = 2_870 + GasAllowance = 3_225 + GasTransferOwnership = 50_000 + GasOwner = 2_870 ) var ( @@ -121,6 +123,16 @@ func (p Precompile) RequiredGas(input []byte) uint64 { return GasTransferFrom case ApproveMethod: return GasApprove + case MintMethod: + return GasTransfer + case BurnMethod: + return GasTransfer + case Burn0Method: + return GasTransfer + case BurnFromMethod: + return GasTransfer + case TransferOwnershipMethod: + return GasTransferOwnership // ERC-20 queries case NameMethod: return GasName @@ -134,6 +146,8 @@ func (p Precompile) RequiredGas(input []byte) uint64 { return GasBalanceOf case AllowanceMethod: return GasAllowance + case OwnerMethod: + return GasOwner default: return 0 } @@ -167,7 +181,12 @@ func (Precompile) IsTransaction(method *abi.Method) bool { switch method.Name { case TransferMethod, TransferFromMethod, - ApproveMethod: + ApproveMethod, + MintMethod, + BurnMethod, + Burn0Method, + BurnFromMethod, + TransferOwnershipMethod: return true default: return false @@ -190,6 +209,16 @@ func (p *Precompile) HandleMethod( bz, err = p.TransferFrom(ctx, contract, stateDB, method, args) case ApproveMethod: bz, err = p.Approve(ctx, contract, stateDB, method, args) + case MintMethod: + bz, err = p.Mint(ctx, contract, stateDB, method, args) + case BurnMethod: + bz, err = p.Burn(ctx, contract, stateDB, method, args) + case Burn0Method: + bz, err = p.Burn0(ctx, contract, stateDB, method, args) + case BurnFromMethod: + bz, err = p.BurnFrom(ctx, contract, stateDB, method, args) + case TransferOwnershipMethod: + bz, err = p.TransferOwnership(ctx, contract, stateDB, method, args) // ERC-20 queries case NameMethod: bz, err = p.Name(ctx, contract, stateDB, method, args) @@ -203,6 +232,8 @@ func (p *Precompile) HandleMethod( bz, err = p.BalanceOf(ctx, contract, stateDB, method, args) case AllowanceMethod: bz, err = p.Allowance(ctx, contract, stateDB, method, args) + case OwnerMethod: + bz, err = p.Owner(ctx, contract, stateDB, method, args) default: return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name) } diff --git a/precompiles/erc20/errors.go b/precompiles/erc20/errors.go index 77f90d882..377a3a2f3 100644 --- a/precompiles/erc20/errors.go +++ b/precompiles/erc20/errors.go @@ -31,6 +31,11 @@ var ( ErrDecreasedAllowanceBelowZero = errors.New("ERC20: decreased allowance below zero") ErrInsufficientAllowance = errors.New("ERC20: insufficient allowance") ErrTransferAmountExceedsBalance = errors.New("ERC20: transfer amount exceeds balance") + ErrOwnableInvalidOwner = errors.New("ERC20: invalid new owner") + ErrOwnableUnauthorizedAccount = errors.New("ERC20: unauthorized account") + ErrMinterIsNotOwner = errors.New("ERC20: minter is not the owner") + ErrSenderIsNotOwner = errors.New("ERC20: sender is not the owner") + ErrContractOwnerNotFound = errors.New("ERC20: contract owner not found") ) // ConvertErrToERC20Error is a helper function which maps errors raised by the Cosmos SDK stack @@ -49,6 +54,12 @@ func ConvertErrToERC20Error(err error) error { return ErrDecreasedAllowanceBelowZero case strings.Contains(err.Error(), cmn.ErrIntegerOverflow): return vm.ErrExecutionReverted + case strings.Contains(err.Error(), "invalid owner"): + return ErrOwnableInvalidOwner + case strings.Contains(err.Error(), "unauthorized") || strings.Contains(err.Error(), "authorization not found"): + return ErrOwnableUnauthorizedAccount + case strings.Contains(err.Error(), "minter is not the owner"): + return ErrMinterIsNotOwner case errors.Is(err, ibc.ErrNoIBCVoucherDenom) || errors.Is(err, ibc.ErrDenomNotFound) || strings.Contains(err.Error(), "invalid base denomination") || diff --git a/precompiles/erc20/events.go b/precompiles/erc20/events.go index 33949fa80..c08623380 100644 --- a/precompiles/erc20/events.go +++ b/precompiles/erc20/events.go @@ -19,6 +19,9 @@ const ( // EventTypeApproval defines the event type for the ERC-20 Approval event. EventTypeApproval = "Approval" + + // EventTypeTransferOwnership defines the event type for the ERC-20 transferOwnership transaction. + EventTypeTransferOwnership = "OwnershipTransferred" ) // EmitTransferEvent creates a new Transfer event emitted on transfer and transferFrom transactions. @@ -92,3 +95,32 @@ func (p Precompile) EmitApprovalEvent(ctx sdk.Context, stateDB vm.StateDB, owner return nil } + +// EmitTransferOwnershipEvent creates a new TransferOwnership event emitted on transferOwnership transactions. +func (p Precompile) EmitTransferOwnershipEvent(ctx sdk.Context, stateDB vm.StateDB, previousOwner, newOwner common.Address) error { + // Prepare the event topics + event := p.Events[EventTypeTransferOwnership] + topics := make([]common.Hash, 3) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(previousOwner) + if err != nil { + return err + } + + topics[2], err = cmn.MakeTopic(newOwner) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + BlockNumber: uint64(ctx.BlockHeight()), //nolint:gosec // G115 + }) + + return nil +} diff --git a/precompiles/erc20/interfaces.go b/precompiles/erc20/interfaces.go index c4bcb6c68..c3cbb6769 100644 --- a/precompiles/erc20/interfaces.go +++ b/precompiles/erc20/interfaces.go @@ -5,6 +5,8 @@ import ( "github.com/ethereum/go-ethereum/common" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -13,4 +15,8 @@ type Erc20Keeper interface { GetAllowance(ctx sdk.Context, erc20 common.Address, owner common.Address, spender common.Address) (*big.Int, error) SetAllowance(ctx sdk.Context, erc20 common.Address, owner common.Address, spender common.Address, value *big.Int) error DeleteAllowance(ctx sdk.Context, erc20 common.Address, owner common.Address, spender common.Address) error + MintCoins(ctx sdk.Context, sender, to sdk.AccAddress, amount math.Int, token string) error + BurnCoins(ctx sdk.Context, sender sdk.AccAddress, amount math.Int, token string) error + GetTokenPairOwnerAddress(ctx sdk.Context, token string) (sdk.AccAddress, error) + TransferOwnership(ctx sdk.Context, sender sdk.AccAddress, newOwner sdk.AccAddress, token string) error } diff --git a/precompiles/erc20/query.go b/precompiles/erc20/query.go index e0c7b72fb..1e7ca782a 100644 --- a/precompiles/erc20/query.go +++ b/precompiles/erc20/query.go @@ -33,6 +33,9 @@ const ( // AllowanceMethod defines the ABI method name for the Allowance // query. AllowanceMethod = "allowance" + // OwnerMethod defines the ABI method name for the ERC-20 Owner + // query. + OwnerMethod = "owner" ) // Name returns the name of the token. If the token metadata is registered in the @@ -200,6 +203,27 @@ func (p Precompile) Allowance( return method.Outputs.Pack(allowance) } +// Owner returns the address of the current owner of the token. +func (p Precompile) Owner( + ctx sdk.Context, + _ *vm.Contract, + _ vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + err := ParseOwnerArgs(args) + if err != nil { + return nil, err + } + + ownerAddr, err := p.erc20Keeper.GetTokenPairOwnerAddress(ctx, p.tokenPair.GetERC20Contract().Hex()) + if err != nil { + return nil, ErrContractOwnerNotFound + } + + return method.Outputs.Pack(common.Address(ownerAddr.Bytes())) +} + // getBaseDenomFromIBCVoucher returns the base denomination from the given IBC voucher denomination. func (p Precompile) getBaseDenomFromIBCVoucher(ctx sdk.Context, voucherDenom string) (string, error) { // Infer the denomination name from the coin denomination base voucherDenom diff --git a/precompiles/erc20/tx.go b/precompiles/erc20/tx.go index f1ed409f2..e634e9fcd 100644 --- a/precompiles/erc20/tx.go +++ b/precompiles/erc20/tx.go @@ -20,11 +20,24 @@ const ( // TransferFromMethod defines the ABI method name for the ERC-20 transferFrom // transaction. TransferFromMethod = "transferFrom" + // MintMethod defines the ABI method name for the ERC-20 mint transaction. + MintMethod = "mint" + // BurnMethod defines the ABI method name for the ERC-20 burn transaction. + BurnMethod = "burn" + // Burn0Method defines the ABI method name for burn transaction with 2 arguments (spender, amount). + Burn0Method = "burn0" + // BurnFromMethod defines the ABI method name for the ERC-20 burnFrom transaction. + BurnFromMethod = "burnFrom" + // TransferOwnershipMethod defines the ABI method name for the ERC-20 transferOwnership transaction. + TransferOwnershipMethod = "transferOwnership" // ApproveMethod defines the ABI method name for ERC-20 Approve // transaction. ApproveMethod = "approve" ) +// ZeroAddress represents the zero address +var ZeroAddress = common.Address{} + // Transfer executes a direct transfer from the caller address to the // destination address. func (p *Precompile) Transfer( @@ -129,3 +142,192 @@ func (p *Precompile) transfer( return method.Outputs.Pack(true) } + +// Mint executes a mint of the caller's tokens. +func (p *Precompile) Mint( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + to, amount, err := ParseMintArgs(args) + if err != nil { + return nil, err + } + + minterAddr := contract.Caller() + minter := sdk.AccAddress(minterAddr.Bytes()) + toAddr := sdk.AccAddress(to.Bytes()) + + err = p.erc20Keeper.MintCoins(ctx, minter, toAddr, math.NewIntFromBigInt(amount), p.tokenPair.GetERC20Contract().Hex()) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + if err = p.EmitTransferEvent(ctx, stateDB, ZeroAddress, to, amount); err != nil { + return nil, err + } + + return method.Outputs.Pack() +} + +// Burn executes a burn of the caller's tokens. +func (p *Precompile) Burn( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + amount, err := ParseBurnArgs(args) + if err != nil { + return nil, err + } + + burnerAddr := contract.Caller() + + if err := p.burn(ctx, stateDB, burnerAddr, amount); err != nil { + return nil, err + } + + return method.Outputs.Pack() +} + +// Burn0 executes a burn of the spender's tokens. +func (p *Precompile) Burn0( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + spender, amount, err := ParseBurn0Args(args) + if err != nil { + return nil, err + } + + owner, err := sdk.AccAddressFromBech32(p.tokenPair.OwnerAddress) + if err != nil { + return nil, err + } + sender := sdk.AccAddress(contract.Caller().Bytes()) + + if !sender.Equals(owner) { + return nil, ConvertErrToERC20Error(ErrSenderIsNotOwner) + } + + if err := p.burn(ctx, stateDB, spender, amount); err != nil { + return nil, err + } + + return method.Outputs.Pack() +} + +// BurnFrom executes a burn of the caller's tokens. +func (p *Precompile) BurnFrom( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + owner, amount, err := ParseBurnFromArgs(args) + if err != nil { + return nil, err + } + + coins := sdk.Coins{{Denom: p.tokenPair.Denom, Amount: math.NewIntFromBigInt(amount)}} + + msg := banktypes.NewMsgSend(owner.Bytes(), ZeroAddress.Bytes(), coins) + + if err = msg.Amount.Validate(); err != nil { + return nil, err + } + spenderAddr := contract.Caller() + + prevAllowance, err := p.erc20Keeper.GetAllowance(ctx, p.Address(), owner, spenderAddr) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + newAllowance := new(big.Int).Sub(prevAllowance, amount) + if newAllowance.Sign() < 0 { + return nil, ErrInsufficientAllowance + } + + if newAllowance.Sign() == 0 { + // If the new allowance is 0, we need to delete it from the store. + err = p.erc20Keeper.DeleteAllowance(ctx, p.Address(), owner, spenderAddr) + } else { + // If the new allowance is not 0, we need to set it in the store. + err = p.erc20Keeper.SetAllowance(ctx, p.Address(), owner, spenderAddr, newAllowance) + } + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + msgSrv := NewMsgServerImpl(p.BankKeeper) + if err = msgSrv.Send(ctx, msg); err != nil { + // This should return an error to avoid the contract from being executed and an event being emitted + return nil, ConvertErrToERC20Error(err) + } + + if err = p.EmitTransferEvent(ctx, stateDB, owner, ZeroAddress, amount); err != nil { + return nil, err + } + + // NOTE: if it's a direct transfer, we return here but if used through transferFrom, + // we need to emit the approval event with the new allowance. + if err = p.EmitApprovalEvent(ctx, stateDB, owner, spenderAddr, newAllowance); err != nil { + return nil, err + } + + return method.Outputs.Pack() +} + +// TransferOwnership executes a transfer of ownership of the token. +func (p *Precompile) TransferOwnership( + ctx sdk.Context, + contract *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + newOwner, err := ParseTransferOwnershipArgs(args) + if err != nil { + return nil, err + } + + sender := sdk.AccAddress(contract.Caller().Bytes()) + + if p.tokenPair.OwnerAddress != sender.String() { + return nil, ConvertErrToERC20Error(ErrSenderIsNotOwner) + } + + err = p.erc20Keeper.TransferOwnership(ctx, sender, newOwner.Bytes(), p.tokenPair.GetERC20Contract().Hex()) + if err != nil { + return nil, ConvertErrToERC20Error(err) + } + + p.tokenPair.OwnerAddress = newOwner.String() + + if err = p.EmitTransferOwnershipEvent(ctx, stateDB, contract.Caller(), newOwner); err != nil { + return nil, err + } + + return method.Outputs.Pack() +} + +// burn is a common function that handles burns for the ERC-20 Burn +// and BurnFrom methods. It executes a bank BurnCoins message. +func (p *Precompile) burn(ctx sdk.Context, stateDB vm.StateDB, burnerAddr common.Address, amount *big.Int) error { + burner := sdk.AccAddress(burnerAddr.Bytes()) + + err := p.erc20Keeper.BurnCoins(ctx, burner, math.NewIntFromBigInt(amount), p.tokenPair.GetERC20Contract().Hex()) + if err != nil { + return ConvertErrToERC20Error(err) + } + + return p.EmitTransferEvent(ctx, stateDB, burnerAddr, ZeroAddress, amount) +} diff --git a/precompiles/erc20/types.go b/precompiles/erc20/types.go index 685f6fa62..0549cf2aa 100644 --- a/precompiles/erc20/types.go +++ b/precompiles/erc20/types.go @@ -127,3 +127,98 @@ func ParseBalanceOfArgs(args []interface{}) (common.Address, error) { return account, nil } + +// ParseOwnerArgs parses the arguments from the owner method and returns the owner address. +func ParseOwnerArgs(args []interface{}) error { + if len(args) != 0 { + return fmt.Errorf("invalid number of arguments; expected 0; got: %d", len(args)) + } + + return nil +} + +// ParseMintArgs parses the arguments from the mint method and returns the +// destination address (to) and amount. +func ParseMintArgs(args []interface{}) (to common.Address, amount *big.Int, err error) { + if len(args) != 2 { + return common.Address{}, nil, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + to, ok := args[0].(common.Address) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid to address: %v", args[0]) + } + + amount, ok = args[1].(*big.Int) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid amount: %v", args[1]) + } + + return to, amount, nil +} + +// ParseBurnArgs parses the arguments from the burn method and returns the amount. +func ParseBurnArgs(args []interface{}) (amount *big.Int, err error) { + if len(args) != 1 { + return nil, fmt.Errorf("invalid number of arguments; expected 1; got: %d", len(args)) + } + + amount, ok := args[0].(*big.Int) + if !ok { + return nil, fmt.Errorf("invalid amount: %v", args[0]) + } + + return amount, nil +} + +func ParseBurn0Args(args []interface{}) (spender common.Address, amount *big.Int, err error) { + if len(args) != 2 { + return common.Address{}, nil, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + spender, ok := args[0].(common.Address) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid spender address: %v", args[0]) + } + + amount, ok = args[1].(*big.Int) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid amount: %v", args[1]) + } + + return spender, amount, nil +} + +// ParseBurnFromArgs parses the arguments from the burnFrom method and returns the +// from address and amount. +func ParseBurnFromArgs(args []interface{}) (from common.Address, amount *big.Int, err error) { + if len(args) != 2 { + return common.Address{}, nil, fmt.Errorf("invalid number of arguments; expected 2; got: %d", len(args)) + } + + from, ok := args[0].(common.Address) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid from address: %v", args[0]) + } + + amount, ok = args[1].(*big.Int) + if !ok { + return common.Address{}, nil, fmt.Errorf("invalid amount: %v", args[1]) + } + + return from, amount, nil +} + +// ParseTransferOwnershipArgs parses the arguments from the transferOwnership method and returns the new owner address. +func ParseTransferOwnershipArgs(args []interface{}) (common.Address, error) { + if len(args) != 1 { + return common.Address{}, fmt.Errorf("invalid number of arguments; expected 1; got: %d", len(args)) + } + + newOwner, ok := args[0].(common.Address) + if !ok { + return common.Address{}, fmt.Errorf("invalid new owner address: %v", args[0]) + } + + return newOwner, nil +} diff --git a/precompiles/ics20/ics20.go b/precompiles/ics20/ics20.go index b184fd674..df90904c4 100644 --- a/precompiles/ics20/ics20.go +++ b/precompiles/ics20/ics20.go @@ -45,6 +45,7 @@ type Precompile struct { stakingKeeper cmn.StakingKeeper transferKeeper cmn.TransferKeeper channelKeeper cmn.ChannelKeeper + erc20Keeper cmn.ERC20Keeper } // NewPrecompile creates a new ICS-20 Precompile instance as a @@ -54,6 +55,7 @@ func NewPrecompile( stakingKeeper cmn.StakingKeeper, transferKeeper cmn.TransferKeeper, channelKeeper cmn.ChannelKeeper, + erc20Keeper cmn.ERC20Keeper, ) *Precompile { return &Precompile{ Precompile: cmn.Precompile{ @@ -67,6 +69,7 @@ func NewPrecompile( transferKeeper: transferKeeper, channelKeeper: channelKeeper, stakingKeeper: stakingKeeper, + erc20Keeper: erc20Keeper, } } diff --git a/precompiles/ics20/tx.go b/precompiles/ics20/tx.go index 6cea580c0..26007e5bd 100644 --- a/precompiles/ics20/tx.go +++ b/precompiles/ics20/tx.go @@ -2,18 +2,25 @@ package ics20 import ( "fmt" + "strings" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + "github.com/hashicorp/go-metrics" cmn "github.com/cosmos/evm/precompiles/common" + erc20types "github.com/cosmos/evm/x/erc20/types" + "github.com/cosmos/evm/x/vm/statedb" transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" connectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" host "github.com/cosmos/ibc-go/v10/modules/core/24-host" errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -87,6 +94,93 @@ func (p *Precompile) validateV1TransferChannel(ctx sdk.Context, msg *transfertyp return nil } +// transferWithStateDB handles IBC transfers with ERC20 token conversion support. +// If user doesn't have enough balance of coin, it will attempt to convert +// ERC20 tokens to the coin denomination, and continue with a regular transfer. +func (p *Precompile) transferWithStateDB(ctx sdk.Context, stateDB *statedb.StateDB, msg *transfertypes.MsgTransfer) (*transfertypes.MsgTransferResponse, error) { + // Temporarily save the KV and transient KV gas config. To avoid extra costs for relayers + // these two gas config are replaced with empty one and should be restored before exiting this function. + kvGasCfg := ctx.KVGasConfig() + transientKVGasCfg := ctx.TransientKVGasConfig() + ctx = ctx. + WithKVGasConfig(storetypes.GasConfig{}). + WithTransientKVGasConfig(storetypes.GasConfig{}) + + defer func() { + // Return the KV gas config to initial values + ctx = ctx. + WithKVGasConfig(kvGasCfg). + WithTransientKVGasConfig(transientKVGasCfg) + }() + + // use native denom or contract address + denom := strings.TrimPrefix(msg.Token.Denom, erc20types.Erc20NativeCoinDenomPrefix) + + pairID := p.erc20Keeper.GetTokenPairID(ctx, denom) + if len(pairID) == 0 { + // no-op: token is not registered so we can proceed with regular transfer + return p.transferKeeper.Transfer(ctx, msg) + } + + pair, _ := p.erc20Keeper.GetTokenPair(ctx, pairID) + if !pair.Enabled { + // no-op: pair is not enabled so we can proceed with regular transfer + return p.transferKeeper.Transfer(ctx, msg) + } + + sender := sdk.MustAccAddressFromBech32(msg.Sender) + + if !p.erc20Keeper.IsERC20Enabled(ctx) { + // no-op: continue with regular transfer + return p.transferKeeper.Transfer(ctx, msg) + } + + // update the msg denom to the token pair denom + msg.Token.Denom = pair.Denom + + if !pair.IsNativeERC20() { + return p.transferKeeper.Transfer(ctx, msg) + } + // if the user has enough balance of the Cosmos representation, then we don't need to Convert + balance := p.bankKeeper.SpendableCoin(ctx, sender, pair.Denom) + if balance.Amount.GTE(msg.Token.Amount) { + + defer func() { + telemetry.IncrCounterWithLabels( + []string{"erc20", "ibc", "transfer", "total"}, + 1, + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + }, + ) + }() + + return p.transferKeeper.Transfer(ctx, msg) + } + + // Only convert if the pair is a native ERC20 + // only convert the remaining difference + difference := msg.Token.Amount.Sub(balance.Amount) + + // Convert the ERC20 tokens to Cosmos IBC Coin + erc20Sender := common.BytesToAddress(sender.Bytes()) + if _, err := p.erc20Keeper.ConvertERC20IntoCoinsForNativeToken(ctx, stateDB, pair.GetERC20Contract(), difference, sender, erc20Sender, true, true); err != nil { + return nil, err + } + + defer func() { + telemetry.IncrCounterWithLabels( + []string{"erc20", "ibc", "transfer", "total"}, + 1, + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + }, + ) + }() + + return p.transferKeeper.Transfer(ctx, msg) +} + // Transfer implements the ICS20 transfer transactions. func (p *Precompile) Transfer( ctx sdk.Context, @@ -119,7 +213,8 @@ func (p *Precompile) Transfer( return nil, fmt.Errorf(cmn.ErrRequesterIsNotMsgSender, msgSender.String(), sender.String()) } - res, err := p.transferKeeper.Transfer(ctx, msg) + stateDBExp := stateDB.(*statedb.StateDB) + res, err := p.transferWithStateDB(ctx, stateDBExp, msg) if err != nil { return nil, err } diff --git a/precompiles/types/defaults.go b/precompiles/types/defaults.go index 65b855e37..45581a06a 100644 --- a/precompiles/types/defaults.go +++ b/precompiles/types/defaults.go @@ -7,7 +7,7 @@ import ( evmaddress "github.com/cosmos/evm/encoding/address" cmn "github.com/cosmos/evm/precompiles/common" erc20Keeper "github.com/cosmos/evm/x/erc20/keeper" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" + transferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" channelkeeper "github.com/cosmos/ibc-go/v10/modules/core/04-channel/keeper" "cosmossdk.io/core/address" @@ -80,7 +80,7 @@ func DefaultStaticPrecompiles( WithBech32Precompile(). WithStakingPrecompile(stakingKeeper, bankKeeper, opts...). WithDistributionPrecompile(distributionKeeper, stakingKeeper, bankKeeper, opts...). - WithICS20Precompile(bankKeeper, stakingKeeper, transferKeeper, channelKeeper). + WithICS20Precompile(bankKeeper, stakingKeeper, transferKeeper, channelKeeper, erc20Keeper). WithBankPrecompile(bankKeeper, erc20Keeper). WithGovPrecompile(govKeeper, bankKeeper, codec, opts...). WithSlashingPrecompile(slashingKeeper, bankKeeper, opts...) diff --git a/precompiles/types/static_precompiles.go b/precompiles/types/static_precompiles.go index ca49445f9..90fa95a2e 100644 --- a/precompiles/types/static_precompiles.go +++ b/precompiles/types/static_precompiles.go @@ -17,7 +17,7 @@ import ( slashingprecompile "github.com/cosmos/evm/precompiles/slashing" stakingprecompile "github.com/cosmos/evm/precompiles/staking" erc20Keeper "github.com/cosmos/evm/x/erc20/keeper" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" + transferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" channelkeeper "github.com/cosmos/ibc-go/v10/modules/core/04-channel/keeper" "github.com/cosmos/cosmos-sdk/codec" @@ -104,12 +104,14 @@ func (s StaticPrecompiles) WithICS20Precompile( stakingKeeper stakingkeeper.Keeper, transferKeeper *transferkeeper.Keeper, channelKeeper *channelkeeper.Keeper, + erc20Keeper *erc20Keeper.Keeper, ) StaticPrecompiles { ibcTransferPrecompile := ics20precompile.NewPrecompile( bankKeeper, stakingKeeper, transferKeeper, channelKeeper, + erc20Keeper, ) s[ibcTransferPrecompile.Address()] = ibcTransferPrecompile diff --git a/precompiles/werc20/abi.json b/precompiles/werc20/abi.json index 3753fd7bc..f7631fb64 100644 --- a/precompiles/werc20/abi.json +++ b/precompiles/werc20/abi.json @@ -28,6 +28,25 @@ "name": "Approval", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, { "anonymous": false, "inputs": [ @@ -274,6 +293,99 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { diff --git a/precompiles/werc20/interfaces.go b/precompiles/werc20/interfaces.go index 9ebf87202..8c93525a8 100644 --- a/precompiles/werc20/interfaces.go +++ b/precompiles/werc20/interfaces.go @@ -5,6 +5,8 @@ import ( "github.com/ethereum/go-ethereum/common" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -12,4 +14,8 @@ type Erc20Keeper interface { GetAllowance(ctx sdk.Context, erc20 common.Address, owner common.Address, spender common.Address) (*big.Int, error) SetAllowance(ctx sdk.Context, erc20 common.Address, owner common.Address, spender common.Address, value *big.Int) error DeleteAllowance(ctx sdk.Context, erc20 common.Address, owner common.Address, spender common.Address) error + BurnCoins(ctx sdk.Context, sender sdk.AccAddress, amount math.Int, token string) error + GetTokenPairOwnerAddress(ctx sdk.Context, token string) (sdk.AccAddress, error) + TransferOwnership(ctx sdk.Context, sender sdk.AccAddress, newOwner sdk.AccAddress, token string) error + MintCoins(ctx sdk.Context, sender, to sdk.AccAddress, amount math.Int, token string) error } diff --git a/proto/cosmos/evm/erc20/v1/erc20.proto b/proto/cosmos/evm/erc20/v1/erc20.proto index d7cd29d2d..94e722df9 100644 --- a/proto/cosmos/evm/erc20/v1/erc20.proto +++ b/proto/cosmos/evm/erc20/v1/erc20.proto @@ -30,6 +30,9 @@ message TokenPair { // contract_owner is the an ENUM specifying the type of ERC20 owner (0 // invalid, 1 ModuleAccount, 2 external address) Owner contract_owner = 4; + // owner_address is the address of the current owner of the token + // Only set if contract_owner is OWNER_MODULE + string owner_address = 5; } // Allowance is a token allowance only for erc20 precompile diff --git a/proto/cosmos/evm/erc20/v1/query.proto b/proto/cosmos/evm/erc20/v1/query.proto index a23a6832c..ebefa3b5a 100644 --- a/proto/cosmos/evm/erc20/v1/query.proto +++ b/proto/cosmos/evm/erc20/v1/query.proto @@ -27,6 +27,13 @@ service Query { rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/cosmos/evm/erc20/v1/params"; } + + // OwnerAddress retrieves the owner address for a given ERC20 contract address + rpc OwnerAddress(QueryOwnerAddressRequest) + returns (QueryOwnerAddressResponse) { + option (google.api.http).get = + "/evmos/erc20/v1/owner_address/{contract_address}"; + } } // QueryTokenPairsRequest is the request type for the Query/TokenPairs RPC @@ -72,3 +79,7 @@ message QueryParamsResponse { Params params = 1 [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ]; } + +message QueryOwnerAddressRequest { string contract_address = 1; } + +message QueryOwnerAddressResponse { string owner_address = 1; } diff --git a/proto/cosmos/evm/erc20/v1/tx.proto b/proto/cosmos/evm/erc20/v1/tx.proto index b8cdbaf39..b70694548 100644 --- a/proto/cosmos/evm/erc20/v1/tx.proto +++ b/proto/cosmos/evm/erc20/v1/tx.proto @@ -38,6 +38,18 @@ service Msg { // module account rpc ToggleConversion(MsgToggleConversion) returns (MsgToggleConversionResponse); + // TransferContractOwnership defines a Msg to transfer the ownership of the + // ERC20 token pair to the new owner + rpc TransferContractOwnership(MsgTransferOwnership) + returns (MsgTransferOwnershipResponse); + // Mint mints ERC20 tokens + rpc Mint(MsgMint) returns (MsgMintResponse) { + option (google.api.http).post = "/cosmos/evm/erc20/v1/tx/mint"; + }; + // Burn burns ERC20 tokens + rpc Burn(MsgBurn) returns (MsgBurnResponse) { + option (google.api.http).post = "/cosmos/evm/erc20/v1/tx/burn"; + }; } // MsgConvertERC20 defines a Msg to convert a ERC20 token to a native Cosmos @@ -134,3 +146,56 @@ message MsgToggleConversion { // MsgToggleConversionResponse defines the response structure for executing a // ToggleConversion message. message MsgToggleConversionResponse {} + + +// MsgTransferOwnership defines a Msg to transfer the ownership of the ERC20 +// token pair to the new owner +message MsgTransferOwnership { + option (cosmos.msg.v1.signer) = "authority"; + + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // token identifier can be either the hex contract address of the ERC20 or the + // Cosmos base denomination + string token = 2; + // new_owner is the hex address of the new owner + string new_owner = 3; +} + +// MsgTransferOwnershipResponse returns no fields +message MsgTransferOwnershipResponse {} + +// MsgMint defines a Msg to mint ERC20 tokens +message MsgMint { + option (cosmos.msg.v1.signer) = "sender"; + // contract_address of an ERC20 token contract, that is registered in a token + // pair + string contract_address = 1; + // amount of ERC20 tokens to mint + string amount = 2 [ + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false + ]; + // to is the address to mint the tokens to + string to = 3; + // sender is the address of the sender + string sender = 4; +} + +message MsgMintResponse {} + +// MsgBurn defines a Msg to burn ERC20 tokens +message MsgBurn { + option (cosmos.msg.v1.signer) = "sender"; + // contract_address of an ERC20 token contract, that is registered in a token + // pair + string contract_address = 1; + // amount of ERC20 tokens to burn + string amount = 2 [ + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false + ]; + // sender is the address of the sender + string sender = 3; +} + +message MsgBurnResponse {} \ No newline at end of file diff --git a/proto/cosmos/evm/crypto/v1/ethsecp256k1/keys.proto b/proto/ethermint/crypto/v1/ethsecp256k1/keys.proto similarity index 93% rename from proto/cosmos/evm/crypto/v1/ethsecp256k1/keys.proto rename to proto/ethermint/crypto/v1/ethsecp256k1/keys.proto index 4f1303bc7..4a061fb75 100644 --- a/proto/cosmos/evm/crypto/v1/ethsecp256k1/keys.proto +++ b/proto/ethermint/crypto/v1/ethsecp256k1/keys.proto @@ -1,6 +1,6 @@ syntax = "proto3"; -package cosmos.evm.crypto.v1.ethsecp256k1; +package ethermint.crypto.v1.ethsecp256k1; import "gogoproto/gogo.proto"; diff --git a/rpc/backend/comet_to_eth.go b/rpc/backend/comet_to_eth.go index 8b4847726..cbbbf1b7a 100644 --- a/rpc/backend/comet_to_eth.go +++ b/rpc/backend/comet_to_eth.go @@ -13,6 +13,7 @@ import ( cmtrpctypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/cosmos/evm/rpc/backend/eth" rpctypes "github.com/cosmos/evm/rpc/types" evmtypes "github.com/cosmos/evm/x/vm/types" @@ -110,12 +111,22 @@ func (b *Backend) EthMsgsFromCometBlock( } for _, msg := range tx.GetMsgs() { - ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { + // Try to adapt the message to our unified interface + ethMsg := eth.TryAdaptEthTxMsg(msg) + if ethMsg == nil { + // Not an Ethereum transaction message continue } - result = append(result, ethMsg) + // Convert to new EVM format for return + // Use the chain ID from the backend + convertedMsg, err := eth.ConvertToNewEVMMsgWithChainID(ethMsg, b.EvmChainID) + if err != nil { + b.Logger.Debug("failed to convert ethereum tx", "height", block.Height, "error", err.Error()) + continue + } + + result = append(result, convertedMsg) } } diff --git a/rpc/backend/eth/adapter.go b/rpc/backend/eth/adapter.go new file mode 100644 index 000000000..4cbb12321 --- /dev/null +++ b/rpc/backend/eth/adapter.go @@ -0,0 +1,37 @@ +package eth + +import ( + "fmt" + + legacytypes "github.com/cosmos/evm/rpc/types/legacy" + evmtypes "github.com/cosmos/evm/x/vm/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// AdaptEthTxMsg converts an sdk.Msg to our unified TxMsg interface. +// This function tries to match the message to known MsgEthereumTx types +// and returns an appropriate adapter. This makes it easy to add support +// for new message types in the future by adding new case statements. +func AdaptEthTxMsg(msg sdk.Msg) (TxMsg, error) { + switch m := msg.(type) { + case *evmtypes.MsgEthereumTx: + // New EVM type + return &NewEVMEthTxMsg{MsgEthereumTx: m}, nil + case *legacytypes.MsgEthereumTx: + // Legacy Evmos type + return &LegacyEvmosEthTxMsg{MsgEthereumTx: m}, nil + default: + return nil, fmt.Errorf("unsupported message type: %T", msg) + } +} + +// TryAdaptEthTxMsg attempts to adapt a message to TxMsg. +// Returns nil if the message is not an Ethereum transaction type. +func TryAdaptEthTxMsg(msg sdk.Msg) TxMsg { + adapted, err := AdaptEthTxMsg(msg) + if err != nil { + return nil + } + return adapted +} diff --git a/rpc/backend/eth/evm.go b/rpc/backend/eth/evm.go new file mode 100644 index 000000000..e77a49719 --- /dev/null +++ b/rpc/backend/eth/evm.go @@ -0,0 +1,62 @@ +package eth + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +var _ TxMsg = NewEVMEthTxMsg{} + +// NewEVMEthTxMsg creates an adapter for the new EVM MsgEthereumTx +type NewEVMEthTxMsg struct { + *evmtypes.MsgEthereumTx +} + +// AsTransaction returns the underlying Ethereum transaction for the new EVM type +func (m NewEVMEthTxMsg) AsTransaction() *ethtypes.Transaction { + return m.MsgEthereumTx.AsTransaction() +} + +// Hash returns the transaction hash for the new EVM type +func (m NewEVMEthTxMsg) Hash() common.Hash { + return m.MsgEthereumTx.Hash() +} + +// GetSenderLegacy returns the sender address for the new EVM type +func (m NewEVMEthTxMsg) GetSenderLegacy(signer ethtypes.Signer) (common.Address, error) { + return m.MsgEthereumTx.GetSenderLegacy(signer) +} + +// GetGas returns the gas limit for the new EVM type +func (m NewEVMEthTxMsg) GetGas() uint64 { + return m.MsgEthereumTx.GetGas() +} + +// ConvertToNewEVMMsg converts any TxMsg to the new EVM MsgEthereumTx format. +// This is useful when we need to work with code that specifically requires +// the new format. For legacy messages, this creates a new message with +// the converted data. +func ConvertToNewEVMMsg(msg TxMsg, signer ethtypes.Signer) (*evmtypes.MsgEthereumTx, error) { + // If it's already the new format, return as-is + if newMsg, ok := msg.(*NewEVMEthTxMsg); ok { + return newMsg.MsgEthereumTx, nil + } + + // For legacy messages, create a new message + tx := msg.AsTransaction() + sender, err := msg.GetSenderLegacy(signer) + if err != nil { + return nil, fmt.Errorf("failed to get sender: %w", err) + } + + newMsg := &evmtypes.MsgEthereumTx{ + From: sender.Bytes(), + } + newMsg.FromEthereumTx(tx) + + return newMsg, nil +} diff --git a/rpc/backend/eth/evmos.go b/rpc/backend/eth/evmos.go new file mode 100644 index 000000000..7aec4038a --- /dev/null +++ b/rpc/backend/eth/evmos.go @@ -0,0 +1,73 @@ +package eth + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + + legacytypes "github.com/cosmos/evm/rpc/types/legacy" + evmtypes "github.com/cosmos/evm/x/vm/types" +) + +var _ TxMsg = LegacyEvmosEthTxMsg{} + +// LegacyEvmosEthTxMsg creates an adapter for the old Evmos MsgEthereumTx +type LegacyEvmosEthTxMsg struct { + *legacytypes.MsgEthereumTx +} + +// AsTransaction returns the underlying Ethereum transaction for the legacy Evmos type +func (m LegacyEvmosEthTxMsg) AsTransaction() *ethtypes.Transaction { + return m.MsgEthereumTx.AsTransaction() +} + +// Hash returns the transaction hash for the legacy Evmos type +func (m LegacyEvmosEthTxMsg) Hash() common.Hash { + // The old type stores hash as hex string, convert it back + if m.MsgEthereumTx.Hash != "" { + return common.HexToHash(m.MsgEthereumTx.Hash) + } + // Fallback: compute from transaction + return m.AsTransaction().Hash() +} + +// GetSenderLegacy returns the sender address for the legacy Evmos type +func (m LegacyEvmosEthTxMsg) GetSenderLegacy(signer ethtypes.Signer) (common.Address, error) { + // If From field is set, use it + if m.From != "" { + return common.HexToAddress(m.From), nil + } + // Otherwise recover from signature + tx := m.AsTransaction() + sender, err := signer.Sender(tx) + if err != nil { + return common.Address{}, err + } + // Cache the sender for future use + m.From = sender.Hex() + return sender, nil +} + +// GetGas returns the gas limit for the legacy Evmos type +func (m LegacyEvmosEthTxMsg) GetGas() uint64 { + return m.MsgEthereumTx.GetGas() +} + +// ConvertToNewEVMMsgWithChainID is like ConvertToNewEVMMsg but uses chainID to create signer +func ConvertToNewEVMMsgWithChainID(msg TxMsg, chainID *big.Int) (*evmtypes.MsgEthereumTx, error) { + // If it's already the new format, return as-is + if newMsg, ok := msg.(*NewEVMEthTxMsg); ok { + return newMsg.MsgEthereumTx, nil + } + + tx := msg.AsTransaction() + var signer ethtypes.Signer + if tx.Protected() { + signer = ethtypes.LatestSignerForChainID(tx.ChainId()) + } else { + signer = ethtypes.FrontierSigner{} + } + + return ConvertToNewEVMMsg(msg, signer) +} diff --git a/rpc/backend/eth/msg.go b/rpc/backend/eth/msg.go new file mode 100644 index 000000000..8e8e117f6 --- /dev/null +++ b/rpc/backend/eth/msg.go @@ -0,0 +1,20 @@ +package eth + +import ( + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +// TxMsg is a unified interface for different versions of MsgEthereumTx +// This interface abstracts the differences between the old Evmos format +// and the new EVM format, making it easy to add support for future versions. +type TxMsg interface { + // AsTransaction returns the underlying Ethereum transaction + AsTransaction() *ethtypes.Transaction + // Hash returns the transaction hash + Hash() common.Hash + // GetSenderLegacy returns the sender address, recovering from signature if needed + GetSenderLegacy(signer ethtypes.Signer) (common.Address, error) + // GetGas returns the gas limit + GetGas() uint64 +} diff --git a/rpc/backend/tracing.go b/rpc/backend/tracing.go index fa1ee67c4..2dfaec58a 100644 --- a/rpc/backend/tracing.go +++ b/rpc/backend/tracing.go @@ -12,6 +12,7 @@ import ( tmrpcclient "github.com/cometbft/cometbft/rpc/client" tmrpctypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/cosmos/evm/rpc/backend/eth" rpctypes "github.com/cosmos/evm/rpc/types" evmtypes "github.com/cosmos/evm/x/vm/types" @@ -57,12 +58,19 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *rpctypes.TraceConfi continue } for _, msg := range tx.GetMsgs() { - ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { + // Try to adapt the message to our unified interface + ethMsg := eth.TryAdaptEthTxMsg(msg) + if ethMsg == nil { continue } - predecessors = append(predecessors, ethMsg) + // Convert to new format for predecessors + convertedMsg, err := eth.ConvertToNewEVMMsgWithChainID(ethMsg, b.EvmChainID) + if err != nil { + b.Logger.Debug("failed to convert ethereum tx", "height", blk.Block.Height, "error", err.Error()) + continue + } + predecessors = append(predecessors, convertedMsg) } } @@ -75,19 +83,33 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *rpctypes.TraceConfi // add predecessor messages in current cosmos tx index := int(transaction.MsgIndex) // #nosec G115 for i := 0; i < index; i++ { - ethMsg, ok := tx.GetMsgs()[i].(*evmtypes.MsgEthereumTx) - if !ok { + ethMsg := eth.TryAdaptEthTxMsg(tx.GetMsgs()[i]) + if ethMsg == nil { + continue + } + // Convert to new format for predecessors + convertedMsg, err := eth.ConvertToNewEVMMsgWithChainID(ethMsg, b.EvmChainID) + if err != nil { + b.Logger.Debug("failed to convert ethereum tx", "error", err.Error()) continue } - predecessors = append(predecessors, ethMsg) + predecessors = append(predecessors, convertedMsg) } - ethMessage, ok := tx.GetMsgs()[transaction.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { + // Adapt the target message + adaptedMsg, err := eth.AdaptEthTxMsg(tx.GetMsgs()[transaction.MsgIndex]) + if err != nil { b.Logger.Debug("invalid transaction type", "type", fmt.Sprintf("%T", tx)) return nil, fmt.Errorf("invalid transaction type %T", tx) } + // Convert to new format + ethMessage, err := eth.ConvertToNewEVMMsgWithChainID(adaptedMsg, b.EvmChainID) + if err != nil { + b.Logger.Debug("failed to convert ethereum tx", "error", err.Error()) + return nil, fmt.Errorf("failed to convert ethereum tx: %w", err) + } + nc, ok := b.ClientCtx.Client.(tmrpcclient.NetworkClient) if !ok { return nil, errors.New("invalid rpc client") @@ -180,12 +202,19 @@ func (b *Backend) TraceBlock(height rpctypes.BlockNumber, } for _, msg := range decodedTx.GetMsgs() { - ethMessage, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { + // Try to adapt the message to our unified interface + ethMsg := eth.TryAdaptEthTxMsg(msg) + if ethMsg == nil { // Just considers Ethereum transactions continue } - txsMessages = append(txsMessages, ethMessage) + // Convert to new format + convertedMsg, err := eth.ConvertToNewEVMMsgWithChainID(ethMsg, b.EvmChainID) + if err != nil { + b.Logger.Debug("failed to convert ethereum tx", "error", err.Error()) + continue + } + txsMessages = append(txsMessages, convertedMsg) } } diff --git a/rpc/backend/tx_info.go b/rpc/backend/tx_info.go index 9c84198ff..658cbd98c 100644 --- a/rpc/backend/tx_info.go +++ b/rpc/backend/tx_info.go @@ -19,6 +19,7 @@ import ( cmtrpctypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/cosmos/evm/mempool/txpool" + "github.com/cosmos/evm/rpc/backend/eth" rpctypes "github.com/cosmos/evm/rpc/types" servertypes "github.com/cosmos/evm/server/types" "github.com/cosmos/evm/utils" @@ -47,9 +48,16 @@ func (b *Backend) GetTransactionByHash(txHash common.Hash) (*rpctypes.RPCTransac } // the `res.MsgIndex` is inferred from tx index, should be within the bound. - msg, ok := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { - return nil, errors.New("invalid ethereum tx") + // Support both new EVM and legacy Evmos message types + ethMsg, err := eth.AdaptEthTxMsg(tx.GetMsgs()[res.MsgIndex]) + if err != nil { + return nil, fmt.Errorf("invalid ethereum tx: %w", err) + } + + // Convert to new format for further processing + msg, err := eth.ConvertToNewEVMMsgWithChainID(ethMsg, b.EvmChainID) + if err != nil { + return nil, fmt.Errorf("failed to convert ethereum tx: %w", err) } blockRes, err := b.RPCClient.BlockResults(b.Ctx, &block.Block.Height) @@ -192,7 +200,19 @@ func (b *Backend) GetTransactionReceipt(hash common.Hash) (map[string]interface{ return nil, fmt.Errorf("block result not found at height %d: %w", res.Height, err) } - ethMsg := tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) + // Support both new EVM and legacy Evmos message types + adaptedMsg, err := eth.AdaptEthTxMsg(tx.GetMsgs()[res.MsgIndex]) + if err != nil { + b.Logger.Debug("invalid ethereum tx", "error", err.Error()) + return nil, fmt.Errorf("invalid ethereum tx: %w", err) + } + + // Convert to new format for receipt formatting + ethMsg, err := eth.ConvertToNewEVMMsgWithChainID(adaptedMsg, b.EvmChainID) + if err != nil { + b.Logger.Debug("failed to convert ethereum tx", "error", err.Error()) + return nil, fmt.Errorf("failed to convert ethereum tx: %w", err) + } receipts, err := b.ReceiptsFromCometBlock(resBlock, blockRes, []*evmtypes.MsgEthereumTx{ethMsg}) if err != nil { return nil, fmt.Errorf("failed to get receipts from comet block") @@ -374,13 +394,19 @@ func (b *Backend) GetTransactionByBlockAndIndex(block *cmtrpctypes.ResultBlock, return nil, nil } - var ok bool // msgIndex is inferred from tx events, should be within bound. - msg, ok = tx.GetMsgs()[res.MsgIndex].(*evmtypes.MsgEthereumTx) - if !ok { + // Support both new EVM and legacy Evmos message types + adaptedMsg, err := eth.AdaptEthTxMsg(tx.GetMsgs()[res.MsgIndex]) + if err != nil { b.Logger.Debug("invalid ethereum tx", "height", block.Block.Header, "index", idx) return nil, nil } + // Convert to new format + msg, err = eth.ConvertToNewEVMMsgWithChainID(adaptedMsg, b.EvmChainID) + if err != nil { + b.Logger.Debug("failed to convert ethereum tx", "height", block.Block.Header, "index", idx, "error", err.Error()) + return nil, nil + } } else { i := int(idx) // #nosec G115 ethMsgs := b.EthMsgsFromCometBlock(block, blockRes) diff --git a/rpc/backend/utils.go b/rpc/backend/utils.go index ca46109b0..a2d76eaa1 100644 --- a/rpc/backend/utils.go +++ b/rpc/backend/utils.go @@ -18,6 +18,7 @@ import ( "github.com/cometbft/cometbft/proto/tendermint/crypto" cmtrpctypes "github.com/cometbft/cometbft/rpc/core/types" + "github.com/cosmos/evm/rpc/backend/eth" "github.com/cosmos/evm/rpc/types" "github.com/cosmos/evm/utils" feemarkettypes "github.com/cosmos/evm/x/feemarket/types" @@ -91,8 +92,9 @@ func (b *Backend) getAccountNonce(accAddr common.Address, pending bool, height i // only supports `MsgEthereumTx` style tx for _, tx := range pendingTxs { for _, msg := range (*tx).GetMsgs() { - ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { + // Try to adapt the message to our unified interface + ethMsg := eth.TryAdaptEthTxMsg(msg) + if ethMsg == nil { // not ethereum tx break } @@ -247,8 +249,9 @@ func (b *Backend) ProcessBlock( } txGasUsed := uint64(cometTxResult.GasUsed) // #nosec G115 for _, msg := range tx.GetMsgs() { - ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { + // Try to adapt the message to our unified interface + ethMsg := eth.TryAdaptEthTxMsg(msg) + if ethMsg == nil { continue } tx := ethMsg.AsTransaction() diff --git a/rpc/types/legacy/access_list.go b/rpc/types/legacy/access_list.go new file mode 100644 index 000000000..50de8b2ac --- /dev/null +++ b/rpc/types/legacy/access_list.go @@ -0,0 +1,57 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +// AccessList is an EIP-2930 access list that represents the slice of +// the protobuf AccessTuples. +type AccessList []AccessTuple + +// NewAccessList creates a new protobuf-compatible AccessList from an ethereum +// core AccessList type +func NewAccessList(ethAccessList *ethtypes.AccessList) AccessList { + if ethAccessList == nil { + return nil + } + + al := AccessList{} + for _, tuple := range *ethAccessList { + storageKeys := make([]string, len(tuple.StorageKeys)) + + for i := range tuple.StorageKeys { + storageKeys[i] = tuple.StorageKeys[i].String() + } + + al = append(al, AccessTuple{ + Address: tuple.Address.String(), + StorageKeys: storageKeys, + }) + } + + return al +} + +// ToEthAccessList is an utility function to convert the protobuf compatible +// AccessList to eth core AccessList from go-ethereum +func (al AccessList) ToEthAccessList() *ethtypes.AccessList { + var ethAccessList ethtypes.AccessList + + for _, tuple := range al { + storageKeys := make([]common.Hash, len(tuple.StorageKeys)) + + for i := range tuple.StorageKeys { + storageKeys[i] = common.HexToHash(tuple.StorageKeys[i]) + } + + ethAccessList = append(ethAccessList, ethtypes.AccessTuple{ + Address: common.HexToAddress(tuple.Address), + StorageKeys: storageKeys, + }) + } + + return ðAccessList +} diff --git a/rpc/types/legacy/access_list_tx.go b/rpc/types/legacy/access_list_tx.go new file mode 100644 index 000000000..be24aae53 --- /dev/null +++ b/rpc/types/legacy/access_list_tx.go @@ -0,0 +1,250 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + errortypes "github.com/cosmos/cosmos-sdk/types/errors" +) + +func newAccessListTx(tx *ethtypes.Transaction) (*AccessListTx, error) { + txData := &AccessListTx{ + Nonce: tx.Nonce(), + Data: tx.Data(), + GasLimit: tx.Gas(), + } + + v, r, s := tx.RawSignatureValues() + if to := tx.To(); to != nil { + txData.To = to.Hex() + } + + if tx.Value() != nil { + amountInt, err := SafeNewIntFromBigInt(tx.Value()) + if err != nil { + return nil, err + } + txData.Amount = &amountInt + } + + if tx.GasPrice() != nil { + gasPriceInt, err := SafeNewIntFromBigInt(tx.GasPrice()) + if err != nil { + return nil, err + } + txData.GasPrice = &gasPriceInt + } + + if tx.AccessList() != nil { + al := tx.AccessList() + txData.Accesses = NewAccessList(&al) + } + + txData.SetSignatureValues(tx.ChainId(), v, r, s) + return txData, nil +} + +// TxType returns the tx type +func (tx *AccessListTx) TxType() uint8 { + return ethtypes.AccessListTxType +} + +// Copy returns an instance with the same field values +func (tx *AccessListTx) Copy() TxData { + return &AccessListTx{ + ChainID: tx.ChainID, + Nonce: tx.Nonce, + GasPrice: tx.GasPrice, + GasLimit: tx.GasLimit, + To: tx.To, + Amount: tx.Amount, + Data: common.CopyBytes(tx.Data), + Accesses: tx.Accesses, + V: common.CopyBytes(tx.V), + R: common.CopyBytes(tx.R), + S: common.CopyBytes(tx.S), + } +} + +// GetChainID returns the chain id field from the AccessListTx +func (tx *AccessListTx) GetChainID() *big.Int { + if tx.ChainID == nil { + return nil + } + + return tx.ChainID.BigInt() +} + +// GetAccessList returns the AccessList field. +func (tx *AccessListTx) GetAccessList() ethtypes.AccessList { + if tx.Accesses == nil { + return nil + } + return *tx.Accesses.ToEthAccessList() +} + +// GetData returns the a copy of the input data bytes. +func (tx *AccessListTx) GetData() []byte { + return common.CopyBytes(tx.Data) +} + +// GetGas returns the gas limit. +func (tx *AccessListTx) GetGas() uint64 { + return tx.GasLimit +} + +// GetGasPrice returns the gas price field. +func (tx *AccessListTx) GetGasPrice() *big.Int { + if tx.GasPrice == nil { + return nil + } + return tx.GasPrice.BigInt() +} + +// GetGasTipCap returns the gas price field. +func (tx *AccessListTx) GetGasTipCap() *big.Int { + return tx.GetGasPrice() +} + +// GetGasFeeCap returns the gas price field. +func (tx *AccessListTx) GetGasFeeCap() *big.Int { + return tx.GetGasPrice() +} + +// GetValue returns the tx amount. +func (tx *AccessListTx) GetValue() *big.Int { + if tx.Amount == nil { + return nil + } + + return tx.Amount.BigInt() +} + +// GetNonce returns the account sequence for the transaction. +func (tx *AccessListTx) GetNonce() uint64 { return tx.Nonce } + +// GetTo returns the pointer to the recipient address. +func (tx *AccessListTx) GetTo() *common.Address { + if tx.To == "" { + return nil + } + to := common.HexToAddress(tx.To) + return &to +} + +// AsEthereumData returns an AccessListTx transaction tx from the proto-formatted +// TxData defined on the Cosmos EVM. +func (tx *AccessListTx) AsEthereumData() ethtypes.TxData { + v, r, s := tx.GetRawSignatureValues() + return ðtypes.AccessListTx{ + ChainID: tx.GetChainID(), + Nonce: tx.GetNonce(), + GasPrice: tx.GetGasPrice(), + Gas: tx.GetGas(), + To: tx.GetTo(), + Value: tx.GetValue(), + Data: tx.GetData(), + AccessList: tx.GetAccessList(), + V: v, + R: r, + S: s, + } +} + +// GetRawSignatureValues returns the V, R, S signature values of the transaction. +// The return values should not be modified by the caller. +func (tx *AccessListTx) GetRawSignatureValues() (v, r, s *big.Int) { + return RawSignatureValues(tx.V, tx.R, tx.S) +} + +// SetSignatureValues sets the signature values to the transaction. +func (tx *AccessListTx) SetSignatureValues(chainID, v, r, s *big.Int) { + if v != nil { + tx.V = v.Bytes() + } + if r != nil { + tx.R = r.Bytes() + } + if s != nil { + tx.S = s.Bytes() + } + if chainID != nil { + chainIDInt := sdkmath.NewIntFromBigInt(chainID) + tx.ChainID = &chainIDInt + } +} + +// Validate performs a stateless validation of the tx fields. +func (tx AccessListTx) Validate() error { + gasPrice := tx.GetGasPrice() + if gasPrice == nil { + return errorsmod.Wrap(ErrInvalidGasPrice, "cannot be nil") + } + if !IsValidInt256(gasPrice) { + return errorsmod.Wrap(ErrInvalidGasPrice, "out of bound") + } + + if gasPrice.Sign() == -1 { + return errorsmod.Wrapf(ErrInvalidGasPrice, "gas price cannot be negative %s", gasPrice) + } + + amount := tx.GetValue() + // Amount can be 0 + if amount != nil && amount.Sign() == -1 { + return errorsmod.Wrapf(ErrInvalidAmount, "amount cannot be negative %s", amount) + } + if !IsValidInt256(amount) { + return errorsmod.Wrap(ErrInvalidAmount, "out of bound") + } + + if !IsValidInt256(tx.Fee()) { + return errorsmod.Wrap(ErrInvalidGasFee, "out of bound") + } + + if tx.To != "" { + if err := ValidateAddress(tx.To); err != nil { + return errorsmod.Wrap(err, "invalid to address") + } + } + + if tx.GetChainID() == nil { + return errorsmod.Wrap( + errortypes.ErrInvalidChainID, + "chain ID must be present on AccessList txs", + ) + } + + return nil +} + +// Fee returns gasprice * gaslimit. +func (tx AccessListTx) Fee() *big.Int { + return fee(tx.GetGasPrice(), tx.GetGas()) +} + +// Cost returns amount + gasprice * gaslimit. +func (tx AccessListTx) Cost() *big.Int { + return cost(tx.Fee(), tx.GetValue()) +} + +// EffectiveGasPrice is the same as GasPrice for AccessListTx +func (tx AccessListTx) EffectiveGasPrice(_ *big.Int) *big.Int { + return tx.GetGasPrice() +} + +// EffectiveFee is the same as Fee for AccessListTx +func (tx AccessListTx) EffectiveFee(_ *big.Int) *big.Int { + return tx.Fee() +} + +// EffectiveCost is the same as Cost for AccessListTx +func (tx AccessListTx) EffectiveCost(_ *big.Int) *big.Int { + return tx.Cost() +} diff --git a/rpc/types/legacy/codec.go b/rpc/types/legacy/codec.go new file mode 100644 index 000000000..d2656b654 --- /dev/null +++ b/rpc/types/legacy/codec.go @@ -0,0 +1,55 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "github.com/cosmos/gogoproto/proto" + + errorsmod "cosmossdk.io/errors" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + errortypes "github.com/cosmos/cosmos-sdk/types/errors" +) + +var ( + amino = codec.NewLegacyAmino() + // ModuleCdc references the global evm module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding. + ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + + // AminoCdc is a amino codec created to support amino JSON compatible msgs. + AminoCdc = codec.NewAminoCodec(amino) //nolint:staticcheck +) + +// PackTxData constructs a new Any packed with the given tx data value. It returns +// an error if the client state can't be casted to a protobuf message or if the concrete +// implementation is not registered to the protobuf codec. +func PackTxData(txData TxData) (*codectypes.Any, error) { + msg, ok := txData.(proto.Message) + if !ok { + return nil, errorsmod.Wrapf(errortypes.ErrPackAny, "cannot proto marshal %T", txData) + } + + anyTxData, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, errorsmod.Wrap(errortypes.ErrPackAny, err.Error()) + } + + return anyTxData, nil +} + +// UnpackTxData unpacks an Any into a TxData. It returns an error if the +// client state can't be unpacked into a TxData. +func UnpackTxData(anyTx *codectypes.Any) (TxData, error) { + if anyTx == nil { + return nil, errorsmod.Wrap(errortypes.ErrUnpackAny, "protobuf Any message cannot be nil") + } + + txData, ok := anyTx.GetCachedValue().(TxData) + if !ok { + return nil, errorsmod.Wrapf(errortypes.ErrUnpackAny, "cannot unpack Any into TxData %T", anyTx) + } + + return txData, nil +} diff --git a/rpc/types/legacy/dynamic_fee_tx.go b/rpc/types/legacy/dynamic_fee_tx.go new file mode 100644 index 000000000..8bb172c1c --- /dev/null +++ b/rpc/types/legacy/dynamic_fee_tx.go @@ -0,0 +1,282 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + errortypes "github.com/cosmos/cosmos-sdk/types/errors" +) + +func NewDynamicFeeTx(tx *ethtypes.Transaction) (*DynamicFeeTx, error) { + txData := &DynamicFeeTx{ + Nonce: tx.Nonce(), + Data: tx.Data(), + GasLimit: tx.Gas(), + } + + v, r, s := tx.RawSignatureValues() + if to := tx.To(); to != nil { + txData.To = to.Hex() + } + + if tx.Value() != nil { + amountInt, err := SafeNewIntFromBigInt(tx.Value()) + if err != nil { + return nil, err + } + txData.Amount = &amountInt + } + + if tx.GasFeeCap() != nil { + gasFeeCapInt, err := SafeNewIntFromBigInt(tx.GasFeeCap()) + if err != nil { + return nil, err + } + txData.GasFeeCap = &gasFeeCapInt + } + + if tx.GasTipCap() != nil { + gasTipCapInt, err := SafeNewIntFromBigInt(tx.GasTipCap()) + if err != nil { + return nil, err + } + txData.GasTipCap = &gasTipCapInt + } + + if tx.AccessList() != nil { + al := tx.AccessList() + txData.Accesses = NewAccessList(&al) + } + + txData.SetSignatureValues(tx.ChainId(), v, r, s) + return txData, nil +} + +// TxType returns the tx type +func (tx *DynamicFeeTx) TxType() uint8 { + return ethtypes.DynamicFeeTxType +} + +// Copy returns an instance with the same field values +func (tx *DynamicFeeTx) Copy() TxData { + return &DynamicFeeTx{ + ChainID: tx.ChainID, + Nonce: tx.Nonce, + GasTipCap: tx.GasTipCap, + GasFeeCap: tx.GasFeeCap, + GasLimit: tx.GasLimit, + To: tx.To, + Amount: tx.Amount, + Data: common.CopyBytes(tx.Data), + Accesses: tx.Accesses, + V: common.CopyBytes(tx.V), + R: common.CopyBytes(tx.R), + S: common.CopyBytes(tx.S), + } +} + +// GetChainID returns the chain id field from the DynamicFeeTx +func (tx *DynamicFeeTx) GetChainID() *big.Int { + if tx.ChainID == nil { + return nil + } + + return tx.ChainID.BigInt() +} + +// GetAccessList returns the AccessList field. +func (tx *DynamicFeeTx) GetAccessList() ethtypes.AccessList { + if tx.Accesses == nil { + return nil + } + return *tx.Accesses.ToEthAccessList() +} + +// GetData returns the a copy of the input data bytes. +func (tx *DynamicFeeTx) GetData() []byte { + return common.CopyBytes(tx.Data) +} + +// GetGas returns the gas limit. +func (tx *DynamicFeeTx) GetGas() uint64 { + return tx.GasLimit +} + +// GetGasPrice returns the gas fee cap field. +func (tx *DynamicFeeTx) GetGasPrice() *big.Int { + return tx.GetGasFeeCap() +} + +// GetGasTipCap returns the gas tip cap field. +func (tx *DynamicFeeTx) GetGasTipCap() *big.Int { + if tx.GasTipCap == nil { + return nil + } + return tx.GasTipCap.BigInt() +} + +// GetGasFeeCap returns the gas fee cap field. +func (tx *DynamicFeeTx) GetGasFeeCap() *big.Int { + if tx.GasFeeCap == nil { + return nil + } + return tx.GasFeeCap.BigInt() +} + +// GetValue returns the tx amount. +func (tx *DynamicFeeTx) GetValue() *big.Int { + if tx.Amount == nil { + return nil + } + + return tx.Amount.BigInt() +} + +// GetNonce returns the account sequence for the transaction. +func (tx *DynamicFeeTx) GetNonce() uint64 { return tx.Nonce } + +// GetTo returns the pointer to the recipient address. +func (tx *DynamicFeeTx) GetTo() *common.Address { + if tx.To == "" { + return nil + } + to := common.HexToAddress(tx.To) + return &to +} + +// AsEthereumData returns an DynamicFeeTx transaction tx from the proto-formatted +// TxData defined on the Cosmos EVM. +func (tx *DynamicFeeTx) AsEthereumData() ethtypes.TxData { + v, r, s := tx.GetRawSignatureValues() + return ðtypes.DynamicFeeTx{ + ChainID: tx.GetChainID(), + Nonce: tx.GetNonce(), + GasTipCap: tx.GetGasTipCap(), + GasFeeCap: tx.GetGasFeeCap(), + Gas: tx.GetGas(), + To: tx.GetTo(), + Value: tx.GetValue(), + Data: tx.GetData(), + AccessList: tx.GetAccessList(), + V: v, + R: r, + S: s, + } +} + +// GetRawSignatureValues returns the V, R, S signature values of the transaction. +// The return values should not be modified by the caller. +func (tx *DynamicFeeTx) GetRawSignatureValues() (v, r, s *big.Int) { + return RawSignatureValues(tx.V, tx.R, tx.S) +} + +// SetSignatureValues sets the signature values to the transaction. +func (tx *DynamicFeeTx) SetSignatureValues(chainID, v, r, s *big.Int) { + if v != nil { + tx.V = v.Bytes() + } + if r != nil { + tx.R = r.Bytes() + } + if s != nil { + tx.S = s.Bytes() + } + if chainID != nil { + chainIDInt := sdkmath.NewIntFromBigInt(chainID) + tx.ChainID = &chainIDInt + } +} + +// Validate performs a stateless validation of the tx fields. +func (tx DynamicFeeTx) Validate() error { + if tx.GasTipCap == nil { + return errorsmod.Wrap(ErrInvalidGasCap, "gas tip cap cannot nil") + } + + if tx.GasFeeCap == nil { + return errorsmod.Wrap(ErrInvalidGasCap, "gas fee cap cannot nil") + } + + if tx.GasTipCap.IsNegative() { + return errorsmod.Wrapf(ErrInvalidGasCap, "gas tip cap cannot be negative %s", tx.GasTipCap) + } + + if tx.GasFeeCap.IsNegative() { + return errorsmod.Wrapf(ErrInvalidGasCap, "gas fee cap cannot be negative %s", tx.GasFeeCap) + } + + if !IsValidInt256(tx.GetGasTipCap()) { + return errorsmod.Wrap(ErrInvalidGasCap, "out of bound") + } + + if !IsValidInt256(tx.GetGasFeeCap()) { + return errorsmod.Wrap(ErrInvalidGasCap, "out of bound") + } + + if tx.GasFeeCap.LT(*tx.GasTipCap) { + return errorsmod.Wrapf( + ErrInvalidGasCap, "max priority fee per gas higher than max fee per gas (%s > %s)", + tx.GasTipCap, tx.GasFeeCap, + ) + } + + if !IsValidInt256(tx.Fee()) { + return errorsmod.Wrap(ErrInvalidGasFee, "out of bound") + } + + amount := tx.GetValue() + // Amount can be 0 + if amount != nil && amount.Sign() == -1 { + return errorsmod.Wrapf(ErrInvalidAmount, "amount cannot be negative %s", amount) + } + if !IsValidInt256(amount) { + return errorsmod.Wrap(ErrInvalidAmount, "out of bound") + } + + if tx.To != "" { + if err := ValidateAddress(tx.To); err != nil { + return errorsmod.Wrap(err, "invalid to address") + } + } + + if tx.GetChainID() == nil { + return errorsmod.Wrap( + errortypes.ErrInvalidChainID, + "chain ID must be present on DynamicFee txs", + ) + } + + return nil +} + +// Fee returns gasprice * gaslimit. +func (tx DynamicFeeTx) Fee() *big.Int { + return fee(tx.GetGasFeeCap(), tx.GasLimit) +} + +// Cost returns amount + gasprice * gaslimit. +func (tx DynamicFeeTx) Cost() *big.Int { + return cost(tx.Fee(), tx.GetValue()) +} + +// EffectiveGasPrice returns the effective gas price +func (tx *DynamicFeeTx) EffectiveGasPrice(baseFee *big.Int) *big.Int { + return EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()) +} + +// EffectiveFee returns effective_gasprice * gaslimit. +func (tx DynamicFeeTx) EffectiveFee(baseFee *big.Int) *big.Int { + return fee(tx.EffectiveGasPrice(baseFee), tx.GasLimit) +} + +// EffectiveCost returns amount + effective_gasprice * gaslimit. +func (tx DynamicFeeTx) EffectiveCost(baseFee *big.Int) *big.Int { + return cost(tx.EffectiveFee(baseFee), tx.GetValue()) +} diff --git a/rpc/types/legacy/errors.go b/rpc/types/legacy/errors.go new file mode 100644 index 000000000..783c7716a --- /dev/null +++ b/rpc/types/legacy/errors.go @@ -0,0 +1,38 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + errorsmod "cosmossdk.io/errors" +) + +const ( + // ModuleName is the name of the legacy types module (for error registration) + + codeErrInvalidAmount = uint32(iota) + 2 + codeErrInvalidGasPrice + codeErrInvalidGasFee + codeErrInvalidGasCap + codeErrGasOverflow + codeErrInvalidGasLimit +) + +var ( + // ErrInvalidAmount returns an error if a tx contains an invalid amount. + ErrInvalidAmount = errorsmod.Register(ModuleName, codeErrInvalidAmount, "invalid transaction amount") + + // ErrInvalidGasPrice returns an error if an invalid gas price is provided to the tx. + ErrInvalidGasPrice = errorsmod.Register(ModuleName, codeErrInvalidGasPrice, "invalid gas price") + + // ErrInvalidGasFee returns an error if the tx gas fee is out of bound. + ErrInvalidGasFee = errorsmod.Register(ModuleName, codeErrInvalidGasFee, "invalid gas fee") + + // ErrInvalidGasCap returns an error if a the gas cap value is negative or invalid + ErrInvalidGasCap = errorsmod.Register(ModuleName, codeErrInvalidGasCap, "invalid gas cap") + + // ErrGasOverflow returns an error if gas computation overflow/underflow + ErrGasOverflow = errorsmod.Register(ModuleName, codeErrGasOverflow, "gas computation overflow/underflow") + + // ErrInvalidGasLimit returns an error if gas limit value is invalid + ErrInvalidGasLimit = errorsmod.Register(ModuleName, codeErrInvalidGasLimit, "invalid gas limit") +) diff --git a/rpc/types/legacy/evm.pb.go b/rpc/types/legacy/evm.pb.go new file mode 100644 index 000000000..2cd565e59 --- /dev/null +++ b/rpc/types/legacy/evm.pb.go @@ -0,0 +1,4585 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ethermint/evm/v1/evm.proto + +package types + +import ( + cosmossdk_io_math "cosmossdk.io/math" + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// AccessType defines the types of permissions for the operations +type AccessType int32 + +const ( + // ACCESS_TYPE_PERMISSIONLESS does not restrict the operation to anyone + AccessTypePermissionless AccessType = 0 + // ACCESS_TYPE_RESTRICTED restrict the operation to anyone + AccessTypeRestricted AccessType = 1 + // ACCESS_TYPE_PERMISSIONED only allows the operation for specific addresses + AccessTypePermissioned AccessType = 2 +) + +var AccessType_name = map[int32]string{ + 0: "ACCESS_TYPE_PERMISSIONLESS", + 1: "ACCESS_TYPE_RESTRICTED", + 2: "ACCESS_TYPE_PERMISSIONED", +} + +var AccessType_value = map[string]int32{ + "ACCESS_TYPE_PERMISSIONLESS": 0, + "ACCESS_TYPE_RESTRICTED": 1, + "ACCESS_TYPE_PERMISSIONED": 2, +} + +func (x AccessType) String() string { + return proto.EnumName(AccessType_name, int32(x)) +} + +func (AccessType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{0} +} + +// Params defines the EVM module parameters +type Params struct { + // evm_denom represents the token denomination used to run the EVM state + // transitions. + EvmDenom string `protobuf:"bytes,1,opt,name=evm_denom,json=evmDenom,proto3" json:"evm_denom,omitempty" yaml:"evm_denom"` + // extra_eips defines the additional EIPs for the vm.Config + ExtraEIPs []string `protobuf:"bytes,4,rep,name=extra_eips,json=extraEips,proto3" json:"extra_eips,omitempty" yaml:"extra_eips"` + // chain_config defines the EVM chain configuration parameters + ChainConfig ChainConfig `protobuf:"bytes,5,opt,name=chain_config,json=chainConfig,proto3" json:"chain_config" yaml:"chain_config"` + // allow_unprotected_txs defines if replay-protected (i.e non EIP155 + // signed) transactions can be executed on the state machine. + AllowUnprotectedTxs bool `protobuf:"varint,6,opt,name=allow_unprotected_txs,json=allowUnprotectedTxs,proto3" json:"allow_unprotected_txs,omitempty"` + // evm_channels is the list of channel identifiers from EVM compatible chains + EVMChannels []string `protobuf:"bytes,8,rep,name=evm_channels,json=evmChannels,proto3" json:"evm_channels,omitempty"` + // access_control defines the permission policy of the EVM + AccessControl AccessControl `protobuf:"bytes,9,opt,name=access_control,json=accessControl,proto3" json:"access_control"` + // active_static_precompiles defines the slice of hex addresses of the precompiled + // contracts that are active + ActiveStaticPrecompiles []string `protobuf:"bytes,10,rep,name=active_static_precompiles,json=activeStaticPrecompiles,proto3" json:"active_static_precompiles,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetEvmDenom() string { + if m != nil { + return m.EvmDenom + } + return "" +} + +func (m *Params) GetExtraEIPs() []string { + if m != nil { + return m.ExtraEIPs + } + return nil +} + +func (m *Params) GetChainConfig() ChainConfig { + if m != nil { + return m.ChainConfig + } + return ChainConfig{} +} + +func (m *Params) GetAllowUnprotectedTxs() bool { + if m != nil { + return m.AllowUnprotectedTxs + } + return false +} + +func (m *Params) GetEVMChannels() []string { + if m != nil { + return m.EVMChannels + } + return nil +} + +func (m *Params) GetAccessControl() AccessControl { + if m != nil { + return m.AccessControl + } + return AccessControl{} +} + +func (m *Params) GetActiveStaticPrecompiles() []string { + if m != nil { + return m.ActiveStaticPrecompiles + } + return nil +} + +// AccessControl defines the permission policy of the EVM +// for creating and calling contracts +type AccessControl struct { + // create defines the permission policy for creating contracts + Create AccessControlType `protobuf:"bytes,1,opt,name=create,proto3" json:"create"` + // call defines the permission policy for calling contracts + Call AccessControlType `protobuf:"bytes,2,opt,name=call,proto3" json:"call"` +} + +func (m *AccessControl) Reset() { *m = AccessControl{} } +func (m *AccessControl) String() string { return proto.CompactTextString(m) } +func (*AccessControl) ProtoMessage() {} +func (*AccessControl) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{1} +} +func (m *AccessControl) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessControl) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessControl.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AccessControl) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessControl.Merge(m, src) +} +func (m *AccessControl) XXX_Size() int { + return m.Size() +} +func (m *AccessControl) XXX_DiscardUnknown() { + xxx_messageInfo_AccessControl.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessControl proto.InternalMessageInfo + +func (m *AccessControl) GetCreate() AccessControlType { + if m != nil { + return m.Create + } + return AccessControlType{} +} + +func (m *AccessControl) GetCall() AccessControlType { + if m != nil { + return m.Call + } + return AccessControlType{} +} + +// AccessControlType defines the permission type for policies +type AccessControlType struct { + // access_type defines which type of permission is required for the operation + AccessType AccessType `protobuf:"varint,1,opt,name=access_type,json=accessType,proto3,enum=ethermint.evm.v1.AccessType" json:"access_type,omitempty" yaml:"access_type"` + // access_control_list defines defines different things depending on the AccessType: + // - ACCESS_TYPE_PERMISSIONLESS: list of addresses that are blocked from performing the operation + // - ACCESS_TYPE_RESTRICTED: ignored + // - ACCESS_TYPE_PERMISSIONED: list of addresses that are allowed to perform the operation + AccessControlList []string `protobuf:"bytes,2,rep,name=access_control_list,json=accessControlList,proto3" json:"access_control_list,omitempty" yaml:"access_control_list"` +} + +func (m *AccessControlType) Reset() { *m = AccessControlType{} } +func (m *AccessControlType) String() string { return proto.CompactTextString(m) } +func (*AccessControlType) ProtoMessage() {} +func (*AccessControlType) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{2} +} +func (m *AccessControlType) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessControlType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessControlType.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AccessControlType) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessControlType.Merge(m, src) +} +func (m *AccessControlType) XXX_Size() int { + return m.Size() +} +func (m *AccessControlType) XXX_DiscardUnknown() { + xxx_messageInfo_AccessControlType.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessControlType proto.InternalMessageInfo + +func (m *AccessControlType) GetAccessType() AccessType { + if m != nil { + return m.AccessType + } + return AccessTypePermissionless +} + +func (m *AccessControlType) GetAccessControlList() []string { + if m != nil { + return m.AccessControlList + } + return nil +} + +// ChainConfig defines the Ethereum ChainConfig parameters using *sdk.Int values +// instead of *big.Int. +type ChainConfig struct { + // homestead_block switch (nil no fork, 0 = already homestead) + HomesteadBlock *cosmossdk_io_math.Int `protobuf:"bytes,1,opt,name=homestead_block,json=homesteadBlock,proto3,customtype=cosmossdk.io/math.Int" json:"homestead_block,omitempty" yaml:"homestead_block"` + // dao_fork_block corresponds to TheDAO hard-fork switch block (nil no fork) + DAOForkBlock *cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=dao_fork_block,json=daoForkBlock,proto3,customtype=cosmossdk.io/math.Int" json:"dao_fork_block,omitempty" yaml:"dao_fork_block"` + // dao_fork_support defines whether the nodes supports or opposes the DAO hard-fork + DAOForkSupport bool `protobuf:"varint,3,opt,name=dao_fork_support,json=daoForkSupport,proto3" json:"dao_fork_support,omitempty" yaml:"dao_fork_support"` + // eip150_block: EIP150 implements the Gas price changes + // (https://github.com/ethereum/EIPs/issues/150) EIP150 HF block (nil no fork) + EIP150Block *cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=eip150_block,json=eip150Block,proto3,customtype=cosmossdk.io/math.Int" json:"eip150_block,omitempty" yaml:"eip150_block"` + // eip150_hash: EIP150 HF hash (needed for header only clients as only gas pricing changed) + EIP150Hash string `protobuf:"bytes,5,opt,name=eip150_hash,json=eip150Hash,proto3" json:"eip150_hash,omitempty" yaml:"byzantium_block"` + // eip155_block: EIP155Block HF block + EIP155Block *cosmossdk_io_math.Int `protobuf:"bytes,6,opt,name=eip155_block,json=eip155Block,proto3,customtype=cosmossdk.io/math.Int" json:"eip155_block,omitempty" yaml:"eip155_block"` + // eip158_block: EIP158 HF block + EIP158Block *cosmossdk_io_math.Int `protobuf:"bytes,7,opt,name=eip158_block,json=eip158Block,proto3,customtype=cosmossdk.io/math.Int" json:"eip158_block,omitempty" yaml:"eip158_block"` + // byzantium_block: Byzantium switch block (nil no fork, 0 = already on byzantium) + ByzantiumBlock *cosmossdk_io_math.Int `protobuf:"bytes,8,opt,name=byzantium_block,json=byzantiumBlock,proto3,customtype=cosmossdk.io/math.Int" json:"byzantium_block,omitempty" yaml:"byzantium_block"` + // constantinople_block: Constantinople switch block (nil no fork, 0 = already activated) + ConstantinopleBlock *cosmossdk_io_math.Int `protobuf:"bytes,9,opt,name=constantinople_block,json=constantinopleBlock,proto3,customtype=cosmossdk.io/math.Int" json:"constantinople_block,omitempty" yaml:"constantinople_block"` + // petersburg_block: Petersburg switch block (nil same as Constantinople) + PetersburgBlock *cosmossdk_io_math.Int `protobuf:"bytes,10,opt,name=petersburg_block,json=petersburgBlock,proto3,customtype=cosmossdk.io/math.Int" json:"petersburg_block,omitempty" yaml:"petersburg_block"` + // istanbul_block: Istanbul switch block (nil no fork, 0 = already on istanbul) + IstanbulBlock *cosmossdk_io_math.Int `protobuf:"bytes,11,opt,name=istanbul_block,json=istanbulBlock,proto3,customtype=cosmossdk.io/math.Int" json:"istanbul_block,omitempty" yaml:"istanbul_block"` + // muir_glacier_block: Eip-2384 (bomb delay) switch block (nil no fork, 0 = already activated) + MuirGlacierBlock *cosmossdk_io_math.Int `protobuf:"bytes,12,opt,name=muir_glacier_block,json=muirGlacierBlock,proto3,customtype=cosmossdk.io/math.Int" json:"muir_glacier_block,omitempty" yaml:"muir_glacier_block"` + // berlin_block: Berlin switch block (nil = no fork, 0 = already on berlin) + BerlinBlock *cosmossdk_io_math.Int `protobuf:"bytes,13,opt,name=berlin_block,json=berlinBlock,proto3,customtype=cosmossdk.io/math.Int" json:"berlin_block,omitempty" yaml:"berlin_block"` + // london_block: London switch block (nil = no fork, 0 = already on london) + LondonBlock *cosmossdk_io_math.Int `protobuf:"bytes,17,opt,name=london_block,json=londonBlock,proto3,customtype=cosmossdk.io/math.Int" json:"london_block,omitempty" yaml:"london_block"` + // arrow_glacier_block: Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) + ArrowGlacierBlock *cosmossdk_io_math.Int `protobuf:"bytes,18,opt,name=arrow_glacier_block,json=arrowGlacierBlock,proto3,customtype=cosmossdk.io/math.Int" json:"arrow_glacier_block,omitempty" yaml:"arrow_glacier_block"` + // gray_glacier_block: EIP-5133 (bomb delay) switch block (nil = no fork, 0 = already activated) + GrayGlacierBlock *cosmossdk_io_math.Int `protobuf:"bytes,20,opt,name=gray_glacier_block,json=grayGlacierBlock,proto3,customtype=cosmossdk.io/math.Int" json:"gray_glacier_block,omitempty" yaml:"gray_glacier_block"` + // merge_netsplit_block: Virtual fork after The Merge to use as a network splitter + MergeNetsplitBlock *cosmossdk_io_math.Int `protobuf:"bytes,21,opt,name=merge_netsplit_block,json=mergeNetsplitBlock,proto3,customtype=cosmossdk.io/math.Int" json:"merge_netsplit_block,omitempty" yaml:"merge_netsplit_block"` + // shanghai_block switch block (nil = no fork, 0 = already on shanghai) + ShanghaiBlock *cosmossdk_io_math.Int `protobuf:"bytes,22,opt,name=shanghai_block,json=shanghaiBlock,proto3,customtype=cosmossdk.io/math.Int" json:"shanghai_block,omitempty" yaml:"shanghai_block"` + // cancun_block switch block (nil = no fork, 0 = already on cancun) + CancunBlock *cosmossdk_io_math.Int `protobuf:"bytes,23,opt,name=cancun_block,json=cancunBlock,proto3,customtype=cosmossdk.io/math.Int" json:"cancun_block,omitempty" yaml:"cancun_block"` +} + +func (m *ChainConfig) Reset() { *m = ChainConfig{} } +func (m *ChainConfig) String() string { return proto.CompactTextString(m) } +func (*ChainConfig) ProtoMessage() {} +func (*ChainConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{3} +} +func (m *ChainConfig) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ChainConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ChainConfig.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ChainConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChainConfig.Merge(m, src) +} +func (m *ChainConfig) XXX_Size() int { + return m.Size() +} +func (m *ChainConfig) XXX_DiscardUnknown() { + xxx_messageInfo_ChainConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_ChainConfig proto.InternalMessageInfo + +func (m *ChainConfig) GetDAOForkSupport() bool { + if m != nil { + return m.DAOForkSupport + } + return false +} + +func (m *ChainConfig) GetEIP150Hash() string { + if m != nil { + return m.EIP150Hash + } + return "" +} + +// State represents a single Storage key value pair item. +type State struct { + // key is the stored key + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // value is the stored value for the given key + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *State) Reset() { *m = State{} } +func (m *State) String() string { return proto.CompactTextString(m) } +func (*State) ProtoMessage() {} +func (*State) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{4} +} +func (m *State) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *State) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_State.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *State) XXX_Merge(src proto.Message) { + xxx_messageInfo_State.Merge(m, src) +} +func (m *State) XXX_Size() int { + return m.Size() +} +func (m *State) XXX_DiscardUnknown() { + xxx_messageInfo_State.DiscardUnknown(m) +} + +var xxx_messageInfo_State proto.InternalMessageInfo + +func (m *State) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *State) GetValue() string { + if m != nil { + return m.Value + } + return "" +} + +// TransactionLogs define the logs generated from a transaction execution +// with a given hash. It it used for import/export data as transactions are not +// persisted on blockchain state after an upgrade. +type TransactionLogs struct { + // hash of the transaction + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + // logs is an array of Logs for the given transaction hash + Logs []*Log `protobuf:"bytes,2,rep,name=logs,proto3" json:"logs,omitempty"` +} + +func (m *TransactionLogs) Reset() { *m = TransactionLogs{} } +func (m *TransactionLogs) String() string { return proto.CompactTextString(m) } +func (*TransactionLogs) ProtoMessage() {} +func (*TransactionLogs) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{5} +} +func (m *TransactionLogs) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TransactionLogs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TransactionLogs.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TransactionLogs) XXX_Merge(src proto.Message) { + xxx_messageInfo_TransactionLogs.Merge(m, src) +} +func (m *TransactionLogs) XXX_Size() int { + return m.Size() +} +func (m *TransactionLogs) XXX_DiscardUnknown() { + xxx_messageInfo_TransactionLogs.DiscardUnknown(m) +} + +var xxx_messageInfo_TransactionLogs proto.InternalMessageInfo + +func (m *TransactionLogs) GetHash() string { + if m != nil { + return m.Hash + } + return "" +} + +func (m *TransactionLogs) GetLogs() []*Log { + if m != nil { + return m.Logs + } + return nil +} + +// Log represents an protobuf compatible Ethereum Log that defines a contract +// log event. These events are generated by the LOG opcode and stored/indexed by +// the node. +// +// NOTE: address, topics and data are consensus fields. The rest of the fields +// are derived, i.e. filled in by the nodes, but not secured by consensus. +type Log struct { + // address of the contract that generated the event + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // topics is a list of topics provided by the contract. + Topics []string `protobuf:"bytes,2,rep,name=topics,proto3" json:"topics,omitempty"` + // data which is supplied by the contract, usually ABI-encoded + Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + // block_number of the block in which the transaction was included + BlockNumber uint64 `protobuf:"varint,4,opt,name=block_number,json=blockNumber,proto3" json:"blockNumber"` + // tx_hash is the transaction hash + TxHash string `protobuf:"bytes,5,opt,name=tx_hash,json=txHash,proto3" json:"transactionHash"` + // tx_index of the transaction in the block + TxIndex uint64 `protobuf:"varint,6,opt,name=tx_index,json=txIndex,proto3" json:"transactionIndex"` + // block_hash of the block in which the transaction was included + BlockHash string `protobuf:"bytes,7,opt,name=block_hash,json=blockHash,proto3" json:"blockHash"` + // index of the log in the block + Index uint64 `protobuf:"varint,8,opt,name=index,proto3" json:"logIndex"` + // removed is true if this log was reverted due to a chain + // reorganisation. You must pay attention to this field if you receive logs + // through a filter query. + Removed bool `protobuf:"varint,9,opt,name=removed,proto3" json:"removed,omitempty"` +} + +func (m *Log) Reset() { *m = Log{} } +func (m *Log) String() string { return proto.CompactTextString(m) } +func (*Log) ProtoMessage() {} +func (*Log) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{6} +} +func (m *Log) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Log) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Log.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Log) XXX_Merge(src proto.Message) { + xxx_messageInfo_Log.Merge(m, src) +} +func (m *Log) XXX_Size() int { + return m.Size() +} +func (m *Log) XXX_DiscardUnknown() { + xxx_messageInfo_Log.DiscardUnknown(m) +} + +var xxx_messageInfo_Log proto.InternalMessageInfo + +func (m *Log) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *Log) GetTopics() []string { + if m != nil { + return m.Topics + } + return nil +} + +func (m *Log) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +func (m *Log) GetBlockNumber() uint64 { + if m != nil { + return m.BlockNumber + } + return 0 +} + +func (m *Log) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +func (m *Log) GetTxIndex() uint64 { + if m != nil { + return m.TxIndex + } + return 0 +} + +func (m *Log) GetBlockHash() string { + if m != nil { + return m.BlockHash + } + return "" +} + +func (m *Log) GetIndex() uint64 { + if m != nil { + return m.Index + } + return 0 +} + +func (m *Log) GetRemoved() bool { + if m != nil { + return m.Removed + } + return false +} + +// TxResult stores results of Tx execution. +type TxResult struct { + // contract_address contains the ethereum address of the created contract (if + // any). If the state transition is an evm.Call, the contract address will be + // empty. + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty" yaml:"contract_address"` + // bloom represents the bloom filter bytes + Bloom []byte `protobuf:"bytes,2,opt,name=bloom,proto3" json:"bloom,omitempty"` + // tx_logs contains the transaction hash and the proto-compatible ethereum + // logs. + TxLogs TransactionLogs `protobuf:"bytes,3,opt,name=tx_logs,json=txLogs,proto3" json:"tx_logs" yaml:"tx_logs"` + // ret defines the bytes from the execution. + Ret []byte `protobuf:"bytes,4,opt,name=ret,proto3" json:"ret,omitempty"` + // reverted flag is set to true when the call has been reverted + Reverted bool `protobuf:"varint,5,opt,name=reverted,proto3" json:"reverted,omitempty"` + // gas_used notes the amount of gas consumed while execution + GasUsed uint64 `protobuf:"varint,6,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` +} + +func (m *TxResult) Reset() { *m = TxResult{} } +func (m *TxResult) String() string { return proto.CompactTextString(m) } +func (*TxResult) ProtoMessage() {} +func (*TxResult) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{7} +} +func (m *TxResult) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TxResult) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TxResult.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TxResult) XXX_Merge(src proto.Message) { + xxx_messageInfo_TxResult.Merge(m, src) +} +func (m *TxResult) XXX_Size() int { + return m.Size() +} +func (m *TxResult) XXX_DiscardUnknown() { + xxx_messageInfo_TxResult.DiscardUnknown(m) +} + +var xxx_messageInfo_TxResult proto.InternalMessageInfo + +// AccessTuple is the element type of an access list. +type AccessTuple struct { + // address is a hex formatted ethereum address + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // storage_keys are hex formatted hashes of the storage keys + StorageKeys []string `protobuf:"bytes,2,rep,name=storage_keys,json=storageKeys,proto3" json:"storageKeys"` +} + +func (m *AccessTuple) Reset() { *m = AccessTuple{} } +func (m *AccessTuple) String() string { return proto.CompactTextString(m) } +func (*AccessTuple) ProtoMessage() {} +func (*AccessTuple) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{8} +} +func (m *AccessTuple) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessTuple) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessTuple.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AccessTuple) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessTuple.Merge(m, src) +} +func (m *AccessTuple) XXX_Size() int { + return m.Size() +} +func (m *AccessTuple) XXX_DiscardUnknown() { + xxx_messageInfo_AccessTuple.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessTuple proto.InternalMessageInfo + +// TraceConfig holds extra parameters to trace functions. +type TraceConfig struct { + // tracer is a custom javascript tracer + Tracer string `protobuf:"bytes,1,opt,name=tracer,proto3" json:"tracer,omitempty"` + // timeout overrides the default timeout of 5 seconds for JavaScript-based tracing + // calls + Timeout string `protobuf:"bytes,2,opt,name=timeout,proto3" json:"timeout,omitempty"` + // reexec defines the number of blocks the tracer is willing to go back + Reexec uint64 `protobuf:"varint,3,opt,name=reexec,proto3" json:"reexec,omitempty"` + // disable_stack switches stack capture + DisableStack bool `protobuf:"varint,5,opt,name=disable_stack,json=disableStack,proto3" json:"disableStack"` + // disable_storage switches storage capture + DisableStorage bool `protobuf:"varint,6,opt,name=disable_storage,json=disableStorage,proto3" json:"disableStorage"` + // debug can be used to print output during capture end + Debug bool `protobuf:"varint,8,opt,name=debug,proto3" json:"debug,omitempty"` + // limit defines the maximum length of output, but zero means unlimited + Limit int32 `protobuf:"varint,9,opt,name=limit,proto3" json:"limit,omitempty"` + // overrides can be used to execute a trace using future fork rules + Overrides *ChainConfig `protobuf:"bytes,10,opt,name=overrides,proto3" json:"overrides,omitempty"` + // enable_memory switches memory capture + EnableMemory bool `protobuf:"varint,11,opt,name=enable_memory,json=enableMemory,proto3" json:"enableMemory"` + // enable_return_data switches the capture of return data + EnableReturnData bool `protobuf:"varint,12,opt,name=enable_return_data,json=enableReturnData,proto3" json:"enableReturnData"` + // tracer_json_config configures the tracer using a JSON string + TracerJsonConfig string `protobuf:"bytes,13,opt,name=tracer_json_config,json=tracerJsonConfig,proto3" json:"tracerConfig"` +} + +func (m *TraceConfig) Reset() { *m = TraceConfig{} } +func (m *TraceConfig) String() string { return proto.CompactTextString(m) } +func (*TraceConfig) ProtoMessage() {} +func (*TraceConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_d21ecc92c8c8583e, []int{9} +} +func (m *TraceConfig) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TraceConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TraceConfig.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TraceConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_TraceConfig.Merge(m, src) +} +func (m *TraceConfig) XXX_Size() int { + return m.Size() +} +func (m *TraceConfig) XXX_DiscardUnknown() { + xxx_messageInfo_TraceConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_TraceConfig proto.InternalMessageInfo + +func (m *TraceConfig) GetTracer() string { + if m != nil { + return m.Tracer + } + return "" +} + +func (m *TraceConfig) GetTimeout() string { + if m != nil { + return m.Timeout + } + return "" +} + +func (m *TraceConfig) GetReexec() uint64 { + if m != nil { + return m.Reexec + } + return 0 +} + +func (m *TraceConfig) GetDisableStack() bool { + if m != nil { + return m.DisableStack + } + return false +} + +func (m *TraceConfig) GetDisableStorage() bool { + if m != nil { + return m.DisableStorage + } + return false +} + +func (m *TraceConfig) GetDebug() bool { + if m != nil { + return m.Debug + } + return false +} + +func (m *TraceConfig) GetLimit() int32 { + if m != nil { + return m.Limit + } + return 0 +} + +func (m *TraceConfig) GetOverrides() *ChainConfig { + if m != nil { + return m.Overrides + } + return nil +} + +func (m *TraceConfig) GetEnableMemory() bool { + if m != nil { + return m.EnableMemory + } + return false +} + +func (m *TraceConfig) GetEnableReturnData() bool { + if m != nil { + return m.EnableReturnData + } + return false +} + +func (m *TraceConfig) GetTracerJsonConfig() string { + if m != nil { + return m.TracerJsonConfig + } + return "" +} + +//func init() { +// proto.RegisterEnum("ethermint.evm.v1.AccessType", AccessType_name, AccessType_value) +// proto.RegisterType((*Params)(nil), "ethermint.evm.v1.Params") +// proto.RegisterType((*AccessControl)(nil), "ethermint.evm.v1.AccessControl") +// proto.RegisterType((*AccessControlType)(nil), "ethermint.evm.v1.AccessControlType") +// proto.RegisterType((*ChainConfig)(nil), "ethermint.evm.v1.ChainConfig") +// proto.RegisterType((*State)(nil), "ethermint.evm.v1.State") +// proto.RegisterType((*TransactionLogs)(nil), "ethermint.evm.v1.TransactionLogs") +// proto.RegisterType((*Log)(nil), "ethermint.evm.v1.Log") +// proto.RegisterType((*TxResult)(nil), "ethermint.evm.v1.TxResult") +// proto.RegisterType((*AccessTuple)(nil), "ethermint.evm.v1.AccessTuple") +// proto.RegisterType((*TraceConfig)(nil), "ethermint.evm.v1.TraceConfig") +//} + +//func init() { proto.RegisterFile("ethermint/evm/v1/evm.proto", fileDescriptor_d21ecc92c8c8583e) } + +var fileDescriptor_d21ecc92c8c8583e = []byte{ + // 1927 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x58, 0x4b, 0x6f, 0x23, 0xc7, + 0x11, 0x16, 0xa5, 0x91, 0x34, 0x6c, 0x52, 0xe4, 0xa8, 0x45, 0xed, 0x72, 0xb9, 0x8e, 0x46, 0x99, + 0x04, 0xc1, 0x66, 0xe1, 0x48, 0x2b, 0xad, 0x95, 0x08, 0xeb, 0xbc, 0x44, 0x89, 0x4e, 0xa4, 0x68, + 0xd7, 0x42, 0x53, 0x8e, 0xe1, 0x20, 0xc1, 0xa0, 0x39, 0xd3, 0x26, 0xc7, 0x9a, 0x99, 0x26, 0xa6, + 0x9b, 0x5c, 0x32, 0xbf, 0xc0, 0xd8, 0xd3, 0xe6, 0x07, 0x2c, 0x60, 0x20, 0x97, 0x1c, 0xfd, 0x13, + 0x72, 0x34, 0x72, 0xf2, 0x31, 0x08, 0x90, 0x41, 0xc0, 0x3d, 0x18, 0xd0, 0x51, 0xf7, 0x00, 0x41, + 0x3f, 0xf8, 0x94, 0x2c, 0x2b, 0x17, 0xaa, 0xab, 0xba, 0xea, 0xfb, 0xaa, 0xaa, 0x6b, 0xfa, 0x21, + 0x50, 0x21, 0xbc, 0x45, 0x92, 0x28, 0x88, 0xf9, 0x36, 0xe9, 0x46, 0xdb, 0xdd, 0x1d, 0xf1, 0x67, + 0xab, 0x9d, 0x50, 0x4e, 0xa1, 0x35, 0x9a, 0xdb, 0x12, 0xca, 0xee, 0x4e, 0x65, 0x15, 0x47, 0x41, + 0x4c, 0xb7, 0xe5, 0xaf, 0x32, 0xaa, 0x94, 0x9a, 0xb4, 0x49, 0xe5, 0x70, 0x5b, 0x8c, 0x94, 0xd6, + 0x79, 0x6d, 0x80, 0xa5, 0x33, 0x9c, 0xe0, 0x88, 0xc1, 0x1d, 0x90, 0x25, 0xdd, 0xc8, 0xf5, 0x49, + 0x4c, 0xa3, 0x72, 0x66, 0x33, 0xf3, 0x28, 0x5b, 0x2d, 0x5d, 0xa5, 0xb6, 0xd5, 0xc7, 0x51, 0xf8, + 0xcc, 0x19, 0x4d, 0x39, 0xc8, 0x24, 0xdd, 0xe8, 0x48, 0x0c, 0xe1, 0x01, 0x00, 0xa4, 0xc7, 0x13, + 0xec, 0x92, 0xa0, 0xcd, 0xca, 0xc6, 0xe6, 0xc2, 0xa3, 0x6c, 0xd5, 0x19, 0xa4, 0x76, 0xb6, 0x26, + 0xb4, 0xb5, 0xe3, 0x33, 0x76, 0x95, 0xda, 0xab, 0x1a, 0x60, 0x64, 0xe8, 0xa0, 0xac, 0x14, 0x6a, + 0x41, 0x9b, 0xc1, 0x06, 0xc8, 0x7b, 0x2d, 0x1c, 0xc4, 0xae, 0x47, 0xe3, 0x4f, 0x83, 0x66, 0x79, + 0x71, 0x33, 0xf3, 0x28, 0xb7, 0xfb, 0xbd, 0xad, 0xd9, 0x94, 0xb6, 0x0e, 0x85, 0xd5, 0xa1, 0x34, + 0xaa, 0x6e, 0x7e, 0x95, 0xda, 0x73, 0x57, 0xa9, 0xbd, 0xa6, 0xa0, 0x27, 0x01, 0x9c, 0xbf, 0x7d, + 0xf3, 0xe5, 0xe3, 0x0c, 0xca, 0x79, 0x63, 0x73, 0xb8, 0x0b, 0xd6, 0x71, 0x18, 0xd2, 0x97, 0x6e, + 0x27, 0x16, 0x59, 0x13, 0x8f, 0x13, 0xdf, 0xe5, 0x3d, 0x56, 0x5e, 0xda, 0xcc, 0x3c, 0x32, 0xd1, + 0x9a, 0x9c, 0xfc, 0x68, 0x3c, 0x77, 0xde, 0x63, 0x70, 0x17, 0xe4, 0x45, 0xca, 0x5e, 0x0b, 0xc7, + 0x31, 0x09, 0x59, 0xd9, 0x94, 0xc9, 0x15, 0x07, 0xa9, 0x9d, 0xab, 0xfd, 0xfe, 0xf9, 0xa1, 0x56, + 0xa3, 0x1c, 0xe9, 0x46, 0x43, 0x01, 0xfe, 0x09, 0x14, 0xb0, 0xe7, 0x11, 0xc6, 0x44, 0x2c, 0x3c, + 0xa1, 0x61, 0x39, 0x2b, 0xb3, 0xb1, 0xaf, 0x67, 0x73, 0x20, 0xed, 0x0e, 0x95, 0x59, 0x75, 0x5d, + 0xe4, 0x33, 0x48, 0xed, 0x95, 0x29, 0x35, 0x5a, 0xc1, 0x93, 0x22, 0x7c, 0x06, 0x1e, 0x60, 0x8f, + 0x07, 0x5d, 0xe2, 0x32, 0x8e, 0x79, 0xe0, 0xb9, 0xed, 0x84, 0x78, 0x34, 0x6a, 0x07, 0x21, 0x61, + 0x65, 0x20, 0xe2, 0x43, 0xf7, 0x95, 0x41, 0x5d, 0xce, 0x9f, 0x8d, 0xa7, 0x9f, 0xdd, 0x7f, 0xf5, + 0xcd, 0x97, 0x8f, 0x21, 0xe9, 0x46, 0x94, 0x6d, 0xf7, 0x64, 0x07, 0xa9, 0x55, 0x3f, 0x31, 0xcc, + 0x79, 0x6b, 0xe1, 0xc4, 0x30, 0x17, 0x2c, 0xe3, 0xc4, 0x30, 0x97, 0x2d, 0xd3, 0xf9, 0x4b, 0x06, + 0x4c, 0xc7, 0x01, 0x0f, 0xc0, 0x92, 0x97, 0x10, 0xcc, 0x89, 0x6c, 0x8b, 0xdc, 0xee, 0x0f, 0xbe, + 0x23, 0x9f, 0xf3, 0x7e, 0x9b, 0x54, 0x0d, 0x91, 0x13, 0xd2, 0x8e, 0xf0, 0x17, 0xc0, 0xf0, 0x70, + 0x18, 0x96, 0xe7, 0xff, 0x5f, 0x00, 0xe9, 0xe6, 0xfc, 0x3b, 0x03, 0x56, 0xaf, 0x59, 0x40, 0x0f, + 0xe4, 0x74, 0xbd, 0x79, 0xbf, 0xad, 0x82, 0x2b, 0xec, 0xbe, 0xf3, 0x6d, 0xd8, 0x12, 0xf4, 0x87, + 0x83, 0xd4, 0x06, 0x63, 0xf9, 0x2a, 0xb5, 0xa1, 0xea, 0xa1, 0x09, 0x20, 0x07, 0x01, 0x3c, 0xb2, + 0x80, 0x1e, 0x58, 0x9b, 0x5e, 0x54, 0x37, 0x0c, 0x18, 0x2f, 0xcf, 0xcb, 0x7e, 0x78, 0x3a, 0x48, + 0xed, 0xe9, 0xc0, 0x4e, 0x03, 0xc6, 0xaf, 0x52, 0xbb, 0x32, 0x85, 0x3a, 0xe9, 0xe9, 0xa0, 0x55, + 0x3c, 0xeb, 0xe0, 0xfc, 0xb7, 0x00, 0x72, 0x13, 0x0d, 0x0e, 0xff, 0x08, 0x8a, 0x2d, 0x1a, 0x11, + 0xc6, 0x09, 0xf6, 0xdd, 0x46, 0x48, 0xbd, 0x0b, 0xfd, 0x45, 0x3e, 0xfd, 0x57, 0x6a, 0xaf, 0x7b, + 0x94, 0x45, 0x94, 0x31, 0xff, 0x62, 0x2b, 0xa0, 0xdb, 0x11, 0xe6, 0xad, 0xad, 0xe3, 0x58, 0x90, + 0xde, 0x53, 0xa4, 0x33, 0x9e, 0x0e, 0x2a, 0x8c, 0x34, 0x55, 0xa1, 0x80, 0x2d, 0x50, 0xf0, 0x31, + 0x75, 0x3f, 0xa5, 0xc9, 0x85, 0x06, 0x9f, 0x97, 0xe0, 0xd5, 0x6f, 0x05, 0x1f, 0xa4, 0x76, 0xfe, + 0xe8, 0xe0, 0xc3, 0x0f, 0x68, 0x72, 0x21, 0x21, 0xae, 0x52, 0x7b, 0x5d, 0x91, 0x4d, 0x03, 0x39, + 0x28, 0xef, 0x63, 0x3a, 0x32, 0x83, 0x1f, 0x03, 0x6b, 0x64, 0xc0, 0x3a, 0xed, 0x36, 0x4d, 0x78, + 0x79, 0x41, 0x7c, 0x74, 0xd5, 0x9f, 0x0c, 0x52, 0xbb, 0xa0, 0x21, 0xeb, 0x6a, 0xe6, 0x2a, 0xb5, + 0xef, 0xcf, 0x80, 0x6a, 0x1f, 0x07, 0x15, 0x34, 0xac, 0x36, 0x15, 0xdb, 0x06, 0x09, 0xda, 0x3b, + 0x7b, 0x4f, 0x74, 0x02, 0x86, 0x4c, 0xe0, 0x57, 0xb7, 0x25, 0x90, 0xab, 0x1d, 0x9f, 0xed, 0xec, + 0x3d, 0x19, 0xc6, 0xaf, 0xf7, 0x8e, 0x49, 0x14, 0x07, 0xe5, 0x94, 0xa8, 0x82, 0x3f, 0x06, 0x5a, + 0x74, 0x5b, 0x98, 0xb5, 0xe4, 0xce, 0x94, 0xad, 0x3e, 0x12, 0x0d, 0xa4, 0x90, 0x7e, 0x8b, 0x59, + 0x6b, 0x5c, 0xf5, 0x46, 0xff, 0xcf, 0x38, 0xe6, 0x41, 0x27, 0x1a, 0x62, 0x01, 0xe5, 0x2c, 0xac, + 0x46, 0xe1, 0xee, 0xe9, 0x70, 0x97, 0xee, 0x1a, 0xee, 0xde, 0x4d, 0xe1, 0xee, 0x4d, 0x87, 0xab, + 0x6c, 0x46, 0x1c, 0xfb, 0x9a, 0x63, 0xf9, 0xae, 0x1c, 0xfb, 0x37, 0x71, 0xec, 0x4f, 0x73, 0x28, + 0x1b, 0xd1, 0x97, 0x33, 0x79, 0x96, 0xcd, 0x3b, 0xf7, 0xe5, 0xb5, 0x0a, 0x15, 0x46, 0x1a, 0x85, + 0x7e, 0x01, 0x4a, 0x1e, 0x8d, 0x19, 0x17, 0xba, 0x98, 0xb6, 0x43, 0xa2, 0x29, 0xb2, 0x92, 0x62, + 0xff, 0x36, 0x8a, 0x87, 0xfa, 0x24, 0xb8, 0xc1, 0xdd, 0x41, 0x6b, 0xd3, 0x6a, 0x45, 0xe6, 0x02, + 0xab, 0x4d, 0x38, 0x49, 0x58, 0xa3, 0x93, 0x34, 0x35, 0x11, 0x90, 0x44, 0xef, 0xdd, 0x46, 0xa4, + 0x3b, 0x74, 0xd6, 0xd5, 0x41, 0xc5, 0xb1, 0x4a, 0x11, 0x7c, 0x02, 0x0a, 0x81, 0x60, 0x6d, 0x74, + 0x42, 0x0d, 0x9f, 0x93, 0xf0, 0xbb, 0xb7, 0xc1, 0xeb, 0xaf, 0x6a, 0xda, 0xd1, 0x41, 0x2b, 0x43, + 0x85, 0x82, 0xf6, 0x01, 0x8c, 0x3a, 0x41, 0xe2, 0x36, 0x43, 0xec, 0x05, 0x24, 0xd1, 0xf0, 0x79, + 0x09, 0xff, 0xd3, 0xdb, 0xe0, 0x1f, 0x28, 0xf8, 0xeb, 0xce, 0x0e, 0xb2, 0x84, 0xf2, 0x37, 0x4a, + 0xa7, 0x58, 0xea, 0x20, 0xdf, 0x20, 0x49, 0x18, 0xc4, 0x1a, 0x7f, 0x45, 0xe2, 0x3f, 0xb9, 0x0d, + 0x5f, 0x77, 0xd0, 0xa4, 0x9b, 0x83, 0x72, 0x4a, 0x1c, 0x81, 0x86, 0x34, 0xf6, 0xe9, 0x10, 0x74, + 0xf5, 0xce, 0xa0, 0x93, 0x6e, 0x0e, 0xca, 0x29, 0x51, 0x81, 0x36, 0xc1, 0x1a, 0x4e, 0x12, 0xfa, + 0x72, 0xa6, 0x20, 0x50, 0x62, 0xff, 0xec, 0x36, 0xec, 0xe1, 0x3e, 0x7d, 0xdd, 0x5b, 0xec, 0xd3, + 0x42, 0x3b, 0x55, 0x12, 0x1f, 0xc0, 0x66, 0x82, 0xfb, 0x33, 0x3c, 0xa5, 0x3b, 0x17, 0xfe, 0xba, + 0xb3, 0x83, 0x2c, 0xa1, 0x9c, 0x62, 0xf9, 0x0c, 0x94, 0x22, 0x92, 0x34, 0x89, 0x1b, 0x13, 0xce, + 0xda, 0x61, 0xc0, 0x35, 0xcf, 0xfa, 0x9d, 0xbf, 0x83, 0x9b, 0xdc, 0x1d, 0x04, 0xa5, 0xfa, 0x85, + 0xd6, 0x8e, 0xba, 0x94, 0xb5, 0x70, 0xdc, 0x6c, 0xe1, 0x40, 0xb3, 0xdc, 0xbb, 0x73, 0x97, 0x4e, + 0x3b, 0x3a, 0x68, 0x65, 0xa8, 0x18, 0x2d, 0xb5, 0x87, 0x63, 0xaf, 0x33, 0x5c, 0xea, 0xfb, 0x77, + 0x5e, 0xea, 0x49, 0x37, 0x07, 0xe5, 0x94, 0x28, 0x41, 0x4f, 0x0c, 0xb3, 0x60, 0x15, 0x4f, 0x0c, + 0xb3, 0x68, 0x59, 0x27, 0x86, 0x69, 0x59, 0xab, 0x27, 0x86, 0xb9, 0x66, 0x95, 0xd0, 0x4a, 0x9f, + 0x86, 0xd4, 0xed, 0x3e, 0x55, 0x4e, 0x28, 0x47, 0x5e, 0x62, 0xa6, 0x37, 0x1a, 0x54, 0xf0, 0x30, + 0xc7, 0x61, 0x9f, 0xe9, 0x42, 0x20, 0x4b, 0x95, 0x67, 0xe2, 0xd8, 0xda, 0x06, 0x8b, 0xe2, 0xce, + 0x44, 0xa0, 0x05, 0x16, 0x2e, 0x48, 0x5f, 0x1d, 0xb6, 0x48, 0x0c, 0x61, 0x09, 0x2c, 0x76, 0x71, + 0xd8, 0x21, 0xea, 0x8c, 0x44, 0x4a, 0x70, 0xce, 0x40, 0xf1, 0x3c, 0xc1, 0x31, 0x13, 0xf7, 0x2d, + 0x1a, 0x9f, 0xd2, 0x26, 0x83, 0x10, 0x18, 0xf2, 0x9c, 0x50, 0xbe, 0x72, 0x0c, 0x7f, 0x0c, 0x8c, + 0x90, 0x36, 0x99, 0xbc, 0x2d, 0xe4, 0x76, 0xd7, 0xaf, 0x5f, 0x4d, 0x4e, 0x69, 0x13, 0x49, 0x13, + 0xe7, 0x1f, 0xf3, 0x60, 0xe1, 0x94, 0x36, 0x61, 0x19, 0x2c, 0x63, 0xdf, 0x4f, 0x08, 0x63, 0x1a, + 0x69, 0x28, 0xc2, 0x7b, 0x60, 0x89, 0xd3, 0x76, 0xe0, 0x29, 0xb8, 0x2c, 0xd2, 0x92, 0x20, 0xf6, + 0x31, 0xc7, 0xf2, 0x60, 0xcd, 0x23, 0x39, 0x16, 0xd7, 0x57, 0x99, 0x99, 0x1b, 0x77, 0xa2, 0x06, + 0x49, 0xe4, 0xf9, 0x68, 0x54, 0x8b, 0x97, 0xa9, 0x9d, 0x93, 0xfa, 0x17, 0x52, 0x8d, 0x26, 0x05, + 0xf8, 0x2e, 0x58, 0xe6, 0xbd, 0xc9, 0xb3, 0x6e, 0xed, 0x32, 0xb5, 0x8b, 0x7c, 0x9c, 0xa6, 0x38, + 0xca, 0xd0, 0x12, 0xef, 0xc9, 0x23, 0x6d, 0x1b, 0x98, 0xbc, 0xe7, 0x06, 0xb1, 0x4f, 0x7a, 0xf2, + 0x38, 0x33, 0xaa, 0xa5, 0xcb, 0xd4, 0xb6, 0x26, 0xcc, 0x8f, 0xc5, 0x1c, 0x5a, 0xe6, 0x3d, 0x39, + 0x80, 0xef, 0x02, 0xa0, 0x42, 0x92, 0x0c, 0xea, 0x74, 0x5a, 0xb9, 0x4c, 0xed, 0xac, 0xd4, 0x4a, + 0xec, 0xf1, 0x10, 0x3a, 0x60, 0x51, 0x61, 0x9b, 0x12, 0x3b, 0x7f, 0x99, 0xda, 0x66, 0x48, 0x9b, + 0x0a, 0x53, 0x4d, 0x89, 0x52, 0x25, 0x24, 0xa2, 0x5d, 0xe2, 0xcb, 0x23, 0xc2, 0x44, 0x43, 0xd1, + 0x79, 0x3d, 0x0f, 0xcc, 0xf3, 0x1e, 0x22, 0xac, 0x13, 0x72, 0xf8, 0x01, 0xb0, 0xe4, 0x05, 0x0c, + 0x7b, 0xdc, 0x9d, 0x2a, 0x6d, 0xf5, 0xe1, 0x78, 0x43, 0x9f, 0xb5, 0x70, 0x50, 0x71, 0xa8, 0x3a, + 0xd0, 0xf5, 0x2f, 0x81, 0xc5, 0x46, 0x48, 0x69, 0x24, 0x3b, 0x21, 0x8f, 0x94, 0x00, 0x3f, 0x96, + 0x55, 0x93, 0xab, 0xbc, 0x20, 0x2f, 0xb7, 0xdf, 0xbf, 0xbe, 0xca, 0x33, 0xad, 0x52, 0x7d, 0xa8, + 0xdf, 0x2f, 0x05, 0xc5, 0xad, 0xfd, 0xf5, 0xd3, 0x65, 0x89, 0xf7, 0x64, 0x3f, 0x59, 0x60, 0x21, + 0x21, 0x5c, 0xae, 0x5c, 0x1e, 0x89, 0x21, 0xac, 0x00, 0x33, 0x21, 0x5d, 0x92, 0x70, 0xe2, 0xcb, + 0x15, 0x32, 0xd1, 0x48, 0x86, 0x0f, 0x80, 0xd9, 0xc4, 0xcc, 0xed, 0x30, 0xe2, 0xab, 0xe5, 0x40, + 0xcb, 0x4d, 0xcc, 0x3e, 0x62, 0xc4, 0x7f, 0x66, 0x7c, 0xfe, 0x85, 0x3d, 0xe7, 0x60, 0x90, 0xd3, + 0xf7, 0xde, 0x4e, 0x3b, 0x24, 0xb7, 0xb4, 0xd9, 0x2e, 0xc8, 0x33, 0x4e, 0x13, 0xdc, 0x24, 0xee, + 0x05, 0xe9, 0xeb, 0x66, 0x53, 0xad, 0xa3, 0xf5, 0xbf, 0x23, 0x7d, 0x86, 0x26, 0x05, 0x4d, 0xf1, + 0x85, 0x01, 0x72, 0xe7, 0x09, 0xf6, 0x88, 0xbe, 0xc5, 0x8a, 0x86, 0x15, 0x62, 0xa2, 0x29, 0xb4, + 0x24, 0xb8, 0x79, 0x10, 0x11, 0xda, 0xe1, 0xfa, 0xa3, 0x1a, 0x8a, 0xc2, 0x23, 0x21, 0xa4, 0x47, + 0x3c, 0x59, 0x4b, 0x03, 0x69, 0x09, 0xee, 0x81, 0x15, 0x3f, 0x60, 0xb8, 0x11, 0xca, 0xb7, 0x8f, + 0x77, 0xa1, 0xd2, 0xaf, 0x5a, 0x97, 0xa9, 0x9d, 0xd7, 0x13, 0x75, 0xa1, 0x47, 0x53, 0x12, 0x7c, + 0x1f, 0x14, 0xc7, 0x6e, 0x32, 0x5a, 0xf5, 0xe4, 0xab, 0xc2, 0xcb, 0xd4, 0x2e, 0x8c, 0x4c, 0xe5, + 0x0c, 0x9a, 0x91, 0xc5, 0x72, 0xfb, 0xa4, 0xd1, 0x69, 0xca, 0x0e, 0x34, 0x91, 0x12, 0x84, 0x36, + 0x0c, 0xa2, 0x80, 0xcb, 0x8e, 0x5b, 0x44, 0x4a, 0x80, 0xef, 0x83, 0x2c, 0xed, 0x92, 0x24, 0x09, + 0x7c, 0xf9, 0x14, 0xfb, 0xee, 0x27, 0x2c, 0x1a, 0xdb, 0x8b, 0xe4, 0x48, 0x2c, 0x83, 0x8c, 0x48, + 0x44, 0x93, 0xbe, 0xbc, 0x27, 0xe8, 0xe4, 0xd4, 0xc4, 0x73, 0xa9, 0x47, 0x53, 0x12, 0xac, 0x02, + 0xa8, 0xdd, 0x12, 0xc2, 0x3b, 0x49, 0xec, 0xca, 0x4d, 0x20, 0x2f, 0x7d, 0xe5, 0xa7, 0xa8, 0x66, + 0x91, 0x9c, 0x3c, 0xc2, 0x1c, 0xa3, 0x6b, 0x1a, 0xf8, 0x4b, 0x00, 0xd5, 0x9a, 0xb8, 0x9f, 0x31, + 0x3a, 0x7a, 0x83, 0xab, 0x83, 0x5e, 0xf2, 0xab, 0x59, 0x1d, 0xb3, 0xa5, 0xa4, 0x13, 0x46, 0x75, + 0x16, 0x27, 0x86, 0x69, 0x58, 0x8b, 0xea, 0xdd, 0x38, 0xaa, 0x9f, 0xce, 0x02, 0xad, 0x0d, 0xe5, + 0x89, 0xf0, 0x1e, 0xff, 0x3d, 0x03, 0x26, 0x9e, 0x5f, 0xf0, 0xe7, 0xa0, 0x72, 0x70, 0x78, 0x58, + 0xab, 0xd7, 0xdd, 0xf3, 0x4f, 0xce, 0x6a, 0xee, 0x59, 0x0d, 0x3d, 0x3f, 0xae, 0xd7, 0x8f, 0x3f, + 0x7c, 0x71, 0x5a, 0xab, 0xd7, 0xad, 0xb9, 0xca, 0x3b, 0xaf, 0xde, 0x6c, 0x96, 0xc7, 0xf6, 0x67, + 0xa2, 0x9e, 0x8c, 0x05, 0x34, 0x0e, 0x45, 0xa7, 0xbe, 0x07, 0xee, 0x4d, 0x7a, 0xa3, 0x5a, 0xfd, + 0x1c, 0x1d, 0x1f, 0x9e, 0xd7, 0x8e, 0xac, 0x4c, 0xa5, 0xfc, 0xea, 0xcd, 0x66, 0x69, 0xec, 0x89, + 0x08, 0xe3, 0x49, 0x20, 0x1e, 0xf7, 0x70, 0x1f, 0x94, 0x6f, 0xe6, 0xac, 0x1d, 0x59, 0xf3, 0x95, + 0xca, 0xab, 0x37, 0x9b, 0xf7, 0x6e, 0x62, 0x24, 0x7e, 0xc5, 0xf8, 0xfc, 0xaf, 0x1b, 0x73, 0xd5, + 0x5f, 0x7f, 0x35, 0xd8, 0xc8, 0x7c, 0x3d, 0xd8, 0xc8, 0xfc, 0x67, 0xb0, 0x91, 0x79, 0xfd, 0x76, + 0x63, 0xee, 0xeb, 0xb7, 0x1b, 0x73, 0xff, 0x7c, 0xbb, 0x31, 0xf7, 0x87, 0x1f, 0x35, 0x03, 0xde, + 0xea, 0x34, 0xb6, 0x3c, 0x1a, 0x6d, 0xab, 0xa7, 0xb6, 0xfa, 0xed, 0xee, 0x3e, 0xd1, 0x8f, 0x6e, + 0xf1, 0xbc, 0x64, 0x8d, 0x25, 0xf9, 0xbf, 0x97, 0xa7, 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x80, + 0xcf, 0xeb, 0x91, 0xd4, 0x11, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ActiveStaticPrecompiles) > 0 { + for iNdEx := len(m.ActiveStaticPrecompiles) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ActiveStaticPrecompiles[iNdEx]) + copy(dAtA[i:], m.ActiveStaticPrecompiles[iNdEx]) + i = encodeVarintEvm(dAtA, i, uint64(len(m.ActiveStaticPrecompiles[iNdEx]))) + i-- + dAtA[i] = 0x52 + } + } + { + size, err := m.AccessControl.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + if len(m.EVMChannels) > 0 { + for iNdEx := len(m.EVMChannels) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.EVMChannels[iNdEx]) + copy(dAtA[i:], m.EVMChannels[iNdEx]) + i = encodeVarintEvm(dAtA, i, uint64(len(m.EVMChannels[iNdEx]))) + i-- + dAtA[i] = 0x42 + } + } + if m.AllowUnprotectedTxs { + i-- + if m.AllowUnprotectedTxs { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 + } + { + size, err := m.ChainConfig.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if len(m.ExtraEIPs) > 0 { + for iNdEx := len(m.ExtraEIPs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ExtraEIPs[iNdEx]) + copy(dAtA[i:], m.ExtraEIPs[iNdEx]) + i = encodeVarintEvm(dAtA, i, uint64(len(m.ExtraEIPs[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } + if len(m.EvmDenom) > 0 { + i -= len(m.EvmDenom) + copy(dAtA[i:], m.EvmDenom) + i = encodeVarintEvm(dAtA, i, uint64(len(m.EvmDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AccessControl) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AccessControl) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessControl) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Call.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.Create.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *AccessControlType) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AccessControlType) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessControlType) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AccessControlList) > 0 { + for iNdEx := len(m.AccessControlList) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.AccessControlList[iNdEx]) + copy(dAtA[i:], m.AccessControlList[iNdEx]) + i = encodeVarintEvm(dAtA, i, uint64(len(m.AccessControlList[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if m.AccessType != 0 { + i = encodeVarintEvm(dAtA, i, uint64(m.AccessType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ChainConfig) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ChainConfig) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ChainConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CancunBlock != nil { + { + size := m.CancunBlock.Size() + i -= size + if _, err := m.CancunBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xba + } + if m.ShanghaiBlock != nil { + { + size := m.ShanghaiBlock.Size() + i -= size + if _, err := m.ShanghaiBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xb2 + } + if m.MergeNetsplitBlock != nil { + { + size := m.MergeNetsplitBlock.Size() + i -= size + if _, err := m.MergeNetsplitBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xaa + } + if m.GrayGlacierBlock != nil { + { + size := m.GrayGlacierBlock.Size() + i -= size + if _, err := m.GrayGlacierBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa2 + } + if m.ArrowGlacierBlock != nil { + { + size := m.ArrowGlacierBlock.Size() + i -= size + if _, err := m.ArrowGlacierBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x92 + } + if m.LondonBlock != nil { + { + size := m.LondonBlock.Size() + i -= size + if _, err := m.LondonBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x8a + } + if m.BerlinBlock != nil { + { + size := m.BerlinBlock.Size() + i -= size + if _, err := m.BerlinBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a + } + if m.MuirGlacierBlock != nil { + { + size := m.MuirGlacierBlock.Size() + i -= size + if _, err := m.MuirGlacierBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + } + if m.IstanbulBlock != nil { + { + size := m.IstanbulBlock.Size() + i -= size + if _, err := m.IstanbulBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } + if m.PetersburgBlock != nil { + { + size := m.PetersburgBlock.Size() + i -= size + if _, err := m.PetersburgBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + if m.ConstantinopleBlock != nil { + { + size := m.ConstantinopleBlock.Size() + i -= size + if _, err := m.ConstantinopleBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + if m.ByzantiumBlock != nil { + { + size := m.ByzantiumBlock.Size() + i -= size + if _, err := m.ByzantiumBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + if m.EIP158Block != nil { + { + size := m.EIP158Block.Size() + i -= size + if _, err := m.EIP158Block.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + if m.EIP155Block != nil { + { + size := m.EIP155Block.Size() + i -= size + if _, err := m.EIP155Block.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if len(m.EIP150Hash) > 0 { + i -= len(m.EIP150Hash) + copy(dAtA[i:], m.EIP150Hash) + i = encodeVarintEvm(dAtA, i, uint64(len(m.EIP150Hash))) + i-- + dAtA[i] = 0x2a + } + if m.EIP150Block != nil { + { + size := m.EIP150Block.Size() + i -= size + if _, err := m.EIP150Block.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.DAOForkSupport { + i-- + if m.DAOForkSupport { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.DAOForkBlock != nil { + { + size := m.DAOForkBlock.Size() + i -= size + if _, err := m.DAOForkBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.HomesteadBlock != nil { + { + size := m.HomesteadBlock.Size() + i -= size + if _, err := m.HomesteadBlock.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *State) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *State) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *State) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x12 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TransactionLogs) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TransactionLogs) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TransactionLogs) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Logs) > 0 { + for iNdEx := len(m.Logs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Logs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Log) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Log) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Log) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Removed { + i-- + if m.Removed { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x48 + } + if m.Index != 0 { + i = encodeVarintEvm(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x40 + } + if len(m.BlockHash) > 0 { + i -= len(m.BlockHash) + copy(dAtA[i:], m.BlockHash) + i = encodeVarintEvm(dAtA, i, uint64(len(m.BlockHash))) + i-- + dAtA[i] = 0x3a + } + if m.TxIndex != 0 { + i = encodeVarintEvm(dAtA, i, uint64(m.TxIndex)) + i-- + dAtA[i] = 0x30 + } + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintEvm(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0x2a + } + if m.BlockNumber != 0 { + i = encodeVarintEvm(dAtA, i, uint64(m.BlockNumber)) + i-- + dAtA[i] = 0x20 + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x1a + } + if len(m.Topics) > 0 { + for iNdEx := len(m.Topics) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Topics[iNdEx]) + copy(dAtA[i:], m.Topics[iNdEx]) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Topics[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TxResult) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TxResult) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TxResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.GasUsed != 0 { + i = encodeVarintEvm(dAtA, i, uint64(m.GasUsed)) + i-- + dAtA[i] = 0x30 + } + if m.Reverted { + i-- + if m.Reverted { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if len(m.Ret) > 0 { + i -= len(m.Ret) + copy(dAtA[i:], m.Ret) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Ret))) + i-- + dAtA[i] = 0x22 + } + { + size, err := m.TxLogs.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Bloom) > 0 { + i -= len(m.Bloom) + copy(dAtA[i:], m.Bloom) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Bloom))) + i-- + dAtA[i] = 0x12 + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintEvm(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AccessTuple) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AccessTuple) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessTuple) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.StorageKeys) > 0 { + for iNdEx := len(m.StorageKeys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.StorageKeys[iNdEx]) + copy(dAtA[i:], m.StorageKeys[iNdEx]) + i = encodeVarintEvm(dAtA, i, uint64(len(m.StorageKeys[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *TraceConfig) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TraceConfig) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TraceConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TracerJsonConfig) > 0 { + i -= len(m.TracerJsonConfig) + copy(dAtA[i:], m.TracerJsonConfig) + i = encodeVarintEvm(dAtA, i, uint64(len(m.TracerJsonConfig))) + i-- + dAtA[i] = 0x6a + } + if m.EnableReturnData { + i-- + if m.EnableReturnData { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x60 + } + if m.EnableMemory { + i-- + if m.EnableMemory { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 + } + if m.Overrides != nil { + { + size, err := m.Overrides.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvm(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + if m.Limit != 0 { + i = encodeVarintEvm(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x48 + } + if m.Debug { + i-- + if m.Debug { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 + } + if m.DisableStorage { + i-- + if m.DisableStorage { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 + } + if m.DisableStack { + i-- + if m.DisableStack { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if m.Reexec != 0 { + i = encodeVarintEvm(dAtA, i, uint64(m.Reexec)) + i-- + dAtA[i] = 0x18 + } + if len(m.Timeout) > 0 { + i -= len(m.Timeout) + copy(dAtA[i:], m.Timeout) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Timeout))) + i-- + dAtA[i] = 0x12 + } + if len(m.Tracer) > 0 { + i -= len(m.Tracer) + copy(dAtA[i:], m.Tracer) + i = encodeVarintEvm(dAtA, i, uint64(len(m.Tracer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintEvm(dAtA []byte, offset int, v uint64) int { + offset -= sovEvm(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.EvmDenom) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if len(m.ExtraEIPs) > 0 { + for _, s := range m.ExtraEIPs { + l = len(s) + n += 1 + l + sovEvm(uint64(l)) + } + } + l = m.ChainConfig.Size() + n += 1 + l + sovEvm(uint64(l)) + if m.AllowUnprotectedTxs { + n += 2 + } + if len(m.EVMChannels) > 0 { + for _, s := range m.EVMChannels { + l = len(s) + n += 1 + l + sovEvm(uint64(l)) + } + } + l = m.AccessControl.Size() + n += 1 + l + sovEvm(uint64(l)) + if len(m.ActiveStaticPrecompiles) > 0 { + for _, s := range m.ActiveStaticPrecompiles { + l = len(s) + n += 1 + l + sovEvm(uint64(l)) + } + } + return n +} + +func (m *AccessControl) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Create.Size() + n += 1 + l + sovEvm(uint64(l)) + l = m.Call.Size() + n += 1 + l + sovEvm(uint64(l)) + return n +} + +func (m *AccessControlType) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.AccessType != 0 { + n += 1 + sovEvm(uint64(m.AccessType)) + } + if len(m.AccessControlList) > 0 { + for _, s := range m.AccessControlList { + l = len(s) + n += 1 + l + sovEvm(uint64(l)) + } + } + return n +} + +func (m *ChainConfig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.HomesteadBlock != nil { + l = m.HomesteadBlock.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.DAOForkBlock != nil { + l = m.DAOForkBlock.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.DAOForkSupport { + n += 2 + } + if m.EIP150Block != nil { + l = m.EIP150Block.Size() + n += 1 + l + sovEvm(uint64(l)) + } + l = len(m.EIP150Hash) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if m.EIP155Block != nil { + l = m.EIP155Block.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.EIP158Block != nil { + l = m.EIP158Block.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.ByzantiumBlock != nil { + l = m.ByzantiumBlock.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.ConstantinopleBlock != nil { + l = m.ConstantinopleBlock.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.PetersburgBlock != nil { + l = m.PetersburgBlock.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.IstanbulBlock != nil { + l = m.IstanbulBlock.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.MuirGlacierBlock != nil { + l = m.MuirGlacierBlock.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.BerlinBlock != nil { + l = m.BerlinBlock.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.LondonBlock != nil { + l = m.LondonBlock.Size() + n += 2 + l + sovEvm(uint64(l)) + } + if m.ArrowGlacierBlock != nil { + l = m.ArrowGlacierBlock.Size() + n += 2 + l + sovEvm(uint64(l)) + } + if m.GrayGlacierBlock != nil { + l = m.GrayGlacierBlock.Size() + n += 2 + l + sovEvm(uint64(l)) + } + if m.MergeNetsplitBlock != nil { + l = m.MergeNetsplitBlock.Size() + n += 2 + l + sovEvm(uint64(l)) + } + if m.ShanghaiBlock != nil { + l = m.ShanghaiBlock.Size() + n += 2 + l + sovEvm(uint64(l)) + } + if m.CancunBlock != nil { + l = m.CancunBlock.Size() + n += 2 + l + sovEvm(uint64(l)) + } + return n +} + +func (m *State) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + return n +} + +func (m *TransactionLogs) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if len(m.Logs) > 0 { + for _, e := range m.Logs { + l = e.Size() + n += 1 + l + sovEvm(uint64(l)) + } + } + return n +} + +func (m *Log) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if len(m.Topics) > 0 { + for _, s := range m.Topics { + l = len(s) + n += 1 + l + sovEvm(uint64(l)) + } + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if m.BlockNumber != 0 { + n += 1 + sovEvm(uint64(m.BlockNumber)) + } + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if m.TxIndex != 0 { + n += 1 + sovEvm(uint64(m.TxIndex)) + } + l = len(m.BlockHash) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if m.Index != 0 { + n += 1 + sovEvm(uint64(m.Index)) + } + if m.Removed { + n += 2 + } + return n +} + +func (m *TxResult) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + l = len(m.Bloom) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + l = m.TxLogs.Size() + n += 1 + l + sovEvm(uint64(l)) + l = len(m.Ret) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if m.Reverted { + n += 2 + } + if m.GasUsed != 0 { + n += 1 + sovEvm(uint64(m.GasUsed)) + } + return n +} + +func (m *AccessTuple) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if len(m.StorageKeys) > 0 { + for _, s := range m.StorageKeys { + l = len(s) + n += 1 + l + sovEvm(uint64(l)) + } + } + return n +} + +func (m *TraceConfig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Tracer) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + l = len(m.Timeout) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + if m.Reexec != 0 { + n += 1 + sovEvm(uint64(m.Reexec)) + } + if m.DisableStack { + n += 2 + } + if m.DisableStorage { + n += 2 + } + if m.Debug { + n += 2 + } + if m.Limit != 0 { + n += 1 + sovEvm(uint64(m.Limit)) + } + if m.Overrides != nil { + l = m.Overrides.Size() + n += 1 + l + sovEvm(uint64(l)) + } + if m.EnableMemory { + n += 2 + } + if m.EnableReturnData { + n += 2 + } + l = len(m.TracerJsonConfig) + if l > 0 { + n += 1 + l + sovEvm(uint64(l)) + } + return n +} + +func sovEvm(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvm(x uint64) (n int) { + return sovEvm(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EvmDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EvmDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExtraEIPs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExtraEIPs = append(m.ExtraEIPs, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainConfig", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ChainConfig.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowUnprotectedTxs", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AllowUnprotectedTxs = bool(v != 0) + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EVMChannels", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EVMChannels = append(m.EVMChannels, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AccessControl", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.AccessControl.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ActiveStaticPrecompiles", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ActiveStaticPrecompiles = append(m.ActiveStaticPrecompiles, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AccessControl) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AccessControl: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessControl: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Create", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Create.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Call", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Call.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AccessControlType) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AccessControlType: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessControlType: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AccessType", wireType) + } + m.AccessType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AccessType |= AccessType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AccessControlList", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AccessControlList = append(m.AccessControlList, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ChainConfig) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ChainConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ChainConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HomesteadBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.HomesteadBlock = &v + if err := m.HomesteadBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DAOForkBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.DAOForkBlock = &v + if err := m.DAOForkBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DAOForkSupport", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.DAOForkSupport = bool(v != 0) + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EIP150Block", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.EIP150Block = &v + if err := m.EIP150Block.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EIP150Hash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EIP150Hash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EIP155Block", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.EIP155Block = &v + if err := m.EIP155Block.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EIP158Block", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.EIP158Block = &v + if err := m.EIP158Block.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ByzantiumBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.ByzantiumBlock = &v + if err := m.ByzantiumBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConstantinopleBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.ConstantinopleBlock = &v + if err := m.ConstantinopleBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PetersburgBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.PetersburgBlock = &v + if err := m.PetersburgBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IstanbulBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.IstanbulBlock = &v + if err := m.IstanbulBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MuirGlacierBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.MuirGlacierBlock = &v + if err := m.MuirGlacierBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BerlinBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.BerlinBlock = &v + if err := m.BerlinBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 17: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LondonBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.LondonBlock = &v + if err := m.LondonBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 18: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ArrowGlacierBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.ArrowGlacierBlock = &v + if err := m.ArrowGlacierBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 20: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GrayGlacierBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.GrayGlacierBlock = &v + if err := m.GrayGlacierBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 21: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MergeNetsplitBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.MergeNetsplitBlock = &v + if err := m.MergeNetsplitBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 22: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ShanghaiBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.ShanghaiBlock = &v + if err := m.ShanghaiBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 23: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CancunBlock", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.CancunBlock = &v + if err := m.CancunBlock.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *State) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: State: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: State: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TransactionLogs) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TransactionLogs: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TransactionLogs: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Logs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Logs = append(m.Logs, &Log{}) + if err := m.Logs[len(m.Logs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Log) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Log: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Log: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Topics", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Topics = append(m.Topics, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockNumber", wireType) + } + m.BlockNumber = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockNumber |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxIndex", wireType) + } + m.TxIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlockHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Removed", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Removed = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TxResult) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TxResult: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TxResult: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Bloom", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Bloom = append(m.Bloom[:0], dAtA[iNdEx:postIndex]...) + if m.Bloom == nil { + m.Bloom = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxLogs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TxLogs.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ret", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Ret = append(m.Ret[:0], dAtA[iNdEx:postIndex]...) + if m.Ret == nil { + m.Ret = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Reverted", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Reverted = bool(v != 0) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasUsed", wireType) + } + m.GasUsed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasUsed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AccessTuple) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AccessTuple: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessTuple: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageKeys", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StorageKeys = append(m.StorageKeys, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TraceConfig) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TraceConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TraceConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Tracer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Tracer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Timeout", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Timeout = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Reexec", wireType) + } + m.Reexec = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Reexec |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DisableStack", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.DisableStack = bool(v != 0) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DisableStorage", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.DisableStorage = bool(v != 0) + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Debug", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Debug = bool(v != 0) + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Overrides", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvm + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Overrides == nil { + m.Overrides = &ChainConfig{} + } + if err := m.Overrides.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EnableMemory", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.EnableMemory = bool(v != 0) + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EnableReturnData", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.EnableReturnData = bool(v != 0) + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TracerJsonConfig", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvm + } + 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 ErrInvalidLengthEvm + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvm + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TracerJsonConfig = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvm(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvm + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEvm(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvm + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvm + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvm + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEvm + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvm + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvm + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEvm = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvm = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvm = fmt.Errorf("proto: unexpected end of group") +) diff --git a/rpc/types/legacy/key.go b/rpc/types/legacy/key.go new file mode 100644 index 000000000..8cba0020f --- /dev/null +++ b/rpc/types/legacy/key.go @@ -0,0 +1,19 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +const ( + // ModuleName string name of module + ModuleName = "legacy_evm" + // StoreKey key for ethereum storage data, account code (StateDB) or block + // related data for Web3. + // The EVM module should use a prefix store. + StoreKey = ModuleName + + // TransientKey is the key to access the EVM transient store, that is reset + // during the Commit phase. + TransientKey = "transient_" + ModuleName + + // RouterKey uses module name for routing + RouterKey = ModuleName +) diff --git a/rpc/types/legacy/legacy_tx.go b/rpc/types/legacy/legacy_tx.go new file mode 100644 index 000000000..7f4acf05a --- /dev/null +++ b/rpc/types/legacy/legacy_tx.go @@ -0,0 +1,228 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + + errorsmod "cosmossdk.io/errors" + + errortypes "github.com/cosmos/cosmos-sdk/types/errors" +) + +func NewLegacyTx(tx *ethtypes.Transaction) (*LegacyTx, error) { + txData := &LegacyTx{ + Nonce: tx.Nonce(), + Data: tx.Data(), + GasLimit: tx.Gas(), + } + + v, r, s := tx.RawSignatureValues() + if to := tx.To(); to != nil { + txData.To = to.Hex() + } + + if tx.Value() != nil { + amountInt, err := SafeNewIntFromBigInt(tx.Value()) + if err != nil { + return nil, err + } + txData.Amount = &amountInt + } + + if tx.GasPrice() != nil { + gasPriceInt, err := SafeNewIntFromBigInt(tx.GasPrice()) + if err != nil { + return nil, err + } + txData.GasPrice = &gasPriceInt + } + + txData.SetSignatureValues(tx.ChainId(), v, r, s) + return txData, nil +} + +// TxType returns the tx type +func (tx *LegacyTx) TxType() uint8 { + return ethtypes.LegacyTxType +} + +// Copy returns an instance with the same field values +func (tx *LegacyTx) Copy() TxData { + return &LegacyTx{ + Nonce: tx.Nonce, + GasPrice: tx.GasPrice, + GasLimit: tx.GasLimit, + To: tx.To, + Amount: tx.Amount, + Data: common.CopyBytes(tx.Data), + V: common.CopyBytes(tx.V), + R: common.CopyBytes(tx.R), + S: common.CopyBytes(tx.S), + } +} + +// GetChainID returns the chain id field from the derived signature values +func (tx *LegacyTx) GetChainID() *big.Int { + v, _, _ := tx.GetRawSignatureValues() + return DeriveChainID(v) +} + +// GetAccessList returns nil +func (tx *LegacyTx) GetAccessList() ethtypes.AccessList { + return nil +} + +// GetData returns the a copy of the input data bytes. +func (tx *LegacyTx) GetData() []byte { + return common.CopyBytes(tx.Data) +} + +// GetGas returns the gas limit. +func (tx *LegacyTx) GetGas() uint64 { + return tx.GasLimit +} + +// GetGasPrice returns the gas price field. +func (tx *LegacyTx) GetGasPrice() *big.Int { + if tx.GasPrice == nil { + return nil + } + return tx.GasPrice.BigInt() +} + +// GetGasTipCap returns the gas price field. +func (tx *LegacyTx) GetGasTipCap() *big.Int { + return tx.GetGasPrice() +} + +// GetGasFeeCap returns the gas price field. +func (tx *LegacyTx) GetGasFeeCap() *big.Int { + return tx.GetGasPrice() +} + +// GetValue returns the tx amount. +func (tx *LegacyTx) GetValue() *big.Int { + if tx.Amount == nil { + return nil + } + return tx.Amount.BigInt() +} + +// GetNonce returns the account sequence for the transaction. +func (tx *LegacyTx) GetNonce() uint64 { return tx.Nonce } + +// GetTo returns the pointer to the recipient address. +func (tx *LegacyTx) GetTo() *common.Address { + if tx.To == "" { + return nil + } + to := common.HexToAddress(tx.To) + return &to +} + +// AsEthereumData returns an LegacyTx transaction tx from the proto-formatted +// TxData defined on the Cosmos EVM. +func (tx *LegacyTx) AsEthereumData() ethtypes.TxData { + v, r, s := tx.GetRawSignatureValues() + return ðtypes.LegacyTx{ + Nonce: tx.GetNonce(), + GasPrice: tx.GetGasPrice(), + Gas: tx.GetGas(), + To: tx.GetTo(), + Value: tx.GetValue(), + Data: tx.GetData(), + V: v, + R: r, + S: s, + } +} + +// GetRawSignatureValues returns the V, R, S signature values of the transaction. +// The return values should not be modified by the caller. +func (tx *LegacyTx) GetRawSignatureValues() (v, r, s *big.Int) { + return RawSignatureValues(tx.V, tx.R, tx.S) +} + +// SetSignatureValues sets the signature values to the transaction. +func (tx *LegacyTx) SetSignatureValues(_, v, r, s *big.Int) { + if v != nil { + tx.V = v.Bytes() + } + if r != nil { + tx.R = r.Bytes() + } + if s != nil { + tx.S = s.Bytes() + } +} + +// Validate performs a stateless validation of the tx fields. +func (tx LegacyTx) Validate() error { + gasPrice := tx.GetGasPrice() + if gasPrice == nil { + return errorsmod.Wrap(ErrInvalidGasPrice, "gas price cannot be nil") + } + + if gasPrice.Sign() == -1 { + return errorsmod.Wrapf(ErrInvalidGasPrice, "gas price cannot be negative %s", gasPrice) + } + if !IsValidInt256(gasPrice) { + return errorsmod.Wrap(ErrInvalidGasPrice, "out of bound") + } + if !IsValidInt256(tx.Fee()) { + return errorsmod.Wrap(ErrInvalidGasFee, "out of bound") + } + + amount := tx.GetValue() + // Amount can be 0 + if amount != nil && amount.Sign() == -1 { + return errorsmod.Wrapf(ErrInvalidAmount, "amount cannot be negative %s", amount) + } + if !IsValidInt256(amount) { + return errorsmod.Wrap(ErrInvalidAmount, "out of bound") + } + + if tx.To != "" { + if err := ValidateAddress(tx.To); err != nil { + return errorsmod.Wrap(err, "invalid to address") + } + } + + if tx.GetChainID() == nil { + return errorsmod.Wrap( + errortypes.ErrInvalidChainID, + "chain ID must be derived from LegacyTx txs", + ) + } + + return nil +} + +// Fee returns gasprice * gaslimit. +func (tx LegacyTx) Fee() *big.Int { + return fee(tx.GetGasPrice(), tx.GetGas()) +} + +// Cost returns amount + gasprice * gaslimit. +func (tx LegacyTx) Cost() *big.Int { + return cost(tx.Fee(), tx.GetValue()) +} + +// EffectiveGasPrice is the same as GasPrice for LegacyTx +func (tx LegacyTx) EffectiveGasPrice(_ *big.Int) *big.Int { + return tx.GetGasPrice() +} + +// EffectiveFee is the same as Fee for LegacyTx +func (tx LegacyTx) EffectiveFee(_ *big.Int) *big.Int { + return tx.Fee() +} + +// EffectiveCost is the same as Cost for LegacyTx +func (tx LegacyTx) EffectiveCost(_ *big.Int) *big.Int { + return tx.Cost() +} diff --git a/rpc/types/legacy/msg.go b/rpc/types/legacy/msg.go new file mode 100644 index 000000000..435b0dc3e --- /dev/null +++ b/rpc/types/legacy/msg.go @@ -0,0 +1,300 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + ethtypes "github.com/ethereum/go-ethereum/core/types" + protov2 "google.golang.org/protobuf/proto" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/client" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + errortypes "github.com/cosmos/cosmos-sdk/types/errors" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/cosmos/cosmos-sdk/x/auth/signing" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" +) + +var ( + _ sdk.Msg = &MsgEthereumTx{} + _ sdk.Tx = &MsgEthereumTx{} + _ ante.GasTx = &MsgEthereumTx{} + _ sdk.Msg = &MsgUpdateParams{} + + _ codectypes.UnpackInterfacesMessage = MsgEthereumTx{} +) + +// message type and route constants +const ( + // TypeMsgEthereumTx defines the type string of an Ethereum transaction + TypeMsgEthereumTx = "ethereum_tx" +) + +// FromEthereumTx populates the message fields from the given ethereum transaction +func (msg *MsgEthereumTx) FromEthereumTx(tx *ethtypes.Transaction) error { + txData, err := NewTxDataFromTx(tx) + if err != nil { + return err + } + + anyTxData, err := PackTxData(txData) + if err != nil { + return err + } + + msg.Data = anyTxData + msg.Hash = tx.Hash().Hex() + return nil +} + +// Route returns the route value of an MsgEthereumTx. +func (msg MsgEthereumTx) Route() string { return RouterKey } + +// Type returns the type value of an MsgEthereumTx. +func (msg MsgEthereumTx) Type() string { return TypeMsgEthereumTx } + +// ValidateBasic implements the sdk.Msg interface. It performs basic validation +// checks of a Transaction. If returns an error if validation fails. +func (msg MsgEthereumTx) ValidateBasic() error { + if msg.From != "" { + if err := ValidateAddress(msg.From); err != nil { + return errorsmod.Wrap(err, "invalid from address") + } + } + + // Validate Size_ field, should be kept empty + if msg.Size_ != 0 { + return errorsmod.Wrapf(errortypes.ErrInvalidRequest, "tx size is deprecated") + } + + txData, err := UnpackTxData(msg.Data) + if err != nil { + return errorsmod.Wrap(err, "failed to unpack tx data") + } + + gas := txData.GetGas() + + // prevent txs with 0 gas to fill up the mempool + if gas == 0 { + return errorsmod.Wrap(ErrInvalidGasLimit, "gas limit must not be zero") + } + + // prevent gas limit from overflow + if g := new(big.Int).SetUint64(gas); !g.IsInt64() { + return errorsmod.Wrap(ErrGasOverflow, "gas limit must be less than math.MaxInt64") + } + + if err := txData.Validate(); err != nil { + return err + } + + // Validate Hash field after validated txData to avoid panic + txHash := msg.AsTransaction().Hash().Hex() + if msg.Hash != txHash { + return errorsmod.Wrapf(errortypes.ErrInvalidRequest, "invalid tx hash %s, expected: %s", msg.Hash, txHash) + } + + return nil +} + +// GetMsgs returns a single MsgEthereumTx as an sdk.Msg. +func (msg *MsgEthereumTx) GetMsgs() []sdk.Msg { + return []sdk.Msg{msg} +} + +func (msg *MsgEthereumTx) GetMsgsV2() ([]protov2.Message, error) { + return nil, errors.New("not implemented") +} + +// GetSignBytes returns the Amino bytes of an Ethereum transaction message used +// for signing. +// +// NOTE: This method cannot be used as a chain ID is needed to create valid bytes +// to sign over. Use 'RLPSignBytes' instead. +func (msg MsgEthereumTx) GetSignBytes() []byte { + panic("must use 'RLPSignBytes' with a chain ID to get the valid bytes to sign") +} + +// Sign calculates a secp256k1 ECDSA signature and signs the transaction. It +// takes a keyring signer and the chainID to sign an Ethereum transaction according to +// EIP155 standard. +// This method mutates the transaction as it populates the V, R, S +// fields of the Transaction's Signature. +// The function will fail if the sender address is not defined for the msg or if +// the sender is not registered on the keyring +func (msg *MsgEthereumTx) Sign(ethSigner ethtypes.Signer, keyringSigner keyring.Signer) error { + from := msg.GetFrom() + if from.Empty() { + return fmt.Errorf("sender address not defined for message") + } + + tx := msg.AsTransaction() + txHash := ethSigner.Hash(tx) + + sig, _, err := keyringSigner.SignByAddress(from, txHash.Bytes(), signingtypes.SignMode_SIGN_MODE_TEXTUAL) + if err != nil { + return err + } + + tx, err = tx.WithSignature(ethSigner, sig) + if err != nil { + return err + } + + return msg.FromEthereumTx(tx) +} + +// GetGas implements the GasTx interface. It returns the GasLimit of the transaction. +func (msg MsgEthereumTx) GetGas() uint64 { + txData, err := UnpackTxData(msg.Data) + if err != nil { + return 0 + } + return txData.GetGas() +} + +// GetFee returns the fee for non dynamic fee tx +func (msg MsgEthereumTx) GetFee() *big.Int { + txData, err := UnpackTxData(msg.Data) + if err != nil { + return nil + } + return txData.Fee() +} + +// GetEffectiveFee returns the fee for dynamic fee tx +func (msg MsgEthereumTx) GetEffectiveFee(baseFee *big.Int) *big.Int { + txData, err := UnpackTxData(msg.Data) + if err != nil { + return nil + } + return txData.EffectiveFee(baseFee) +} + +// GetFrom loads the ethereum sender address from the sigcache and returns an +// sdk.AccAddress from its bytes +func (msg *MsgEthereumTx) GetFrom() sdk.AccAddress { + if msg.From == "" { + return nil + } + + return common.HexToAddress(msg.From).Bytes() +} + +// AsTransaction creates an Ethereum Transaction type from the msg fields +func (msg MsgEthereumTx) AsTransaction() *ethtypes.Transaction { + txData, err := UnpackTxData(msg.Data) + if err != nil { + return nil + } + + return ethtypes.NewTx(txData.AsEthereumData()) +} + +// AsMessage creates an Ethereum core.Message from the msg fields +func (msg MsgEthereumTx) AsMessage(signer ethtypes.Signer, baseFee *big.Int) (core.Message, error) { + tx := msg.AsTransaction() + ethMsg := core.Message{ + Nonce: tx.Nonce(), + GasLimit: tx.Gas(), + GasPrice: new(big.Int).Set(tx.GasPrice()), + GasFeeCap: new(big.Int).Set(tx.GasFeeCap()), + GasTipCap: new(big.Int).Set(tx.GasTipCap()), + To: tx.To(), + Value: tx.Value(), + Data: tx.Data(), + AccessList: tx.AccessList(), + SetCodeAuthorizations: tx.SetCodeAuthorizations(), + SkipNonceChecks: false, + SkipFromEOACheck: false, + BlobHashes: tx.BlobHashes(), + BlobGasFeeCap: tx.BlobGasFeeCap(), + } + // If baseFee provided, set gasPrice to effectiveGasPrice. + if baseFee != nil { + ethMsg.GasPrice = ethMsg.GasPrice.Add(ethMsg.GasTipCap, baseFee) + if ethMsg.GasPrice.Cmp(ethMsg.GasFeeCap) > 0 { + ethMsg.GasPrice = ethMsg.GasFeeCap + } + } + var err error + ethMsg.From, err = msg.GetSender(signer.ChainID()) + if err != nil { + return core.Message{}, err + } + return ethMsg, nil +} + +// GetSender extracts the sender address from the signature values using the latest signer for the given chainID. +func (msg *MsgEthereumTx) GetSender(chainID *big.Int) (common.Address, error) { + signer := ethtypes.LatestSignerForChainID(chainID) + from, err := signer.Sender(msg.AsTransaction()) + if err != nil { + return common.Address{}, err + } + + msg.From = from.Hex() + return from, nil +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (msg MsgEthereumTx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + return unpacker.UnpackAny(msg.Data, new(TxData)) +} + +// UnmarshalBinary decodes the canonical encoding of transactions. +func (msg *MsgEthereumTx) UnmarshalBinary(b []byte) error { + tx := ðtypes.Transaction{} + if err := tx.UnmarshalBinary(b); err != nil { + return err + } + return msg.FromEthereumTx(tx) +} + +// BuildTx builds the canonical cosmos tx from ethereum msg +func (msg *MsgEthereumTx) BuildTx(b client.TxBuilder, evmDenom string) (signing.Tx, error) { + builder, ok := b.(authtx.ExtensionOptionsTxBuilder) + if !ok { + return nil, errors.New("unsupported builder") + } + + option, err := codectypes.NewAnyWithValue(&ExtensionOptionsEthereumTx{}) + if err != nil { + return nil, err + } + + txData, err := UnpackTxData(msg.Data) + if err != nil { + return nil, err + } + fees := make(sdk.Coins, 0) + feeAmt := sdkmath.NewIntFromBigInt(txData.Fee()) + if feeAmt.Sign() > 0 { + fees = append(fees, sdk.NewCoin(evmDenom, feeAmt)) + } + + builder.SetExtensionOptions(option) + + // A valid msg should have empty `From` + msg.From = "" + + err = builder.SetMsgs(msg) + if err != nil { + return nil, err + } + builder.SetFeeAmount(fees) + builder.SetGasLimit(msg.GetGas()) + tx := builder.GetTx() + return tx, nil +} diff --git a/rpc/types/legacy/tx.go b/rpc/types/legacy/tx.go new file mode 100644 index 000000000..cb1ce27c1 --- /dev/null +++ b/rpc/types/legacy/tx.go @@ -0,0 +1,25 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +// EvmTxArgs encapsulates all possible params to create all EVM txs types. +// This includes LegacyTx, DynamicFeeTx and AccessListTx +type EvmTxArgs struct { + Nonce uint64 + GasLimit uint64 + Input []byte + GasFeeCap *big.Int + GasPrice *big.Int + ChainID *big.Int + Amount *big.Int + GasTipCap *big.Int + To *common.Address + Accesses *ethtypes.AccessList +} diff --git a/rpc/types/legacy/tx.pb.go b/rpc/types/legacy/tx.pb.go new file mode 100644 index 000000000..94f2601bd --- /dev/null +++ b/rpc/types/legacy/tx.pb.go @@ -0,0 +1,3276 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: ethermint/evm/v1/tx.proto + +package types + +import ( + context "context" + cosmossdk_io_math "cosmossdk.io/math" + encoding_binary "encoding/binary" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgEthereumTx encapsulates an Ethereum transaction as an SDK message. +type MsgEthereumTx struct { + // data is inner transaction data of the Ethereum transaction + Data *types.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + // size is the encoded storage size of the transaction (DEPRECATED) + Size_ float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"-"` + // hash of the transaction in hex format + Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"` + // from is the ethereum signer address in hex format. This address value is checked + // against the address derived from the signature (V, R, S) using the + // secp256k1 elliptic curve + From string `protobuf:"bytes,4,opt,name=from,proto3" json:"from,omitempty"` +} + +func (m *MsgEthereumTx) Reset() { *m = MsgEthereumTx{} } +func (m *MsgEthereumTx) String() string { return proto.CompactTextString(m) } +func (*MsgEthereumTx) ProtoMessage() {} +func (*MsgEthereumTx) Descriptor() ([]byte, []int) { + return fileDescriptor_f75ac0a12d075f21, []int{0} +} +func (m *MsgEthereumTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgEthereumTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgEthereumTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgEthereumTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgEthereumTx.Merge(m, src) +} +func (m *MsgEthereumTx) XXX_Size() int { + return m.Size() +} +func (m *MsgEthereumTx) XXX_DiscardUnknown() { + xxx_messageInfo_MsgEthereumTx.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgEthereumTx proto.InternalMessageInfo + +// LegacyTx is the transaction data of regular Ethereum transactions. +// NOTE: All non-protected transactions (i.e non EIP155 signed) will fail if the +// AllowUnprotectedTxs parameter is disabled. +type LegacyTx struct { + // nonce corresponds to the account nonce (transaction sequence). + Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"` + // gas_price defines the value for each gas unit + GasPrice *cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=gas_price,json=gasPrice,proto3,customtype=cosmossdk.io/math.Int" json:"gas_price,omitempty"` + // gas defines the gas limit defined for the transaction. + GasLimit uint64 `protobuf:"varint,3,opt,name=gas,proto3" json:"gas,omitempty"` + // to is the hex formatted address of the recipient + To string `protobuf:"bytes,4,opt,name=to,proto3" json:"to,omitempty"` + // value defines the unsigned integer value of the transaction amount. + Amount *cosmossdk_io_math.Int `protobuf:"bytes,5,opt,name=value,proto3,customtype=cosmossdk.io/math.Int" json:"value,omitempty"` + // data is the data payload bytes of the transaction. + Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` + // v defines the signature value + V []byte `protobuf:"bytes,7,opt,name=v,proto3" json:"v,omitempty"` + // r defines the signature value + R []byte `protobuf:"bytes,8,opt,name=r,proto3" json:"r,omitempty"` + // s define the signature value + S []byte `protobuf:"bytes,9,opt,name=s,proto3" json:"s,omitempty"` +} + +func (m *LegacyTx) Reset() { *m = LegacyTx{} } +func (m *LegacyTx) String() string { return proto.CompactTextString(m) } +func (*LegacyTx) ProtoMessage() {} +func (*LegacyTx) Descriptor() ([]byte, []int) { + return fileDescriptor_f75ac0a12d075f21, []int{1} +} +func (m *LegacyTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LegacyTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LegacyTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LegacyTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_LegacyTx.Merge(m, src) +} +func (m *LegacyTx) XXX_Size() int { + return m.Size() +} +func (m *LegacyTx) XXX_DiscardUnknown() { + xxx_messageInfo_LegacyTx.DiscardUnknown(m) +} + +var xxx_messageInfo_LegacyTx proto.InternalMessageInfo + +// AccessListTx is the data of EIP-2930 access list transactions. +type AccessListTx struct { + // chain_id of the destination EVM chain + ChainID *cosmossdk_io_math.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=cosmossdk.io/math.Int" json:"chainID"` + // nonce corresponds to the account nonce (transaction sequence). + Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + // gas_price defines the value for each gas unit + GasPrice *cosmossdk_io_math.Int `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice,proto3,customtype=cosmossdk.io/math.Int" json:"gas_price,omitempty"` + // gas defines the gas limit defined for the transaction. + GasLimit uint64 `protobuf:"varint,4,opt,name=gas,proto3" json:"gas,omitempty"` + // to is the recipient address in hex format + To string `protobuf:"bytes,5,opt,name=to,proto3" json:"to,omitempty"` + // value defines the unsigned integer value of the transaction amount. + Amount *cosmossdk_io_math.Int `protobuf:"bytes,6,opt,name=value,proto3,customtype=cosmossdk.io/math.Int" json:"value,omitempty"` + // data is the data payload bytes of the transaction. + Data []byte `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"` + // accesses is an array of access tuples + Accesses AccessList `protobuf:"bytes,8,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"` + // v defines the signature value + V []byte `protobuf:"bytes,9,opt,name=v,proto3" json:"v,omitempty"` + // r defines the signature value + R []byte `protobuf:"bytes,10,opt,name=r,proto3" json:"r,omitempty"` + // s define the signature value + S []byte `protobuf:"bytes,11,opt,name=s,proto3" json:"s,omitempty"` +} + +func (m *AccessListTx) Reset() { *m = AccessListTx{} } +func (m *AccessListTx) String() string { return proto.CompactTextString(m) } +func (*AccessListTx) ProtoMessage() {} +func (*AccessListTx) Descriptor() ([]byte, []int) { + return fileDescriptor_f75ac0a12d075f21, []int{2} +} +func (m *AccessListTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessListTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessListTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AccessListTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessListTx.Merge(m, src) +} +func (m *AccessListTx) XXX_Size() int { + return m.Size() +} +func (m *AccessListTx) XXX_DiscardUnknown() { + xxx_messageInfo_AccessListTx.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessListTx proto.InternalMessageInfo + +// DynamicFeeTx is the data of EIP-1559 dynamic fee transactions. +type DynamicFeeTx struct { + // chain_id of the destination EVM chain + ChainID *cosmossdk_io_math.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=cosmossdk.io/math.Int" json:"chainID"` + // nonce corresponds to the account nonce (transaction sequence). + Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + // gas_tip_cap defines the max value for the gas tip + GasTipCap *cosmossdk_io_math.Int `protobuf:"bytes,3,opt,name=gas_tip_cap,json=gasTipCap,proto3,customtype=cosmossdk.io/math.Int" json:"gas_tip_cap,omitempty"` + // gas_fee_cap defines the max value for the gas fee + GasFeeCap *cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=gas_fee_cap,json=gasFeeCap,proto3,customtype=cosmossdk.io/math.Int" json:"gas_fee_cap,omitempty"` + // gas defines the gas limit defined for the transaction. + GasLimit uint64 `protobuf:"varint,5,opt,name=gas,proto3" json:"gas,omitempty"` + // to is the hex formatted address of the recipient + To string `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` + // value defines the transaction amount. + Amount *cosmossdk_io_math.Int `protobuf:"bytes,7,opt,name=value,proto3,customtype=cosmossdk.io/math.Int" json:"value,omitempty"` + // data is the data payload bytes of the transaction. + Data []byte `protobuf:"bytes,8,opt,name=data,proto3" json:"data,omitempty"` + // accesses is an array of access tuples + Accesses AccessList `protobuf:"bytes,9,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"` + // v defines the signature value + V []byte `protobuf:"bytes,10,opt,name=v,proto3" json:"v,omitempty"` + // r defines the signature value + R []byte `protobuf:"bytes,11,opt,name=r,proto3" json:"r,omitempty"` + // s define the signature value + S []byte `protobuf:"bytes,12,opt,name=s,proto3" json:"s,omitempty"` +} + +func (m *DynamicFeeTx) Reset() { *m = DynamicFeeTx{} } +func (m *DynamicFeeTx) String() string { return proto.CompactTextString(m) } +func (*DynamicFeeTx) ProtoMessage() {} +func (*DynamicFeeTx) Descriptor() ([]byte, []int) { + return fileDescriptor_f75ac0a12d075f21, []int{3} +} +func (m *DynamicFeeTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DynamicFeeTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DynamicFeeTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DynamicFeeTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_DynamicFeeTx.Merge(m, src) +} +func (m *DynamicFeeTx) XXX_Size() int { + return m.Size() +} +func (m *DynamicFeeTx) XXX_DiscardUnknown() { + xxx_messageInfo_DynamicFeeTx.DiscardUnknown(m) +} + +var xxx_messageInfo_DynamicFeeTx proto.InternalMessageInfo + +// ExtensionOptionsEthereumTx is an extension option for ethereum transactions +type ExtensionOptionsEthereumTx struct { +} + +func (m *ExtensionOptionsEthereumTx) Reset() { *m = ExtensionOptionsEthereumTx{} } +func (m *ExtensionOptionsEthereumTx) String() string { return proto.CompactTextString(m) } +func (*ExtensionOptionsEthereumTx) ProtoMessage() {} +func (*ExtensionOptionsEthereumTx) Descriptor() ([]byte, []int) { + return fileDescriptor_f75ac0a12d075f21, []int{4} +} +func (m *ExtensionOptionsEthereumTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExtensionOptionsEthereumTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExtensionOptionsEthereumTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExtensionOptionsEthereumTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtensionOptionsEthereumTx.Merge(m, src) +} +func (m *ExtensionOptionsEthereumTx) XXX_Size() int { + return m.Size() +} +func (m *ExtensionOptionsEthereumTx) XXX_DiscardUnknown() { + xxx_messageInfo_ExtensionOptionsEthereumTx.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtensionOptionsEthereumTx proto.InternalMessageInfo + +// MsgEthereumTxResponse defines the Msg/EthereumTx response type. +type MsgEthereumTxResponse struct { + // hash of the ethereum transaction in hex format. This hash differs from the + // Tendermint sha256 hash of the transaction bytes. See + // https://github.com/tendermint/tendermint/issues/6539 for reference + Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` + // logs contains the transaction hash and the proto-compatible ethereum + // logs. + Logs []*Log `protobuf:"bytes,2,rep,name=logs,proto3" json:"logs,omitempty"` + // ret is the returned data from evm function (result or data supplied with revert + // opcode) + Ret []byte `protobuf:"bytes,3,opt,name=ret,proto3" json:"ret,omitempty"` + // vm_error is the error returned by vm execution + VmError string `protobuf:"bytes,4,opt,name=vm_error,json=vmError,proto3" json:"vm_error,omitempty"` + // gas_used specifies how much gas was consumed by the transaction + GasUsed uint64 `protobuf:"varint,5,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` +} + +func (m *MsgEthereumTxResponse) Reset() { *m = MsgEthereumTxResponse{} } +func (m *MsgEthereumTxResponse) String() string { return proto.CompactTextString(m) } +func (*MsgEthereumTxResponse) ProtoMessage() {} +func (*MsgEthereumTxResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f75ac0a12d075f21, []int{5} +} +func (m *MsgEthereumTxResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgEthereumTxResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgEthereumTxResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgEthereumTxResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgEthereumTxResponse.Merge(m, src) +} +func (m *MsgEthereumTxResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgEthereumTxResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgEthereumTxResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgEthereumTxResponse proto.InternalMessageInfo + +// MsgUpdateParams defines a Msg for updating the x/evm module parameters. +type MsgUpdateParams struct { + // authority is the address of the governance account. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // params defines the x/evm parameters to update. + // NOTE: All parameters must be supplied. + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_f75ac0a12d075f21, []int{6} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +func (m *MsgUpdateParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateParams) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +type MsgUpdateParamsResponse struct { +} + +func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse{} } +func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParamsResponse) ProtoMessage() {} +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f75ac0a12d075f21, []int{7} +} +func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParamsResponse.Merge(m, src) +} +func (m *MsgUpdateParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo + +func init() { + // NOTE: Proto type registration is enabled here for the EVM module. + // Since the node application uses a local replace (github.com/cosmos/evm => ../evm), + // both the node and EVM will use these same proto registrations. + // + // To avoid duplicate registration errors, ensure that node/types/legacy/ethermint/evm/tx.pb.go + // has proto registration DISABLED (commented out). + + proto.RegisterType((*MsgEthereumTx)(nil), "ethermint.evm.v1.MsgEthereumTx") + proto.RegisterType((*LegacyTx)(nil), "ethermint.evm.v1.LegacyTx") + proto.RegisterType((*AccessListTx)(nil), "ethermint.evm.v1.AccessListTx") + proto.RegisterType((*DynamicFeeTx)(nil), "ethermint.evm.v1.DynamicFeeTx") + proto.RegisterType((*ExtensionOptionsEthereumTx)(nil), "ethermint.evm.v1.ExtensionOptionsEthereumTx") + proto.RegisterType((*MsgEthereumTxResponse)(nil), "ethermint.evm.v1.MsgEthereumTxResponse") + proto.RegisterType((*MsgUpdateParams)(nil), "ethermint.evm.v1.MsgUpdateParams") + proto.RegisterType((*MsgUpdateParamsResponse)(nil), "ethermint.evm.v1.MsgUpdateParamsResponse") +} + +//func init() { proto.RegisterFile("ethermint/evm/v1/tx.proto", fileDescriptor_f75ac0a12d075f21) } + +var fileDescriptor_f75ac0a12d075f21 = []byte{ + // 1038 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x96, 0x4f, 0x6f, 0xe3, 0xc4, + 0x1b, 0xc7, 0xeb, 0xc4, 0xf9, 0x37, 0xc9, 0xef, 0x47, 0xb1, 0x5a, 0xea, 0x64, 0x21, 0xce, 0x1a, + 0x16, 0xd2, 0x4a, 0xb5, 0xd9, 0x22, 0x21, 0x6d, 0xb8, 0xd0, 0x6c, 0xbb, 0x68, 0x51, 0x2b, 0x56, + 0x26, 0x7b, 0x41, 0x48, 0x61, 0xea, 0x4c, 0x9d, 0x11, 0xb1, 0xc7, 0xf2, 0x4c, 0xac, 0x84, 0x13, + 0xda, 0x13, 0xe2, 0x84, 0xc4, 0x95, 0x03, 0x07, 0x0e, 0x2b, 0x4e, 0x3d, 0x2c, 0xbc, 0x86, 0x15, + 0xa7, 0x15, 0x5c, 0x10, 0x87, 0x80, 0x52, 0x50, 0xa5, 0x1e, 0x79, 0x05, 0x68, 0x66, 0x9c, 0x26, + 0x69, 0x68, 0xbb, 0xac, 0x04, 0x97, 0x6a, 0x9e, 0x79, 0xfe, 0xcc, 0x93, 0xcf, 0xf3, 0xed, 0x8c, + 0x41, 0x19, 0xb1, 0x2e, 0x8a, 0x7c, 0x1c, 0x30, 0x1b, 0xc5, 0xbe, 0x1d, 0xdf, 0xb4, 0xd9, 0xc0, + 0x0a, 0x23, 0xc2, 0x88, 0xb6, 0x7c, 0xe6, 0xb2, 0x50, 0xec, 0x5b, 0xf1, 0xcd, 0xca, 0xf3, 0xd0, + 0xc7, 0x01, 0xb1, 0xc5, 0x5f, 0x19, 0x54, 0x59, 0x73, 0x09, 0xf5, 0x09, 0xb5, 0x7d, 0xea, 0xf1, + 0x64, 0x9f, 0x7a, 0x89, 0xa3, 0x2c, 0x1d, 0x6d, 0x61, 0xd9, 0xd2, 0x48, 0x5c, 0x95, 0x85, 0x33, + 0x79, 0x7d, 0xe9, 0x5b, 0xf1, 0x88, 0x47, 0x64, 0x0e, 0x5f, 0x25, 0xbb, 0x2f, 0x7a, 0x84, 0x78, + 0x3d, 0x64, 0xc3, 0x10, 0xdb, 0x30, 0x08, 0x08, 0x83, 0x0c, 0x93, 0x60, 0x52, 0xaf, 0x9c, 0x78, + 0x85, 0x75, 0xd0, 0x3f, 0xb4, 0x61, 0x30, 0x94, 0x2e, 0xf3, 0x3b, 0x05, 0xfc, 0x6f, 0x9f, 0x7a, + 0xbb, 0xfc, 0x40, 0xd4, 0xf7, 0x5b, 0x03, 0xad, 0x0e, 0xd4, 0x0e, 0x64, 0x50, 0x57, 0x6a, 0x4a, + 0xbd, 0xb8, 0xb5, 0x62, 0xc9, 0x5c, 0x6b, 0x92, 0x6b, 0x6d, 0x07, 0x43, 0x47, 0x44, 0x68, 0x55, + 0xa0, 0x52, 0xfc, 0x09, 0xd2, 0x53, 0x35, 0xa5, 0xae, 0x34, 0xc1, 0xe9, 0xc8, 0x50, 0x36, 0x1f, + 0x9e, 0x1c, 0x6d, 0x28, 0x8e, 0xd8, 0xd7, 0x5e, 0x01, 0x6a, 0x17, 0xd2, 0xae, 0x9e, 0xae, 0x29, + 0xf5, 0x42, 0x73, 0xf9, 0xcf, 0x91, 0x91, 0x8b, 0x7a, 0x61, 0xc3, 0xdc, 0x34, 0x93, 0x28, 0xee, + 0xd5, 0x34, 0xa0, 0x1e, 0x46, 0xc4, 0xd7, 0x55, 0x1e, 0xe5, 0x88, 0x75, 0xa3, 0xf6, 0xd9, 0xd7, + 0xc6, 0xd2, 0xe7, 0x27, 0x47, 0x1b, 0x6b, 0x53, 0x12, 0x73, 0x5d, 0x9a, 0x0f, 0x53, 0x20, 0xbf, + 0x87, 0x3c, 0xe8, 0x0e, 0x5b, 0x03, 0x6d, 0x05, 0x64, 0x02, 0x12, 0xb8, 0x48, 0xf4, 0xac, 0x3a, + 0xd2, 0xd0, 0xde, 0x04, 0x05, 0x0f, 0x72, 0xbe, 0xd8, 0x95, 0x3d, 0x16, 0x9a, 0xe5, 0x5f, 0x46, + 0xc6, 0xaa, 0x44, 0x4d, 0x3b, 0x1f, 0x5b, 0x98, 0xd8, 0x3e, 0x64, 0x5d, 0xeb, 0x6e, 0xc0, 0x9c, + 0xbc, 0x07, 0xe9, 0x3d, 0x1e, 0xaa, 0x55, 0x41, 0xda, 0x83, 0x54, 0x74, 0xad, 0x36, 0x4b, 0xe3, + 0x91, 0x91, 0x7f, 0x07, 0xd2, 0x3d, 0xec, 0x63, 0xe6, 0x70, 0x87, 0xf6, 0x7f, 0x90, 0x62, 0x24, + 0x69, 0x37, 0xc5, 0x88, 0x76, 0x0b, 0x64, 0x62, 0xd8, 0xeb, 0x23, 0x3d, 0x23, 0xce, 0x78, 0xf9, + 0xc2, 0x33, 0xc6, 0x23, 0x23, 0xbb, 0xed, 0x93, 0x7e, 0xc0, 0x1c, 0x99, 0xc1, 0x7f, 0xbb, 0x60, + 0x9d, 0xad, 0x29, 0xf5, 0x52, 0x42, 0xb5, 0x04, 0x94, 0x58, 0xcf, 0x89, 0x0d, 0x25, 0xe6, 0x56, + 0xa4, 0xe7, 0xa5, 0x15, 0x71, 0x8b, 0xea, 0x05, 0x69, 0xd1, 0xc6, 0x0d, 0x4e, 0xe9, 0x87, 0x47, + 0x9b, 0xd9, 0xd6, 0x60, 0x07, 0x32, 0xc8, 0x79, 0x69, 0x53, 0x5e, 0x13, 0x3a, 0xe6, 0x28, 0x0d, + 0x4a, 0xdb, 0xae, 0x8b, 0x28, 0xdd, 0xc3, 0x94, 0xb5, 0x06, 0xda, 0xbb, 0x20, 0xef, 0x76, 0x21, + 0x0e, 0xda, 0xb8, 0x23, 0x88, 0x15, 0x9a, 0xf6, 0x65, 0x3d, 0xe7, 0x6e, 0xf3, 0xe0, 0xbb, 0x3b, + 0xa7, 0x23, 0x23, 0xe7, 0xca, 0xa5, 0x93, 0x2c, 0x3a, 0x53, 0xf4, 0xa9, 0x0b, 0xd1, 0xa7, 0xff, + 0x31, 0x7a, 0xf5, 0x72, 0xf4, 0x99, 0x45, 0xf4, 0xd9, 0x67, 0x46, 0x9f, 0x9b, 0x41, 0xff, 0x11, + 0xc8, 0x43, 0x01, 0x0a, 0x51, 0x3d, 0x5f, 0x4b, 0xd7, 0x8b, 0x5b, 0x2f, 0x59, 0xe7, 0xff, 0xc7, + 0x2d, 0x89, 0xb2, 0xd5, 0x0f, 0x7b, 0xa8, 0x79, 0xe3, 0xf1, 0xc8, 0x58, 0x3a, 0x1d, 0x19, 0x00, + 0x9e, 0xf1, 0xfd, 0xf6, 0x57, 0x03, 0x4c, 0x69, 0x4b, 0xa1, 0x9f, 0x55, 0x95, 0xc3, 0x2d, 0xcc, + 0x0d, 0x17, 0xcc, 0x0d, 0xb7, 0x38, 0x19, 0xee, 0xfa, 0xe2, 0x70, 0x5f, 0x98, 0x0e, 0x77, 0x76, + 0x9e, 0xe6, 0x57, 0x2a, 0x28, 0xed, 0x0c, 0x03, 0xe8, 0x63, 0xf7, 0x0e, 0x42, 0xff, 0xc9, 0x80, + 0x6f, 0x81, 0x22, 0x1f, 0x30, 0xc3, 0x61, 0xdb, 0x85, 0xe1, 0xd5, 0x23, 0xe6, 0x72, 0x68, 0xe1, + 0xf0, 0x36, 0x0c, 0x27, 0xa9, 0x87, 0x08, 0x89, 0x54, 0xf5, 0x69, 0x52, 0xef, 0x20, 0xc4, 0x53, + 0x13, 0x79, 0x64, 0x2e, 0x97, 0x47, 0x76, 0x51, 0x1e, 0xb9, 0x67, 0x96, 0x47, 0xfe, 0x02, 0x79, + 0x14, 0xfe, 0x3d, 0x79, 0x80, 0x39, 0x79, 0x14, 0xe7, 0xe4, 0x51, 0x7a, 0x3a, 0x79, 0xcc, 0xaa, + 0xc1, 0x34, 0x41, 0x65, 0x77, 0xc0, 0x50, 0x40, 0x31, 0x09, 0xde, 0x0b, 0xc5, 0xbb, 0x30, 0xbd, + 0x48, 0x1b, 0x2a, 0x2f, 0x64, 0x7e, 0xa3, 0x80, 0xd5, 0xb9, 0x0b, 0xd6, 0x41, 0x34, 0x24, 0x01, + 0x15, 0x20, 0xc4, 0x25, 0xae, 0xc8, 0xeb, 0x59, 0x5c, 0xd9, 0xeb, 0x40, 0xed, 0x11, 0x8f, 0xea, + 0x29, 0x01, 0x61, 0x75, 0x11, 0xc2, 0x1e, 0xf1, 0x1c, 0x11, 0xa2, 0x2d, 0x83, 0x74, 0x84, 0x98, + 0x10, 0x48, 0xc9, 0xe1, 0x4b, 0xad, 0x0c, 0xf2, 0xb1, 0xdf, 0x46, 0x51, 0x44, 0xa2, 0xe4, 0x12, + 0xcd, 0xc5, 0xfe, 0x2e, 0x37, 0xb9, 0x8b, 0x4b, 0xa3, 0x4f, 0x51, 0x47, 0x0e, 0xd9, 0xc9, 0x79, + 0x90, 0xde, 0xa7, 0xa8, 0x93, 0xb4, 0xf9, 0xbd, 0x02, 0x9e, 0xdb, 0xa7, 0xde, 0xfd, 0xb0, 0x03, + 0x19, 0xba, 0x07, 0x23, 0xe8, 0x53, 0x7e, 0xd7, 0xc0, 0x3e, 0xeb, 0x92, 0x08, 0xb3, 0x61, 0xa2, + 0x76, 0xfd, 0xc7, 0x47, 0x9b, 0x2b, 0xc9, 0x8b, 0xba, 0xdd, 0xe9, 0x44, 0x88, 0xd2, 0xf7, 0x59, + 0x84, 0x03, 0xcf, 0x99, 0x86, 0x6a, 0x6f, 0x81, 0x6c, 0x28, 0x2a, 0x08, 0x65, 0x17, 0xb7, 0xf4, + 0xc5, 0x9f, 0x21, 0x4f, 0x68, 0x16, 0xf8, 0x18, 0xe5, 0xa8, 0x92, 0x94, 0x86, 0xf5, 0xe0, 0xe4, + 0x68, 0x63, 0x5a, 0x8c, 0xe3, 0xbf, 0x86, 0x62, 0xfe, 0xce, 0x0f, 0xc4, 0x93, 0x7d, 0xae, 0x49, + 0xb3, 0x0c, 0xd6, 0xce, 0x6d, 0x4d, 0x00, 0x6f, 0xfd, 0xa1, 0x80, 0xf4, 0x3e, 0xf5, 0xb4, 0x21, + 0x00, 0x33, 0xaf, 0xb0, 0xb1, 0xd8, 0xcd, 0xdc, 0x7c, 0x2a, 0xaf, 0x5d, 0x11, 0x30, 0xa9, 0x6f, + 0x5e, 0x7f, 0xf0, 0xd3, 0xef, 0x5f, 0xa6, 0xae, 0x99, 0x65, 0x5b, 0x36, 0x38, 0xf9, 0xa2, 0x48, + 0x22, 0xdb, 0x6c, 0xa0, 0x7d, 0x08, 0x4a, 0x73, 0x48, 0xaf, 0xff, 0x6d, 0xed, 0xd9, 0x90, 0xca, + 0xfa, 0x95, 0x21, 0x93, 0x06, 0x2a, 0x99, 0x4f, 0x39, 0xba, 0xe6, 0xdb, 0x8f, 0xc7, 0x55, 0xe5, + 0xc9, 0xb8, 0xaa, 0xfc, 0x36, 0xae, 0x2a, 0x5f, 0x1c, 0x57, 0x97, 0x9e, 0x1c, 0x57, 0x97, 0x7e, + 0x3e, 0xae, 0x2e, 0x7d, 0xf0, 0xaa, 0x87, 0x59, 0xb7, 0x7f, 0x60, 0xb9, 0xc4, 0x9f, 0xf6, 0x48, + 0xa8, 0x1d, 0x6f, 0xbd, 0x9e, 0xe0, 0x64, 0xc3, 0x10, 0xd1, 0x83, 0xac, 0xf8, 0x06, 0x79, 0xe3, + 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x94, 0x7d, 0xc7, 0x93, 0x09, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // EthereumTx defines a method submitting Ethereum transactions. + EthereumTx(ctx context.Context, in *MsgEthereumTx, opts ...grpc.CallOption) (*MsgEthereumTxResponse, error) + // UpdateParams defined a governance operation for updating the x/evm module parameters. + // The authority is hard-coded to the Cosmos SDK x/gov module account + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) EthereumTx(ctx context.Context, in *MsgEthereumTx, opts ...grpc.CallOption) (*MsgEthereumTxResponse, error) { + out := new(MsgEthereumTxResponse) + err := c.cc.Invoke(ctx, "/ethermint.evm.v1.Msg/EthereumTx", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, "/ethermint.evm.v1.Msg/UpdateParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // EthereumTx defines a method submitting Ethereum transactions. + EthereumTx(context.Context, *MsgEthereumTx) (*MsgEthereumTxResponse, error) + // UpdateParams defined a governance operation for updating the x/evm module parameters. + // The authority is hard-coded to the Cosmos SDK x/gov module account + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) EthereumTx(ctx context.Context, req *MsgEthereumTx) (*MsgEthereumTxResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method EthereumTx not implemented") +} +func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_EthereumTx_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgEthereumTx) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).EthereumTx(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ethermint.evm.v1.Msg/EthereumTx", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).EthereumTx(ctx, req.(*MsgEthereumTx)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/ethermint.evm.v1.Msg/UpdateParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "ethermint.evm.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "EthereumTx", + Handler: _Msg_EthereumTx_Handler, + }, + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "ethermint/evm/v1/tx.proto", +} + +func (m *MsgEthereumTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgEthereumTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgEthereumTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.From) > 0 { + i -= len(m.From) + copy(dAtA[i:], m.From) + i = encodeVarintTx(dAtA, i, uint64(len(m.From))) + i-- + dAtA[i] = 0x22 + } + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintTx(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0x1a + } + if m.Size_ != 0 { + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.Size_)))) + i-- + dAtA[i] = 0x11 + } + if m.Data != nil { + { + size, err := m.Data.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *LegacyTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LegacyTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LegacyTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.S) > 0 { + i -= len(m.S) + copy(dAtA[i:], m.S) + i = encodeVarintTx(dAtA, i, uint64(len(m.S))) + i-- + dAtA[i] = 0x4a + } + if len(m.R) > 0 { + i -= len(m.R) + copy(dAtA[i:], m.R) + i = encodeVarintTx(dAtA, i, uint64(len(m.R))) + i-- + dAtA[i] = 0x42 + } + if len(m.V) > 0 { + i -= len(m.V) + copy(dAtA[i:], m.V) + i = encodeVarintTx(dAtA, i, uint64(len(m.V))) + i-- + dAtA[i] = 0x3a + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x32 + } + if m.Amount != nil { + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x22 + } + if m.GasLimit != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.GasLimit)) + i-- + dAtA[i] = 0x18 + } + if m.GasPrice != nil { + { + size := m.GasPrice.Size() + i -= size + if _, err := m.GasPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Nonce != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *AccessListTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AccessListTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessListTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.S) > 0 { + i -= len(m.S) + copy(dAtA[i:], m.S) + i = encodeVarintTx(dAtA, i, uint64(len(m.S))) + i-- + dAtA[i] = 0x5a + } + if len(m.R) > 0 { + i -= len(m.R) + copy(dAtA[i:], m.R) + i = encodeVarintTx(dAtA, i, uint64(len(m.R))) + i-- + dAtA[i] = 0x52 + } + if len(m.V) > 0 { + i -= len(m.V) + copy(dAtA[i:], m.V) + i = encodeVarintTx(dAtA, i, uint64(len(m.V))) + i-- + dAtA[i] = 0x4a + } + if len(m.Accesses) > 0 { + for iNdEx := len(m.Accesses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Accesses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x3a + } + if m.Amount != nil { + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x2a + } + if m.GasLimit != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.GasLimit)) + i-- + dAtA[i] = 0x20 + } + if m.GasPrice != nil { + { + size := m.GasPrice.Size() + i -= size + if _, err := m.GasPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Nonce != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x10 + } + if m.ChainID != nil { + { + size := m.ChainID.Size() + i -= size + if _, err := m.ChainID.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DynamicFeeTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DynamicFeeTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DynamicFeeTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.S) > 0 { + i -= len(m.S) + copy(dAtA[i:], m.S) + i = encodeVarintTx(dAtA, i, uint64(len(m.S))) + i-- + dAtA[i] = 0x62 + } + if len(m.R) > 0 { + i -= len(m.R) + copy(dAtA[i:], m.R) + i = encodeVarintTx(dAtA, i, uint64(len(m.R))) + i-- + dAtA[i] = 0x5a + } + if len(m.V) > 0 { + i -= len(m.V) + copy(dAtA[i:], m.V) + i = encodeVarintTx(dAtA, i, uint64(len(m.V))) + i-- + dAtA[i] = 0x52 + } + if len(m.Accesses) > 0 { + for iNdEx := len(m.Accesses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Accesses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x42 + } + if m.Amount != nil { + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x32 + } + if m.GasLimit != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.GasLimit)) + i-- + dAtA[i] = 0x28 + } + if m.GasFeeCap != nil { + { + size := m.GasFeeCap.Size() + i -= size + if _, err := m.GasFeeCap.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.GasTipCap != nil { + { + size := m.GasTipCap.Size() + i -= size + if _, err := m.GasTipCap.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Nonce != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x10 + } + if m.ChainID != nil { + { + size := m.ChainID.Size() + i -= size + if _, err := m.ChainID.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ExtensionOptionsEthereumTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExtensionOptionsEthereumTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExtensionOptionsEthereumTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgEthereumTxResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgEthereumTxResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgEthereumTxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.GasUsed != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.GasUsed)) + i-- + dAtA[i] = 0x28 + } + if len(m.VmError) > 0 { + i -= len(m.VmError) + copy(dAtA[i:], m.VmError) + i = encodeVarintTx(dAtA, i, uint64(len(m.VmError))) + i-- + dAtA[i] = 0x22 + } + if len(m.Ret) > 0 { + i -= len(m.Ret) + copy(dAtA[i:], m.Ret) + i = encodeVarintTx(dAtA, i, uint64(len(m.Ret))) + i-- + dAtA[i] = 0x1a + } + if len(m.Logs) > 0 { + for iNdEx := len(m.Logs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Logs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintTx(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgEthereumTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Data != nil { + l = m.Data.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.Size_ != 0 { + n += 9 + } + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.From) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *LegacyTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Nonce != 0 { + n += 1 + sovTx(uint64(m.Nonce)) + } + if m.GasPrice != nil { + l = m.GasPrice.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasLimit != 0 { + n += 1 + sovTx(uint64(m.GasLimit)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Amount != nil { + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.V) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.R) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.S) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *AccessListTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainID != nil { + l = m.ChainID.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.Nonce != 0 { + n += 1 + sovTx(uint64(m.Nonce)) + } + if m.GasPrice != nil { + l = m.GasPrice.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasLimit != 0 { + n += 1 + sovTx(uint64(m.GasLimit)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Amount != nil { + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Accesses) > 0 { + for _, e := range m.Accesses { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + l = len(m.V) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.R) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.S) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *DynamicFeeTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainID != nil { + l = m.ChainID.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.Nonce != 0 { + n += 1 + sovTx(uint64(m.Nonce)) + } + if m.GasTipCap != nil { + l = m.GasTipCap.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasFeeCap != nil { + l = m.GasFeeCap.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasLimit != 0 { + n += 1 + sovTx(uint64(m.GasLimit)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Amount != nil { + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Accesses) > 0 { + for _, e := range m.Accesses { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + l = len(m.V) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.R) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.S) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *ExtensionOptionsEthereumTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgEthereumTxResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Logs) > 0 { + for _, e := range m.Logs { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + l = len(m.Ret) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.VmError) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.GasUsed != 0 { + n += 1 + sovTx(uint64(m.GasUsed)) + } + return n +} + +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgEthereumTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgEthereumTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgEthereumTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Data == nil { + m.Data = &types.Any{} + } + if err := m.Data.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field Size_", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.Size_ = float64(math.Float64frombits(v)) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field From", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.From = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LegacyTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LegacyTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LegacyTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.GasPrice = &v + if err := m.GasPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType) + } + m.GasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.Amount = &v + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field V", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.V = append(m.V[:0], dAtA[iNdEx:postIndex]...) + if m.V == nil { + m.V = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field R", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.R = append(m.R[:0], dAtA[iNdEx:postIndex]...) + if m.R == nil { + m.R = []byte{} + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field S", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.S = append(m.S[:0], dAtA[iNdEx:postIndex]...) + if m.S == nil { + m.S = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AccessListTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AccessListTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessListTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.ChainID = &v + if err := m.ChainID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.GasPrice = &v + if err := m.GasPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType) + } + m.GasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.Amount = &v + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Accesses", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Accesses = append(m.Accesses, AccessTuple{}) + if err := m.Accesses[len(m.Accesses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field V", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.V = append(m.V[:0], dAtA[iNdEx:postIndex]...) + if m.V == nil { + m.V = []byte{} + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field R", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.R = append(m.R[:0], dAtA[iNdEx:postIndex]...) + if m.R == nil { + m.R = []byte{} + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field S", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.S = append(m.S[:0], dAtA[iNdEx:postIndex]...) + if m.S == nil { + m.S = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DynamicFeeTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DynamicFeeTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DynamicFeeTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.ChainID = &v + if err := m.ChainID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasTipCap", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.GasTipCap = &v + if err := m.GasTipCap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasFeeCap", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.GasFeeCap = &v + if err := m.GasFeeCap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType) + } + m.GasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v cosmossdk_io_math.Int + m.Amount = &v + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Accesses", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Accesses = append(m.Accesses, AccessTuple{}) + if err := m.Accesses[len(m.Accesses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field V", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.V = append(m.V[:0], dAtA[iNdEx:postIndex]...) + if m.V == nil { + m.V = []byte{} + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field R", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.R = append(m.R[:0], dAtA[iNdEx:postIndex]...) + if m.R == nil { + m.R = []byte{} + } + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field S", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.S = append(m.S[:0], dAtA[iNdEx:postIndex]...) + if m.S == nil { + m.S = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ExtensionOptionsEthereumTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExtensionOptionsEthereumTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExtensionOptionsEthereumTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgEthereumTxResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgEthereumTxResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgEthereumTxResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Logs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Logs = append(m.Logs, &Log{}) + if err := m.Logs[len(m.Logs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ret", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Ret = append(m.Ret[:0], dAtA[iNdEx:postIndex]...) + if m.Ret == nil { + m.Ret = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VmError", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.VmError = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasUsed", wireType) + } + m.GasUsed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasUsed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/rpc/types/legacy/tx_data.go b/rpc/types/legacy/tx_data.go new file mode 100644 index 000000000..81ad1e521 --- /dev/null +++ b/rpc/types/legacy/tx_data.go @@ -0,0 +1,80 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +var ( + _ TxData = &LegacyTx{} + _ TxData = &AccessListTx{} + _ TxData = &DynamicFeeTx{} +) + +// TxData implements the Ethereum transaction tx structure. It is used +// solely as intended in Ethereum abiding by the protocol. +type TxData interface { + TxType() byte + Copy() TxData + GetChainID() *big.Int + GetAccessList() ethtypes.AccessList + GetData() []byte + GetNonce() uint64 + GetGas() uint64 + GetGasPrice() *big.Int + GetGasTipCap() *big.Int + GetGasFeeCap() *big.Int + GetValue() *big.Int + GetTo() *common.Address + + GetRawSignatureValues() (v, r, s *big.Int) + SetSignatureValues(chainID, v, r, s *big.Int) + + AsEthereumData() ethtypes.TxData + Validate() error + + // static fee + Fee() *big.Int + Cost() *big.Int + + // effective gasPrice/fee/cost according to current base fee + EffectiveGasPrice(baseFee *big.Int) *big.Int + EffectiveFee(baseFee *big.Int) *big.Int + EffectiveCost(baseFee *big.Int) *big.Int +} + +// NOTE: All non-protected transactions (i.e non EIP155 signed) will fail if the +// AllowUnprotectedTxs parameter is disabled. +func NewTxDataFromTx(tx *ethtypes.Transaction) (TxData, error) { + var txData TxData + var err error + switch tx.Type() { + case ethtypes.DynamicFeeTxType: + txData, err = NewDynamicFeeTx(tx) + case ethtypes.AccessListTxType: + txData, err = newAccessListTx(tx) + default: + txData, err = NewLegacyTx(tx) + } + if err != nil { + return nil, err + } + + return txData, nil +} + +func fee(gasPrice *big.Int, gas uint64) *big.Int { + gasLimit := new(big.Int).SetUint64(gas) + return new(big.Int).Mul(gasPrice, gasLimit) +} + +func cost(fee, value *big.Int) *big.Int { + if value != nil { + return new(big.Int).Add(fee, value) + } + return fee +} diff --git a/rpc/types/legacy/utils.go b/rpc/types/legacy/utils.go new file mode 100644 index 000000000..196758cdf --- /dev/null +++ b/rpc/types/legacy/utils.go @@ -0,0 +1,84 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "fmt" + "math/big" + + sdkmath "cosmossdk.io/math" +) + +const maxBitLen = 256 + +// SafeNewIntFromBigInt constructs Int from big.Int, return error if more than 256bits +func SafeNewIntFromBigInt(i *big.Int) (sdkmath.Int, error) { + if !IsValidInt256(i) { + return sdkmath.NewInt(0), fmt.Errorf("big int out of bound: %s", i) + } + return sdkmath.NewIntFromBigInt(i), nil +} + +// IsValidInt256 check the bound of 256 bit number +func IsValidInt256(i *big.Int) bool { + return i == nil || i.BitLen() <= maxBitLen +} + +// DeriveChainID derives the chain id from the given v parameter. +// +// CONTRACT: v value is either: +// +// - {0,1} + CHAIN_ID * 2 + 35, if EIP155 is used +// - {0,1} + 27, otherwise +// +// Ref: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md +func DeriveChainID(v *big.Int) *big.Int { + if v == nil || v.Sign() < 1 { + return nil + } + + if v.BitLen() <= 64 { + v := v.Uint64() + if v == 27 || v == 28 { + return new(big.Int) + } + + if v < 35 { + return nil + } + + // V MUST be of the form {0,1} + CHAIN_ID * 2 + 35 + return new(big.Int).SetUint64((v - 35) / 2) + } + v = new(big.Int).Sub(v, big.NewInt(35)) + return v.Div(v, big.NewInt(2)) +} + +// RawSignatureValues is a helper function +// that parses the v,r and s fields of an Ethereum transaction +func RawSignatureValues(vBz, rBz, sBz []byte) (v, r, s *big.Int) { + if len(vBz) > 0 { + v = new(big.Int).SetBytes(vBz) + } + if len(rBz) > 0 { + r = new(big.Int).SetBytes(rBz) + } + if len(sBz) > 0 { + s = new(big.Int).SetBytes(sBz) + } + return v, r, s +} + +// EffectiveGasPrice computes the effective gas price based on eip-1559 rules +// `effectiveGasPrice = min(baseFee + tipCap, feeCap)` +func EffectiveGasPrice(baseFee, feeCap, tipCap *big.Int) *big.Int { + return bigMin(new(big.Int).Add(tipCap, baseFee), feeCap) +} + +// bigMin returns the smaller of a and b +func bigMin(a, b *big.Int) *big.Int { + if a.Cmp(b) < 0 { + return a + } + return b +} diff --git a/rpc/types/legacy/validation.go b/rpc/types/legacy/validation.go new file mode 100644 index 000000000..d25214767 --- /dev/null +++ b/rpc/types/legacy/validation.go @@ -0,0 +1,22 @@ +// Copyright Tharsis Labs Ltd.(Evmos) +// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE) +package types + +import ( + "github.com/ethereum/go-ethereum/common" + + errorsmod "cosmossdk.io/errors" + + errortypes "github.com/cosmos/cosmos-sdk/types/errors" +) + +// ValidateAddress returns an error if the provided string is either not a hex formatted string address +func ValidateAddress(address string) error { + if !common.IsHexAddress(address) { + return errorsmod.Wrapf( + errortypes.ErrInvalidAddress, "address '%s' is not a valid ethereum hex address", + address, + ) + } + return nil +} diff --git a/rpc/types/types_test.go b/rpc/types/types_test.go index 33360236e..c2aca1692 100644 --- a/rpc/types/types_test.go +++ b/rpc/types/types_test.go @@ -27,7 +27,7 @@ func (p *precompileContract) Run(evm *vm.EVM, contract *vm.Contract, readonly bo func TestApply(t *testing.T) { emptyTxConfig := statedb.NewEmptyTxConfig() - db := statedb.New(sdk.Context{}, mocks.NewEVMKeeper(), emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), mocks.NewEVMKeeper(), emptyTxConfig) precompiles := map[common.Address]vm.PrecompiledContract{ common.BytesToAddress([]byte{0x1}): &precompileContract{}, common.BytesToAddress([]byte{0x2}): &precompileContract{}, diff --git a/tests/integration/precompiles/erc20/test_burn.go b/tests/integration/precompiles/erc20/test_burn.go new file mode 100644 index 000000000..88b193c24 --- /dev/null +++ b/tests/integration/precompiles/erc20/test_burn.go @@ -0,0 +1,94 @@ +package erc20 + +import ( + "math/big" + + utiltx "github.com/cosmos/evm/testutil/tx" + "github.com/cosmos/evm/x/erc20/types" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (suite *PrecompileTestSuite) TestBurnCoins() { + var ctx sdk.Context + sender := sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + expPair := types.NewTokenPair(utiltx.GenerateAddress(), "coin", types.OWNER_MODULE) + expPair.SetOwnerAddress(sender.String()) + amount := big.NewInt(1000000) + id := expPair.GetID() + + testcases := []struct { + name string + malleate func() + postCheck func() + expErr bool + errContains string + }{ + { + name: "fail - token pair not found", + malleate: func() { + params := types.DefaultParams() + params.EnableErc20 = true + suite.network.App.GetErc20Keeper().SetParams(ctx, params) //nolint:errcheck + }, + postCheck: func() {}, + expErr: true, + errContains: "", + }, + { + "fail - pair is not native coin", + func() { + expPair.ContractOwner = types.OWNER_EXTERNAL + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + }, + func() {}, + true, + types.ErrNonNativeCoinBurningDisabled.Error(), + }, + { + "pass", + func() { + expPair.ContractOwner = types.OWNER_MODULE + if err := suite.network.App.GetBankKeeper().MintCoins(ctx, types.ModuleName, sdk.Coins{{Denom: expPair.Denom, Amount: math.NewIntFromBigInt(amount)}}); err != nil { + suite.FailNow(err.Error()) + } + if err := suite.network.App.GetBankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, sdk.Coins{{Denom: expPair.Denom, Amount: math.NewIntFromBigInt(amount)}}); err != nil { + suite.FailNow(err.Error()) + } + expPair.SetOwnerAddress(sender.String()) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + }, + func() { + balance := suite.network.App.GetBankKeeper().GetBalance(ctx, sender, expPair.Denom) + suite.Require().Equal(balance.Amount.Int64(), math.NewInt(0).Int64()) + }, + false, + "", + }, + } + + for _, tc := range testcases { + suite.Run(tc.name, func() { + suite.SetupTest() + + ctx = suite.network.GetContext() + + tc.malleate() + + err := suite.network.App.GetErc20Keeper().BurnCoins(ctx, sender, math.NewIntFromBigInt(amount), expPair.Erc20Address) + if tc.expErr { + suite.Require().Error(err, "expected transfer transaction to fail") + suite.Require().Contains(err.Error(), tc.errContains, "expected transfer transaction to fail with specific error") + } else { + suite.Require().NoError(err, "expected transfer transaction succeeded") + tc.postCheck() + } + }) + } +} diff --git a/tests/integration/precompiles/erc20/test_erc20.go b/tests/integration/precompiles/erc20/test_erc20.go index 227ac20a2..d5bbb4dce 100644 --- a/tests/integration/precompiles/erc20/test_erc20.go +++ b/tests/integration/precompiles/erc20/test_erc20.go @@ -20,6 +20,10 @@ func (s *PrecompileTestSuite) TestIsTransaction() { s.Require().False(s.precompile.IsTransaction(&method)) method = s.precompile.Methods[erc20.TotalSupplyMethod] s.Require().False(s.precompile.IsTransaction(&method)) + method = s.precompile.Methods[erc20.AllowanceMethod] + s.Require().False(s.precompile.IsTransaction(&method)) + method = s.precompile.Methods[erc20.OwnerMethod] + s.Require().False(s.precompile.IsTransaction(&method)) // Transactions method = s.precompile.Methods[erc20.ApproveMethod] @@ -28,6 +32,16 @@ func (s *PrecompileTestSuite) TestIsTransaction() { s.Require().True(s.precompile.IsTransaction(&method)) method = s.precompile.Methods[erc20.TransferFromMethod] s.Require().True(s.precompile.IsTransaction(&method)) + method = s.precompile.Methods[erc20.MintMethod] + s.Require().True(s.precompile.IsTransaction(&method)) + method = s.precompile.Methods[erc20.BurnMethod] + s.Require().True(s.precompile.IsTransaction(&method)) + method = s.precompile.Methods[erc20.BurnFromMethod] + s.Require().True(s.precompile.IsTransaction(&method)) + method = s.precompile.Methods[erc20.Burn0Method] + s.Require().True(s.precompile.IsTransaction(&method)) + method = s.precompile.Methods[erc20.TransferOwnershipMethod] + s.Require().True(s.precompile.IsTransaction(&method)) } func (s *PrecompileTestSuite) TestRequiredGas() { diff --git a/tests/integration/precompiles/erc20/test_mint.go b/tests/integration/precompiles/erc20/test_mint.go new file mode 100644 index 000000000..284da6bd0 --- /dev/null +++ b/tests/integration/precompiles/erc20/test_mint.go @@ -0,0 +1,264 @@ +package erc20 + +import ( + "fmt" + "math/big" + + utiltx "github.com/cosmos/evm/testutil/tx" + "github.com/cosmos/evm/x/erc20/types" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func (suite *PrecompileTestSuite) TestMintingEnabled() { + var ctx sdk.Context + receiver := sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + expPair := types.NewTokenPair(utiltx.GenerateAddress(), "coin", types.OWNER_MODULE) + id := expPair.GetID() + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "conversion is disabled globally", + func() { + params := types.DefaultParams() + params.EnableErc20 = false + suite.network.App.GetErc20Keeper().SetParams(ctx, params) //nolint:errcheck + }, + false, + }, + { + "token pair not found", + func() {}, + false, + }, + { + "conversion is disabled for the given pair", + func() { + expPair.Enabled = false + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + }, + false, + }, + { + "token transfers are disabled", + func() { + expPair.Enabled = true + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + + suite.network.App.GetBankKeeper().SetSendEnabled(ctx, expPair.Denom, false) + }, + false, + }, + { + "token not registered", + func() { + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + }, + false, + }, + { + "receiver address is blocked (module account)", + func() { + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + + acc := suite.network.App.GetAccountKeeper().GetModuleAccount(ctx, types.ModuleName) + receiver = acc.GetAddress() + }, + false, + }, + { + "ok", + func() { + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + + receiver = sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + ctx = suite.network.GetContext() + + tc.malleate() + + pair, err := suite.network.App.GetErc20Keeper().MintingEnabled(ctx, receiver, expPair.Erc20Address) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expPair, pair) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *PrecompileTestSuite) TestMintCoins() { + var ctx sdk.Context + sender := sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + to := sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + expPair := types.NewTokenPair(utiltx.GenerateAddress(), "coin", types.OWNER_MODULE) + expPair.SetOwnerAddress(sender.String()) + amount := big.NewInt(1000000) + id := expPair.GetID() + + testcases := []struct { + name string + malleate func() + postCheck func() + expErr bool + errContains string + }{ + { + "fail - conversion is disabled globally", + func() { + params := types.DefaultParams() + params.EnableErc20 = false + suite.network.App.GetErc20Keeper().SetParams(ctx, params) //nolint:errcheck + }, + func() {}, + true, + "", + }, + { + "fail - token pair not found", + func() {}, + func() {}, + true, + "", + }, + { + "fail - conversion is disabled for the given pair", + func() { + expPair.Enabled = false + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + }, + func() {}, + true, + "", + }, + { + "fail - token transfers are disabled", + func() { + expPair.Enabled = true + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + + params := banktypes.DefaultParams() + params.SendEnabled = []*banktypes.SendEnabled{ + {Denom: expPair.Denom, Enabled: false}, + } + err := suite.network.App.GetBankKeeper().SetParams(ctx, params) + suite.Require().NoError(err) + }, + func() {}, + true, + "", + }, + { + "fail - token not registered", + func() { + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + }, + func() {}, + true, + "", + }, + { + "fail - receiver address is blocked (module account)", + func() { + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + + acc := suite.network.App.GetAccountKeeper().GetModuleAccount(ctx, types.ModuleName) + to = acc.GetAddress() + }, + func() {}, + true, + "", + }, + { + "fail - pair is not native coin", + func() { + expPair.ContractOwner = types.OWNER_EXTERNAL + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + + to = sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + }, + func() {}, + true, + types.ErrNonNativeCoinMintingDisabled.Error(), + }, + { + "fail - minter is not the owner", + func() { + expPair.ContractOwner = types.OWNER_MODULE + expPair.SetOwnerAddress(sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String()) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + }, + func() {}, + true, + types.ErrMinterIsNotOwner.Error(), + }, + { + "pass", + func() { + expPair.SetOwnerAddress(sender.String()) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, expPair) + suite.network.App.GetErc20Keeper().SetDenomMap(ctx, expPair.Denom, id) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, expPair.GetERC20Contract(), id) + + to = sdk.AccAddress(utiltx.GenerateAddress().Bytes()) + }, + func() {}, + false, + "", + }, + } + + for _, tc := range testcases { + suite.Run(tc.name, func() { + suite.SetupTest() + + ctx = suite.network.GetContext() + + tc.malleate() + + err := suite.network.App.GetErc20Keeper().MintCoins(ctx, sender, to, math.NewIntFromBigInt(amount), expPair.Erc20Address) + if tc.expErr { + suite.Require().Error(err, "expected transfer transaction to fail") + suite.Require().Contains(err.Error(), tc.errContains, "expected transfer transaction to fail with specific error") + } else { + suite.Require().NoError(err, "expected transfer transaction succeeded") + tc.postCheck() + } + }) + } +} diff --git a/tests/integration/precompiles/erc20/test_params.go b/tests/integration/precompiles/erc20/test_params.go new file mode 100644 index 000000000..e40f60ec3 --- /dev/null +++ b/tests/integration/precompiles/erc20/test_params.go @@ -0,0 +1,38 @@ +package erc20 + +import ( + "github.com/cosmos/evm/x/erc20/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (suite *PrecompileTestSuite) TestParams() { + var ctx sdk.Context + + testCases := []struct { + name string + paramsFun func() interface{} + getFun func() interface{} + expected bool + }{ + { + "success - Checks if the default params are set correctly", + func() interface{} { + return types.DefaultParams() + }, + func() interface{} { + return suite.network.App.GetErc20Keeper().GetParams(ctx) + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + suite.SetupTest() + ctx = suite.network.GetContext() + + suite.Require().Equal(tc.paramsFun(), tc.getFun()) + }) + } +} diff --git a/tests/integration/precompiles/erc20/test_query.go b/tests/integration/precompiles/erc20/test_query.go index f462bc2c1..580a7f7c4 100644 --- a/tests/integration/precompiles/erc20/test_query.go +++ b/tests/integration/precompiles/erc20/test_query.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/evm/precompiles/erc20" "github.com/cosmos/evm/testutil" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" + transferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" sdkmath "cosmossdk.io/math" diff --git a/tests/integration/precompiles/erc20/test_token_pairs.go b/tests/integration/precompiles/erc20/test_token_pairs.go new file mode 100644 index 000000000..ad1565515 --- /dev/null +++ b/tests/integration/precompiles/erc20/test_token_pairs.go @@ -0,0 +1,492 @@ +package erc20 + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + + testconstants "github.com/cosmos/evm/testutil/constants" + utiltx "github.com/cosmos/evm/testutil/tx" + "github.com/cosmos/evm/x/erc20/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (suite *PrecompileTestSuite) TestGetTokenPairs() { + var ( + ctx sdk.Context + expRes []types.TokenPair + ) + + testCases := []struct { + name string + malleate func() + }{ + { + "no pair registered", func() { + // Account for the token pair created during SetupTest() + expRes = testconstants.ExampleTokenPairs + // Get the token pair created during setup + tokenPairID := suite.network.App.GetErc20Keeper().GetDenomMap(suite.network.GetContext(), suite.tokenDenom) + if tokenPairID != nil { + tokenPair, found := suite.network.App.GetErc20Keeper().GetTokenPair(suite.network.GetContext(), tokenPairID) + if found { + expRes = append(expRes, tokenPair) + } + } + }, + }, + { + "1 pair registered", + func() { + pair := types.NewTokenPair(utiltx.GenerateAddress(), "coin", types.OWNER_MODULE) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + expRes = testconstants.ExampleTokenPairs + // Get the token pair created during setup + tokenPairID := suite.network.App.GetErc20Keeper().GetDenomMap(suite.network.GetContext(), suite.tokenDenom) + if tokenPairID != nil { + tokenPair, found := suite.network.App.GetErc20Keeper().GetTokenPair(suite.network.GetContext(), tokenPairID) + if found { + expRes = append(expRes, tokenPair) + } + } + expRes = append(expRes, pair) + }, + }, + { + "2 pairs registered", + func() { + pair := types.NewTokenPair(utiltx.GenerateAddress(), "coin", types.OWNER_MODULE) + pair2 := types.NewTokenPair(utiltx.GenerateAddress(), "coin2", types.OWNER_MODULE) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair2) + expRes = testconstants.ExampleTokenPairs + // Get the token pair created during setup + tokenPairID := suite.network.App.GetErc20Keeper().GetDenomMap(suite.network.GetContext(), suite.tokenDenom) + if tokenPairID != nil { + tokenPair, found := suite.network.App.GetErc20Keeper().GetTokenPair(suite.network.GetContext(), tokenPairID) + if found { + expRes = append(expRes, tokenPair) + } + } + expRes = append(expRes, []types.TokenPair{pair, pair2}...) + }, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + ctx = suite.network.GetContext() + + tc.malleate() + res := suite.network.App.GetErc20Keeper().GetTokenPairs(ctx) + + suite.Require().ElementsMatch(expRes, res, tc.name) + }) + } +} + +func (suite *PrecompileTestSuite) TestGetTokenPairID() { + baseDenom, err := sdk.GetBaseDenom() + suite.Require().NoError(err, "failed to get base denom") + + pair := types.NewTokenPair(utiltx.GenerateAddress(), baseDenom, types.OWNER_MODULE) + + testCases := []struct { + name string + token string + expID []byte + }{ + {"nil token", "", nil}, + {"valid hex token", utiltx.GenerateAddress().Hex(), []byte{}}, + {"valid hex token", utiltx.GenerateAddress().String(), []byte{}}, + } + for _, tc := range testCases { + suite.SetupTest() + ctx := suite.network.GetContext() + + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + + id := suite.network.App.GetErc20Keeper().GetTokenPairID(ctx, tc.token) + if id != nil { + suite.Require().Equal(tc.expID, id, tc.name) + } else { + suite.Require().Nil(id) + } + } +} + +func (suite *PrecompileTestSuite) TestGetTokenPair() { + baseDenom, err := sdk.GetBaseDenom() + suite.Require().NoError(err, "failed to get base denom") + + pair := types.NewTokenPair(utiltx.GenerateAddress(), baseDenom, types.OWNER_MODULE) + + testCases := []struct { + name string + id []byte + ok bool + }{ + {"nil id", nil, false}, + {"valid id", pair.GetID(), true}, + {"pair not found", []byte{}, false}, + } + for _, tc := range testCases { + suite.SetupTest() + ctx := suite.network.GetContext() + + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + p, found := suite.network.App.GetErc20Keeper().GetTokenPair(ctx, tc.id) + if tc.ok { + suite.Require().True(found, tc.name) + suite.Require().Equal(pair, p, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} + +func (suite *PrecompileTestSuite) TestDeleteTokenPair() { + tokenDenom := "random" + + var ctx sdk.Context + pair := types.NewTokenPair(utiltx.GenerateAddress(), tokenDenom, types.OWNER_MODULE) + id := pair.GetID() + + testCases := []struct { + name string + id []byte + malleate func() + ok bool + }{ + {"nil id", nil, func() {}, false}, + {"pair not found", []byte{}, func() {}, false}, + {"valid id", id, func() {}, true}, + { + "delete tokenpair", + id, + func() { + suite.network.App.GetErc20Keeper().DeleteTokenPair(ctx, pair) + }, + false, + }, + } + for _, tc := range testCases { + suite.SetupTest() + ctx = suite.network.GetContext() + err := suite.network.App.GetErc20Keeper().SetToken(ctx, pair) + suite.Require().NoError(err) + + tc.malleate() + p, found := suite.network.App.GetErc20Keeper().GetTokenPair(ctx, tc.id) + if tc.ok { + suite.Require().True(found, tc.name) + suite.Require().Equal(pair, p, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} + +func (suite *PrecompileTestSuite) TestIsTokenPairRegistered() { + baseDenom, err := sdk.GetBaseDenom() + suite.Require().NoError(err, "failed to get base denom") + + var ctx sdk.Context + pair := types.NewTokenPair(utiltx.GenerateAddress(), baseDenom, types.OWNER_MODULE) + + testCases := []struct { + name string + id []byte + ok bool + }{ + {"valid id", pair.GetID(), true}, + {"pair not found", []byte{}, false}, + } + for _, tc := range testCases { + suite.SetupTest() + ctx = suite.network.GetContext() + + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + found := suite.network.App.GetErc20Keeper().IsTokenPairRegistered(ctx, tc.id) + if tc.ok { + suite.Require().True(found, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} + +func (suite *PrecompileTestSuite) TestIsERC20Registered() { + var ctx sdk.Context + addr := utiltx.GenerateAddress() + pair := types.NewTokenPair(addr, "coin", types.OWNER_MODULE) + + testCases := []struct { + name string + erc20 common.Address + malleate func() + ok bool + }{ + {"nil erc20 address", common.Address{}, func() {}, false}, + {"valid erc20 address", pair.GetERC20Contract(), func() {}, true}, + { + "deleted erc20 map", + pair.GetERC20Contract(), + func() { + suite.network.App.GetErc20Keeper().DeleteTokenPair(ctx, pair) + }, + false, + }, + } + for _, tc := range testCases { + suite.SetupTest() + ctx = suite.network.GetContext() + + err := suite.network.App.GetErc20Keeper().SetToken(ctx, pair) + suite.Require().NoError(err) + + tc.malleate() + + found := suite.network.App.GetErc20Keeper().IsERC20Registered(ctx, tc.erc20) + + if tc.ok { + suite.Require().True(found, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} + +func (suite *PrecompileTestSuite) TestIsDenomRegistered() { + var ctx sdk.Context + addr := utiltx.GenerateAddress() + pair := types.NewTokenPair(addr, "coin", types.OWNER_MODULE) + + testCases := []struct { + name string + denom string + malleate func() + ok bool + }{ + {"empty denom", "", func() {}, false}, + {"valid denom", pair.GetDenom(), func() {}, true}, + { + "deleted denom map", + pair.GetDenom(), + func() { + suite.network.App.GetErc20Keeper().DeleteTokenPair(ctx, pair) + }, + false, + }, + } + for _, tc := range testCases { + suite.SetupTest() + ctx = suite.network.GetContext() + + err := suite.network.App.GetErc20Keeper().SetToken(ctx, pair) + suite.Require().NoError(err) + + tc.malleate() + + found := suite.network.App.GetErc20Keeper().IsDenomRegistered(ctx, tc.denom) + + if tc.ok { + suite.Require().True(found, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} + +func (suite *PrecompileTestSuite) TestGetTokenDenom() { + var ctx sdk.Context + tokenAddress := utiltx.GenerateAddress() + tokenDenom := "token" + + testCases := []struct { + name string + tokenDenom string + malleate func() + expError bool + errContains string + }{ + { + "denom found", + tokenDenom, + func() { + pair := types.NewTokenPair(tokenAddress, tokenDenom, types.OWNER_MODULE) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, tokenAddress, pair.GetID()) + }, + true, + "", + }, + { + "denom not found", + tokenDenom, + func() { + address := utiltx.GenerateAddress() + pair := types.NewTokenPair(address, tokenDenom, types.OWNER_MODULE) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, address, pair.GetID()) + }, + false, + fmt.Sprintf("token '%s' not registered", tokenAddress), + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() + ctx = suite.network.GetContext() + + tc.malleate() + res, err := suite.network.App.GetErc20Keeper().GetTokenDenom(ctx, tokenAddress) + + if tc.expError { + suite.Require().NoError(err) + suite.Require().Equal(res, tokenDenom) + } else { + suite.Require().Error(err, "expected an error while getting the token denom") + suite.Require().ErrorContains(err, tc.errContains) + } + }) + } +} + +func (suite *PrecompileTestSuite) TestSetToken() { + testCases := []struct { + name string + pair1 types.TokenPair + pair2 types.TokenPair + expError bool + }{ + {"same denom", types.NewTokenPair(common.HexToAddress("0x1"), "denom1", types.OWNER_MODULE), types.NewTokenPair(common.HexToAddress("0x2"), "denom1", types.OWNER_MODULE), true}, + {"same erc20", types.NewTokenPair(common.HexToAddress("0x1"), "denom1", types.OWNER_MODULE), types.NewTokenPair(common.HexToAddress("0x1"), "denom2", types.OWNER_MODULE), true}, + {"same pair", types.NewTokenPair(common.HexToAddress("0x1"), "denom1", types.OWNER_MODULE), types.NewTokenPair(common.HexToAddress("0x1"), "denom1", types.OWNER_MODULE), true}, + {"two different pairs", types.NewTokenPair(common.HexToAddress("0x1"), "denom1", types.OWNER_MODULE), types.NewTokenPair(common.HexToAddress("0x2"), "denom2", types.OWNER_MODULE), false}, + } + for _, tc := range testCases { + suite.SetupTest() + ctx := suite.network.GetContext() + + err := suite.network.App.GetErc20Keeper().SetToken(ctx, tc.pair1) + suite.Require().NoError(err) + err = suite.network.App.GetErc20Keeper().SetToken(ctx, tc.pair2) + if tc.expError { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + } + } +} + +func (suite *PrecompileTestSuite) TestGetTokenPairOwnerAddress() { + var ctx sdk.Context + + tokenAddress := utiltx.GenerateAddress() + ownerAddress := utiltx.GenerateAddress() + testCases := []struct { + name string + ownerAddress sdk.AccAddress + malleate func() + expError bool + errContains string + }{ + { + "owner address found", + sdk.AccAddress(ownerAddress.Bytes()), + func() { + pair := types.NewTokenPair(tokenAddress, "coin", types.OWNER_MODULE) + pair.SetOwnerAddress(sdk.AccAddress(ownerAddress.Bytes()).String()) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, tokenAddress, pair.GetID()) + }, + true, + "", + }, + { + "owner address not found", + sdk.AccAddress(utiltx.GenerateAddress().Bytes()), + func() { + address := utiltx.GenerateAddress() + pair := types.NewTokenPair(address, "coin", types.OWNER_MODULE) + pair.SetOwnerAddress(sdk.AccAddress(address.Bytes()).String()) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, address, pair.GetID()) + }, + false, + fmt.Sprintf("token '%s' not registered", tokenAddress), + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + ctx = suite.network.GetContext() + + tc.malleate() + res, err := suite.network.App.GetErc20Keeper().GetTokenPairOwnerAddress(ctx, tokenAddress.Hex()) + + if tc.expError { + suite.Require().NoError(err) + suite.Require().Equal(res.String(), tc.ownerAddress.String()) + } else { + suite.Require().Error(err, "expected an error while getting the token denom") + suite.Require().ErrorContains(err, tc.errContains) + } + }) + } +} + +func (suite *PrecompileTestSuite) TestSetTokenPairOwnerAddress() { + var ctx sdk.Context + tokenAddress := utiltx.GenerateAddress() + newOwnerAddress := utiltx.GenerateAddress() + + testCases := []struct { + name string + newOwnerAddress sdk.AccAddress + malleate func() types.TokenPair + postCheck func(*types.TokenPair, string) error + expError bool + errContains string + }{ + { + "owner address set", + sdk.AccAddress(newOwnerAddress.Bytes()), + func() types.TokenPair { + pair := types.NewTokenPair(tokenAddress, "coin", types.OWNER_MODULE) + pair.SetOwnerAddress(sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String()) + suite.network.App.GetErc20Keeper().SetTokenPair(ctx, pair) + suite.network.App.GetErc20Keeper().SetERC20Map(ctx, tokenAddress, pair.GetID()) + return pair + }, + func(tp *types.TokenPair, expectedNewOwner string) error { + pair, found := suite.network.App.GetErc20Keeper().GetTokenPair(ctx, tp.GetID()) + if !found { + return fmt.Errorf("token pair not found") + } + + if pair.OwnerAddress != expectedNewOwner { + return fmt.Errorf("owner address mismatch: expected %s, got %s", expectedNewOwner, pair.OwnerAddress) + } + return nil + }, + true, + "", + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + ctx = suite.network.GetContext() + + pair := tc.malleate() + suite.network.App.GetErc20Keeper().SetTokenPairOwnerAddress(ctx, pair, tc.newOwnerAddress.String()) + + suite.Require().Nil(tc.postCheck(&pair, tc.newOwnerAddress.String())) + }) + } +} diff --git a/tests/integration/precompiles/erc20/test_tx.go b/tests/integration/precompiles/erc20/test_tx.go index e50f3425a..0555baffc 100644 --- a/tests/integration/precompiles/erc20/test_tx.go +++ b/tests/integration/precompiles/erc20/test_tx.go @@ -3,6 +3,7 @@ package erc20 import ( "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/holiman/uint256" @@ -10,6 +11,8 @@ import ( "github.com/cosmos/evm/precompiles/common/mocks" "github.com/cosmos/evm/precompiles/erc20" "github.com/cosmos/evm/precompiles/testutil" + "github.com/cosmos/evm/testutil/keyring" + utiltx "github.com/cosmos/evm/testutil/tx" erc20types "github.com/cosmos/evm/x/erc20/types" "github.com/cosmos/evm/x/vm/statedb" vmtypes "github.com/cosmos/evm/x/vm/types" @@ -367,3 +370,532 @@ func (s *PrecompileTestSuite) TestSend() { }) } } + +func (s *PrecompileTestSuite) TestMint() { + method := s.precompile.Methods[erc20.MintMethod] + sender := s.keyring.GetKey(0) + spender := s.keyring.GetKey(1) + + testcases := []struct { + name string + malleate func() ([]interface{}, erc20types.TokenPair) + postCheck func() + expErr bool + errContains string + }{ + { + "fail - negative amount", + func() ([]interface{}, erc20types.TokenPair) { + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), s.tokenDenom, erc20types.OWNER_MODULE) + tokenPair.SetOwnerAddress(sender.AccAddr.String()) + s.network.App.GetErc20Keeper().SetTokenPair(s.network.GetContext(), tokenPair) + s.network.App.GetErc20Keeper().SetDenomMap(s.network.GetContext(), tokenPair.Denom, tokenPair.GetID()) + s.network.App.GetErc20Keeper().SetERC20Map(s.network.GetContext(), tokenPair.GetERC20Contract(), tokenPair.GetID()) + return []interface{}{toAddr, big.NewInt(-1)}, tokenPair + }, + func() {}, + true, + "-1xmpl: invalid coins", + }, + { + "fail - invalid to address", + func() ([]interface{}, erc20types.TokenPair) { + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), s.tokenDenom, erc20types.OWNER_MODULE) + tokenPair.SetOwnerAddress(sender.AccAddr.String()) + s.network.App.GetErc20Keeper().SetTokenPair(s.network.GetContext(), tokenPair) + s.network.App.GetErc20Keeper().SetDenomMap(s.network.GetContext(), tokenPair.Denom, tokenPair.GetID()) + s.network.App.GetErc20Keeper().SetERC20Map(s.network.GetContext(), tokenPair.GetERC20Contract(), tokenPair.GetID()) + return []interface{}{"", big.NewInt(100)}, tokenPair + }, + func() {}, + true, + "invalid to address", + }, + { + "fail - invalid amount", + func() ([]interface{}, erc20types.TokenPair) { + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), s.tokenDenom, erc20types.OWNER_MODULE) + tokenPair.SetOwnerAddress(sender.AccAddr.String()) + s.network.App.GetErc20Keeper().SetTokenPair(s.network.GetContext(), tokenPair) + s.network.App.GetErc20Keeper().SetDenomMap(s.network.GetContext(), tokenPair.Denom, tokenPair.GetID()) + s.network.App.GetErc20Keeper().SetERC20Map(s.network.GetContext(), tokenPair.GetERC20Contract(), tokenPair.GetID()) + return []interface{}{toAddr, ""}, tokenPair + }, + func() {}, + true, + "invalid amount", + }, + { + "fail - minter is not the owner", + func() ([]interface{}, erc20types.TokenPair) { + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), s.tokenDenom, erc20types.OWNER_MODULE) + tokenPair.SetOwnerAddress(sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String()) + s.network.App.GetErc20Keeper().SetTokenPair(s.network.GetContext(), tokenPair) + s.network.App.GetErc20Keeper().SetDenomMap(s.network.GetContext(), tokenPair.Denom, tokenPair.GetID()) + s.network.App.GetErc20Keeper().SetERC20Map(s.network.GetContext(), tokenPair.GetERC20Contract(), tokenPair.GetID()) + return []interface{}{spender.Addr, big.NewInt(100)}, tokenPair + }, + func() {}, + true, + erc20types.ErrMinterIsNotOwner.Error(), + }, + { + "pass", + func() ([]interface{}, erc20types.TokenPair) { + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), s.tokenDenom, erc20types.OWNER_MODULE) + tokenPair.SetOwnerAddress(sender.AccAddr.String()) + s.network.App.GetErc20Keeper().SetTokenPair(s.network.GetContext(), tokenPair) + s.network.App.GetErc20Keeper().SetDenomMap(s.network.GetContext(), tokenPair.Denom, tokenPair.GetID()) + s.network.App.GetErc20Keeper().SetERC20Map(s.network.GetContext(), tokenPair.GetERC20Contract(), tokenPair.GetID()) + + coins := sdk.Coins{{Denom: tokenDenom, Amount: math.NewInt(100)}} + err := s.network.App.GetBankKeeper().MintCoins(s.network.GetContext(), erc20types.ModuleName, coins) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.GetBankKeeper().SendCoinsFromModuleToAccount(s.network.GetContext(), erc20types.ModuleName, sdk.AccAddress(toAddr.Bytes()), coins) + s.Require().NoError(err, "failed to send coins from module to account") + return []interface{}{spender.Addr, big.NewInt(100)}, tokenPair + }, + func() { + toAddrBalance := s.network.App.GetBankKeeper().GetBalance(s.network.GetContext(), toAddr.Bytes(), tokenDenom) + s.Require().Equal(big.NewInt(100), toAddrBalance.Amount.BigInt(), "expected toAddr to have 100 XMPL") + }, + false, + "", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + stateDB := s.network.GetStateDB() + + args, tokenPair := tc.malleate() + + precompile, err := setupERC20PrecompileForTokenPair(*s.network, tokenPair) + s.Require().NoError(err, "failed to set up %q erc20 precompile", tokenPair.Denom) + + var contract *vm.Contract + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), sender.Addr, precompile.Address(), 0) + + // Mint some coins to the module account and then send to the from address + err = s.network.App.GetBankKeeper().MintCoins(s.network.GetContext(), erc20types.ModuleName, XMPLCoin) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.GetBankKeeper().SendCoinsFromModuleToAccount(s.network.GetContext(), erc20types.ModuleName, sender.AccAddr, XMPLCoin) + s.Require().NoError(err, "failed to send coins from module to account") + + _, err = precompile.Mint(ctx, contract, stateDB, &method, args) + if tc.expErr { + s.Require().Error(err, "expected transfer transaction to fail") + s.Require().Contains(err.Error(), tc.errContains, "expected transfer transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected transfer transaction succeeded") + tc.postCheck() + } + }) + } +} + +func (s *PrecompileTestSuite) TestBurn() { + method := s.precompile.Methods[erc20.BurnMethod] + amount := int64(100) + + testcases := []struct { + name string + contractDeployer keyring.Key + prefundedAccount keyring.Key + malleate func() (keyring.Key, keyring.Key, []interface{}) + postCheck func() + expErr bool + errContains string + }{ + { + "fail - invalid args", + s.keyring.GetKey(0), + s.keyring.GetKey(0), + func() (keyring.Key, keyring.Key, []interface{}) { + return s.keyring.GetKey(0), s.keyring.GetKey(0), []interface{}{} + }, + func() {}, + true, + "invalid number of arguments", + }, + { + "pass - burn from caller", + s.keyring.GetKey(0), + s.keyring.GetKey(0), + func() (keyring.Key, keyring.Key, []interface{}) { + return s.keyring.GetKey(0), s.keyring.GetKey(0), []interface{}{ + big.NewInt(amount), + } + }, + func() {}, + false, + "", + }, + { + "pass - burn tokens", + s.keyring.GetKey(0), + s.keyring.GetKey(1), + func() (keyring.Key, keyring.Key, []interface{}) { + s.setupSendAuthz( + s.keyring.GetAccAddr(1), + s.keyring.GetPrivKey(0), + sdk.NewCoins(sdk.NewInt64Coin(s.tokenDenom, amount)), + ) + return s.keyring.GetKey(0), s.keyring.GetKey(1), []interface{}{ + big.NewInt(amount), + } + }, + func() {}, + false, + "", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + + contractDeployer, prefundedAccount, args := tc.malleate() + + stateDB := s.network.GetStateDB() + + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), s.tokenDenom, erc20types.OWNER_MODULE) + tokenPair.SetOwnerAddress(contractDeployer.AccAddr.String()) + s.network.App.GetErc20Keeper().SetTokenPair(s.network.GetContext(), tokenPair) + s.network.App.GetErc20Keeper().SetDenomMap(s.network.GetContext(), tokenPair.Denom, tokenPair.GetID()) + s.network.App.GetErc20Keeper().SetERC20Map(s.network.GetContext(), tokenPair.GetERC20Contract(), tokenPair.GetID()) + + precompile, err := setupERC20PrecompileForTokenPair(*s.network, tokenPair) + s.Require().NoError(err, "failed to set up %q erc20 precompile", tokenPair.Denom) + + var contract *vm.Contract + // For the "pass - burn from address" test, we need to use the prefunded account as the caller + // since that's the account that has the tokens to burn + callerAddr := contractDeployer.Addr + if !tc.expErr { + callerAddr = prefundedAccount.Addr + } + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), callerAddr, precompile.Address(), 0) + + // Mint some coins to the module account and then send to the from address + err = s.network.App.GetBankKeeper().MintCoins(s.network.GetContext(), erc20types.ModuleName, XMPLCoin) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.GetBankKeeper().SendCoinsFromModuleToAccount(s.network.GetContext(), erc20types.ModuleName, prefundedAccount.AccAddr, XMPLCoin) + s.Require().NoError(err, "failed to send coins from module to account") + + _, err = precompile.Burn(ctx, contract, stateDB, &method, args) + if tc.expErr { + s.Require().Error(err, "expected burn transaction to fail") + s.Require().Contains(err.Error(), tc.errContains, "expected burn transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected transfer transaction succeeded") + tc.postCheck() + } + }) + } +} + +func (s *PrecompileTestSuite) TestBurn0() { + method := s.precompile.Methods[erc20.Burn0Method] + amount := int64(100) + + testcases := []struct { + name string + malleate func() (keyring.Key, keyring.Key, keyring.Key, []interface{}) + postCheck func() + expErr bool + errContains string + }{ + { + "should fail - empty args", + func() (keyring.Key, keyring.Key, keyring.Key, []interface{}) { + return s.keyring.GetKey(0), s.keyring.GetKey(1), s.keyring.GetKey(0), nil + }, + func() {}, + true, + "invalid number of arguments", + }, + { + "should fail - invalid spender address", + func() (keyring.Key, keyring.Key, keyring.Key, []interface{}) { + return s.keyring.GetKey(0), s.keyring.GetKey(1), s.keyring.GetKey(0), []interface{}{ + "invalid", + big.NewInt(amount), + } + }, + func() {}, + true, + "invalid spender address", + }, + { + "should fail - invalid amount", + func() (keyring.Key, keyring.Key, keyring.Key, []interface{}) { + return s.keyring.GetKey(0), s.keyring.GetKey(1), s.keyring.GetKey(0), []interface{}{ + s.keyring.GetAddr(0), + "invalid", + } + }, + func() {}, + true, + "invalid amount", + }, + { + "should fail - sender is not the owner", + func() (keyring.Key, keyring.Key, keyring.Key, []interface{}) { + return s.keyring.GetKey(1), s.keyring.GetKey(0), s.keyring.GetKey(0), []interface{}{ + s.keyring.GetAddr(0), + big.NewInt(1000), + } + }, + func() {}, + true, + "sender is not the owner", + }, + { + "should pass - valid burn0", + func() (keyring.Key, keyring.Key, keyring.Key, []interface{}) { + return s.keyring.GetKey(0), s.keyring.GetKey(1), s.keyring.GetKey(0), []interface{}{ + s.keyring.GetAddr(1), + big.NewInt(amount), + } + }, + func() {}, + false, + "", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + + contractDeployer, prefundedAccount, owner, args := tc.malleate() + + stateDB := s.network.GetStateDB() + + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), s.tokenDenom, erc20types.OWNER_MODULE) + tokenPair.SetOwnerAddress(owner.AccAddr.String()) + s.network.App.GetErc20Keeper().SetTokenPair(s.network.GetContext(), tokenPair) + s.network.App.GetErc20Keeper().SetDenomMap(s.network.GetContext(), tokenPair.Denom, tokenPair.GetID()) + s.network.App.GetErc20Keeper().SetERC20Map(s.network.GetContext(), tokenPair.GetERC20Contract(), tokenPair.GetID()) + + precompile, err := setupERC20PrecompileForTokenPair(*s.network, tokenPair) + s.Require().NoError(err, "failed to set up %q erc20 precompile", tokenPair.Denom) + + var contract *vm.Contract + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), contractDeployer.Addr, precompile.Address(), 0) + + // Mint some coins to the module account and then send to the from address + err = s.network.App.GetBankKeeper().MintCoins(s.network.GetContext(), erc20types.ModuleName, XMPLCoin) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.GetBankKeeper().SendCoinsFromModuleToAccount(s.network.GetContext(), erc20types.ModuleName, prefundedAccount.AccAddr, XMPLCoin) + s.Require().NoError(err, "failed to send coins from module to account") + + _, err = precompile.Burn0(ctx, contract, stateDB, &method, args) + if tc.expErr { + s.Require().Error(err, "expected burn0 transaction to fail") + s.Require().Contains(err.Error(), tc.errContains, "expected burn0 transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected burn0 transaction succeeded") + tc.postCheck() + } + }) + } +} + +func (s *PrecompileTestSuite) TestBurnFrom() { + method := s.precompile.Methods[erc20.BurnFromMethod] + amount := int64(100) + + testcases := []struct { + name string + malleate func() []interface{} + postCheck func() + expErr bool + errContains string + }{ + { + "should fail - empty args", + func() []interface{} { + return nil + }, + func() {}, + true, + "invalid number of arguments", + }, + { + "should fail - invalid address", + func() []interface{} { + return []interface{}{ + "invalid", + big.NewInt(amount), + } + }, + func() {}, + true, + "invalid from address", + }, + { + "should fail - invalid amount", + func() []interface{} { + return []interface{}{ + s.keyring.GetAddr(0), + "invalid", + } + }, + func() {}, + true, + "invalid amount", + }, + { + "should fail - allowance is 0", + func() []interface{} { + return []interface{}{ + s.keyring.GetAddr(0), + big.NewInt(100), + } + }, + func() {}, + true, + "", + }, + { + "should fail - allowance is less than amount", + func() []interface{} { + s.setupSendAuthz( + s.keyring.GetAccAddr(1), + s.keyring.GetPrivKey(0), + sdk.NewCoins(sdk.NewInt64Coin(s.tokenDenom, 1)), + ) + + return []interface{}{ + s.keyring.GetAddr(0), + big.NewInt(amount), + } + }, + func() {}, + true, + "", + }, + { + "should pass", + func() []interface{} { + return []interface{}{ + s.keyring.GetAddr(1), + big.NewInt(amount), + } + }, + func() {}, + false, + "", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + stateDB := s.network.GetStateDB() + + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), s.tokenDenom, erc20types.OWNER_MODULE) + tokenPair.SetOwnerAddress(s.keyring.GetAddr(0).String()) + s.network.App.GetErc20Keeper().SetTokenPair(s.network.GetContext(), tokenPair) + s.network.App.GetErc20Keeper().SetDenomMap(s.network.GetContext(), tokenPair.Denom, tokenPair.GetID()) + s.network.App.GetErc20Keeper().SetERC20Map(s.network.GetContext(), tokenPair.GetERC20Contract(), tokenPair.GetID()) + + precompile, err := setupERC20PrecompileForTokenPair(*s.network, tokenPair) + s.Require().NoError(err, "failed to set up %q erc20 precompile", tokenPair.Denom) + + // Set allowance for the "should pass" test case + if !tc.expErr { + err = s.network.App.GetErc20Keeper().SetAllowance(s.network.GetContext(), precompile.Address(), s.keyring.GetAddr(1), s.keyring.GetAddr(0), big.NewInt(200)) + s.Require().NoError(err, "failed to set allowance") + } + + var contract *vm.Contract + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), s.keyring.GetAddr(0), precompile.Address(), 0) + + // Mint some coins to the module account and then send to the from address + err = s.network.App.GetBankKeeper().MintCoins(s.network.GetContext(), erc20types.ModuleName, XMPLCoin) + s.Require().NoError(err, "failed to mint coins") + err = s.network.App.GetBankKeeper().SendCoinsFromModuleToAccount(s.network.GetContext(), erc20types.ModuleName, s.keyring.GetAccAddr(1), XMPLCoin) + s.Require().NoError(err, "failed to send coins from module to account") + + _, err = precompile.BurnFrom(ctx, contract, stateDB, &method, tc.malleate()) + if tc.expErr { + s.Require().Error(err, "expected burn transaction to fail") + s.Require().Contains(err.Error(), tc.errContains, "expected burn transaction to fail with specific error") + } else { + s.Require().NoError(err, "expected transfer transaction succeeded") + tc.postCheck() + } + }) + } +} + +func (s *PrecompileTestSuite) TestTransferOwnership() { + method := s.precompile.Methods[erc20.TransferOwnershipMethod] + from := s.keyring.GetKey(0) + newOwner := common.Address(utiltx.GenerateAddress().Bytes()) + + testcases := []struct { + name string + malleate func() []interface{} + postCheck func() + expErr bool + errContains string + }{ + { + name: "fail - invalid number of arguments", + malleate: func() []interface{} { + return []interface{}{} + }, + expErr: true, + errContains: "invalid number of arguments; expected 1; got: 0", + }, + { + name: "fail - invalid address", + malleate: func() []interface{} { + return []interface{}{"invalid"} + }, + expErr: true, + errContains: "invalid new owner address", + }, + { + name: "pass", + malleate: func() []interface{} { + return []interface{}{newOwner} + }, + postCheck: func() {}, + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + s.SetupTest() + stateDB := s.network.GetStateDB() + + tokenPair := erc20types.NewTokenPair(utiltx.GenerateAddress(), s.tokenDenom, erc20types.OWNER_MODULE) + tokenPair.SetOwnerAddress(from.AccAddr.String()) + s.network.App.GetErc20Keeper().SetTokenPair(s.network.GetContext(), tokenPair) + s.network.App.GetErc20Keeper().SetDenomMap(s.network.GetContext(), tokenPair.Denom, tokenPair.GetID()) + s.network.App.GetErc20Keeper().SetERC20Map(s.network.GetContext(), tokenPair.GetERC20Contract(), tokenPair.GetID()) + + precompile, err := setupERC20PrecompileForTokenPair(*s.network, tokenPair) + s.Require().NoError(err, "failed to set up %q erc20 precompile", tokenPair.Denom) + + var contract *vm.Contract + + contract, ctx := testutil.NewPrecompileContract(s.T(), s.network.GetContext(), from.Addr, precompile.Address(), 0) + + _, err = precompile.TransferOwnership(ctx, contract, stateDB, &method, tc.malleate()) + if tc.expErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.errContains) + } else { + s.Require().NoError(err) + tc.postCheck() + } + }) + } +} diff --git a/tests/integration/precompiles/erc20/test_types.go b/tests/integration/precompiles/erc20/test_types.go index 46cbfecd5..4a6e668a7 100644 --- a/tests/integration/precompiles/erc20/test_types.go +++ b/tests/integration/precompiles/erc20/test_types.go @@ -300,3 +300,37 @@ func (s *PrecompileTestSuite) TestParseBalanceOfArgs() { }) } } + +func (s *PrecompileTestSuite) TestParseOwnerArgs() { + testcases := []struct { + name string + args []interface{} + expPass bool + errContains string + }{ + { + name: "pass - correct arguments", + args: []interface{}{}, + expPass: true, + }, + { + name: "fail - invalid number of arguments", + args: []interface{}{ + 1, 2, 3, + }, + errContains: "invalid number of arguments", + }, + } + + for _, tc := range testcases { + s.Run(tc.name, func() { + err := erc20.ParseOwnerArgs(tc.args) + if tc.expPass { + s.Require().NoError(err, "unexpected error parsing the owner arguments") + } else { + s.Require().Error(err, "expected an error parsing the owner arguments") + s.Require().ErrorContains(err, tc.errContains, "expected different error message") + } + }) + } +} diff --git a/tests/integration/precompiles/erc20/test_utils.go b/tests/integration/precompiles/erc20/test_utils.go index e68530faa..269d5b829 100644 --- a/tests/integration/precompiles/erc20/test_utils.go +++ b/tests/integration/precompiles/erc20/test_utils.go @@ -5,6 +5,7 @@ import ( "fmt" "math/big" "slices" + "time" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -16,6 +17,7 @@ import ( "github.com/cosmos/evm/crypto/ethsecp256k1" "github.com/cosmos/evm/precompiles/erc20" "github.com/cosmos/evm/precompiles/testutil" + commonfactory "github.com/cosmos/evm/testutil/integration/base/factory" "github.com/cosmos/evm/testutil/integration/evm/network" utiltx "github.com/cosmos/evm/testutil/tx" testutiltypes "github.com/cosmos/evm/testutil/types" @@ -28,6 +30,8 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) // CallType indicates which type of contract call is made during the integration tests. @@ -448,3 +452,50 @@ func GenerateAddress() common.Address { addr, _ := NewAddrKey() return addr } + +func (s *PrecompileTestSuite) setupSendAuthz( + grantee sdk.AccAddress, granterPriv cryptotypes.PrivKey, amount sdk.Coins, +) { + err := setupSendAuthz( + s.network, + s.factory, + grantee, + granterPriv, + amount, + ) + s.Require().NoError(err, "failed to set up send authorization") +} + +func setupSendAuthz( + network network.Network, + factory commonfactory.BaseTxFactory, + grantee sdk.AccAddress, + granterPriv cryptotypes.PrivKey, + amount sdk.Coins, +) error { + granter := sdk.AccAddress(granterPriv.PubKey().Address()) + expiration := network.GetContext().BlockHeader().Time.Add(time.Hour) + sendAuthz := banktypes.NewSendAuthorization( + amount, + []sdk.AccAddress{}, + ) + + msgGrant, err := authz.NewMsgGrant( + granter, + grantee, + sendAuthz, + &expiration, + ) + if err != nil { + return errorsmod.Wrap(err, "failed to create MsgGrant") + } + + // Create an authorization + txArgs := commonfactory.CosmosTxArgs{Msgs: []sdk.Msg{msgGrant}} + _, err = factory.ExecuteCosmosTx(granterPriv, txArgs) + if err != nil { + return errorsmod.Wrap(err, "failed to execute MsgGrant") + } + + return nil +} diff --git a/tests/integration/precompiles/ics20/test_setup.go b/tests/integration/precompiles/ics20/test_setup.go index cd90158c5..3476668db 100644 --- a/tests/integration/precompiles/ics20/test_setup.go +++ b/tests/integration/precompiles/ics20/test_setup.go @@ -48,6 +48,7 @@ func (s *PrecompileTestSuite) SetupTest() { *evmAppA.GetStakingKeeper(), evmAppA.GetTransferKeeper(), evmAppA.GetIBCKeeper().ChannelKeeper, + evmAppA.GetErc20Keeper(), ) s.chainABondDenom, _ = evmAppA.GetStakingKeeper().BondDenom(s.chainA.GetContext()) evmAppB := s.chainB.App.(evm.EvmApp) @@ -56,6 +57,7 @@ func (s *PrecompileTestSuite) SetupTest() { *evmAppB.GetStakingKeeper(), evmAppB.GetTransferKeeper(), evmAppB.GetIBCKeeper().ChannelKeeper, + evmAppB.GetErc20Keeper(), ) s.chainBBondDenom, _ = evmAppB.GetStakingKeeper().BondDenom(s.chainB.GetContext()) } diff --git a/tests/integration/x/erc20/test_convert.go b/tests/integration/x/erc20/test_convert.go new file mode 100644 index 000000000..a0d1599b6 --- /dev/null +++ b/tests/integration/x/erc20/test_convert.go @@ -0,0 +1,383 @@ +package erc20 + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/holiman/uint256" + "github.com/stretchr/testify/mock" + "go.uber.org/mock/gomock" + + "github.com/cosmos/evm/testutil/integration/evm/utils" + "github.com/cosmos/evm/x/erc20/keeper" + "github.com/cosmos/evm/x/erc20/types" + erc20mocks "github.com/cosmos/evm/x/erc20/types/mocks" + "github.com/cosmos/evm/x/vm/statedb" + evmtypes "github.com/cosmos/evm/x/vm/types" + + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" +) + +// TestConvertERC20IntoCoinsForNativeToken tests the core conversion logic +func (s *KeeperTestSuite) TestConvertERC20IntoCoinsForNativeToken() { + var ( + contractAddr common.Address + coinName string + ) + testCases := []struct { + name string + mint int64 + transfer int64 + malleate func(common.Address) + extra func() + contractType int + expPass bool + selfdestructed bool + }{ + { + "ok - sufficient funds", + 100, + 10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + true, + false, + }, + { + "ok - equal funds", + 10, + 10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + true, + false, + }, + { + "fail - insufficient funds - callEVM", + 0, + 10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + false, + false, + }, + { + "fail - minting disabled", + 100, + 10, + func(contractAddr common.Address) { + params := types.DefaultParams() + params.EnableErc20 = false + err := utils.UpdateERC20Params( + utils.UpdateParamsInput{ + Tf: s.factory, + Network: s.network, + Pk: s.keyring.GetPrivKey(0), + Params: params, + }, + ) + s.Require().NoError(err) + }, + func() {}, + contractMinterBurner, + false, + false, + }, + { + "fail - direct balance manipulation contract", + 100, + 10, + func(common.Address) {}, + func() {}, + contractDirectBalanceManipulation, + false, + false, + }, + { + "pass - delayed malicious contract", + 10, + 10, + func(common.Address) {}, + func() {}, + contractMaliciousDelayed, + true, + false, + }, + { + "fail - negative transfer amount", + 10, + -10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + false, + false, + }, + { + "fail - force evm fail", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &erc20mocks.EVMKeeper{} + transferKeeper := s.network.App.GetTransferKeeper() + erc20Keeper := keeper.NewKeeper( + s.network.App.GetKey("erc20"), s.network.App.AppCodec(), + authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), + s.network.App.GetBankKeeper(), mockEVMKeeper, s.network.App.GetStakingKeeper(), + &transferKeeper, + ) + s.network.App.SetErc20Keeper(erc20Keeper) + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force get balance fail", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &erc20mocks.EVMKeeper{} + transferKeeper := s.network.App.GetTransferKeeper() + erc20Keeper := keeper.NewKeeper( + s.network.App.GetKey("erc20"), s.network.App.AppCodec(), + authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), + s.network.App.GetBankKeeper(), mockEVMKeeper, s.network.App.GetStakingKeeper(), + &transferKeeper, + ) + s.network.App.SetErc20Keeper(erc20Keeper) + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} + balance := make([]uint8, 32) + balance[31] = uint8(1) + mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Twice() + mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced balance error")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force transfer unpack fail", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &erc20mocks.EVMKeeper{} + transferKeeper := s.network.App.GetTransferKeeper() + erc20Keeper := keeper.NewKeeper( + s.network.App.GetKey("erc20"), s.network.App.AppCodec(), + authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), + s.network.App.GetBankKeeper(), mockEVMKeeper, s.network.App.GetStakingKeeper(), + &transferKeeper, + ) + s.network.App.SetErc20Keeper(erc20Keeper) + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force invalid transfer fail", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &erc20mocks.EVMKeeper{} + transferKeeper := s.network.App.GetTransferKeeper() + erc20Keeper := keeper.NewKeeper( + s.network.App.GetKey("erc20"), s.network.App.AppCodec(), + authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), + s.network.App.GetBankKeeper(), mockEVMKeeper, s.network.App.GetStakingKeeper(), + &transferKeeper, + ) + s.network.App.SetErc20Keeper(erc20Keeper) + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force mint fail", + 100, + 10, + func(common.Address) {}, + func() { + ctrl := gomock.NewController(s.T()) + mockBankKeeper := erc20mocks.NewMockBankKeeper(ctrl) + transferKeeper := s.network.App.GetTransferKeeper() + erc20Keeper := keeper.NewKeeper( + s.network.App.GetKey("erc20"), s.network.App.AppCodec(), + authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), + mockBankKeeper, s.network.App.GetEVMKeeper(), s.network.App.GetStakingKeeper(), + &transferKeeper, + ) + s.network.App.SetErc20Keeper(erc20Keeper) + + mockBankKeeper.EXPECT().MintCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("failed to mint")).AnyTimes() + mockBankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("failed to unescrow")).AnyTimes() + mockBankKeeper.EXPECT().BlockedAddr(gomock.Any()).Return(false).AnyTimes() + mockBankKeeper.EXPECT().GetBalance(gomock.Any(), gomock.Any(), gomock.Any()).Return(sdk.Coin{Denom: "coin", Amount: math.OneInt()}).AnyTimes() + mockBankKeeper.EXPECT().IsSendEnabledCoin(gomock.Any(), gomock.Any()).Return(true).AnyTimes() + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force send minted fail", + 100, + 10, + func(common.Address) {}, + func() { + ctrl := gomock.NewController(s.T()) + mockBankKeeper := erc20mocks.NewMockBankKeeper(ctrl) + transferKeeper := s.network.App.GetTransferKeeper() + erc20Keeper := keeper.NewKeeper( + s.network.App.GetKey("erc20"), s.network.App.AppCodec(), + authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), + mockBankKeeper, s.network.App.GetEVMKeeper(), s.network.App.GetStakingKeeper(), + &transferKeeper, + ) + s.network.App.SetErc20Keeper(erc20Keeper) + + mockBankKeeper.EXPECT().MintCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + mockBankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("failed to unescrow")) + mockBankKeeper.EXPECT().BlockedAddr(gomock.Any()).Return(false) + mockBankKeeper.EXPECT().GetBalance(gomock.Any(), gomock.Any(), gomock.Any()).Return(sdk.Coin{Denom: "coin", Amount: math.OneInt()}) + mockBankKeeper.EXPECT().IsSendEnabledCoin(gomock.Any(), gomock.Any()).Return(true).AnyTimes() + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force bank balance fail", + 100, + 10, + func(common.Address) {}, + func() { + ctrl := gomock.NewController(s.T()) + mockBankKeeper := erc20mocks.NewMockBankKeeper(ctrl) + transferKeeper := s.network.App.GetTransferKeeper() + erc20Keeper := keeper.NewKeeper( + s.network.App.GetKey("erc20"), s.network.App.AppCodec(), + authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), + mockBankKeeper, s.network.App.GetEVMKeeper(), s.network.App.GetStakingKeeper(), + &transferKeeper, + ) + s.network.App.SetErc20Keeper(erc20Keeper) + + mockBankKeeper.EXPECT().MintCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + mockBankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + mockBankKeeper.EXPECT().BlockedAddr(gomock.Any()).Return(false) + mockBankKeeper.EXPECT().GetBalance(gomock.Any(), gomock.Any(), gomock.Any()).Return(sdk.Coin{Denom: coinName, Amount: math.OneInt()}).AnyTimes() + mockBankKeeper.EXPECT().IsSendEnabledCoin(gomock.Any(), gomock.Any()).Return(true).AnyTimes() + }, + contractMinterBurner, + false, + false, + }, + } + for _, tc := range testCases { + s.Run(fmt.Sprintf("Case %s", tc.name), func() { + var err error + s.mintFeeCollector = true + defer func() { + s.mintFeeCollector = false + }() + + s.SetupTest() + + contractAddr, err = s.setupRegisterERC20Pair(tc.contractType) + s.Require().NoError(err) + + tc.malleate(contractAddr) + s.Require().NotNil(contractAddr) + + coinName = types.CreateDenom(contractAddr.String()) + sender := s.keyring.GetAccAddr(0) + senderHex := s.keyring.GetAddr(0) + + _, err = s.MintERC20Token(contractAddr, senderHex, big.NewInt(tc.mint)) + s.Require().NoError(err) + + tc.extra() + + // Get context AFTER state modifications so changes are visible + ctx := s.network.GetContext() + stateDB := statedb.New(ctx, s.network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + + if tc.expPass { + // Call the conversion function directly + _, err = s.network.App.GetErc20Keeper().ConvertERC20IntoCoinsForNativeToken(ctx, stateDB, contractAddr, math.NewInt(tc.transfer), sender, senderHex, true, false) + s.Require().NoError(err, tc.name) + + cosmosBalance := s.network.App.GetBankKeeper().GetBalance(ctx, sender, coinName) + + acc := s.network.App.GetEVMKeeper().GetAccountWithoutBalance(ctx, contractAddr) + if tc.selfdestructed { + s.Require().Nil(acc, "expected contract to be destroyed") + } else { + s.Require().NotNil(acc) + } + + isContract := s.network.App.GetEVMKeeper().IsContract(ctx, contractAddr) + if tc.selfdestructed || !isContract { + id := s.network.App.GetErc20Keeper().GetTokenPairID(ctx, contractAddr.String()) + _, found := s.network.App.GetErc20Keeper().GetTokenPair(ctx, id) + s.Require().False(found) + } else { + s.Require().Equal(cosmosBalance.Amount, math.NewInt(tc.transfer)) + } + } else { + // Call the conversion function directly + _, err = s.network.App.GetErc20Keeper().ConvertERC20IntoCoinsForNativeToken(ctx, stateDB, contractAddr, math.NewInt(tc.transfer), sender, senderHex, true, false) + s.Require().Error(err, tc.name) + } + }) + } + s.mintFeeCollector = false +} diff --git a/tests/integration/x/erc20/test_evm.go b/tests/integration/x/erc20/test_evm.go index 4e1977414..832d14244 100644 --- a/tests/integration/x/erc20/test_evm.go +++ b/tests/integration/x/erc20/test_evm.go @@ -84,8 +84,8 @@ func (s *KeeperTestSuite) TestBalanceOf() { { "Failed to call Evm", func() { - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) }, int64(0), false, @@ -93,8 +93,8 @@ func (s *KeeperTestSuite) TestBalanceOf() { { "Incorrect res", func() { - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() }, int64(0), false, @@ -104,8 +104,8 @@ func (s *KeeperTestSuite) TestBalanceOf() { func() { balance := make([]uint8, 32) balance[31] = uint8(10) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() }, int64(10), true, @@ -147,16 +147,16 @@ func (s *KeeperTestSuite) TestQueryERC20ForceFail() { { "Failed to call Evm", func() { - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) }, false, }, { "Incorrect res", func() { - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() }, false, }, @@ -165,8 +165,8 @@ func (s *KeeperTestSuite) TestQueryERC20ForceFail() { func() { ret := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 67, 111, 105, 110, 32, 84, 111, 107, 101, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{VmError: "Error"}, nil).Once() + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{VmError: "Error"}, nil).Once() }, false, }, @@ -174,10 +174,10 @@ func (s *KeeperTestSuite) TestQueryERC20ForceFail() { "incorrect symbol res", func() { ret := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 67, 111, 105, 110, 32, 84, 111, 107, 101, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() }, false, }, @@ -186,11 +186,11 @@ func (s *KeeperTestSuite) TestQueryERC20ForceFail() { func() { ret := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 67, 111, 105, 110, 32, 84, 111, 107, 101, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} retSymbol := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 67, 84, 75, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: retSymbol}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{VmError: "Error"}, nil).Once() }, false, @@ -200,12 +200,12 @@ func (s *KeeperTestSuite) TestQueryERC20ForceFail() { func() { ret := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 67, 111, 105, 110, 32, 84, 111, 107, 101, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} retSymbol := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 67, 84, 75, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: retSymbol}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: retSymbol}, nil).Once() + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() }, false, }, @@ -286,11 +286,11 @@ func (s *KeeperTestSuite) TestQueryERC20Bytes32Fallback() { symbolData := createStringData("MKR") decimalsData := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18} - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). Return(&evmtypes.MsgEthereumTxResponse{Ret: nameData}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). Return(&evmtypes.MsgEthereumTxResponse{Ret: symbolData}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "decimals"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "decimals"). Return(&evmtypes.MsgEthereumTxResponse{Ret: decimalsData}, nil).Once() }, types.ERC20Data{Name: "Maker", Symbol: "MKR", Decimals: 18}, @@ -304,11 +304,11 @@ func (s *KeeperTestSuite) TestQueryERC20Bytes32Fallback() { decimalsData := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18} // First call tries string unpacking (will fail), then tries bytes32 (will succeed) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). Return(&evmtypes.MsgEthereumTxResponse{Ret: nameData}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). Return(&evmtypes.MsgEthereumTxResponse{Ret: symbolData}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "decimals"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "decimals"). Return(&evmtypes.MsgEthereumTxResponse{Ret: decimalsData}, nil).Once() }, types.ERC20Data{Name: "Maker", Symbol: "MKR", Decimals: 18}, @@ -321,11 +321,11 @@ func (s *KeeperTestSuite) TestQueryERC20Bytes32Fallback() { symbolData := createBytes32Data("MKR") decimalsData := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18} - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). Return(&evmtypes.MsgEthereumTxResponse{Ret: nameData}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). Return(&evmtypes.MsgEthereumTxResponse{Ret: symbolData}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "decimals"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "decimals"). Return(&evmtypes.MsgEthereumTxResponse{Ret: decimalsData}, nil).Once() }, types.ERC20Data{Name: "Maker", Symbol: "MKR", Decimals: 18}, @@ -345,11 +345,11 @@ func (s *KeeperTestSuite) TestQueryERC20Bytes32Fallback() { decimalsData := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18} - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). Return(&evmtypes.MsgEthereumTxResponse{Ret: nameData}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). Return(&evmtypes.MsgEthereumTxResponse{Ret: symbolData}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "decimals"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "decimals"). Return(&evmtypes.MsgEthereumTxResponse{Ret: decimalsData}, nil).Once() }, types.ERC20Data{Name: "Maker", Symbol: "MKR", Decimals: 18}, @@ -358,7 +358,7 @@ func (s *KeeperTestSuite) TestQueryERC20Bytes32Fallback() { { "EVM call fails for name", func() { - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). Return(nil, fmt.Errorf("EVM call failed")).Once() }, types.ERC20Data{}, @@ -369,7 +369,7 @@ func (s *KeeperTestSuite) TestQueryERC20Bytes32Fallback() { func() { invalidData := []byte{0xFF, 0xFF} // Invalid data that will fail both unpacking methods - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). Return(&evmtypes.MsgEthereumTxResponse{Ret: invalidData}, nil).Once() }, types.ERC20Data{}, @@ -380,9 +380,9 @@ func (s *KeeperTestSuite) TestQueryERC20Bytes32Fallback() { func() { nameData := createStringData("Maker") - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "name"). Return(&evmtypes.MsgEthereumTxResponse{Ret: nameData}, nil).Once() - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, "symbol"). Return(nil, fmt.Errorf("EVM call failed")).Once() }, types.ERC20Data{}, diff --git a/tests/integration/x/erc20/test_ibc_callback.go b/tests/integration/x/erc20/test_ibc_callback.go index 0086d4b78..957a7e629 100644 --- a/tests/integration/x/erc20/test_ibc_callback.go +++ b/tests/integration/x/erc20/test_ibc_callback.go @@ -426,8 +426,8 @@ func (s *KeeperTestSuite) TestConvertCoinToERC20FromPacket() { ), ) s.Require().NoError(err) - - _, err = s.network.App.GetEVMKeeper().CallEVM(ctx, contracts.ERC20MinterBurnerDecimalsContract.ABI, s.keyring.GetAddr(0), contractAddr, true, nil, "mint", types.ModuleAddress, big.NewInt(10)) + stateDB := statedb.New(ctx, s.network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + _, err = s.network.App.GetEVMKeeper().CallEVM(ctx, stateDB, contracts.ERC20MinterBurnerDecimalsContract.ABI, s.keyring.GetAddr(0), contractAddr, true, false, nil, "mint", types.ModuleAddress, big.NewInt(10)) s.Require().NoError(err) return transfertypes.NewFungibleTokenPacketData(pair.Denom, "10", senderAddr, "", "") @@ -563,7 +563,8 @@ func (s *KeeperTestSuite) TestOnAcknowledgementPacket() { ) s.Require().NoError(err) - _, err = s.network.App.GetEVMKeeper().CallEVM(ctx, contracts.ERC20MinterBurnerDecimalsContract.ABI, s.keyring.GetAddr(0), contractAddr, true, nil, "mint", types.ModuleAddress, big.NewInt(100)) + stateDB := statedb.New(ctx, s.network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + _, err = s.network.App.GetEVMKeeper().CallEVM(ctx, stateDB, contracts.ERC20MinterBurnerDecimalsContract.ABI, s.keyring.GetAddr(0), contractAddr, true, false, nil, "mint", types.ModuleAddress, big.NewInt(100)) s.Require().NoError(err) ack = channeltypes.NewErrorAcknowledgement(errors.New("error")) @@ -669,7 +670,8 @@ func (s *KeeperTestSuite) TestOnTimeoutPacket() { pair, _ = s.network.App.GetErc20Keeper().GetTokenPair(ctx, id) s.Require().NotNil(pair) - _, err = s.network.App.GetEVMKeeper().CallEVM(ctx, contracts.ERC20MinterBurnerDecimalsContract.ABI, s.keyring.GetAddr(0), contractAddr, true, nil, "mint", types.ModuleAddress, big.NewInt(100)) + stateDB := statedb.New(ctx, s.network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + _, err = s.network.App.GetEVMKeeper().CallEVM(ctx, stateDB, contracts.ERC20MinterBurnerDecimalsContract.ABI, s.keyring.GetAddr(0), contractAddr, true, false, nil, "mint", types.ModuleAddress, big.NewInt(100)) s.Require().NoError(err) // Fund module account with ATOM, ERC20 coins and IBC vouchers diff --git a/tests/integration/x/erc20/test_msg_server.go b/tests/integration/x/erc20/test_msg_server.go index 06ed180d8..18f5d010c 100644 --- a/tests/integration/x/erc20/test_msg_server.go +++ b/tests/integration/x/erc20/test_msg_server.go @@ -10,7 +10,6 @@ import ( "go.uber.org/mock/gomock" "github.com/cosmos/evm/testutil/integration/base/factory" - "github.com/cosmos/evm/testutil/integration/evm/utils" "github.com/cosmos/evm/x/erc20/keeper" "github.com/cosmos/evm/x/erc20/types" erc20mocks "github.com/cosmos/evm/x/erc20/types/mocks" @@ -24,366 +23,121 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) -func (s *KeeperTestSuite) TestConvertERC20NativeERC20() { - var ( - contractAddr common.Address - coinName string - ) +// TestConvertERC20 tests the ConvertERC20 msg server method, +// focusing on message validation and address parsing +func (s *KeeperTestSuite) TestConvertERC20() { testCases := []struct { - name string - mint int64 - transfer int64 - malleate func(common.Address) - extra func() - contractType int - expPass bool - selfdestructed bool + name string + setup func() *types.MsgConvertERC20 + expPass bool }{ { - "ok - sufficient funds", - 100, - 10, - func(common.Address) {}, - func() {}, - contractMinterBurner, - true, - false, - }, - { - "ok - equal funds", - 10, - 10, - func(common.Address) {}, - func() {}, - contractMinterBurner, - true, - false, - }, - { - "fail - insufficient funds - callEVM", - 0, - 10, - func(common.Address) {}, - func() {}, - contractMinterBurner, - false, - false, - }, - { - "fail - minting disabled", - 100, - 10, - func(common.Address) { - params := types.DefaultParams() - params.EnableErc20 = false - err := utils.UpdateERC20Params( - utils.UpdateParamsInput{ - Tf: s.factory, - Network: s.network, - Pk: s.keyring.GetPrivKey(0), - Params: params, - }, - ) + "pass - valid message with proper addresses", + func() *types.MsgConvertERC20 { + contractAddr, err := s.setupRegisterERC20Pair(contractMinterBurner) s.Require().NoError(err) - }, - func() {}, - contractMinterBurner, - false, - false, - }, - { - "fail - direct balance manipulation contract", - 100, - 10, - func(common.Address) {}, - func() {}, - contractDirectBalanceManipulation, - false, - false, - }, - { - "pass - delayed malicious contract", - 10, - 10, - func(common.Address) {}, - func() {}, - contractMaliciousDelayed, - true, - false, - }, - { - "fail - negative transfer contract", - 10, - -10, - func(common.Address) {}, - func() {}, - contractMinterBurner, - false, - false, - }, - { - "fail - force evm fail", - 100, - 10, - func(common.Address) {}, - func() { - mockEVMKeeper := &erc20mocks.EVMKeeper{} - transferKeeper := s.network.App.GetTransferKeeper() - erc20Keeper := keeper.NewKeeper( - s.network.App.GetKey("erc20"), s.network.App.AppCodec(), - authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), - s.network.App.GetBankKeeper(), mockEVMKeeper, s.network.App.GetStakingKeeper(), - &transferKeeper, - ) - s.network.App.SetErc20Keeper(erc20Keeper) - existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} - balance := make([]uint8, 32) - mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() - mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) - mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) - mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) - }, - contractMinterBurner, - false, - false, - }, - { - "fail - force get balance fail", - 100, - 10, - func(common.Address) {}, - func() { - mockEVMKeeper := &erc20mocks.EVMKeeper{} - transferKeeper := s.network.App.GetTransferKeeper() - erc20Keeper := keeper.NewKeeper( - s.network.App.GetKey("erc20"), s.network.App.AppCodec(), - authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), - s.network.App.GetBankKeeper(), mockEVMKeeper, s.network.App.GetStakingKeeper(), - &transferKeeper, - ) - s.network.App.SetErc20Keeper(erc20Keeper) + sender := s.keyring.GetAccAddr(0) + senderHex := s.keyring.GetAddr(0) - existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} - balance := make([]uint8, 32) - balance[31] = uint8(1) - mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Twice() - mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced balance error")) - mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) - mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) + _, err = s.MintERC20Token(contractAddr, senderHex, big.NewInt(100)) + s.Require().NoError(err) + + return types.NewMsgConvertERC20( + math.NewInt(10), + sender, + contractAddr, + senderHex, + ) }, - contractMinterBurner, - false, - false, + true, }, { - "fail - force transfer unpack fail", - 100, - 10, - func(common.Address) {}, - func() { - mockEVMKeeper := &erc20mocks.EVMKeeper{} - transferKeeper := s.network.App.GetTransferKeeper() - erc20Keeper := keeper.NewKeeper( - s.network.App.GetKey("erc20"), s.network.App.AppCodec(), - authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), - s.network.App.GetBankKeeper(), mockEVMKeeper, s.network.App.GetStakingKeeper(), - &transferKeeper, - ) - s.network.App.SetErc20Keeper(erc20Keeper) + "fail - invalid receiver bech32 address format", + func() *types.MsgConvertERC20 { + contractAddr, err := s.setupRegisterERC20Pair(contractMinterBurner) + s.Require().NoError(err) - existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} - balance := make([]uint8, 32) - mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() - mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) - mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) - mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) - }, - contractMinterBurner, - false, - false, - }, + sender := s.keyring.GetAccAddr(0) + senderHex := s.keyring.GetAddr(0) - { - "fail - force invalid transfer fail", - 100, - 10, - func(common.Address) {}, - func() { - mockEVMKeeper := &erc20mocks.EVMKeeper{} - transferKeeper := s.network.App.GetTransferKeeper() - erc20Keeper := keeper.NewKeeper( - s.network.App.GetKey("erc20"), s.network.App.AppCodec(), - authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), - s.network.App.GetBankKeeper(), mockEVMKeeper, s.network.App.GetStakingKeeper(), - &transferKeeper, - ) - s.network.App.SetErc20Keeper(erc20Keeper) + _, err = s.MintERC20Token(contractAddr, senderHex, big.NewInt(100)) + s.Require().NoError(err) - existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} - balance := make([]uint8, 32) - mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() - mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil) - mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) - mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) - }, - contractMinterBurner, - false, - false, - }, - { - "fail - force mint fail", - 100, - 10, - func(common.Address) {}, - func() { - ctrl := gomock.NewController(s.T()) - mockBankKeeper := erc20mocks.NewMockBankKeeper(ctrl) - transferKeeper := s.network.App.GetTransferKeeper() - erc20Keeper := keeper.NewKeeper( - s.network.App.GetKey("erc20"), s.network.App.AppCodec(), - authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), - mockBankKeeper, s.network.App.GetEVMKeeper(), s.network.App.GetStakingKeeper(), - &transferKeeper, + msg := types.NewMsgConvertERC20( + math.NewInt(10), + sender, + contractAddr, + senderHex, ) - s.network.App.SetErc20Keeper(erc20Keeper) - - mockBankKeeper.EXPECT().MintCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("failed to mint")).AnyTimes() - mockBankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("failed to unescrow")).AnyTimes() - mockBankKeeper.EXPECT().BlockedAddr(gomock.Any()).Return(false).AnyTimes() - mockBankKeeper.EXPECT().GetBalance(gomock.Any(), gomock.Any(), gomock.Any()).Return(sdk.Coin{Denom: "coin", Amount: math.OneInt()}).AnyTimes() - mockBankKeeper.EXPECT().IsSendEnabledCoin(gomock.Any(), gomock.Any()).Return(true).AnyTimes() + // Create invalid bech32 address with valid length but invalid format + // Using wrong prefix or invalid checksum + msg.Receiver = "cosmos100000000000000000000000000000000" + return msg }, - contractMinterBurner, - false, false, }, { - "fail - force send minted fail", - 100, - 10, - func(common.Address) {}, - func() { - ctrl := gomock.NewController(s.T()) - mockBankKeeper := erc20mocks.NewMockBankKeeper(ctrl) - transferKeeper := s.network.App.GetTransferKeeper() - erc20Keeper := keeper.NewKeeper( - s.network.App.GetKey("erc20"), s.network.App.AppCodec(), - authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), - mockBankKeeper, s.network.App.GetEVMKeeper(), s.network.App.GetStakingKeeper(), - &transferKeeper, - ) - s.network.App.SetErc20Keeper(erc20Keeper) + "fail - invalid sender hex address format", + func() *types.MsgConvertERC20 { + contractAddr, err := s.setupRegisterERC20Pair(contractMinterBurner) + s.Require().NoError(err) - mockBankKeeper.EXPECT().MintCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - mockBankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(fmt.Errorf("failed to unescrow")) - mockBankKeeper.EXPECT().BlockedAddr(gomock.Any()).Return(false) - mockBankKeeper.EXPECT().GetBalance(gomock.Any(), gomock.Any(), gomock.Any()).Return(sdk.Coin{Denom: "coin", Amount: math.OneInt()}) - mockBankKeeper.EXPECT().IsSendEnabledCoin(gomock.Any(), gomock.Any()).Return(true).AnyTimes() + sender := s.keyring.GetAccAddr(0) + senderHex := s.keyring.GetAddr(0) + + _, err = s.MintERC20Token(contractAddr, senderHex, big.NewInt(100)) + s.Require().NoError(err) + + msg := types.NewMsgConvertERC20( + math.NewInt(10), + sender, + contractAddr, + senderHex, + ) + // Create invalid hex address - not a valid hex string + msg.Sender = "0xZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + return msg }, - contractMinterBurner, - false, false, }, { - "fail - force bank balance fail", - 100, - 10, - func(common.Address) {}, - func() { - ctrl := gomock.NewController(s.T()) - mockBankKeeper := erc20mocks.NewMockBankKeeper(ctrl) - transferKeeper := s.network.App.GetTransferKeeper() - erc20Keeper := keeper.NewKeeper( - s.network.App.GetKey("erc20"), s.network.App.AppCodec(), - authtypes.NewModuleAddress(govtypes.ModuleName), s.network.App.GetAccountKeeper(), - mockBankKeeper, s.network.App.GetEVMKeeper(), s.network.App.GetStakingKeeper(), - &transferKeeper, + "fail - invalid contract hex address format", + func() *types.MsgConvertERC20 { + sender := s.keyring.GetAccAddr(0) + senderHex := s.keyring.GetAddr(0) + + msg := types.NewMsgConvertERC20( + math.NewInt(10), + sender, + common.HexToAddress("0x0"), + senderHex, ) - s.network.App.SetErc20Keeper(erc20Keeper) - - mockBankKeeper.EXPECT().MintCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - mockBankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) - mockBankKeeper.EXPECT().BlockedAddr(gomock.Any()).Return(false) - mockBankKeeper.EXPECT().GetBalance(gomock.Any(), gomock.Any(), gomock.Any()).Return(sdk.Coin{Denom: coinName, Amount: math.OneInt()}).AnyTimes() - mockBankKeeper.EXPECT().IsSendEnabledCoin(gomock.Any(), gomock.Any()).Return(true).AnyTimes() + // Create invalid hex address - not a valid hex string + msg.ContractAddress = "0xGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" + return msg }, - contractMinterBurner, - false, false, }, } + for _, tc := range testCases { - s.Run(fmt.Sprintf("Case %s", tc.name), func() { - var err error + s.Run(tc.name, func() { s.mintFeeCollector = true - defer func() { - s.mintFeeCollector = false - }() + defer func() { s.mintFeeCollector = false }() s.SetupTest() - - contractAddr, err = s.setupRegisterERC20Pair(tc.contractType) - s.Require().NoError(err) - - tc.malleate(contractAddr) - s.Require().NotNil(contractAddr) - - coinName = types.CreateDenom(contractAddr.String()) - sender := s.keyring.GetAccAddr(0) - - _, err = s.MintERC20Token(contractAddr, s.keyring.GetAddr(0), big.NewInt(tc.mint)) - s.Require().NoError(err) - // update context with latest committed changes - - tc.extra() - - convertERC20Msg := types.NewMsgConvertERC20( - math.NewInt(tc.transfer), - sender, - contractAddr, - s.keyring.GetAddr(0), - ) - - ctx := s.network.GetContext() + msg := tc.setup() if tc.expPass { - _, err = s.factory.CommitCosmosTx(s.keyring.GetPrivKey(0), factory.CosmosTxArgs{Msgs: []sdk.Msg{convertERC20Msg}}) + _, err := s.network.App.GetErc20Keeper().ConvertERC20(s.network.GetContext(), msg) s.Require().NoError(err, tc.name) - - cosmosBalance := s.network.App.GetBankKeeper().GetBalance(ctx, sender, coinName) - - acc := s.network.App.GetEVMKeeper().GetAccountWithoutBalance(ctx, contractAddr) - if tc.selfdestructed { - s.Require().Nil(acc, "expected contract to be destroyed") - } else { - s.Require().NotNil(acc) - } - - isContract := s.network.App.GetEVMKeeper().IsContract(s.network.GetContext(), contractAddr) - if tc.selfdestructed || !isContract { - id := s.network.App.GetErc20Keeper().GetTokenPairID(ctx, contractAddr.String()) - _, found := s.network.App.GetErc20Keeper().GetTokenPair(ctx, id) - s.Require().False(found) - } else { - s.Require().Equal(cosmosBalance.Amount, math.NewInt(tc.transfer)) - } } else { - _, err = s.network.App.GetErc20Keeper().ConvertERC20(ctx, convertERC20Msg) + _, err := s.network.App.GetErc20Keeper().ConvertERC20(s.network.GetContext(), msg) s.Require().Error(err, tc.name) } }) } - s.mintFeeCollector = false } func (s *KeeperTestSuite) TestConvertNativeERC20ToEVMERC20() { @@ -450,10 +204,10 @@ func (s *KeeperTestSuite) TestConvertNativeERC20ToEVMERC20() { existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} balance := make([]uint8, 32) mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, fmt.Errorf("forced ApplyMessage error")).Once() - mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, fmt.Errorf("forced ApplyMessage error")).Once() + mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) }, @@ -481,8 +235,11 @@ func (s *KeeperTestSuite) TestConvertNativeERC20ToEVMERC20() { balance := make([]uint8, 32) balance[31] = uint8(1) mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Times(3) - mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced balance error")) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Times(3) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Maybe() + mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced balance error")) mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) }, @@ -509,9 +266,9 @@ func (s *KeeperTestSuite) TestConvertNativeERC20ToEVMERC20() { existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} balance := make([]uint8, 32) mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Twice() - mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Twice() + mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) }, @@ -539,9 +296,9 @@ func (s *KeeperTestSuite) TestConvertNativeERC20ToEVMERC20() { existingAcc := &statedb.Account{Nonce: uint64(1), Balance: uint256.NewInt(1)} balance := make([]uint8, 32) mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Twice() - mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, + mockEVMKeeper.On("CallEVMWithData", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil) mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) mockEVMKeeper.On("IsContract", mock.Anything, mock.Anything).Return(true) diff --git a/tests/integration/x/erc20/test_proposals.go b/tests/integration/x/erc20/test_proposals.go index 997bd9d8e..86fbc9e58 100644 --- a/tests/integration/x/erc20/test_proposals.go +++ b/tests/integration/x/erc20/test_proposals.go @@ -168,7 +168,7 @@ func (s *KeeperTestSuite) TestRegisterERC20() { s.network.App.SetErc20Keeper(erc20Keeper) mockEVMKeeper.On("EstimateGasInternal", mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) - mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced CallEVM error")) + mockEVMKeeper.On("CallEVM", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced CallEVM error")) mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) }, s.keyring.GetAccAddr(0).String(), diff --git a/tests/integration/x/ibc/test_keeper.go b/tests/integration/x/ibc/test_keeper.go index 71a21f685..6c36a9ad0 100644 --- a/tests/integration/x/ibc/test_keeper.go +++ b/tests/integration/x/ibc/test_keeper.go @@ -42,8 +42,6 @@ type KeeperTestSuite struct { otherDenom string } -var timeoutHeight = clienttypes.NewHeight(1000, 1000) - func NewKeeperTestSuite(create network.CreateEvmApp, options ...network.ConfigOption) *KeeperTestSuite { return &KeeperTestSuite{ create: create, diff --git a/tests/integration/x/ibc/test_msg_server.go b/tests/integration/x/ibc/test_msg_server.go deleted file mode 100644 index 56a9599ce..000000000 --- a/tests/integration/x/ibc/test_msg_server.go +++ /dev/null @@ -1,517 +0,0 @@ -package ibc - -import ( - "fmt" - "strings" - - "github.com/stretchr/testify/mock" - - "github.com/cosmos/evm/testutil/integration/evm/utils" - testutils "github.com/cosmos/evm/testutil/integration/evm/utils" - "github.com/cosmos/evm/testutil/keyring" - erc20types "github.com/cosmos/evm/x/erc20/types" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" - evmtypes "github.com/cosmos/evm/x/vm/types" - "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types" - - "cosmossdk.io/math" - - "github.com/cosmos/cosmos-sdk/runtime" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" -) - -func (suite *KeeperTestSuite) TestTransfer() { - var ( - ctx sdk.Context - sender keyring.Key - ) - mockChannelKeeper := &MockChannelKeeper{} - mockICS4Wrapper := &MockICS4Wrapper{} - mockChannelKeeper.On("GetNextSequenceSend", mock.Anything, mock.Anything, mock.Anything).Return(1, true) - mockChannelKeeper.On("GetChannel", mock.Anything, mock.Anything, mock.Anything).Return(channeltypes.Channel{Counterparty: channeltypes.NewCounterparty("transfer", "channel-1")}, true) - mockICS4Wrapper.On("SendPacket", mock.Anything, mock.Anything, mock.Anything).Return(nil) - authAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() - receiver := sdk.AccAddress([]byte("receiver")) - chan0 := "channel-0" - - testCases := []struct { - name string - malleate func() *types.MsgTransfer - expPass bool - }{ - { - "pass - no token pair", - func() *types.MsgTransfer { - transferMsg := types.NewMsgTransfer(types.PortID, chan0, sdk.NewCoin(evmtypes.GetEVMCoinDenom(), math.NewInt(10)), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - return transferMsg - }, - true, - }, - { - "error - invalid sender", - func() *types.MsgTransfer { - addr := "" - contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) - suite.Require().NoError(err) - - transferMsg := types.NewMsgTransfer(types.PortID, chan0, sdk.NewCoin(erc20types.CreateDenom(contractAddr.String()), math.NewInt(10)), addr, receiver.String(), timeoutHeight, 0, "") - return transferMsg - }, - false, - }, - { - "no-op - disabled erc20 by params - sufficient sdk.Coins balance", - func() *types.MsgTransfer { - contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) - suite.Require().NoError(err) - - pair, err := utils.RegisterERC20(suite.factory, suite.network, utils.ERC20RegistrationData{ - Addresses: []string{contractAddr.Hex()}, - ProposerPriv: sender.Priv, - }) - suite.Require().NoError(err) - suite.Require().True(len(pair) == 1) - - amt := math.NewInt(10) - _, err = suite.MintERC20Token(contractAddr, sender.Addr, amt.BigInt()) - suite.Require().NoError(err) - - // convert all ERC20 to IBC coin - err = suite.ConvertERC20(sender, contractAddr, amt) - suite.Require().NoError(err) - - params := suite.network.App.GetErc20Keeper().GetParams(ctx) - params.EnableErc20 = false - - err = utils.UpdateERC20Params(utils.UpdateParamsInput{ - Tf: suite.factory, - Network: suite.network, - Pk: sender.Priv, - Params: params, - }) - suite.Require().NoError(err) - - coin := sdk.NewCoin(pair[0].Denom, amt) - transferMsg := types.NewMsgTransfer(types.PortID, chan0, coin, sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - - return transferMsg - }, - true, - }, - { - "error - disabled erc20 by params - insufficient sdk.Coins balance", - func() *types.MsgTransfer { - contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) - suite.Require().NoError(err) - - pair, err := utils.RegisterERC20(suite.factory, suite.network, utils.ERC20RegistrationData{ - Addresses: []string{contractAddr.Hex()}, - ProposerPriv: sender.Priv, - }) - suite.Require().NoError(err) - suite.Require().True(len(pair) == 1) - - amt := math.NewInt(10) - _, err = suite.MintERC20Token(contractAddr, sender.Addr, amt.BigInt()) - suite.Require().NoError(err) - - // No conversion to IBC coin, so the balance is insufficient - suite.Require().EqualValues(suite.network.App.GetBankKeeper().GetBalance( - ctx, sender.AccAddr, pair[0].Denom).Amount, math.ZeroInt()) - - params := suite.network.App.GetErc20Keeper().GetParams(ctx) - params.EnableErc20 = false - err = utils.UpdateERC20Params(utils.UpdateParamsInput{ - Tf: suite.factory, - Network: suite.network, - Pk: sender.Priv, - Params: params, - }) - suite.Require().NoError(err) - - coin := sdk.NewCoin(pair[0].Denom, amt) - transferMsg := types.NewMsgTransfer(types.PortID, chan0, coin, sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - - return transferMsg - }, - false, - }, - { - "no-op - pair not registered", - func() *types.MsgTransfer { - coin := sdk.NewCoin(suite.otherDenom, math.NewInt(10)) - transferMsg := types.NewMsgTransfer(types.PortID, chan0, coin, sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - return transferMsg - }, - true, - }, - { - "no-op - pair is disabled", - func() *types.MsgTransfer { - contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) - suite.Require().NoError(err) - - pair, err := utils.RegisterERC20(suite.factory, suite.network, utils.ERC20RegistrationData{ - Addresses: []string{contractAddr.Hex()}, - ProposerPriv: sender.Priv, - }) - suite.Require().NoError(err) - suite.Require().True(len(pair) == 1) - - amt := math.NewInt(10) - _, err = suite.MintERC20Token(contractAddr, sender.Addr, amt.BigInt()) - suite.Require().NoError(err) - - // convert all erc20 to coins to perform regular transfer without conversion - err = suite.ConvertERC20(sender, contractAddr, amt) - suite.Require().NoError(err) - - // disable token conversion - err = utils.ToggleTokenConversion(suite.factory, suite.network, sender.Priv, pair[0].Denom) - suite.Require().NoError(err) - - coin := sdk.NewCoin(pair[0].Denom, math.NewInt(10)) - transferMsg := types.NewMsgTransfer(types.PortID, chan0, coin, sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - - return transferMsg - }, - true, - }, - { - "pass - has enough balance in erc20 - need to convert", - func() *types.MsgTransfer { - contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) - suite.Require().NoError(err) - - res, err := utils.RegisterERC20(suite.factory, suite.network, utils.ERC20RegistrationData{ - Addresses: []string{contractAddr.Hex()}, - ProposerPriv: sender.Priv, - }) - suite.Require().NoError(err) - suite.Require().True(len(res) == 1) - pair := res[0] - suite.Require().Equal(erc20types.CreateDenom(pair.Erc20Address), pair.Denom) - - amt := math.NewInt(10) - _, err = suite.MintERC20Token(contractAddr, sender.Addr, amt.BigInt()) - suite.Require().NoError(err) - - transferMsg := types.NewMsgTransfer(types.PortID, chan0, sdk.NewCoin(pair.Denom, amt), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - - return transferMsg - }, - true, - }, - { - "pass - has enough balance in coins", - func() *types.MsgTransfer { - contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) - suite.Require().NoError(err) - - pair, err := utils.RegisterERC20(suite.factory, suite.network, utils.ERC20RegistrationData{ - Addresses: []string{contractAddr.Hex()}, - ProposerPriv: sender.Priv, - }) - suite.Require().NoError(err) - suite.Require().True(len(pair) == 1) - - // mint some erc20 tokens - amt := math.NewInt(10) - _, err = suite.MintERC20Token(contractAddr, suite.keyring.GetAddr(0), amt.BigInt()) - suite.Require().NoError(err) - - // convert all to IBC coins - err = suite.ConvertERC20(sender, contractAddr, amt) - suite.Require().NoError(err) - - transferMsg := types.NewMsgTransfer(types.PortID, chan0, sdk.NewCoin(pair[0].Denom, amt), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - - return transferMsg - }, - true, - }, - { - "error - fail conversion - no balance in erc20", - func() *types.MsgTransfer { - contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) - suite.Require().NoError(err) - - pair, err := utils.RegisterERC20(suite.factory, suite.network, utils.ERC20RegistrationData{ - Addresses: []string{contractAddr.Hex()}, - ProposerPriv: sender.Priv, - }) - suite.Require().NoError(err) - suite.Require().True(len(pair) == 1) - - transferMsg := types.NewMsgTransfer(types.PortID, chan0, sdk.NewCoin(pair[0].Denom, math.NewInt(10)), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - return transferMsg - }, - false, - }, - { - "pass - verify correct prefix trimming for ERC20 native tokens", - func() *types.MsgTransfer { - contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) - suite.Require().NoError(err) - - pair, err := testutils.RegisterERC20(suite.factory, suite.network, testutils.ERC20RegistrationData{ - Addresses: []string{contractAddr.Hex()}, - ProposerPriv: sender.Priv, - }) - suite.Require().NoError(err) - suite.Require().True(len(pair) == 1) - - // Mint ERC20 tokens - amt := math.NewInt(10) - _, err = suite.MintERC20Token(contractAddr, sender.Addr, amt.BigInt()) - suite.Require().NoError(err) - - // Create a denom with erc20: prefix - erc20Denom := erc20types.CreateDenom(contractAddr.String()) - suite.Require().Equal(erc20types.Erc20NativeCoinDenomPrefix+contractAddr.String(), erc20Denom) - - // Verify that GetTokenPairID works correctly with the contract address (hex string) - pairIDFromAddress := suite.network.App.GetErc20Keeper().GetTokenPairID(ctx, contractAddr.String()) - suite.Require().NotEmpty(pairIDFromAddress) - - // Verify that GetTokenPairID works correctly with the full denom - pairIDFromDenom := suite.network.App.GetErc20Keeper().GetTokenPairID(ctx, erc20Denom) - suite.Require().NotEmpty(pairIDFromDenom) - - // Both should return the same pair ID - suite.Require().Equal(pairIDFromAddress, pairIDFromDenom) - - transferMsg := types.NewMsgTransfer(types.PortID, chan0, sdk.NewCoin(erc20Denom, amt), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - - return transferMsg - }, - true, - }, - - // STRV2 - // native coin - perform normal ibc transfer - { - "no-op - fail transfer", - func() *types.MsgTransfer { - senderAcc := suite.keyring.GetAccAddr(0) - - denom := "ibc/DF63978F803A2E27CA5CC9B7631654CCF0BBC788B3B7F0A10200508E37C70992" - coinMetadata := banktypes.Metadata{ - Name: "Generic IBC name", - Symbol: "IBC", - Description: "Generic IBC token description", - DenomUnits: []*banktypes.DenomUnit{ - { - Denom: denom, - Exponent: 0, - Aliases: []string{denom}, - }, - { - Denom: denom, - Exponent: 18, - }, - }, - Display: denom, - Base: denom, - } - - coin := sdk.NewCoin(denom, math.NewInt(10)) - - pair, err := suite.network.App.GetErc20Keeper().RegisterERC20Extension(suite.network.GetContext(), coinMetadata.Base) - suite.Require().Equal(pair.Denom, denom) - suite.Require().NoError(err) - - transferMsg := types.NewMsgTransfer(types.PortID, chan0, coin, senderAcc.String(), receiver.String(), timeoutHeight, 0, "") - - return transferMsg - }, - false, - }, - } - for _, tc := range testCases { - suite.Run(fmt.Sprintf("Case %s", tc.name), func() { - suite.SetupTest() - sender = suite.keyring.GetKey(0) - ctx = suite.network.GetContext() - - suite.network.App.SetTransferKeeper(transferkeeper.NewKeeper( - suite.network.App.AppCodec(), - runtime.NewKVStoreService(suite.network.App.GetKey(types.StoreKey)), - &MockICS4Wrapper{}, // ICS4 Wrapper - mockChannelKeeper, - suite.network.App.MsgServiceRouter(), - suite.network.App.GetAccountKeeper(), - suite.network.App.GetBankKeeper(), - suite.network.App.GetErc20Keeper(), // Add ERC20 Keeper for ERC20 transfers - authAddr, - )) - msg := tc.malleate() - - // get updated context with the latest changes - ctx = suite.network.GetContext() - - _, err := suite.network.App.GetTransferKeeper().Transfer(ctx, msg) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -// TestPrefixTrimming tests that the Transfer method correctly trims the erc20: prefix -// This test specifically catches the bug where "erc20/" was being trimmed instead of "erc20:" -func (suite *KeeperTestSuite) TestPrefixTrimming() { - var ( - ctx sdk.Context - sender keyring.Key - ) - mockChannelKeeper := &MockChannelKeeper{} - mockICS4Wrapper := &MockICS4Wrapper{} - mockChannelKeeper.On("GetNextSequenceSend", mock.Anything, mock.Anything, mock.Anything).Return(1, true) - mockChannelKeeper.On("GetChannel", mock.Anything, mock.Anything, mock.Anything).Return(channeltypes.Channel{Counterparty: channeltypes.NewCounterparty("transfer", "channel-1")}, true) - mockICS4Wrapper.On("SendPacket", mock.Anything, mock.Anything, mock.Anything).Return(nil) - authAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String() - receiver := sdk.AccAddress([]byte("receiver")) - chan0 := "channel-0" - - testCases := []struct { - name string - malleate func() *types.MsgTransfer - expPass bool - description string - }{ - { - name: "pass - correct prefix trimming erc20:", - malleate: func() *types.MsgTransfer { - contractAddr, err := suite.DeployContract("coin", "token", uint8(6)) - suite.Require().NoError(err) - - pair, err := testutils.RegisterERC20(suite.factory, suite.network, testutils.ERC20RegistrationData{ - Addresses: []string{contractAddr.Hex()}, - ProposerPriv: sender.Priv, - }) - suite.Require().NoError(err) - suite.Require().True(len(pair) == 1) - - // Mint ERC20 tokens - amt := math.NewInt(10) - _, err = suite.MintERC20Token(contractAddr, sender.Addr, amt.BigInt()) - suite.Require().NoError(err) - - // Create a denom with erc20: prefix - erc20Denom := erc20types.CreateDenom(contractAddr.String()) - suite.Require().Equal(erc20types.Erc20NativeCoinDenomPrefix+contractAddr.String(), erc20Denom) - - // TEST: Verify that the prefix trimming works correctly - // The Transfer method should trim "erc20:" prefix to get the hex address - expectedTrimmed := strings.TrimPrefix(erc20Denom, erc20types.Erc20NativeCoinDenomPrefix) - suite.Require().Equal(contractAddr.String(), expectedTrimmed) - - // Verify that GetTokenPairID works correctly with the contract address (hex string) - pairIDFromAddress := suite.network.App.GetErc20Keeper().GetTokenPairID(ctx, contractAddr.String()) - suite.Require().NotEmpty(pairIDFromAddress) - - // Verify that GetTokenPairID works correctly with the full denom - pairIDFromDenom := suite.network.App.GetErc20Keeper().GetTokenPairID(ctx, erc20Denom) - suite.Require().NotEmpty(pairIDFromDenom) - - // Both should return the same pair ID - suite.Require().Equal(pairIDFromAddress, pairIDFromDenom) - - // TEST: Verify that incorrect prefix trimming would fail - // If we incorrectly trim "erc20/" instead of "erc20:", we'd get the wrong string - incorrectTrimmed := strings.TrimPrefix(erc20Denom, erc20types.ModuleName+"/") - suite.Require().NotEqual(contractAddr.String(), incorrectTrimmed) - suite.Require().Equal(erc20Denom, incorrectTrimmed) // Since "erc20/" is not in the string, it returns unchanged - - transferMsg := types.NewMsgTransfer(types.PortID, chan0, sdk.NewCoin(erc20Denom, amt), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - - return transferMsg - }, - expPass: true, - description: "Test that verifies correct prefix trimming for ERC20 native tokens", - }, - { - name: "pass - demonstrate bug impact", - malleate: func() *types.MsgTransfer { - contractAddr, err := suite.DeployContract("coin2", "token2", uint8(6)) - suite.Require().NoError(err) - - pair, err := testutils.RegisterERC20(suite.factory, suite.network, testutils.ERC20RegistrationData{ - Addresses: []string{contractAddr.Hex()}, - ProposerPriv: sender.Priv, - }) - suite.Require().NoError(err) - suite.Require().True(len(pair) == 1) - - // Mint ERC20 tokens - amt := math.NewInt(10) - _, err = suite.MintERC20Token(contractAddr, sender.Addr, amt.BigInt()) - suite.Require().NoError(err) - - // Create a denom with erc20: prefix - erc20Denom := erc20types.CreateDenom(contractAddr.String()) - - // TEST: Demonstrate the bug's impact - // With correct prefix trimming ("erc20:"), we get the hex address - correctTrimmed := strings.TrimPrefix(erc20Denom, erc20types.Erc20NativeCoinDenomPrefix) - suite.Require().Equal(contractAddr.String(), correctTrimmed) - - // With incorrect prefix trimming ("erc20/"), we get the full denom (no change) - incorrectTrimmed := strings.TrimPrefix(erc20Denom, erc20types.ModuleName+"/") - suite.Require().Equal(erc20Denom, incorrectTrimmed) - - // Both lookups should work due to dual mapping, but use different code paths - pairIDFromCorrect := suite.network.App.GetErc20Keeper().GetTokenPairID(ctx, correctTrimmed) - pairIDFromIncorrect := suite.network.App.GetErc20Keeper().GetTokenPairID(ctx, incorrectTrimmed) - - suite.Require().NotEmpty(pairIDFromCorrect) - suite.Require().NotEmpty(pairIDFromIncorrect) - suite.Require().Equal(pairIDFromCorrect, pairIDFromIncorrect) - - transferMsg := types.NewMsgTransfer(types.PortID, chan0, sdk.NewCoin(erc20Denom, amt), sender.AccAddr.String(), receiver.String(), timeoutHeight, 0, "") - - return transferMsg - }, - expPass: true, - description: "Test that demonstrates why the bug wasn't caught - both lookups work", - }, - } - - for _, tc := range testCases { - suite.Run(fmt.Sprintf("Case %s", tc.name), func() { - suite.SetupTest() - sender = suite.keyring.GetKey(0) - ctx = suite.network.GetContext() - - suite.network.App.SetTransferKeeper(transferkeeper.NewKeeper( - suite.network.App.AppCodec(), - runtime.NewKVStoreService(suite.network.App.GetKey(types.StoreKey)), - &MockICS4Wrapper{}, // ICS4 Wrapper - mockChannelKeeper, - suite.network.App.MsgServiceRouter(), - suite.network.App.GetAccountKeeper(), - suite.network.App.GetBankKeeper(), - suite.network.App.GetErc20Keeper(), // Add ERC20 Keeper for ERC20 transfers - authAddr, - )) - msg := tc.malleate() - - // get updated context with the latest changes - ctx = suite.network.GetContext() - - _, err := suite.network.App.GetTransferKeeper().Transfer(ctx, msg) - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} diff --git a/tests/integration/x/vm/state_transition_benchmark.go b/tests/integration/x/vm/state_transition_benchmark.go index e3e0a2c93..566306484 100644 --- a/tests/integration/x/vm/state_transition_benchmark.go +++ b/tests/integration/x/vm/state_transition_benchmark.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" utiltx "github.com/cosmos/evm/testutil/tx" + "github.com/cosmos/evm/x/vm/statedb" evmtypes "github.com/cosmos/evm/x/vm/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" @@ -287,8 +288,10 @@ func BenchmarkApplyMessage(b *testing.B) { ) require.NoError(b, err) + stateDB := statedb.New(suite.Network.GetContext(), suite.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + b.StartTimer() - resp, err := suite.Network.App.GetEVMKeeper().ApplyMessage(suite.Network.GetContext(), *m, nil, true, false) + resp, err := suite.Network.App.GetEVMKeeper().ApplyMessage(suite.Network.GetContext(), stateDB, *m, nil, true, false, false) b.StopTimer() require.NoError(b, err) @@ -321,8 +324,10 @@ func BenchmarkApplyMessageWithLegacyTx(b *testing.B) { ) require.NoError(b, err) + stateDB := statedb.New(suite.Network.GetContext(), suite.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + b.StartTimer() - resp, err := suite.Network.App.GetEVMKeeper().ApplyMessage(suite.Network.GetContext(), *m, nil, true, false) + resp, err := suite.Network.App.GetEVMKeeper().ApplyMessage(suite.Network.GetContext(), stateDB, *m, nil, true, false, false) b.StopTimer() require.NoError(b, err) @@ -355,8 +360,10 @@ func BenchmarkApplyMessageWithDynamicFeeTx(b *testing.B) { ) require.NoError(b, err) + stateDB := statedb.New(suite.Network.GetContext(), suite.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + b.StartTimer() - resp, err := suite.Network.App.GetEVMKeeper().ApplyMessage(suite.Network.GetContext(), *m, nil, true, false) + resp, err := suite.Network.App.GetEVMKeeper().ApplyMessage(suite.Network.GetContext(), stateDB, *m, nil, true, false, false) b.StopTimer() require.NoError(b, err) diff --git a/tests/integration/x/vm/test_call_evm.go b/tests/integration/x/vm/test_call_evm.go index 013b200f2..ba24039a5 100644 --- a/tests/integration/x/vm/test_call_evm.go +++ b/tests/integration/x/vm/test_call_evm.go @@ -9,25 +9,39 @@ import ( testconstants "github.com/cosmos/evm/testutil/constants" utiltx "github.com/cosmos/evm/testutil/tx" "github.com/cosmos/evm/x/erc20/types" + "github.com/cosmos/evm/x/vm/statedb" evmtypes "github.com/cosmos/evm/x/vm/types" ) func (s *KeeperTestSuite) TestCallEVM() { wcosmosEVMContract := common.HexToAddress(testconstants.WEVMOSContractMainnet) testCases := []struct { - name string - method string - expPass bool + name string + method string + stateDB *statedb.StateDB + expPass bool + expError string }{ { "unknown method", "", + nil, false, + "", }, { "pass", "balanceOf", + nil, true, + "", + }, + { + "fail with nil statedb", + "balanceOf", + nil, + false, + "stateDB cannot be nil", }, } for _, tc := range testCases { @@ -35,12 +49,23 @@ func (s *KeeperTestSuite) TestCallEVM() { erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI account := utiltx.GenerateAddress() - res, err := s.Network.App.GetEVMKeeper().CallEVM(s.Network.GetContext(), erc20, types.ModuleAddress, wcosmosEVMContract, false, nil, tc.method, account) + + var stateDB *statedb.StateDB + if tc.stateDB == nil && tc.name != "fail with nil statedb" { + stateDB = statedb.New(s.Network.GetContext(), s.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + } else { + stateDB = tc.stateDB + } + + res, err := s.Network.App.GetEVMKeeper().CallEVM(s.Network.GetContext(), stateDB, erc20, types.ModuleAddress, wcosmosEVMContract, false, false, nil, tc.method, account) if tc.expPass { s.Require().IsTypef(&evmtypes.MsgEthereumTxResponse{}, res, tc.name) s.Require().NoError(err) } else { s.Require().Error(err) + if tc.expError != "" { + s.Require().Contains(err.Error(), tc.expError) + } } } } @@ -53,64 +78,88 @@ func (s *KeeperTestSuite) TestCallEVMWithData() { from common.Address malleate func() []byte deploy bool + useNilDB bool expPass bool + expError string }{ { - "pass with unknown method", - types.ModuleAddress, - func() []byte { + name: "pass with unknown method", + from: types.ModuleAddress, + malleate: func() []byte { account := utiltx.GenerateAddress() data, _ := erc20.Pack("", account) return data }, - false, - true, + deploy: false, + useNilDB: false, + expPass: true, + expError: "", }, { - "pass", - types.ModuleAddress, - func() []byte { + name: "pass", + from: types.ModuleAddress, + malleate: func() []byte { account := utiltx.GenerateAddress() data, _ := erc20.Pack("balanceOf", account) return data }, - false, - true, + deploy: false, + useNilDB: false, + expPass: true, + expError: "", }, { - "pass with empty data", - types.ModuleAddress, - func() []byte { + name: "pass with empty data", + from: types.ModuleAddress, + malleate: func() []byte { return []byte{} }, - false, - true, + deploy: false, + useNilDB: false, + expPass: true, + expError: "", }, - { - "fail empty sender", - common.Address{}, - func() []byte { + name: "fail empty sender", + from: common.Address{}, + malleate: func() []byte { return []byte{} }, - false, - false, + deploy: false, + useNilDB: false, + expPass: false, + expError: "", }, { - "deploy", - types.ModuleAddress, - func() []byte { + name: "fail with nil statedb", + from: types.ModuleAddress, + malleate: func() []byte { + account := utiltx.GenerateAddress() + data, _ := erc20.Pack("balanceOf", account) + return data + }, + deploy: false, + useNilDB: true, + expPass: false, + expError: "stateDB cannot be nil", + }, + { + name: "deploy", + from: types.ModuleAddress, + malleate: func() []byte { ctorArgs, _ := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("", "test", "test", uint8(18)) data := append(contracts.ERC20MinterBurnerDecimalsContract.Bin, ctorArgs...) //nolint:gocritic return data }, - true, - true, + deploy: true, + useNilDB: false, + expPass: true, + expError: "", }, { - "fail deploy", - types.ModuleAddress, - func() []byte { + name: "fail deploy", + from: types.ModuleAddress, + malleate: func() []byte { params := s.Network.App.GetEVMKeeper().GetParams(s.Network.GetContext()) params.AccessControl.Create = evmtypes.AccessControlType{ AccessType: evmtypes.AccessTypeRestricted, @@ -120,8 +169,23 @@ func (s *KeeperTestSuite) TestCallEVMWithData() { data := append(contracts.ERC20MinterBurnerDecimalsContract.Bin, ctorArgs...) //nolint:gocritic return data }, - true, - false, + deploy: true, + useNilDB: false, + expPass: false, + expError: "", + }, + { + name: "fail deploy with nil statedb", + from: types.ModuleAddress, + malleate: func() []byte { + ctorArgs, _ := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("", "test", "test", uint8(18)) + data := append(contracts.ERC20MinterBurnerDecimalsContract.Bin, ctorArgs...) //nolint:gocritic + return data + }, + deploy: true, + useNilDB: true, + expPass: false, + expError: "stateDB cannot be nil", }, } @@ -133,10 +197,15 @@ func (s *KeeperTestSuite) TestCallEVMWithData() { var res *evmtypes.MsgEthereumTxResponse var err error + var stateDB *statedb.StateDB + if !tc.useNilDB { + stateDB = statedb.New(s.Network.GetContext(), s.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + } + if tc.deploy { - res, err = s.Network.App.GetEVMKeeper().CallEVMWithData(s.Network.GetContext(), tc.from, nil, data, true, nil) + res, err = s.Network.App.GetEVMKeeper().CallEVMWithData(s.Network.GetContext(), stateDB, tc.from, nil, data, true, false, nil) } else { - res, err = s.Network.App.GetEVMKeeper().CallEVMWithData(s.Network.GetContext(), tc.from, &wcosmosEVMContract, data, false, nil) + res, err = s.Network.App.GetEVMKeeper().CallEVMWithData(s.Network.GetContext(), stateDB, tc.from, &wcosmosEVMContract, data, false, false, nil) } if tc.expPass { @@ -144,6 +213,9 @@ func (s *KeeperTestSuite) TestCallEVMWithData() { s.Require().NoError(err) } else { s.Require().Error(err) + if tc.expError != "" { + s.Require().Contains(err.Error(), tc.expError) + } } }) } diff --git a/tests/integration/x/vm/test_commit_idempotency.go b/tests/integration/x/vm/test_commit_idempotency.go new file mode 100644 index 000000000..42cf358b1 --- /dev/null +++ b/tests/integration/x/vm/test_commit_idempotency.go @@ -0,0 +1,235 @@ +package vm + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/holiman/uint256" + + vmkeeper "github.com/cosmos/evm/x/vm/keeper" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TestCommitIdempotency verifies that calling FlushToCacheCtx multiple times +// without any state changes produces identical results across all branches in commitWithCtx: +// - DeleteAccount (self-destructed) +// - SetCode/DeleteCode (code operations) +// - SetAccount (account updates) +// - SetState/DeleteState (storage operations) +func (s *KeeperTestSuite) TestCommitIdempotency() { + s.SetupTest() + evmKeeper := s.Network.App.GetEVMKeeper() + + // Setup test accounts + addr1 := common.BytesToAddress([]byte("addr1")) + addr2 := common.BytesToAddress([]byte("addr2")) + addr3 := common.BytesToAddress([]byte("addr3")) + addr4 := common.BytesToAddress([]byte("addr4")) + + // Test data + code := []byte{0x60, 0x80, 0x60, 0x40, 0x52} // sample bytecode + emptyCodeHash := crypto.Keccak256Hash(nil) + storageKey1 := common.HexToHash("0x1") + storageKey2 := common.HexToHash("0x2") + + // Setup state to cover all branches + db := s.StateDB() + cacheCtx, err := db.GetCacheContext() + s.Require().NoError(err) + + // addr1: Account with code and storage (tests SetCode + SetState) + db.CreateAccount(addr1) + code1 := []byte{0x60, 0x42} + db.SetCode(addr1, code1) + db.SetState(addr1, storageKey1, common.HexToHash("0x456")) + db.AddBalance(addr1, uint256ToInt(big.NewInt(1000)), 0) + + // addr2: Account with empty/deleted code (tests DeleteCode) + db.CreateAccount(addr2) + db.SetCode(addr2, nil) + db.AddBalance(addr2, uint256ToInt(big.NewInt(2000)), 0) + + // addr3: Self-destructed account (tests DeleteAccount) + db.CreateAccount(addr3) + db.SetCode(addr3, code) + db.SelfDestruct(addr3) + + // addr4: Account with storage deleted (tests DeleteState) + db.CreateAccount(addr4) + db.SetState(addr4, storageKey1, common.Hash{}) // deleted storage + db.SetState(addr4, storageKey2, common.HexToHash("0x789")) + db.AddBalance(addr4, uint256ToInt(big.NewInt(4000)), 0) + + // Commit once to persist state + err = db.FlushToCacheCtx() + s.Require().NoError(err) + + // Capture state after first commit + snapshot1 := captureState(cacheCtx, evmKeeper, []common.Address{addr1, addr2, addr3, addr4}) + + err = db.FlushToCacheCtx() + s.Require().NoError(err) + + snapshot2 := captureState(cacheCtx, evmKeeper, []common.Address{addr1, addr2, addr3, addr4}) + + err = db.FlushToCacheCtx() + s.Require().NoError(err) + + snapshot3 := captureState(cacheCtx, evmKeeper, []common.Address{addr1, addr2, addr3, addr4}) + + // All snapshots should be identical + s.Require().Equal(snapshot1, snapshot2, "First and second commit should produce identical state") + s.Require().Equal(snapshot2, snapshot3, "Second and third commit should produce identical state") + + // Verify specific invariants + s.Require().Equal(code1, evmKeeper.GetCode(cacheCtx, crypto.Keccak256Hash(code1))) + s.Require().Empty(evmKeeper.GetCode(cacheCtx, emptyCodeHash)) + s.Require().Nil(evmKeeper.GetAccount(cacheCtx, addr3)) + s.Require().Equal(common.Hash{}, evmKeeper.GetState(cacheCtx, addr4, storageKey1)) +} + +// TestCommitIdempotencyWithStorage tests idempotency of storage operations +func (s *KeeperTestSuite) TestCommitIdempotencyWithStorage() { + s.SetupTest() + evmKeeper := s.Network.App.GetEVMKeeper() + + addr := common.BytesToAddress([]byte("testaddr")) + storageKey := common.HexToHash("0x1") + targetValue := common.HexToHash("0x222") + + // Setup: Create account and set storage + db := s.StateDB() + cacheCtx, err := db.GetCacheContext() + s.Require().NoError(err) + db.CreateAccount(addr) + db.SetState(addr, storageKey, targetValue) + err = db.FlushToCacheCtx() + s.Require().NoError(err) + + snapshot1 := evmKeeper.GetState(cacheCtx, addr, storageKey) + + // Multiple commits without changes should be idempotent + err = db.FlushToCacheCtx() + s.Require().NoError(err) + snapshot2 := evmKeeper.GetState(cacheCtx, addr, storageKey) + + err = db.FlushToCacheCtx() + s.Require().NoError(err) + snapshot3 := evmKeeper.GetState(cacheCtx, addr, storageKey) + + s.Require().Equal(snapshot1, snapshot2) + s.Require().Equal(snapshot2, snapshot3) + s.Require().Equal(targetValue, snapshot3) +} + +// TestCommitIdempotencyWithCodeDeletion tests idempotency of code deletion +func (s *KeeperTestSuite) TestCommitIdempotencyWithCodeDeletion() { + s.SetupTest() + evmKeeper := s.Network.App.GetEVMKeeper() + + addr := common.BytesToAddress([]byte("testaddr")) + + // Setup: Create account and delete code + db := s.StateDB() + cacheCtx, err := db.GetCacheContext() + s.Require().NoError(err) + db.CreateAccount(addr) + db.SetCode(addr, nil) + err = db.FlushToCacheCtx() + s.Require().NoError(err) + + codeHash1 := evmKeeper.GetCodeHash(cacheCtx, addr) + + // Multiple commits without changes should be idempotent + err = db.FlushToCacheCtx() + s.Require().NoError(err) + codeHash2 := evmKeeper.GetCodeHash(cacheCtx, addr) + + err = db.FlushToCacheCtx() + s.Require().NoError(err) + codeHash3 := evmKeeper.GetCodeHash(cacheCtx, addr) + + s.Require().Equal(codeHash1, codeHash2) + s.Require().Equal(codeHash2, codeHash3) +} + +// TestCommitIdempotencyWithSelfDestruct tests idempotency of account deletion +func (s *KeeperTestSuite) TestCommitIdempotencyWithSelfDestruct() { + s.SetupTest() + evmKeeper := s.Network.App.GetEVMKeeper() + + addr := common.BytesToAddress([]byte("testaddr")) + + // Setup: Create account and self-destruct + db := s.StateDB() + cacheCtx, err := db.GetCacheContext() + s.Require().NoError(err) + db.CreateAccount(addr) + db.SelfDestruct(addr) + err = db.FlushToCacheCtx() + s.Require().NoError(err) + + account1 := evmKeeper.GetAccount(cacheCtx, addr) + + // Multiple commits without changes should be idempotent + err = db.FlushToCacheCtx() + s.Require().NoError(err) + account2 := evmKeeper.GetAccount(cacheCtx, addr) + + err = db.FlushToCacheCtx() + s.Require().NoError(err) + account3 := evmKeeper.GetAccount(cacheCtx, addr) + + s.Require().Nil(account1) + s.Require().Nil(account2) + s.Require().Nil(account3) +} + +// accountState captures relevant account state for comparison +type accountState struct { + Exists bool + Balance *big.Int + Nonce uint64 + CodeHash common.Hash + StorageState map[common.Hash]common.Hash +} + +// stateSnapshot captures the state of multiple accounts +type stateSnapshot map[common.Address]accountState + +// captureState reads and captures the current state of given addresses +func captureState(ctx sdk.Context, evmKeeper *vmkeeper.Keeper, addrs []common.Address) stateSnapshot { + snapshot := make(stateSnapshot) + + for _, addr := range addrs { + account := evmKeeper.GetAccount(ctx, addr) + if account == nil { + snapshot[addr] = accountState{Exists: false} + continue + } + + storage := make(map[common.Hash]common.Hash) + // Capture all storage keys for this address + evmKeeper.ForEachStorage(ctx, addr, func(key, value common.Hash) bool { + storage[key] = value + return true + }) + + snapshot[addr] = accountState{ + Exists: true, + Balance: account.Balance.ToBig(), + Nonce: account.Nonce, + CodeHash: common.BytesToHash(account.CodeHash), + StorageState: storage, + } + } + + return snapshot +} + +func uint256ToInt(i *big.Int) *uint256.Int { + u, _ := uint256.FromBig(i) + return u +} diff --git a/tests/integration/x/vm/test_state_transition.go b/tests/integration/x/vm/test_state_transition.go index f44f5d5e6..1847c9026 100644 --- a/tests/integration/x/vm/test_state_transition.go +++ b/tests/integration/x/vm/test_state_transition.go @@ -26,6 +26,7 @@ import ( utiltx "github.com/cosmos/evm/testutil/tx" feemarkettypes "github.com/cosmos/evm/x/feemarket/types" "github.com/cosmos/evm/x/vm/keeper" + "github.com/cosmos/evm/x/vm/statedb" "github.com/cosmos/evm/x/vm/types" sdkmath "cosmossdk.io/math" @@ -800,31 +801,68 @@ func (s *KeeperTestSuite) TestApplyMessage() { defer func() { s.EnableFeemarket = false }() s.SetupTest() - // Generate a transfer tx message - sender := s.Keyring.GetKey(0) - recipient := s.Keyring.GetAddr(1) - transferArgs := types.EvmTxArgs{ - To: &recipient, - Amount: big.NewInt(100), + testCases := []struct { + name string + useNilDB bool + expPass bool + expError string + }{ + { + name: "success", + useNilDB: false, + expPass: true, + expError: "", + }, + { + name: "fail with nil statedb", + useNilDB: true, + expPass: false, + expError: "stateDB cannot be nil", + }, } - coreMsg, err := s.Factory.GenerateGethCoreMsg( - sender.Priv, - transferArgs, - ) - s.Require().NoError(err) - tracer := s.Network.App.GetEVMKeeper().Tracer( - s.Network.GetContext(), - *coreMsg, - types.GetEthChainConfig(), - ) - res, err := s.Network.App.GetEVMKeeper().ApplyMessage(s.Network.GetContext(), *coreMsg, tracer, true, false) - s.Require().NoError(err) - s.Require().False(res.Failed()) + for _, tc := range testCases { + s.Run(fmt.Sprintf("Case %s", tc.name), func() { + // Generate a transfer tx message + sender := s.Keyring.GetKey(0) + recipient := s.Keyring.GetAddr(1) + transferArgs := types.EvmTxArgs{ + To: &recipient, + Amount: big.NewInt(100), + } + coreMsg, err := s.Factory.GenerateGethCoreMsg( + sender.Priv, + transferArgs, + ) + s.Require().NoError(err) + + tracer := s.Network.App.GetEVMKeeper().Tracer( + s.Network.GetContext(), + *coreMsg, + types.GetEthChainConfig(), + ) + + var stateDB *statedb.StateDB + if !tc.useNilDB { + stateDB = statedb.New(s.Network.GetContext(), s.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + } + + res, err := s.Network.App.GetEVMKeeper().ApplyMessage(s.Network.GetContext(), stateDB, *coreMsg, tracer, true, false, false) - // Compare gas to a transfer tx gas - expectedGasUsed := params.TxGas - s.Require().Equal(expectedGasUsed, res.GasUsed) + if tc.expPass { + s.Require().NoError(err) + s.Require().False(res.Failed()) + // Compare gas to a transfer tx gas + expectedGasUsed := params.TxGas + s.Require().Equal(expectedGasUsed, res.GasUsed) + } else { + s.Require().Error(err) + if tc.expError != "" { + s.Require().Contains(err.Error(), tc.expError) + } + } + }) + } } func (s *KeeperTestSuite) TestApplyMessageWithConfig() { @@ -849,6 +887,7 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() { getEVMParams func() types.Params getFeeMarketParams func() feemarkettypes.Params overrides *rpctypes.StateOverride + useNilDB bool expErr bool expVMErr bool expectedGasUsed uint64 @@ -869,6 +908,7 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() { getEVMParams: types.DefaultParams, getFeeMarketParams: feemarkettypes.DefaultParams, overrides: nil, + useNilDB: false, expErr: false, expVMErr: false, expectedGasUsed: params.TxGas, @@ -1091,11 +1131,33 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() { return params }, overrides: nil, + useNilDB: false, expErr: true, expVMErr: false, expectedGasUsed: 0, postCheck: nil, }, + { + name: "fail with nil statedb", + getMessage: func() core.Message { + sender := s.Keyring.GetKey(0) + recipient := s.Keyring.GetAddr(1) + msg, err := s.Factory.GenerateGethCoreMsg(sender.Priv, types.EvmTxArgs{ + To: &recipient, + Amount: big.NewInt(100), + }) + s.Require().NoError(err) + return *msg + }, + getEVMParams: types.DefaultParams, + getFeeMarketParams: feemarkettypes.DefaultParams, + overrides: nil, + useNilDB: true, + expErr: true, + expVMErr: false, + expectedGasUsed: 0, + postCheck: nil, + }, } for _, tc := range testCases { @@ -1125,16 +1187,12 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() { ) s.Require().NoError(err) - res, err := s.Network.App.GetEVMKeeper().ApplyMessageWithConfig( - s.Network.GetContext(), - msg, - nil, - true, - config, - txConfig, - false, - tc.overrides, - ) + var stateDB *statedb.StateDB + if !tc.useNilDB { + stateDB = statedb.New(s.Network.GetContext(), s.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + } + + res, err := s.Network.App.GetEVMKeeper().ApplyMessageWithConfig(s.Network.GetContext(), stateDB, msg, nil, true, false, config, txConfig, false, tc.overrides) if tc.expErr { s.Require().Error(err) @@ -1222,13 +1280,9 @@ func (s *KeeperTestSuite) TestApplyMessageWithNegativeAmount() { ctx := s.Network.GetContext() balance0Before := s.Network.App.GetBankKeeper().GetBalance(ctx, s.Keyring.GetAccAddr(0), "aatom") balance1Before := s.Network.App.GetBankKeeper().GetBalance(ctx, s.Keyring.GetAccAddr(1), "aatom") - res, err := s.Network.App.GetEVMKeeper().ApplyMessage( - s.Network.GetContext(), - *coreMsg, - tracer, - true, - false, - ) + stateDB := statedb.New(s.Network.GetContext(), s.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig()) + + res, err := s.Network.App.GetEVMKeeper().ApplyMessage(s.Network.GetContext(), stateDB, *coreMsg, tracer, true, false, false) s.Require().Nil(res) s.Require().Error(err) diff --git a/tests/solidity/suites/precompiles/test/3_erc20/erc20.js b/tests/solidity/suites/precompiles/test/3_erc20/erc20.js index daedebc2b..e1a52a2fc 100644 --- a/tests/solidity/suites/precompiles/test/3_erc20/erc20.js +++ b/tests/solidity/suites/precompiles/test/3_erc20/erc20.js @@ -3,20 +3,36 @@ const hre = require('hardhat') const { findEvent, waitWithTimeout, RETRY_DELAY_FUNC} = require('../common') describe('ERC20 Precompile', function () { - let erc20, owner, spender, recipient + let erc20, erc20BurnContract, erc20Burn0Contract, owner, spender, recipient const GAS_LIMIT = 1_000_000 // skip gas estimation for simplicity + const ERC20_PRECOMPILE_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' + + const ERC20_BURN_ABI = [ + 'function mint(address to, uint256 amount) external returns (bool)', + 'function burn(uint256 amount) external', + ] + + // Get the ERC20 precompile contract instance + const ERC20_BURN0_ABI = [ + 'function mint(address to, uint256 amount) external returns (bool)', + 'function burn(address from, uint256 amount) external', + ] + before(async function () { [owner, spender, recipient] = await hre.ethers.getSigners() erc20 = await hre.ethers.getContractAt( 'IERC20Metadata', '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' ) + + erc20BurnContract = new hre.ethers.Contract(ERC20_PRECOMPILE_ADDRESS, ERC20_BURN_ABI, owner) + erc20Burn0Contract = new hre.ethers.Contract(ERC20_PRECOMPILE_ADDRESS, ERC20_BURN0_ABI, owner) }) it('should return the name', async function () { const name = await erc20.name() - expect(name).to.contain('Test Token') + expect(name).to.contain('Token') }) it('should return the symbol', async function () { @@ -44,6 +60,12 @@ describe('ERC20 Precompile', function () { expect(allowance).to.equal(0n) }) + + it('should return the contract owner address', async function () { + const ownerAddr = await erc20.owner() + expect(ownerAddr).to.equal(owner.address) + }) + it('should transfer tokens', async function () { const amount = hre.ethers.parseEther('1') const prev = await erc20.balanceOf(spender.address) @@ -66,10 +88,10 @@ describe('ERC20 Precompile', function () { // owner gives spender permission to move amount const approvalTx = await erc20. - connect(owner) + connect(owner) .approve(spender.address, amount, {gasLimit: GAS_LIMIT}) const approvalReceipt = await waitWithTimeout(approvalTx, 20000, RETRY_DELAY_FUNC) - console.log(`Approval transaction hash: ${approvalTx.hash}`) + const approvalEvent = findEvent(approvalReceipt.logs, erc20.interface, 'Approval') expect(approvalEvent, 'Approval event must be emitted').to.exist @@ -80,15 +102,12 @@ describe('ERC20 Precompile', function () { // record pre-transfer balances and allowance const prevBalance = await erc20.balanceOf(recipient.address) const prevAllowance = await erc20.allowance(owner.address, spender.address) - console.log(`Pre-transfer balance of recipient: ${prevBalance}`) - console.log(`Pre-transfer allowance of spender: ${prevAllowance}`) // spender pulls from owner → recipient const tx = await erc20 .connect(spender) .transferFrom(owner.address, recipient.address, amount, {gasLimit: GAS_LIMIT}) const receipt = await waitWithTimeout(tx, 20000, RETRY_DELAY_FUNC) - console.log(`Transfer transaction hash: ${tx.hash}`) const transferEvent = findEvent(receipt.logs, erc20.interface, 'Transfer') expect(transferEvent, 'Transfer event must be emitted').to.exist @@ -106,4 +125,234 @@ describe('ERC20 Precompile', function () { // allowance should have decreased by `amount` expect(afterAllowance).to.equal(prevAllowance - amount) }) + + + describe('mint', function () { + it('should revert if the caller is not the contract owner', async function () { + const mintAmount = hre.ethers.parseEther('100') + + // Connect as spender (non-owner) and mint - this should revert + const spenderContract = erc20.connect(spender) + + // Mint tokens as non-owner spender to recipient - should revert + await expect(spenderContract.mint(recipient.address, mintAmount)) + .to.be.reverted + }) + + it('should mint tokens to the recipient if the caller is the contract owner', async function () { + const mintAmount = hre.ethers.parseEther('100') + + // Connect as owner and mint + const contractOwner = erc20.connect(owner) + + // Get initial balance + const initialBalance = await erc20.balanceOf(recipient.address) + + // Mint tokens as owner + const tx = await contractOwner.mint(recipient.address, mintAmount) + const receipt = await waitWithTimeout(tx, 20000, RETRY_DELAY_FUNC) + + expect(tx).to.not.be.reverted + + // Check Transfer event was emitted + const transferEvent = findEvent(receipt.logs, erc20.interface, 'Transfer') + expect(transferEvent, 'Transfer event must be emitted').to.exist + expect(transferEvent.args.from).to.equal('0x0000000000000000000000000000000000000000') // Zero address for minting + expect(transferEvent.args.to).to.equal(recipient.address) + expect(transferEvent.args.value).to.equal(mintAmount) + + // Check new balance + const newBalance = await erc20.balanceOf(recipient.address) + expect(newBalance).to.equal(initialBalance + mintAmount) + }) + }) + + describe('burn', function () { + it('should burn tokens from the caller', async function () { + const mintAmount = hre.ethers.parseEther('100') + const burnAmount = hre.ethers.parseEther('50') + + // First mint some tokens to owner (use owner for this test to avoid conflicts) + const mintTx = await erc20BurnContract.mint(spender.address, mintAmount) + const mintReceipt = await waitWithTimeout(mintTx, 20000, RETRY_DELAY_FUNC) + + const spenderContract = new hre.ethers.Contract(ERC20_PRECOMPILE_ADDRESS, ERC20_BURN_ABI, spender) + // Get initial balance + const initialBalance = await erc20.balanceOf(spender.address) + + // Owner burns their own tokens + const burnTx = await spenderContract.burn(burnAmount) + const burnReceipt = await waitWithTimeout(burnTx, 20000, RETRY_DELAY_FUNC) + + // Check Transfer event was emitted + const transferEvent = findEvent(burnReceipt.logs, erc20.interface, 'Transfer') + expect(transferEvent, 'Transfer event must be emitted').to.exist + expect(transferEvent.args.from).to.equal(spender.address) + expect(transferEvent.args.to).to.equal('0x0000000000000000000000000000000000000000') // Zero address for burning + expect(transferEvent.args.value).to.equal(burnAmount) + }) + }) + + describe('burn0', function () { + it('should revert if the caller is not the contract owner', async function () { + const burnAmount = hre.ethers.parseEther('10') + + // Connect as spender (non-owner) and attempt to burn from recipient - this should revert + const contractAsSpender = new hre.ethers.Contract(ERC20_PRECOMPILE_ADDRESS, ERC20_BURN0_ABI, spender) + + // Attempt to burn tokens from recipient as non-owner spender - should revert + await expect(contractAsSpender.burn(recipient.address, burnAmount)) + .to.be.reverted + }) + + it('should allow owner to burn tokens from any address', async function () { + const mintAmount = hre.ethers.parseEther('100') + const burnAmount = hre.ethers.parseEther('30') + + // First mint some tokens to spender + const mintTx = await erc20Burn0Contract.mint(spender.address, mintAmount) + const mintReceipt = await waitWithTimeout(mintTx, 20000, RETRY_DELAY_FUNC) + + // Get initial balance of spender + const initialBalance = await erc20.balanceOf(spender.address) + + // Owner burns tokens from spender's account + const burnTx = await erc20Burn0Contract.burn(spender.address, burnAmount) + const burnReceipt = await waitWithTimeout(burnTx, 20000, RETRY_DELAY_FUNC) + + expect(burnTx).to.not.be.reverted + + // Check Transfer event was emitted + const transferEvent = findEvent(burnReceipt.logs, erc20.interface, 'Transfer') + expect(transferEvent, 'Transfer event must be emitted').to.exist + expect(transferEvent.args.from).to.equal(spender.address) + expect(transferEvent.args.to).to.equal('0x0000000000000000000000000000000000000000') // Zero address for burning + expect(transferEvent.args.value).to.equal(burnAmount) + + // Check new balance + const newBalance = await erc20.balanceOf(spender.address) + expect(newBalance).to.equal(initialBalance - burnAmount) + }) + + it('should revert when trying to burn more than available balance', async function () { + // Get current balance of spender + const currentBalance = await erc20.balanceOf(spender.address) + const burnAmount = currentBalance + hre.ethers.parseEther('1') // Try to burn more than available + + // Owner attempts to burn more tokens than spender has - should revert + await expect(erc20Burn0Contract.burn(spender.address, burnAmount)) + .to.be.reverted + }) + }) + + describe('burnFrom', function () { + it('should allow any caller to burn from account with allowance', async function () { + const mintAmount = hre.ethers.parseEther('100') + const burnAmount = hre.ethers.parseEther('50') + + // First mint some tokens to spender + const mintTx = await erc20.connect(owner).mint(spender.address, mintAmount) + const mintReceipt = await waitWithTimeout(mintTx, 20000, RETRY_DELAY_FUNC) + + // Spender approves recipient to spend tokens + const contractAsSpender = erc20.connect(spender) + const approveTx = await contractAsSpender.approve(recipient.address, burnAmount) + const approveReceipt = await waitWithTimeout(approveTx, 20000, RETRY_DELAY_FUNC) + + // Get initial balance and allowance + const initialBalance = await erc20.balanceOf(spender.address) + const initialAllowance = await erc20.allowance(spender.address, recipient.address) + + // Connect as recipient (non-owner) and burnFrom - this should succeed with allowance + const contractAsRecipient = erc20.connect(recipient) + + const burnFromTx = await contractAsRecipient.burnFrom(spender.address, burnAmount) + const burnFromReceipt = await waitWithTimeout(burnFromTx, 20000, RETRY_DELAY_FUNC) + + // Check Transfer event was emitted + const transferEvent = findEvent(burnFromReceipt.logs, erc20.interface, 'Transfer') + expect(transferEvent, 'Transfer event must be emitted').to.exist + expect(transferEvent.args.from).to.equal(spender.address) + expect(transferEvent.args.to).to.equal('0x0000000000000000000000000000000000000000') // Zero address for burning + expect(transferEvent.args.value).to.equal(burnAmount) + + // Check new balance + const newBalance = await erc20.balanceOf(spender.address) + expect(newBalance).to.equal(initialBalance - burnAmount) + + // Check allowance was reduced + const newAllowance = await erc20.allowance(spender.address, recipient.address) + expect(newAllowance).to.equal(0) + }) + + it('should burn tokens from the specified account with allowance', async function () { + const mintAmount = hre.ethers.parseEther('200') // Use different amount to avoid conflicts + const burnAmount = hre.ethers.parseEther('75') // Use different amount to avoid conflicts + + // First mint some tokens to recipient (use recipient for this test) + const mintTx = await erc20.connect(owner).mint(recipient.address, mintAmount) + const mintReceipt = await waitWithTimeout(mintTx, 20000, RETRY_DELAY_FUNC) + + // Recipient approves spender to spend tokens (different direction than first burnFrom test) + const contractAsRecipient = erc20.connect(recipient) + const approveTx = await contractAsRecipient.approve(spender.address, burnAmount) + const approveReceipt = await waitWithTimeout(approveTx, 20000, RETRY_DELAY_FUNC) + + // Get initial balance and allowance + const initialBalance = await erc20.balanceOf(recipient.address) + const initialAllowance = await erc20.allowance(recipient.address, spender.address) + + // Spender burns tokens from recipient's account + const contractAsSpender = erc20.connect(spender) + const burnFromTx = await contractAsSpender.burnFrom(recipient.address, burnAmount) + const burnFromReceipt = await waitWithTimeout(burnFromTx, 20000, RETRY_DELAY_FUNC) + + // Check Transfer event was emitted + const transferEvent = findEvent(burnFromReceipt.logs, erc20.interface, 'Transfer') + expect(transferEvent, 'Transfer event must be emitted').to.exist + expect(transferEvent.args.from).to.equal(recipient.address) + expect(transferEvent.args.to).to.equal('0x0000000000000000000000000000000000000000') // Zero address for burning + expect(transferEvent.args.value).to.equal(burnAmount) + + // Check new balance + const newBalance = await erc20.balanceOf(recipient.address) + expect(newBalance).to.equal(initialBalance - burnAmount) + + // Check allowance was reduced + const newAllowance = await erc20.allowance(recipient.address, spender.address) + expect(newAllowance).to.equal(0) + }) + }) + + describe('transferOwnership', function () { + it('should revert if the caller is not the contract owner', async function () { + // Connect as spender (non-owner) and attempt to transfer ownership - this should revert + const contractAsSpender = erc20.connect(spender) + + // Attempt to transfer ownership as non-owner spender to recipient - should revert + await expect(contractAsSpender.transferOwnership(recipient.address)) + .to.be.reverted + }) + + it('should transfer ownership when called by the current owner', async function () { + // Get initial owner + const initialOwner = await erc20.owner() + expect(initialOwner).to.equal(owner.address) + + // Connect as owner and transfer ownership + const contractAsOwner = erc20.connect(owner) + + // Transfer ownership to spender + const tx = await contractAsOwner.transferOwnership(spender.address) + const receipt = await waitWithTimeout(tx, 20000, RETRY_DELAY_FUNC) + + expect(tx).to.not.be.reverted + + // Check ownership has changed + const newOwner = await erc20.owner() + expect(newOwner).to.equal(spender.address) + }) + }) + + }) diff --git a/tests/systemtests/Makefile b/tests/systemtests/Makefile index 05b3d2e49..b0aa5b041 100644 --- a/tests/systemtests/Makefile +++ b/tests/systemtests/Makefile @@ -9,4 +9,4 @@ test: go test -failfast -timeout=30m -p=1 -mod=readonly -tags='system_test' -v ./... -run TestExceptions --wait-time=$(WAIT_TIME) --block-time=8s --binary evmd --chain-id local-4221 go test -failfast -timeout=30m -p=1 -mod=readonly -tags='system_test' -v ./... -run TestEIP7702 --wait-time=$(WAIT_TIME) --block-time=5s --binary evmd --chain-id local-4221 go test -failfast -timeout=30m -p=1 -mod=readonly -tags='system_test' -v ./... -run TestEIP712 --wait-time=$(WAIT_TIME) --block-time=5s --binary evmd --chain-id local-4221 - go test -failfast -timeout=30m -p=1 -mod=readonly -tags='system_test' -v ./... -run 'TestUpgrade|TestEth' --wait-time=$(WAIT_TIME) --block-time=5s --binary evmd --chain-id local-4221 + go test -failfast -timeout=30m -p=1 -mod=readonly -tags='system_test' -v ./... -run 'TestChainUpgrade|TestEth' --wait-time=$(WAIT_TIME) --block-time=5s --binary evmd --chain-id local-4221 diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index 34c36d65a..5ab649fb8 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -5,8 +5,8 @@ go 1.24.4 require ( cosmossdk.io/math v1.5.3 cosmossdk.io/systemtests v1.4.0 - github.com/cometbft/cometbft v0.38.19 - github.com/cosmos/cosmos-sdk v0.53.5-0.20251030204916-768cb210885c + github.com/cometbft/cometbft v0.38.21 + github.com/cosmos/cosmos-sdk v0.53.6 github.com/cosmos/evm v0.5.0-rc.0 github.com/ethereum/go-ethereum v1.15.11 github.com/holiman/uint256 v1.3.2 @@ -61,7 +61,7 @@ require ( github.com/cosmos/iavl v1.2.6 // indirect github.com/cosmos/ibc-go/v10 v10.3.1-0.20250909102629-ed3b125c7b6f // indirect github.com/cosmos/ics23/go v0.11.0 // indirect - github.com/cosmos/ledger-cosmos-go v0.16.0 // indirect + github.com/cosmos/ledger-cosmos-go v1.0.0 // indirect github.com/crate-crypto/go-eth-kzg v1.3.0 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect github.com/creachadair/tomledit v0.0.29 // indirect diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index f53fd3b2c..568e7f412 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -178,8 +178,8 @@ github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g= github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.19 h1:vNdtCkvhuwUlrcLPAyigV7lQpmmo+tAq8CsB8gZjEYw= -github.com/cometbft/cometbft v0.38.19/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= +github.com/cometbft/cometbft v0.38.21 h1:qcIJSH9LiwU5s6ZgKR5eRbsLNucbubfraDs5bzgjtOI= +github.com/cometbft/cometbft v0.38.21/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= github.com/cometbft/cometbft-db v1.0.4 h1:cezb8yx/ZWcF124wqUtAFjAuDksS1y1yXedvtprUFxs= github.com/cometbft/cometbft-db v1.0.4/go.mod h1:M+BtHAGU2XLrpUxo3Nn1nOCcnVCiLM9yx5OuT0u5SCA= github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= @@ -196,8 +196,8 @@ github.com/cosmos/cosmos-db v1.1.3 h1:7QNT77+vkefostcKkhrzDK9uoIEryzFrU9eoMeaQOP github.com/cosmos/cosmos-db v1.1.3/go.mod h1:kN+wGsnwUJZYn8Sy5Q2O0vCYA99MJllkKASbs6Unb9U= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/cosmos-sdk v0.53.5-0.20251030204916-768cb210885c h1:HMVLvm0q3ahGvsyExkSCBcmvcdItMpTxAh4jllL4rJ4= -github.com/cosmos/cosmos-sdk v0.53.5-0.20251030204916-768cb210885c/go.mod h1:nifazrMGFjpmOuaVIZBQ8akQc160imzySYFEA8A7tus= +github.com/cosmos/cosmos-sdk v0.53.6 h1:aJeInld7rbsHtH1qLHu2aZJF9t40mGlqp3ylBLDT0HI= +github.com/cosmos/cosmos-sdk v0.53.6/go.mod h1:N6YuprhAabInbT3YGumGDKONbvPX5dNro7RjHvkQoKE= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/go-ethereum v1.16.2-cosmos-1 h1:QIaIS6HIdPSBdTvpFhxswhMLUJgcr4irbd2o9ZKldAI= @@ -213,8 +213,8 @@ github.com/cosmos/ibc-go/v10 v10.3.1-0.20250909102629-ed3b125c7b6f h1:I5t5Tuewh6 github.com/cosmos/ibc-go/v10 v10.3.1-0.20250909102629-ed3b125c7b6f/go.mod h1:a74pAPUSJ7NewvmvELU74hUClJhwnmm5MGbEaiTw/kE= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= -github.com/cosmos/ledger-cosmos-go v0.16.0 h1:YKlWPG9NnGZIEUb2bEfZ6zhON1CHlNTg0QKRRGcNEd0= -github.com/cosmos/ledger-cosmos-go v0.16.0/go.mod h1:WrM2xEa8koYoH2DgeIuZXNarF7FGuZl3mrIOnp3Dp0o= +github.com/cosmos/ledger-cosmos-go v1.0.0 h1:jNKW89nPf0vR0EkjHG8Zz16h6p3zqwYEOxlHArwgYtw= +github.com/cosmos/ledger-cosmos-go v1.0.0/go.mod h1:mGaw2wDOf+Z6SfRJsMGxU9DIrBa4du0MAiPlpPhLAOE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= diff --git a/tests/systemtests/upgrade_test.go b/tests/systemtests/upgrade_test.go index 9ae700e88..2aebdbaca 100644 --- a/tests/systemtests/upgrade_test.go +++ b/tests/systemtests/upgrade_test.go @@ -18,7 +18,7 @@ import ( const ( upgradeHeight int64 = 22 - upgradeName = "v0.4.0-to-v0.5.0" // must match UpgradeName in evmd/upgrades.go + upgradeName = "v0.5.0-to-v0.6.0" // must match UpgradeName in evmd/upgrades.go ) func TestChainUpgrade(t *testing.T) { @@ -31,7 +31,7 @@ func TestChainUpgrade(t *testing.T) { currentBranchBinary := systest.Sut.ExecBinary() currentInitializer := systest.Sut.TestnetInitializer() - legacyBinary := systest.WorkDir + "/binaries/v0.4/evmd" + legacyBinary := systest.WorkDir + "/binaries/v0.5/evmd" systest.Sut.SetExecBinary(legacyBinary) systest.Sut.SetTestnetInitializer(systest.InitializerWithBinary(legacyBinary, systest.Sut)) systest.Sut.SetupChain() diff --git a/testutil/tx/eip712.go b/testutil/tx/eip712.go index 89b4a57ae..f13e89f5f 100644 --- a/testutil/tx/eip712.go +++ b/testutil/tx/eip712.go @@ -73,11 +73,10 @@ func PrepareEIP712CosmosTx( return nil, err } - // using nolint:all because the staticcheck nolint is not working as expected - fee := legacytx.NewStdFee(txArgs.Gas, txArgs.Fees) //nolint:all + fee := legacytx.NewStdFee(txArgs.Gas, txArgs.Fees) //nolint:staticcheck // check against deprecated type msgs := txArgs.Msgs - data := legacytx.StdSignBytes(ctx.ChainID(), accNumber, nonce, 0, fee, msgs, "") + data := legacytx.StdSignBytes(ctx.ChainID(), accNumber, nonce, 0, fee, msgs, "") //nolint:staticcheck // check against deprecated type typedDataArgs := typedDataArgs{ chainID: args.EVMChainID, diff --git a/x/erc20/client/cli/query.go b/x/erc20/client/cli/query.go index 6e54481f3..36458fb3f 100644 --- a/x/erc20/client/cli/query.go +++ b/x/erc20/client/cli/query.go @@ -2,7 +2,9 @@ package cli import ( "context" + "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/spf13/cobra" "github.com/cosmos/evm/x/erc20/types" @@ -25,6 +27,7 @@ func GetQueryCmd() *cobra.Command { GetTokenPairsCmd(), GetTokenPairCmd(), GetParamsCmd(), + GetOwnerAddressCmd(), ) return cmd } @@ -128,3 +131,37 @@ func GetParamsCmd() *cobra.Command { flags.AddQueryFlagsToCmd(cmd) return cmd } + +func GetOwnerAddressCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "owner-address CONTRACT_ADDRESS", + Short: "Gets the owner address for a given ERC20 contract address", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + if !common.IsHexAddress(args[0]) { + return fmt.Errorf("invalid contract address") + } + + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryOwnerAddressRequest{ + ContractAddress: args[0], + } + + res, err := queryClient.OwnerAddress(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/erc20/client/cli/tx.go b/x/erc20/client/cli/tx.go index 34b1b8e7a..c61d3a09d 100644 --- a/x/erc20/client/cli/tx.go +++ b/x/erc20/client/cli/tx.go @@ -31,6 +31,8 @@ func NewTxCmd() *cobra.Command { NewConvertCoinCmd(), NewConvertERC20Cmd(), NewMsgRegisterERC20Cmd(), + NewMintCmd(), + NewBurnCmd(), ) return txCmd } @@ -158,3 +160,85 @@ func NewMsgRegisterERC20Cmd() *cobra.Command { flags.AddTxFlagsToCmd(cmd) return cmd } + +// NewMintCmd implements the command to mint an ERC20 token +func NewMintCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "mint CONTRACT_ADDRESS TO AMOUNT", + Args: cobra.ExactArgs(3), + Short: "Mint an ERC20 token", + Long: "Mint an ERC20 token", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + contract := args[0] + if err := utils.ValidateAddress(contract); err != nil { + return fmt.Errorf("invalid ERC20 contract address %w", err) + } + + to, err := sdk.AccAddressFromBech32(args[1]) + if err != nil { + return err + } + + amount, ok := math.NewIntFromString(args[2]) + if !ok { + return fmt.Errorf("invalid amount %s", args[2]) + } + + from := clientCtx.GetFromAddress() + + msg := &types.MsgMint{ + ContractAddress: contract, + Amount: amount, + Sender: from.String(), + To: to.String(), + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewBurnCmd implements the command to burn an ERC20 token +func NewBurnCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "burn CONTRACT_ADDRESS AMOUNT", + Args: cobra.ExactArgs(2), + Short: "Burn an ERC20 token", + Long: "Burn an ERC20 token", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + contract := args[0] + if err := utils.ValidateAddress(contract); err != nil { + return fmt.Errorf("invalid ERC20 contract address %w", err) + } + + amount, ok := math.NewIntFromString(args[1]) + if !ok { + return fmt.Errorf("invalid amount %s", args[1]) + } + + msg := &types.MsgBurn{ + ContractAddress: contract, + Amount: amount, + Sender: clientCtx.GetFromAddress().String(), + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/erc20/keeper/burn.go b/x/erc20/keeper/burn.go new file mode 100644 index 000000000..f4a954b68 --- /dev/null +++ b/x/erc20/keeper/burn.go @@ -0,0 +1,45 @@ +package keeper + +import ( + "github.com/cosmos/evm/x/erc20/types" + + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// BurnCoins burns the provided amount of coins from the given address. +func (k Keeper) BurnCoins(ctx sdk.Context, sender sdk.AccAddress, amount math.Int, token string) error { + pair, found := k.GetTokenPair(ctx, k.GetTokenPairID(ctx, token)) + if !found { + return errorsmod.Wrapf(types.ErrTokenPairNotFound, "token '%s' not registered", token) + } + + if !pair.IsNativeCoin() { + return errorsmod.Wrap(types.ErrNonNativeCoinBurningDisabled, token) + } + + coins := sdk.Coins{{Denom: pair.Denom, Amount: amount}} + + err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, coins) + if err != nil { + return err + } + + err = k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins) + if err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyAction, types.TypeMsgBurn), + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, sender.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.String()), + ), + ) + return nil +} diff --git a/x/erc20/keeper/convert.go b/x/erc20/keeper/convert.go new file mode 100644 index 000000000..aa06cf9e8 --- /dev/null +++ b/x/erc20/keeper/convert.go @@ -0,0 +1,167 @@ +package keeper + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/hashicorp/go-metrics" + + "github.com/cosmos/evm/contracts" + "github.com/cosmos/evm/x/erc20/types" + "github.com/cosmos/evm/x/vm/statedb" + + "cosmossdk.io/errors" + "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + errortypes "github.com/cosmos/cosmos-sdk/types/errors" +) + +// ConvertERC20IntoCoinsForNativeToken handles the erc20 conversion for a native erc20 token pair. +// This function is used by both the msg server and precompiles (like ICS20). +// It performs the following operations: +// - validates the token pair and checks if conversion is enabled +// - removes the token pair if the contract is suicided +// - escrows tokens on module account +// - mints coins on bank module +// - sends minted coins to the receiver +// - checks if coin balance increased by amount +// - checks if token balance decreased by amount +// - checks for unexpected `Approval` event in logs +func (k Keeper) ConvertERC20IntoCoinsForNativeToken(ctx sdk.Context, stateDB *statedb.StateDB, contract common.Address, amount math.Int, receiver sdk.AccAddress, sender common.Address, commit bool, callFromPrecompile bool) (*types.MsgConvertERC20Response, error) { + // Validate and get token pair + pair, err := k.MintingEnabled(ctx, receiver, contract.Hex()) + if err != nil { + return nil, err + } + + // Check that this is a native ERC20 token + if !pair.IsNativeERC20() { + if pair.IsNativeCoin() { + return nil, types.ErrNativeConversionDisabled + } + return nil, types.ErrUndefinedOwner + } + + // Remove token pair if contract is suicided + acc := k.evmKeeper.GetAccountWithoutBalance(ctx, pair.GetERC20Contract()) + if acc == nil || !acc.HasCodeHash() { + k.DeleteTokenPair(ctx, pair) + k.Logger(ctx).Debug( + "deleting selfdestructed token pair from state", + "contract", pair.Erc20Address, + ) + // NOTE: return nil error to persist the changes from the deletion + return nil, nil + } + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + erc20Contract := pair.GetERC20Contract() + balanceCoin := k.bankKeeper.GetBalance(ctx, receiver, pair.Denom) + balanceToken := k.BalanceOf(ctx, erc20, erc20Contract, types.ModuleAddress) + if balanceToken == nil { + return nil, errors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + + // Escrow tokens on module account + transferData, err := erc20.Pack("transfer", types.ModuleAddress, amount.BigInt()) + if err != nil { + return nil, err + } + + res, err := k.evmKeeper.CallEVMWithData(ctx, stateDB, sender, &erc20Contract, transferData, commit, callFromPrecompile, nil) + if err != nil { + return nil, err + } + + // Check evm call response + var unpackedRet types.ERC20BoolResponse + if len(res.Ret) == 0 { + // if the token does not return a value, check for the transfer event in logs + if err := validateTransferEventExists(res.Logs, erc20Contract); err != nil { + return nil, err + } + } else { + if err := erc20.UnpackIntoInterface(&unpackedRet, "transfer", res.Ret); err != nil { + return nil, err + } + if !unpackedRet.Value { + return nil, errors.Wrap(errortypes.ErrLogic, "failed to execute transfer") + } + } + + // Check expected escrow balance after transfer execution + coins := sdk.Coins{sdk.Coin{Denom: pair.Denom, Amount: amount}} + tokens := coins[0].Amount.BigInt() + balanceTokenAfter := k.BalanceOf(ctx, erc20, erc20Contract, types.ModuleAddress) + if balanceTokenAfter == nil { + return nil, errors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + + expToken := big.NewInt(0).Add(balanceToken, tokens) + + if r := balanceTokenAfter.Cmp(expToken); r != 0 { + return nil, errors.Wrapf( + types.ErrBalanceInvariance, + "invalid token balance - expected: %v, actual: %v", + expToken, balanceTokenAfter, + ) + } + + // Mint coins + if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { + return nil, err + } + + // Send minted coins to the receiver + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiver, coins); err != nil { + return nil, err + } + + // Check expected receiver balance after transfer + balanceCoinAfter := k.bankKeeper.GetBalance(ctx, receiver, pair.Denom) + expCoin := balanceCoin.Add(coins[0]) + + if ok := balanceCoinAfter.Equal(expCoin); !ok { + return nil, errors.Wrapf( + types.ErrBalanceInvariance, + "invalid coin balance - expected: %v, actual: %v", + expCoin, balanceCoinAfter, + ) + } + + defer func() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "erc20", "total"}, + 1, + []metrics.Label{ + telemetry.NewLabel("coin", pair.Denom), + }, + ) + + if amount.IsInt64() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "erc20", "amount", "total"}, + float32(amount.Int64()), + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + }, + ) + } + }() + + ctx.EventManager().EmitEvents( + sdk.Events{ + sdk.NewEvent( + types.EventTypeConvertERC20, + sdk.NewAttribute(sdk.AttributeKeySender, sender.Hex()), + sdk.NewAttribute(types.AttributeKeyReceiver, receiver.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.String()), + sdk.NewAttribute(types.AttributeKeyCosmosCoin, pair.Denom), + sdk.NewAttribute(types.AttributeKeyERC20Token, contract.Hex()), + ), + }, + ) + + return &types.MsgConvertERC20Response{}, nil +} diff --git a/x/erc20/keeper/evm.go b/x/erc20/keeper/evm.go index 05fdafb3d..1e14d2754 100644 --- a/x/erc20/keeper/evm.go +++ b/x/erc20/keeper/evm.go @@ -10,11 +10,11 @@ import ( "github.com/cosmos/evm/contracts" "github.com/cosmos/evm/utils" "github.com/cosmos/evm/x/erc20/types" + "github.com/cosmos/evm/x/vm/statedb" errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) var ( @@ -25,45 +25,6 @@ var ( logApprovalSigHash = crypto.Keccak256Hash(logApprovalSig) ) -// DeployERC20Contract creates and deploys an ERC20 contract on the EVM with the -// erc20 module account as owner. -func (k Keeper) DeployERC20Contract( - ctx sdk.Context, - coinMetadata banktypes.Metadata, -) (common.Address, error) { - decimals := uint8(0) - if len(coinMetadata.DenomUnits) > 0 { - decimalsIdx := len(coinMetadata.DenomUnits) - 1 - decimals = uint8(coinMetadata.DenomUnits[decimalsIdx].Exponent) //#nosec G115 // exponent will not exceed uint8 - } - ctorArgs, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack( - "", - coinMetadata.Name, - coinMetadata.Symbol, - decimals, - ) - if err != nil { - return common.Address{}, errorsmod.Wrapf(types.ErrABIPack, "coin metadata is invalid %s: %s", coinMetadata.Name, err.Error()) - } - - data := make([]byte, len(contracts.ERC20MinterBurnerDecimalsContract.Bin)+len(ctorArgs)) - copy(data[:len(contracts.ERC20MinterBurnerDecimalsContract.Bin)], contracts.ERC20MinterBurnerDecimalsContract.Bin) - copy(data[len(contracts.ERC20MinterBurnerDecimalsContract.Bin):], ctorArgs) - - nonce, err := k.accountKeeper.GetSequence(ctx, types.ModuleAddress.Bytes()) - if err != nil { - return common.Address{}, err - } - - contractAddr := crypto.CreateAddress(types.ModuleAddress, nonce) - _, err = k.evmKeeper.CallEVMWithData(ctx, types.ModuleAddress, nil, data, true, nil) - if err != nil { - return common.Address{}, errorsmod.Wrapf(err, "failed to deploy contract for %s", coinMetadata.Name) - } - - return contractAddr, nil -} - // QueryERC20 returns the data of a deployed ERC20 contract func (k Keeper) QueryERC20( ctx sdk.Context, @@ -84,7 +45,9 @@ func (k Keeper) QueryERC20( } // Decimals - standard uint8, no fallback needed - res, err := k.evmKeeper.CallEVM(ctx, erc20, types.ModuleAddress, contract, false, nil, "decimals") + stateDB := statedb.New(ctx, k.evmKeeper, statedb.NewEmptyTxConfig()) + // Okay to assume we're not calling from a precompile, as queries will just revert state changes. + res, err := k.evmKeeper.CallEVM(ctx, stateDB, erc20, types.ModuleAddress, contract, false, false, nil, "decimals") if err != nil { return types.ERC20Data{}, err } @@ -107,7 +70,9 @@ func (k Keeper) queryERC20String( method string, ) (string, error) { // 1) Call into the EVM - res, err := k.evmKeeper.CallEVM(ctx, erc20, types.ModuleAddress, contract, false, nil, method) + stateDB := statedb.New(ctx, k.evmKeeper, statedb.NewEmptyTxConfig()) + // Okay to assume we're not calling from a precompile, as queries will just revert state changes. + res, err := k.evmKeeper.CallEVM(ctx, stateDB, erc20, types.ModuleAddress, contract, false, false, nil, method) if err != nil { return "", err } @@ -140,7 +105,9 @@ func (k Keeper) BalanceOf( abi abi.ABI, contract, account common.Address, ) *big.Int { - res, err := k.evmKeeper.CallEVM(ctx, abi, types.ModuleAddress, contract, false, nil, "balanceOf", account) + stateDB := statedb.New(ctx, k.evmKeeper, statedb.NewEmptyTxConfig()) + // Okay to assume we're not calling from a precompile, as queries will just revert state changes. + res, err := k.evmKeeper.CallEVM(ctx, stateDB, abi, types.ModuleAddress, contract, false, false, nil, "balanceOf", account) if err != nil { return nil } diff --git a/x/erc20/keeper/grpc_query.go b/x/erc20/keeper/grpc_query.go index 8ca7191df..da6985203 100644 --- a/x/erc20/keeper/grpc_query.go +++ b/x/erc20/keeper/grpc_query.go @@ -84,3 +84,10 @@ func (k Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.Q params := k.GetParams(ctx) return &types.QueryParamsResponse{Params: params}, nil } + +// OwnerAddress returns the owner address for a given ERC20 contract address +func (k Keeper) OwnerAddress(c context.Context, req *types.QueryOwnerAddressRequest) (*types.QueryOwnerAddressResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + owner := k.GetOwnerAddress(ctx, req.ContractAddress) + return &types.QueryOwnerAddressResponse{OwnerAddress: owner}, nil +} diff --git a/x/erc20/keeper/ibc_callbacks.go b/x/erc20/keeper/ibc_callbacks.go index 4848dc10b..3b30a557b 100644 --- a/x/erc20/keeper/ibc_callbacks.go +++ b/x/erc20/keeper/ibc_callbacks.go @@ -134,7 +134,7 @@ func (k Keeper) OnRecvPacket( return channeltypes.NewErrorAcknowledgement(err) } - if err := k.ConvertCoinNativeERC20(ctx, pair, coin.Amount, common.BytesToAddress(recipient.Bytes()), recipient); err != nil { + if err := k.ConvertCoinNativeERC20(ctx, pair, coin.Amount, common.BytesToAddress(recipient.Bytes()), recipient, false); err != nil { return channeltypes.NewErrorAcknowledgement(err) } @@ -234,7 +234,7 @@ func (k Keeper) ConvertCoinToERC20FromPacket(ctx sdk.Context, data transfertypes } // Convert from Coin to ERC20 - if err := k.ConvertCoinNativeERC20(ctx, pair, coin.Amount, common.BytesToAddress(sender), sender); err != nil { + if err := k.ConvertCoinNativeERC20(ctx, pair, coin.Amount, common.BytesToAddress(sender), sender, false); err != nil { // We want to record only the failed attempt to reconvert the coins during IBC. defer func() { telemetry.IncrCounter(1, types.ModuleName, "ibc", "error", "total") diff --git a/x/erc20/keeper/keeper.go b/x/erc20/keeper/keeper.go index 981a2de14..f800eba58 100644 --- a/x/erc20/keeper/keeper.go +++ b/x/erc20/keeper/keeper.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/cosmos/evm/x/erc20/types" - transferkeeper "github.com/cosmos/evm/x/ibc/transfer/keeper" + transferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" "cosmossdk.io/core/address" "cosmossdk.io/log" diff --git a/x/erc20/keeper/mint.go b/x/erc20/keeper/mint.go index be8fb44fa..9076569d2 100644 --- a/x/erc20/keeper/mint.go +++ b/x/erc20/keeper/mint.go @@ -4,6 +4,7 @@ import ( "github.com/cosmos/evm/x/erc20/types" errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" @@ -65,3 +66,46 @@ func (k Keeper) MintingEnabled( return pair, nil } + +// MintCoins mints the provided amount of coins to the given address. +func (k Keeper) MintCoins(ctx sdk.Context, sender, to sdk.AccAddress, amount math.Int, token string) error { + pair, err := k.MintingEnabled(ctx, to, token) + if err != nil { + return err + } + + if !pair.IsNativeCoin() { + return errorsmod.Wrap(types.ErrNonNativeCoinMintingDisabled, token) + } + + contractOwnerAddr, err := sdk.AccAddressFromBech32(pair.OwnerAddress) + if err != nil { + return errorsmod.Wrapf(err, "invalid owner address") + } + if !sender.Equals(contractOwnerAddr) { + return types.ErrMinterIsNotOwner + } + + coins := sdk.Coins{{Denom: pair.Denom, Amount: amount}} + err = k.bankKeeper.MintCoins(ctx, types.ModuleName, coins) + if err != nil { + return err + } + + err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, to, coins) + if err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyAction, types.TypeMsgMint), + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, sender.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, amount.String()), + ), + ) + + return nil +} diff --git a/x/erc20/keeper/msg_server.go b/x/erc20/keeper/msg_server.go index 51c8621e4..7fcda36ec 100644 --- a/x/erc20/keeper/msg_server.go +++ b/x/erc20/keeper/msg_server.go @@ -5,15 +5,14 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/hashicorp/go-metrics" "github.com/cosmos/evm/contracts" "github.com/cosmos/evm/x/erc20/types" + "github.com/cosmos/evm/x/vm/statedb" sdkerrors "cosmossdk.io/errors" "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -29,162 +28,18 @@ func (k Keeper) ConvertERC20( ) (*types.MsgConvertERC20Response, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // Error checked during msg validation - receiver := sdk.MustAccAddressFromBech32(msg.Receiver) - sender := common.HexToAddress(msg.Sender) - - pair, err := k.MintingEnabled(ctx, receiver, msg.ContractAddress) + // Parse message + receiver, err := sdk.AccAddressFromBech32(msg.Receiver) if err != nil { return nil, err } + sender := common.HexToAddress(msg.Sender) + contract := common.HexToAddress(msg.ContractAddress) - // Check ownership and execute conversion - if pair.IsNativeERC20() { - // Remove token pair if contract is suicided - acc := k.evmKeeper.GetAccountWithoutBalance(ctx, pair.GetERC20Contract()) - if acc == nil || !acc.HasCodeHash() { - k.DeleteTokenPair(ctx, pair) - k.Logger(ctx).Debug( - "deleting selfdestructed token pair from state", - "contract", pair.Erc20Address, - ) - // NOTE: return nil error to persist the changes from the deletion - return nil, nil - } - - return k.convertERC20IntoCoinsForNativeToken(ctx, pair, msg, receiver, sender) // case 2.1 - } else if pair.IsNativeCoin() { - return nil, types.ErrNativeConversionDisabled - } - - return nil, types.ErrUndefinedOwner -} - -// convertERC20IntoCoinsForNativeToken handles the erc20 conversion for a native erc20 token -// pair: -// - escrow tokens on module account -// - mint coins on bank module -// - send minted coins to the receiver -// - check if coin balance increased by amount -// - check if token balance decreased by amount -// - check for unexpected `Approval` event in logs -func (k Keeper) convertERC20IntoCoinsForNativeToken( - ctx sdk.Context, - pair types.TokenPair, - msg *types.MsgConvertERC20, - receiver sdk.AccAddress, - sender common.Address, -) (*types.MsgConvertERC20Response, error) { - erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI - contract := pair.GetERC20Contract() - balanceCoin := k.bankKeeper.GetBalance(ctx, receiver, pair.Denom) - balanceToken := k.BalanceOf(ctx, erc20, contract, types.ModuleAddress) - if balanceToken == nil { - return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") - } - - // Escrow tokens on module account - transferData, err := erc20.Pack("transfer", types.ModuleAddress, msg.Amount.BigInt()) - if err != nil { - return nil, err - } - - res, err := k.evmKeeper.CallEVMWithData(ctx, sender, &contract, transferData, true, nil) - if err != nil { - return nil, err - } - - // Check evm call response - var unpackedRet types.ERC20BoolResponse - if len(res.Ret) == 0 { - // if the token does not return a value, check for the transfer event in logs - if err := validateTransferEventExists(res.Logs, contract); err != nil { - return nil, err - } - } else { - if err := erc20.UnpackIntoInterface(&unpackedRet, "transfer", res.Ret); err != nil { - return nil, err - } - if !unpackedRet.Value { - return nil, sdkerrors.Wrap(errortypes.ErrLogic, "failed to execute transfer") - } - } - - // Check expected escrow balance after transfer execution - // NOTE: coin fields already validated in the ValidateBasic() of the message - coins := sdk.Coins{sdk.Coin{Denom: pair.Denom, Amount: msg.Amount}} - tokens := coins[0].Amount.BigInt() - balanceTokenAfter := k.BalanceOf(ctx, erc20, contract, types.ModuleAddress) - if balanceTokenAfter == nil { - return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") - } - - expToken := big.NewInt(0).Add(balanceToken, tokens) - - if r := balanceTokenAfter.Cmp(expToken); r != 0 { - return nil, sdkerrors.Wrapf( - types.ErrBalanceInvariance, - "invalid token balance - expected: %v, actual: %v", - expToken, balanceTokenAfter, - ) - } - - // Mint coins - if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { - return nil, err - } - - // Send minted coins to the receiver - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiver, coins); err != nil { - return nil, err - } - - // Check expected receiver balance after transfer - balanceCoinAfter := k.bankKeeper.GetBalance(ctx, receiver, pair.Denom) - expCoin := balanceCoin.Add(coins[0]) - - if ok := balanceCoinAfter.Equal(expCoin); !ok { - return nil, sdkerrors.Wrapf( - types.ErrBalanceInvariance, - "invalid coin balance - expected: %v, actual: %v", - expCoin, balanceCoinAfter, - ) - } - - defer func() { - telemetry.IncrCounterWithLabels( - []string{"tx", "msg", "convert", "erc20", "total"}, - 1, - []metrics.Label{ - telemetry.NewLabel("coin", pair.Denom), - }, - ) - - if msg.Amount.IsInt64() { - telemetry.IncrCounterWithLabels( - []string{"tx", "msg", "convert", "erc20", "amount", "total"}, - float32(msg.Amount.Int64()), - []metrics.Label{ - telemetry.NewLabel("denom", pair.Denom), - }, - ) - } - }() + // Create stateDB for this transaction + stateDB := statedb.New(ctx, k.evmKeeper, statedb.NewEmptyTxConfig()) - ctx.EventManager().EmitEvents( - sdk.Events{ - sdk.NewEvent( - types.EventTypeConvertERC20, - sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), - sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), - sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), - sdk.NewAttribute(types.AttributeKeyCosmosCoin, pair.Denom), - sdk.NewAttribute(types.AttributeKeyERC20Token, msg.ContractAddress), - ), - }, - ) - - return &types.MsgConvertERC20Response{}, nil + return k.ConvertERC20IntoCoinsForNativeToken(ctx, stateDB, contract, msg.Amount, receiver, sender, true, false) } // ConvertCoin converts native Cosmos coins into ERC20 tokens for both @@ -219,7 +74,7 @@ func (k Keeper) ConvertCoin( return nil, nil } - return nil, k.ConvertCoinNativeERC20(ctx, pair, msg.Coin.Amount, receiver, sender) + return nil, k.ConvertCoinNativeERC20(ctx, pair, msg.Coin.Amount, receiver, sender, false) case pair.IsNativeCoin(): return nil, types.ErrNativeConversionDisabled } @@ -234,13 +89,7 @@ func (k Keeper) ConvertCoin( // - burn escrowed Coins // - check if token balance increased by amount // - check for unexpected `Approval` event in logs -func (k Keeper) ConvertCoinNativeERC20( - ctx sdk.Context, - pair types.TokenPair, - amount math.Int, - receiver common.Address, - sender sdk.AccAddress, -) error { +func (k Keeper) ConvertCoinNativeERC20(ctx sdk.Context, pair types.TokenPair, amount math.Int, receiver common.Address, sender sdk.AccAddress, callFromPrecompile bool) error { if !amount.IsPositive() { return sdkerrors.Wrap(types.ErrNegativeToken, "converted coin amount must be positive") } @@ -260,7 +109,8 @@ func (k Keeper) ConvertCoinNativeERC20( } // Unescrow Tokens and send to receiver - res, err := k.evmKeeper.CallEVM(ctx, erc20, types.ModuleAddress, contract, true, nil, "transfer", receiver, amount.BigInt()) + stateDB := statedb.New(ctx, k.evmKeeper, statedb.NewEmptyTxConfig()) + res, err := k.evmKeeper.CallEVM(ctx, stateDB, erc20, types.ModuleAddress, contract, true, callFromPrecompile, nil, "transfer", receiver, amount.BigInt()) if err != nil { return err } @@ -321,6 +171,66 @@ func (k *Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) return &types.MsgUpdateParamsResponse{}, nil } +// TransferOwnership implements the MsgServer interface for the ERC20 module. +func (k Keeper) TransferContractOwnership(goCtx context.Context, msg *types.MsgTransferOwnership) (*types.MsgTransferOwnershipResponse, error) { + if err := k.validateAuthority(msg.Authority); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + newOwner, err := sdk.AccAddressFromBech32(msg.NewOwner) + if err != nil { + return nil, err + } + + err = k.TransferOwnershipProposal(ctx, newOwner, msg.Token) + if err != nil { + return nil, err + } + + return &types.MsgTransferOwnershipResponse{}, nil +} + +// Mint implements the MsgServer interface for the ERC20 module. It mints ERC20 tokens to a given address. +func (k Keeper) Mint(goCtx context.Context, msg *types.MsgMint) (*types.MsgMintResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + sender, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, err + } + + receiver, err := sdk.AccAddressFromBech32(msg.To) + if err != nil { + return nil, err + } + + err = k.MintCoins(ctx, sender, receiver, math.NewIntFromBigInt(msg.Amount.BigInt()), msg.ContractAddress) + if err != nil { + return nil, err + } + + return &types.MsgMintResponse{}, nil +} + +// Burn implements the MsgServer interface for the ERC20 module. It burns ERC20 tokens from a given address. +func (k Keeper) Burn(goCtx context.Context, msg *types.MsgBurn) (*types.MsgBurnResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + sender, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, err + } + + err = k.BurnCoins(ctx, sender, math.NewIntFromBigInt(msg.Amount.BigInt()), msg.ContractAddress) + if err != nil { + return nil, err + } + + return &types.MsgBurnResponse{}, nil +} + // RegisterERC20 implements the gRPC MsgServer interface. Any account can permissionlessly // register a native ERC20 contract to map to a Cosmos Coin. func (k *Keeper) RegisterERC20(goCtx context.Context, req *types.MsgRegisterERC20) (*types.MsgRegisterERC20Response, error) { diff --git a/x/erc20/keeper/token_pairs.go b/x/erc20/keeper/token_pairs.go index 6957ab35b..3ca0fc138 100644 --- a/x/erc20/keeper/token_pairs.go +++ b/x/erc20/keeper/token_pairs.go @@ -218,3 +218,25 @@ func (k Keeper) GetTokenDenom(ctx sdk.Context, tokenAddress common.Address) (str return tokenPair.Denom, nil } + +// GetTokenOwnerAddress returns the OwnerAddress of the token +func (k Keeper) GetTokenPairOwnerAddress(ctx sdk.Context, token string) (sdk.AccAddress, error) { + tokenPairID := k.GetERC20Map(ctx, common.HexToAddress(token)) + if len(tokenPairID) == 0 { + return nil, errorsmod.Wrapf(types.ErrTokenPairNotFound, "token '%s' not registered", token) + } + + tokenPair, found := k.GetTokenPair(ctx, tokenPairID) + if !found { + return nil, errorsmod.Wrapf(types.ErrTokenPairNotFound, "token '%s' not registered", token) + } + + return sdk.AccAddressFromBech32(tokenPair.OwnerAddress) +} + +// SetTokenPairOwnerAddress sets the owner address for the token pair +func (k Keeper) SetTokenPairOwnerAddress(ctx sdk.Context, pair types.TokenPair, newOwner string) { + pair.SetOwnerAddress(newOwner) + + k.SetTokenPair(ctx, pair) +} diff --git a/x/erc20/keeper/transfer_ownership.go b/x/erc20/keeper/transfer_ownership.go new file mode 100644 index 000000000..d5b7115f4 --- /dev/null +++ b/x/erc20/keeper/transfer_ownership.go @@ -0,0 +1,67 @@ +package keeper + +import ( + "github.com/cosmos/evm/x/erc20/types" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TransferOwnershipProposal transfers ownership of the token to the new owner through a proposal +func (k Keeper) TransferOwnershipProposal(ctx sdk.Context, newOwner sdk.AccAddress, token string) error { + pair, found := k.GetTokenPair(ctx, k.GetTokenPairID(ctx, token)) + if !found { + return errorsmod.Wrapf(types.ErrTokenPairNotFound, "token '%s' not registered", token) + } + + return k.transferOwnership(ctx, newOwner, pair) +} + +// TransferOwnership transfers ownership of the token to the new owner. +func (k Keeper) TransferOwnership(ctx sdk.Context, sender, newOwner sdk.AccAddress, token string) error { + pair, found := k.GetTokenPair(ctx, k.GetTokenPairID(ctx, token)) + if !found { + return errorsmod.Wrapf(types.ErrTokenPairNotFound, "token '%s' not registered", token) + } + + ownerAddr, err := sdk.AccAddressFromBech32(pair.OwnerAddress) + if err != nil { + return errorsmod.Wrapf(err, "invalid owner address") + } + + if !sender.Equals(ownerAddr) { + return errorsmod.Wrap(types.ErrMinterIsNotOwner, "sender is not the owner of the token") + } + + return k.transferOwnership(ctx, newOwner, pair) +} + +// transferOwnership transfers ownership of the token to the new owner +func (k Keeper) transferOwnership(ctx sdk.Context, newOwner sdk.AccAddress, token types.TokenPair) error { + if !token.IsNativeCoin() { + return errorsmod.Wrap(types.ErrNonNativeTransferOwnershipDisabled, token.Erc20Address) + } + + k.SetTokenPairOwnerAddress(ctx, token, newOwner.String()) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyAction, types.TypeMsgTransferOwnership), + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyNewOwner, newOwner.String()), + ), + ) + + return nil +} + +func (k Keeper) GetOwnerAddress(ctx sdk.Context, contractAddress string) string { + pair, found := k.GetTokenPair(ctx, k.GetTokenPairID(ctx, contractAddress)) + if !found { + return "" + } + + return pair.OwnerAddress +} diff --git a/x/erc20/module.go b/x/erc20/module.go index 332509f11..854a3326c 100644 --- a/x/erc20/module.go +++ b/x/erc20/module.go @@ -31,7 +31,7 @@ const consensusVersion = 1 // type check to ensure the interface is properly implemented var ( - _ module.AppModule = AppModule{} + _ module.AppModule = AppModule{} //nolint:staticcheck // check against deprecated type _ module.AppModuleBasic = AppModuleBasic{} _ module.AppModuleSimulation = AppModule{} diff --git a/x/erc20/types/erc20.pb.go b/x/erc20/types/erc20.pb.go index 9370f63d2..43a59d137 100644 --- a/x/erc20/types/erc20.pb.go +++ b/x/erc20/types/erc20.pb.go @@ -69,6 +69,9 @@ type TokenPair struct { // contract_owner is the an ENUM specifying the type of ERC20 owner (0 // invalid, 1 ModuleAccount, 2 external address) ContractOwner Owner `protobuf:"varint,4,opt,name=contract_owner,json=contractOwner,proto3,enum=cosmos.evm.erc20.v1.Owner" json:"contract_owner,omitempty"` + // owner_address is the address of the current owner of the token + // Only set if contract_owner is OWNER_MODULE + OwnerAddress string `protobuf:"bytes,5,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` } func (m *TokenPair) Reset() { *m = TokenPair{} } @@ -132,6 +135,13 @@ func (m *TokenPair) GetContractOwner() Owner { return OWNER_UNSPECIFIED } +func (m *TokenPair) GetOwnerAddress() string { + if m != nil { + return m.OwnerAddress + } + return "" +} + // Allowance is a token allowance only for erc20 precompile type Allowance struct { // erc20_address is the hex address of ERC20 contract @@ -463,43 +473,44 @@ func init() { func init() { proto.RegisterFile("cosmos/evm/erc20/v1/erc20.proto", fileDescriptor_1164958b5b106e92) } var fileDescriptor_1164958b5b106e92 = []byte{ - // 574 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0xb1, 0x6b, 0xdb, 0x4e, - 0x14, 0xc7, 0x75, 0x89, 0xf3, 0xfb, 0x45, 0x97, 0xc4, 0xb8, 0xd7, 0x04, 0x84, 0xc1, 0xb2, 0x71, - 0xa0, 0x98, 0x0e, 0x52, 0xec, 0x6c, 0x85, 0x52, 0x6c, 0x47, 0x05, 0x97, 0xc4, 0x36, 0x8a, 0x43, - 0x4b, 0x17, 0x73, 0x96, 0x0e, 0x45, 0x58, 0xba, 0x33, 0xba, 0x8b, 0xd2, 0x0e, 0xdd, 0x3b, 0x76, - 0xe9, 0xd4, 0xa5, 0xd0, 0xa9, 0xff, 0x49, 0xc6, 0x8c, 0xa5, 0x43, 0x28, 0xf6, 0xd2, 0x3f, 0xa3, - 0xe8, 0x4e, 0x2a, 0x69, 0xe9, 0x50, 0x9a, 0xed, 0xbe, 0x5f, 0xbf, 0xf7, 0xfc, 0x79, 0xf7, 0x9e, - 0x0e, 0xd6, 0x3d, 0xc6, 0x63, 0xc6, 0x6d, 0x92, 0xc6, 0x36, 0x49, 0xbc, 0xce, 0x81, 0x9d, 0xb6, - 0xd5, 0xc1, 0x5a, 0x24, 0x4c, 0x30, 0x74, 0x5f, 0x05, 0x58, 0x24, 0x8d, 0x2d, 0xe5, 0xa7, 0xed, - 0xaa, 0x99, 0x67, 0xcd, 0x30, 0x9d, 0xdb, 0x69, 0x7b, 0x46, 0x04, 0x6e, 0x4b, 0xa1, 0x92, 0xaa, - 0xbb, 0x01, 0x0b, 0x98, 0x3c, 0xda, 0xd9, 0x49, 0xb9, 0xcd, 0xcf, 0x00, 0xea, 0x13, 0x36, 0x27, - 0x74, 0x8c, 0xc3, 0x04, 0xed, 0xc3, 0x1d, 0x59, 0x6f, 0x8a, 0x7d, 0x3f, 0x21, 0x9c, 0x1b, 0xa0, - 0x01, 0x5a, 0xba, 0xbb, 0x2d, 0xcd, 0xae, 0xf2, 0xd0, 0x2e, 0xdc, 0xf0, 0x09, 0x65, 0xb1, 0xb1, - 0x26, 0x7f, 0x54, 0x02, 0x19, 0xf0, 0x7f, 0x42, 0xf1, 0x2c, 0x22, 0xbe, 0xb1, 0xde, 0x00, 0xad, - 0x4d, 0xb7, 0x90, 0xa8, 0x0b, 0xcb, 0x1e, 0xa3, 0x22, 0xc1, 0x9e, 0x98, 0xb2, 0x4b, 0x4a, 0x12, - 0xa3, 0xd4, 0x00, 0xad, 0x72, 0xa7, 0x6a, 0xfd, 0xa1, 0x0d, 0x6b, 0x94, 0x45, 0xb8, 0x3b, 0x45, - 0x86, 0x94, 0x8f, 0x4a, 0xdf, 0x3f, 0xd6, 0x41, 0xf3, 0x03, 0x80, 0x7a, 0x37, 0x8a, 0xd8, 0x25, - 0xa6, 0x1e, 0xf9, 0x6b, 0x56, 0xf5, 0x97, 0x39, 0xab, 0x14, 0x19, 0x2b, 0x5f, 0x10, 0xea, 0x93, - 0x44, 0xb2, 0xea, 0x6e, 0x21, 0xd1, 0x21, 0xdc, 0x48, 0x71, 0x74, 0x41, 0x24, 0xa2, 0xde, 0xab, - 0x5d, 0xdd, 0xd4, 0xb5, 0xaf, 0x37, 0xf5, 0x3d, 0x45, 0xca, 0xfd, 0xb9, 0x15, 0x32, 0x3b, 0xc6, - 0xe2, 0xdc, 0x1a, 0x50, 0xe1, 0xaa, 0x58, 0x49, 0xa7, 0x35, 0xdf, 0x03, 0xb8, 0xeb, 0x92, 0x20, - 0xe4, 0x82, 0x24, 0x7d, 0x16, 0xd2, 0x71, 0xc2, 0x16, 0x8c, 0xe3, 0x28, 0x63, 0x10, 0xa1, 0x88, - 0x48, 0x0e, 0xa8, 0x04, 0x6a, 0xc0, 0x2d, 0x9f, 0x70, 0x2f, 0x09, 0x17, 0x22, 0x64, 0x34, 0xe7, - 0xbb, 0x6d, 0xa1, 0x27, 0x70, 0x33, 0x26, 0x02, 0xfb, 0x58, 0x60, 0x63, 0xbd, 0xb1, 0xde, 0xda, - 0xea, 0xd4, 0x8a, 0x1b, 0x93, 0x63, 0xcd, 0x67, 0x6c, 0x9d, 0xe4, 0x41, 0xbd, 0x52, 0x46, 0xeb, - 0xfe, 0x4c, 0xca, 0xb9, 0x4e, 0x61, 0xa5, 0x40, 0x29, 0x22, 0x7f, 0x29, 0x0d, 0xfe, 0xa1, 0x74, - 0xf3, 0x0d, 0xdc, 0x2b, 0x7a, 0x75, 0xdc, 0x7e, 0xe7, 0xe0, 0xce, 0xcd, 0x3e, 0x80, 0x65, 0x39, - 0xb8, 0x7c, 0x98, 0x84, 0xcb, 0x96, 0x75, 0xf7, 0x37, 0x37, 0xef, 0x89, 0xc3, 0xda, 0x84, 0x05, - 0x41, 0x44, 0xe4, 0xea, 0xf6, 0x19, 0x4d, 0x49, 0xc2, 0x43, 0x76, 0xf7, 0x3b, 0xcf, 0xf2, 0xb2, - 0x92, 0xf9, 0x5e, 0x28, 0xa1, 0xd6, 0xef, 0xe1, 0x33, 0xb8, 0x21, 0xb7, 0x11, 0xed, 0xc1, 0x7b, - 0xa3, 0xe7, 0x43, 0xc7, 0x9d, 0x9e, 0x0d, 0x4f, 0xc7, 0x4e, 0x7f, 0xf0, 0x74, 0xe0, 0x1c, 0x55, - 0x34, 0x54, 0x81, 0xdb, 0xca, 0x3e, 0x19, 0x1d, 0x9d, 0x1d, 0x3b, 0x15, 0x80, 0x10, 0x2c, 0x2b, - 0xc7, 0x79, 0x31, 0x71, 0xdc, 0x61, 0xf7, 0xb8, 0xb2, 0x56, 0x2d, 0xbd, 0xfd, 0x64, 0x6a, 0xbd, - 0xc7, 0x57, 0x4b, 0x13, 0x5c, 0x2f, 0x4d, 0xf0, 0x6d, 0x69, 0x82, 0x77, 0x2b, 0x53, 0xbb, 0x5e, - 0x99, 0xda, 0x97, 0x95, 0xa9, 0xbd, 0xdc, 0x0f, 0x42, 0x71, 0x7e, 0x31, 0xb3, 0x3c, 0x16, 0xdb, - 0xb7, 0xde, 0x81, 0x57, 0xf9, 0x4b, 0x20, 0x5e, 0x2f, 0x08, 0x9f, 0xfd, 0x27, 0x3f, 0xde, 0xc3, - 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8c, 0xc4, 0x5f, 0x9c, 0x2a, 0x04, 0x00, 0x00, + // 582 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x31, 0x6b, 0xdb, 0x40, + 0x18, 0xd5, 0x25, 0x76, 0x1b, 0x5d, 0x12, 0xe3, 0xaa, 0x09, 0x08, 0x43, 0x64, 0xe3, 0x40, 0x31, + 0x1d, 0xa4, 0xd8, 0xd9, 0x0a, 0xa5, 0x38, 0x8e, 0x0a, 0x2e, 0x89, 0x6d, 0x14, 0x87, 0x96, 0x2e, + 0xe6, 0x2c, 0x1d, 0x8a, 0xb0, 0x74, 0x67, 0x74, 0x17, 0xa5, 0x1d, 0xba, 0x77, 0xec, 0xd2, 0xa9, + 0x4b, 0xa1, 0x7f, 0x26, 0x53, 0xc9, 0x58, 0x3a, 0x84, 0x62, 0x2f, 0xfd, 0x19, 0x45, 0x77, 0xa7, + 0x90, 0x96, 0x0e, 0xa5, 0xd9, 0xee, 0x3d, 0x7d, 0xef, 0xe3, 0xbd, 0xfb, 0x3e, 0x1d, 0xac, 0xfb, + 0x94, 0x25, 0x94, 0x39, 0x38, 0x4b, 0x1c, 0x9c, 0xfa, 0x9d, 0x3d, 0x27, 0x6b, 0xcb, 0x83, 0x3d, + 0x4f, 0x29, 0xa7, 0xc6, 0x43, 0x59, 0x60, 0xe3, 0x2c, 0xb1, 0x25, 0x9f, 0xb5, 0x6b, 0x96, 0x52, + 0x4d, 0x11, 0x99, 0x39, 0x59, 0x7b, 0x8a, 0x39, 0x6a, 0x0b, 0x20, 0x45, 0xb5, 0xad, 0x90, 0x86, + 0x54, 0x1c, 0x9d, 0xfc, 0x24, 0xd9, 0xe6, 0x57, 0x00, 0xf5, 0x31, 0x9d, 0x61, 0x32, 0x42, 0x51, + 0x6a, 0xec, 0xc2, 0x4d, 0xd1, 0x6f, 0x82, 0x82, 0x20, 0xc5, 0x8c, 0x99, 0xa0, 0x01, 0x5a, 0xba, + 0xb7, 0x21, 0xc8, 0xae, 0xe4, 0x8c, 0x2d, 0x58, 0x0e, 0x30, 0xa1, 0x89, 0xb9, 0x22, 0x3e, 0x4a, + 0x60, 0x98, 0xf0, 0x3e, 0x26, 0x68, 0x1a, 0xe3, 0xc0, 0x5c, 0x6d, 0x80, 0xd6, 0x9a, 0x57, 0x40, + 0xa3, 0x0b, 0x2b, 0x3e, 0x25, 0x3c, 0x45, 0x3e, 0x9f, 0xd0, 0x0b, 0x82, 0x53, 0xb3, 0xd4, 0x00, + 0xad, 0x4a, 0xa7, 0x66, 0xff, 0x25, 0x86, 0x3d, 0xcc, 0x2b, 0xbc, 0xcd, 0x42, 0x21, 0x60, 0xee, + 0x4b, 0x28, 0x6f, 0x7c, 0x95, 0xa5, 0x2f, 0x41, 0x2a, 0x5f, 0x4f, 0x4a, 0x3f, 0x3f, 0xd7, 0x41, + 0xf3, 0x13, 0x80, 0x7a, 0x37, 0x8e, 0xe9, 0x05, 0x22, 0x3e, 0xfe, 0xe7, 0x40, 0xd2, 0x97, 0x0a, + 0x24, 0x40, 0x1e, 0x88, 0xcd, 0x31, 0x09, 0x70, 0x2a, 0x02, 0xe9, 0x5e, 0x01, 0x8d, 0x7d, 0x58, + 0xce, 0x50, 0x7c, 0x8e, 0x45, 0x0e, 0xfd, 0x60, 0xe7, 0xf2, 0xba, 0xae, 0x7d, 0xbf, 0xae, 0x6f, + 0xcb, 0x38, 0x2c, 0x98, 0xd9, 0x11, 0x75, 0x12, 0xc4, 0xcf, 0xec, 0x3e, 0xe1, 0x9e, 0xac, 0x15, + 0xee, 0xb4, 0xe6, 0x47, 0x00, 0xb7, 0x3c, 0x1c, 0x46, 0x8c, 0xe3, 0xb4, 0x47, 0x23, 0x32, 0x4a, + 0xe9, 0x9c, 0x32, 0x14, 0xe7, 0x1e, 0x78, 0xc4, 0x63, 0xac, 0x0c, 0x4a, 0x60, 0x34, 0xe0, 0x7a, + 0x80, 0x99, 0x9f, 0x46, 0x73, 0x1e, 0x51, 0xa2, 0xfc, 0xdd, 0xa6, 0x8c, 0x67, 0x70, 0x2d, 0xc1, + 0x1c, 0x05, 0x88, 0x23, 0x73, 0xb5, 0xb1, 0xda, 0x5a, 0xef, 0xec, 0x14, 0xd7, 0x2a, 0x66, 0xaf, + 0x16, 0xc1, 0x3e, 0x56, 0x45, 0x07, 0xa5, 0xdc, 0xad, 0x77, 0x23, 0x52, 0xbe, 0x4e, 0x60, 0xb5, + 0xb0, 0x52, 0x54, 0xfe, 0xd6, 0x1a, 0xfc, 0x47, 0xeb, 0xe6, 0x3b, 0xb8, 0x5d, 0x64, 0x75, 0xbd, + 0x5e, 0x67, 0xef, 0xce, 0x61, 0x1f, 0xc1, 0x8a, 0x18, 0x9c, 0x1a, 0x26, 0x66, 0x22, 0xb2, 0xee, + 0xfd, 0xc1, 0xaa, 0x4c, 0x0c, 0xee, 0x8c, 0x69, 0x18, 0xc6, 0x58, 0xec, 0x77, 0x8f, 0x92, 0x0c, + 0xa7, 0x2c, 0xa2, 0x77, 0xbf, 0xf3, 0x5c, 0x97, 0xb7, 0x54, 0x7b, 0x21, 0x81, 0x5c, 0xbf, 0xc7, + 0x2f, 0x60, 0x59, 0xae, 0xec, 0x36, 0x7c, 0x30, 0x7c, 0x39, 0x70, 0xbd, 0xc9, 0xe9, 0xe0, 0x64, + 0xe4, 0xf6, 0xfa, 0xcf, 0xfb, 0xee, 0x61, 0x55, 0x33, 0xaa, 0x70, 0x43, 0xd2, 0xc7, 0xc3, 0xc3, + 0xd3, 0x23, 0xb7, 0x0a, 0x0c, 0x03, 0x56, 0x24, 0xe3, 0xbe, 0x1a, 0xbb, 0xde, 0xa0, 0x7b, 0x54, + 0x5d, 0xa9, 0x95, 0xde, 0x7f, 0xb1, 0xb4, 0x83, 0xa7, 0x97, 0x0b, 0x0b, 0x5c, 0x2d, 0x2c, 0xf0, + 0x63, 0x61, 0x81, 0x0f, 0x4b, 0x4b, 0xbb, 0x5a, 0x5a, 0xda, 0xb7, 0xa5, 0xa5, 0xbd, 0xde, 0x0d, + 0x23, 0x7e, 0x76, 0x3e, 0xb5, 0x7d, 0x9a, 0x38, 0xb7, 0x1e, 0x8b, 0x37, 0xea, 0xb9, 0xe0, 0x6f, + 0xe7, 0x98, 0x4d, 0xef, 0x89, 0x3f, 0x7c, 0xff, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbe, 0x52, + 0x13, 0x1b, 0x4f, 0x04, 0x00, 0x00, } func (this *TokenPair) Equal(that interface{}) bool { @@ -533,6 +544,9 @@ func (this *TokenPair) Equal(that interface{}) bool { if this.ContractOwner != that1.ContractOwner { return false } + if this.OwnerAddress != that1.OwnerAddress { + return false + } return true } func (this *ToggleTokenConversionProposal) Equal(that interface{}) bool { @@ -585,6 +599,13 @@ func (m *TokenPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.OwnerAddress) > 0 { + i -= len(m.OwnerAddress) + copy(dAtA[i:], m.OwnerAddress) + i = encodeVarintErc20(dAtA, i, uint64(len(m.OwnerAddress))) + i-- + dAtA[i] = 0x2a + } if m.ContractOwner != 0 { i = encodeVarintErc20(dAtA, i, uint64(m.ContractOwner)) i-- @@ -880,6 +901,10 @@ func (m *TokenPair) Size() (n int) { if m.ContractOwner != 0 { n += 1 + sovErc20(uint64(m.ContractOwner)) } + l = len(m.OwnerAddress) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } return n } @@ -1126,6 +1151,38 @@ func (m *TokenPair) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OwnerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + 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 ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OwnerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipErc20(dAtA[iNdEx:]) diff --git a/x/erc20/types/errors.go b/x/erc20/types/errors.go index 99ad293f2..7012d12c1 100644 --- a/x/erc20/types/errors.go +++ b/x/erc20/types/errors.go @@ -6,23 +6,28 @@ import ( // errors var ( - ErrERC20Disabled = errorsmod.Register(ModuleName, 2, "erc20 module is disabled") - ErrInternalTokenPair = errorsmod.Register(ModuleName, 3, "internal ethereum token mapping error") - ErrTokenPairNotFound = errorsmod.Register(ModuleName, 4, "token pair not found") - ErrTokenPairAlreadyExists = errorsmod.Register(ModuleName, 5, "token pair already exists") - ErrUndefinedOwner = errorsmod.Register(ModuleName, 6, "undefined owner of contract pair") - ErrBalanceInvariance = errorsmod.Register(ModuleName, 7, "post transfer balance invariant failed") - ErrUnexpectedEvent = errorsmod.Register(ModuleName, 8, "unexpected event") - ErrABIPack = errorsmod.Register(ModuleName, 9, "contract ABI pack failed") - ErrABIUnpack = errorsmod.Register(ModuleName, 10, "contract ABI unpack failed") - ErrEVMDenom = errorsmod.Register(ModuleName, 11, "EVM denomination registration") - ErrEVMCall = errorsmod.Register(ModuleName, 12, "EVM call unexpected error") - ErrERC20TokenPairDisabled = errorsmod.Register(ModuleName, 13, "erc20 token pair is disabled") - ErrInvalidIBC = errorsmod.Register(ModuleName, 14, "invalid IBC transaction") - ErrTokenPairOwnedByModule = errorsmod.Register(ModuleName, 15, "token pair owned by module") - ErrNativeConversionDisabled = errorsmod.Register(ModuleName, 16, "native coins manual conversion is disabled") - ErrAllowanceNotFound = errorsmod.Register(ModuleName, 17, "allowance not found") - ErrInvalidAllowance = errorsmod.Register(ModuleName, 18, "invalid allowance") - ErrNegativeToken = errorsmod.Register(ModuleName, 19, "token amount is negative") - ErrExpectedEvent = errorsmod.Register(ModuleName, 20, "expected event") + ErrERC20Disabled = errorsmod.Register(ModuleName, 2, "erc20 module is disabled") + ErrInternalTokenPair = errorsmod.Register(ModuleName, 3, "internal ethereum token mapping error") + ErrTokenPairNotFound = errorsmod.Register(ModuleName, 4, "token pair not found") + ErrTokenPairAlreadyExists = errorsmod.Register(ModuleName, 5, "token pair already exists") + ErrUndefinedOwner = errorsmod.Register(ModuleName, 6, "undefined owner of contract pair") + ErrBalanceInvariance = errorsmod.Register(ModuleName, 7, "post transfer balance invariant failed") + ErrUnexpectedEvent = errorsmod.Register(ModuleName, 8, "unexpected event") + ErrABIPack = errorsmod.Register(ModuleName, 9, "contract ABI pack failed") + ErrABIUnpack = errorsmod.Register(ModuleName, 10, "contract ABI unpack failed") + ErrEVMDenom = errorsmod.Register(ModuleName, 11, "EVM denomination registration") + ErrEVMCall = errorsmod.Register(ModuleName, 12, "EVM call unexpected error") + ErrERC20TokenPairDisabled = errorsmod.Register(ModuleName, 13, "erc20 token pair is disabled") + ErrInvalidIBC = errorsmod.Register(ModuleName, 14, "invalid IBC transaction") + ErrTokenPairOwnedByModule = errorsmod.Register(ModuleName, 15, "token pair owned by module") + ErrNativeConversionDisabled = errorsmod.Register(ModuleName, 16, "native coins manual conversion is disabled") + ErrAllowanceNotFound = errorsmod.Register(ModuleName, 17, "allowance not found") + ErrInvalidAllowance = errorsmod.Register(ModuleName, 18, "invalid allowance") + ErrNegativeToken = errorsmod.Register(ModuleName, 19, "token amount is negative") + ErrExpectedEvent = errorsmod.Register(ModuleName, 20, "expected event") + ErrMinterIsNotOwner = errorsmod.Register(ModuleName, 21, "minter is not the owner") + ErrSenderIsNotOwner = errorsmod.Register(ModuleName, 22, "sender is not the owner") + ErrNonNativeCoinMintingDisabled = errorsmod.Register(ModuleName, 23, "minting non-native coins is disabled") + ErrNonNativeCoinBurningDisabled = errorsmod.Register(ModuleName, 24, "burning non-native coins is disabled") + ErrNonNativeTransferOwnershipDisabled = errorsmod.Register(ModuleName, 25, "transferring ownership of non-native coins is disabled") ) diff --git a/x/erc20/types/interfaces.go b/x/erc20/types/interfaces.go index 327057333..a03dbe2f3 100644 --- a/x/erc20/types/interfaces.go +++ b/x/erc20/types/interfaces.go @@ -17,6 +17,7 @@ import ( "cosmossdk.io/core/address" "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -41,16 +42,23 @@ type EVMKeeper interface { GetParams(ctx sdk.Context) evmtypes.Params GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) *statedb.Account EstimateGasInternal(c context.Context, req *evmtypes.EthCallRequest, fromType evmtypes.CallType) (*evmtypes.EstimateGasResponse, error) - ApplyMessage(ctx sdk.Context, msg core.Message, tracer *tracing.Hooks, commit, internal bool) (*evmtypes.MsgEthereumTxResponse, error) + ApplyMessage(ctx sdk.Context, stateDB *statedb.StateDB, msg core.Message, tracer *tracing.Hooks, commit, callFromPrecompile, internal bool) (*evmtypes.MsgEthereumTxResponse, error) DeleteAccount(ctx sdk.Context, addr common.Address) error IsAvailableStaticPrecompile(params *evmtypes.Params, address common.Address) bool - CallEVM(ctx sdk.Context, abi abi.ABI, from, contract common.Address, commit bool, gasCap *big.Int, method string, args ...interface{}) (*evmtypes.MsgEthereumTxResponse, error) - CallEVMWithData(ctx sdk.Context, from common.Address, contract *common.Address, data []byte, commit bool, gasCap *big.Int) (*evmtypes.MsgEthereumTxResponse, error) + CallEVM(ctx sdk.Context, stateDB *statedb.StateDB, abi abi.ABI, from, contract common.Address, commit, callFromPrecompile bool, gasCap *big.Int, method string, args ...interface{}) (*evmtypes.MsgEthereumTxResponse, error) + CallEVMWithData(ctx sdk.Context, stateDB *statedb.StateDB, from common.Address, contract *common.Address, data []byte, commit bool, callFromPrecompile bool, gasCap *big.Int) (*evmtypes.MsgEthereumTxResponse, error) GetCode(ctx sdk.Context, hash common.Hash) []byte SetCode(ctx sdk.Context, hash []byte, bytecode []byte) SetAccount(ctx sdk.Context, address common.Address, account statedb.Account) error GetAccount(ctx sdk.Context, address common.Address) *statedb.Account IsContract(ctx sdk.Context, address common.Address) bool + GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash + GetCodeHash(ctx sdk.Context, addr common.Address) common.Hash + ForEachStorage(ctx sdk.Context, addr common.Address, cb func(key, value common.Hash) bool) + DeleteState(ctx sdk.Context, addr common.Address, key common.Hash) + SetState(ctx sdk.Context, addr common.Address, key common.Hash, value []byte) + DeleteCode(ctx sdk.Context, codeHash []byte) + KVStoreKeys() map[string]*storetypes.KVStoreKey } type Erc20Keeper interface { diff --git a/x/erc20/types/mocks/EVMKeeper.go b/x/erc20/types/mocks/EVMKeeper.go index eacc172d6..71dba53cf 100644 --- a/x/erc20/types/mocks/EVMKeeper.go +++ b/x/erc20/types/mocks/EVMKeeper.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.53.0. DO NOT EDIT. +// Code generated by mockery v2.53.4. DO NOT EDIT. package mocks @@ -17,6 +17,8 @@ import ( statedb "github.com/cosmos/evm/x/vm/statedb" + storetypes "cosmossdk.io/store/types" + tracing "github.com/ethereum/go-ethereum/core/tracing" types "github.com/cosmos/cosmos-sdk/types" @@ -29,9 +31,9 @@ type EVMKeeper struct { mock.Mock } -// ApplyMessage provides a mock function with given fields: ctx, msg, tracer, commit -func (_m *EVMKeeper) ApplyMessage(ctx types.Context, msg core.Message, tracer *tracing.Hooks, commit bool, internal bool) (*vmtypes.MsgEthereumTxResponse, error) { - ret := _m.Called(ctx, msg, tracer, commit) +// ApplyMessage provides a mock function with given fields: ctx, stateDB, msg, tracer, commit, callFromPrecompile, internal +func (_m *EVMKeeper) ApplyMessage(ctx types.Context, stateDB *statedb.StateDB, msg core.Message, tracer *tracing.Hooks, commit bool, callFromPrecompile bool, internal bool) (*vmtypes.MsgEthereumTxResponse, error) { + ret := _m.Called(ctx, stateDB, msg, tracer, commit, callFromPrecompile, internal) if len(ret) == 0 { panic("no return value specified for ApplyMessage") @@ -39,19 +41,19 @@ func (_m *EVMKeeper) ApplyMessage(ctx types.Context, msg core.Message, tracer *t var r0 *vmtypes.MsgEthereumTxResponse var r1 error - if rf, ok := ret.Get(0).(func(types.Context, core.Message, *tracing.Hooks, bool) (*vmtypes.MsgEthereumTxResponse, error)); ok { - return rf(ctx, msg, tracer, commit) + if rf, ok := ret.Get(0).(func(types.Context, *statedb.StateDB, core.Message, *tracing.Hooks, bool, bool, bool) (*vmtypes.MsgEthereumTxResponse, error)); ok { + return rf(ctx, stateDB, msg, tracer, commit, callFromPrecompile, internal) } - if rf, ok := ret.Get(0).(func(types.Context, core.Message, *tracing.Hooks, bool) *vmtypes.MsgEthereumTxResponse); ok { - r0 = rf(ctx, msg, tracer, commit) + if rf, ok := ret.Get(0).(func(types.Context, *statedb.StateDB, core.Message, *tracing.Hooks, bool, bool, bool) *vmtypes.MsgEthereumTxResponse); ok { + r0 = rf(ctx, stateDB, msg, tracer, commit, callFromPrecompile, internal) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*vmtypes.MsgEthereumTxResponse) } } - if rf, ok := ret.Get(1).(func(types.Context, core.Message, *tracing.Hooks, bool) error); ok { - r1 = rf(ctx, msg, tracer, commit) + if rf, ok := ret.Get(1).(func(types.Context, *statedb.StateDB, core.Message, *tracing.Hooks, bool, bool, bool) error); ok { + r1 = rf(ctx, stateDB, msg, tracer, commit, callFromPrecompile, internal) } else { r1 = ret.Error(1) } @@ -59,10 +61,10 @@ func (_m *EVMKeeper) ApplyMessage(ctx types.Context, msg core.Message, tracer *t return r0, r1 } -// CallEVM provides a mock function with given fields: ctx, _a1, from, contract, commit, gasCap, method, args -func (_m *EVMKeeper) CallEVM(ctx types.Context, _a1 abi.ABI, from common.Address, contract common.Address, commit bool, gasCap *big.Int, method string, args ...interface{}) (*vmtypes.MsgEthereumTxResponse, error) { +// CallEVM provides a mock function with given fields: ctx, stateDB, _a2, from, contract, commit, callFromPrecompile, gasCap, method, args +func (_m *EVMKeeper) CallEVM(ctx types.Context, stateDB *statedb.StateDB, _a2 abi.ABI, from common.Address, contract common.Address, commit bool, callFromPrecompile bool, gasCap *big.Int, method string, args ...interface{}) (*vmtypes.MsgEthereumTxResponse, error) { var _ca []interface{} - _ca = append(_ca, ctx, _a1, from, contract, commit, gasCap, method) + _ca = append(_ca, ctx, stateDB, _a2, from, contract, commit, callFromPrecompile, gasCap, method) _ca = append(_ca, args...) ret := _m.Called(_ca...) @@ -72,19 +74,19 @@ func (_m *EVMKeeper) CallEVM(ctx types.Context, _a1 abi.ABI, from common.Address var r0 *vmtypes.MsgEthereumTxResponse var r1 error - if rf, ok := ret.Get(0).(func(types.Context, abi.ABI, common.Address, common.Address, bool, *big.Int, string, ...interface{}) (*vmtypes.MsgEthereumTxResponse, error)); ok { - return rf(ctx, _a1, from, contract, commit, gasCap, method, args...) + if rf, ok := ret.Get(0).(func(types.Context, *statedb.StateDB, abi.ABI, common.Address, common.Address, bool, bool, *big.Int, string, ...interface{}) (*vmtypes.MsgEthereumTxResponse, error)); ok { + return rf(ctx, stateDB, _a2, from, contract, commit, callFromPrecompile, gasCap, method, args...) } - if rf, ok := ret.Get(0).(func(types.Context, abi.ABI, common.Address, common.Address, bool, *big.Int, string, ...interface{}) *vmtypes.MsgEthereumTxResponse); ok { - r0 = rf(ctx, _a1, from, contract, commit, gasCap, method, args...) + if rf, ok := ret.Get(0).(func(types.Context, *statedb.StateDB, abi.ABI, common.Address, common.Address, bool, bool, *big.Int, string, ...interface{}) *vmtypes.MsgEthereumTxResponse); ok { + r0 = rf(ctx, stateDB, _a2, from, contract, commit, callFromPrecompile, gasCap, method, args...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*vmtypes.MsgEthereumTxResponse) } } - if rf, ok := ret.Get(1).(func(types.Context, abi.ABI, common.Address, common.Address, bool, *big.Int, string, ...interface{}) error); ok { - r1 = rf(ctx, _a1, from, contract, commit, gasCap, method, args...) + if rf, ok := ret.Get(1).(func(types.Context, *statedb.StateDB, abi.ABI, common.Address, common.Address, bool, bool, *big.Int, string, ...interface{}) error); ok { + r1 = rf(ctx, stateDB, _a2, from, contract, commit, callFromPrecompile, gasCap, method, args...) } else { r1 = ret.Error(1) } @@ -92,9 +94,9 @@ func (_m *EVMKeeper) CallEVM(ctx types.Context, _a1 abi.ABI, from common.Address return r0, r1 } -// CallEVMWithData provides a mock function with given fields: ctx, from, contract, data, commit, gasCap -func (_m *EVMKeeper) CallEVMWithData(ctx types.Context, from common.Address, contract *common.Address, data []byte, commit bool, gasCap *big.Int) (*vmtypes.MsgEthereumTxResponse, error) { - ret := _m.Called(ctx, from, contract, data, commit, gasCap) +// CallEVMWithData provides a mock function with given fields: ctx, stateDB, from, contract, data, commit, callFromPrecompile, gasCap +func (_m *EVMKeeper) CallEVMWithData(ctx types.Context, stateDB *statedb.StateDB, from common.Address, contract *common.Address, data []byte, commit bool, callFromPrecompile bool, gasCap *big.Int) (*vmtypes.MsgEthereumTxResponse, error) { + ret := _m.Called(ctx, stateDB, from, contract, data, commit, callFromPrecompile, gasCap) if len(ret) == 0 { panic("no return value specified for CallEVMWithData") @@ -102,19 +104,19 @@ func (_m *EVMKeeper) CallEVMWithData(ctx types.Context, from common.Address, con var r0 *vmtypes.MsgEthereumTxResponse var r1 error - if rf, ok := ret.Get(0).(func(types.Context, common.Address, *common.Address, []byte, bool, *big.Int) (*vmtypes.MsgEthereumTxResponse, error)); ok { - return rf(ctx, from, contract, data, commit, gasCap) + if rf, ok := ret.Get(0).(func(types.Context, *statedb.StateDB, common.Address, *common.Address, []byte, bool, bool, *big.Int) (*vmtypes.MsgEthereumTxResponse, error)); ok { + return rf(ctx, stateDB, from, contract, data, commit, callFromPrecompile, gasCap) } - if rf, ok := ret.Get(0).(func(types.Context, common.Address, *common.Address, []byte, bool, *big.Int) *vmtypes.MsgEthereumTxResponse); ok { - r0 = rf(ctx, from, contract, data, commit, gasCap) + if rf, ok := ret.Get(0).(func(types.Context, *statedb.StateDB, common.Address, *common.Address, []byte, bool, bool, *big.Int) *vmtypes.MsgEthereumTxResponse); ok { + r0 = rf(ctx, stateDB, from, contract, data, commit, callFromPrecompile, gasCap) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*vmtypes.MsgEthereumTxResponse) } } - if rf, ok := ret.Get(1).(func(types.Context, common.Address, *common.Address, []byte, bool, *big.Int) error); ok { - r1 = rf(ctx, from, contract, data, commit, gasCap) + if rf, ok := ret.Get(1).(func(types.Context, *statedb.StateDB, common.Address, *common.Address, []byte, bool, bool, *big.Int) error); ok { + r1 = rf(ctx, stateDB, from, contract, data, commit, callFromPrecompile, gasCap) } else { r1 = ret.Error(1) } @@ -140,6 +142,16 @@ func (_m *EVMKeeper) DeleteAccount(ctx types.Context, addr common.Address) error return r0 } +// DeleteCode provides a mock function with given fields: ctx, codeHash +func (_m *EVMKeeper) DeleteCode(ctx types.Context, codeHash []byte) { + _m.Called(ctx, codeHash) +} + +// DeleteState provides a mock function with given fields: ctx, addr, key +func (_m *EVMKeeper) DeleteState(ctx types.Context, addr common.Address, key common.Hash) { + _m.Called(ctx, addr, key) +} + // EstimateGasInternal provides a mock function with given fields: c, req, fromType func (_m *EVMKeeper) EstimateGasInternal(c context.Context, req *vmtypes.EthCallRequest, fromType vmtypes.CallType) (*vmtypes.EstimateGasResponse, error) { ret := _m.Called(c, req, fromType) @@ -170,6 +182,11 @@ func (_m *EVMKeeper) EstimateGasInternal(c context.Context, req *vmtypes.EthCall return r0, r1 } +// ForEachStorage provides a mock function with given fields: ctx, addr, cb +func (_m *EVMKeeper) ForEachStorage(ctx types.Context, addr common.Address, cb func(common.Hash, common.Hash) bool) { + _m.Called(ctx, addr, cb) +} + // GetAccount provides a mock function with given fields: ctx, address func (_m *EVMKeeper) GetAccount(ctx types.Context, address common.Address) *statedb.Account { ret := _m.Called(ctx, address) @@ -230,6 +247,26 @@ func (_m *EVMKeeper) GetCode(ctx types.Context, hash common.Hash) []byte { return r0 } +// GetCodeHash provides a mock function with given fields: ctx, addr +func (_m *EVMKeeper) GetCodeHash(ctx types.Context, addr common.Address) common.Hash { + ret := _m.Called(ctx, addr) + + if len(ret) == 0 { + panic("no return value specified for GetCodeHash") + } + + var r0 common.Hash + if rf, ok := ret.Get(0).(func(types.Context, common.Address) common.Hash); ok { + r0 = rf(ctx, addr) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(common.Hash) + } + } + + return r0 +} + // GetParams provides a mock function with given fields: ctx func (_m *EVMKeeper) GetParams(ctx types.Context) vmtypes.Params { ret := _m.Called(ctx) @@ -248,6 +285,26 @@ func (_m *EVMKeeper) GetParams(ctx types.Context) vmtypes.Params { return r0 } +// GetState provides a mock function with given fields: ctx, addr, key +func (_m *EVMKeeper) GetState(ctx types.Context, addr common.Address, key common.Hash) common.Hash { + ret := _m.Called(ctx, addr, key) + + if len(ret) == 0 { + panic("no return value specified for GetState") + } + + var r0 common.Hash + if rf, ok := ret.Get(0).(func(types.Context, common.Address, common.Hash) common.Hash); ok { + r0 = rf(ctx, addr, key) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(common.Hash) + } + } + + return r0 +} + // IsAvailableStaticPrecompile provides a mock function with given fields: params, address func (_m *EVMKeeper) IsAvailableStaticPrecompile(params *vmtypes.Params, address common.Address) bool { ret := _m.Called(params, address) @@ -284,6 +341,26 @@ func (_m *EVMKeeper) IsContract(ctx types.Context, address common.Address) bool return r0 } +// KVStoreKeys provides a mock function with no fields +func (_m *EVMKeeper) KVStoreKeys() map[string]*storetypes.KVStoreKey { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for KVStoreKeys") + } + + var r0 map[string]*storetypes.KVStoreKey + if rf, ok := ret.Get(0).(func() map[string]*storetypes.KVStoreKey); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]*storetypes.KVStoreKey) + } + } + + return r0 +} + // SetAccount provides a mock function with given fields: ctx, address, account func (_m *EVMKeeper) SetAccount(ctx types.Context, address common.Address, account statedb.Account) error { ret := _m.Called(ctx, address, account) @@ -307,13 +384,17 @@ func (_m *EVMKeeper) SetCode(ctx types.Context, hash []byte, bytecode []byte) { _m.Called(ctx, hash, bytecode) } +// SetState provides a mock function with given fields: ctx, addr, key, value +func (_m *EVMKeeper) SetState(ctx types.Context, addr common.Address, key common.Hash, value []byte) { + _m.Called(ctx, addr, key, value) +} + // NewEVMKeeper creates a new instance of EVMKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewEVMKeeper(t interface { mock.TestingT Cleanup(func()) -}, -) *EVMKeeper { +}) *EVMKeeper { mock := &EVMKeeper{} mock.Mock.Test(t) diff --git a/x/erc20/types/msg.go b/x/erc20/types/msg.go index 8c4213b13..12db3cb50 100644 --- a/x/erc20/types/msg.go +++ b/x/erc20/types/msg.go @@ -19,16 +19,28 @@ var ( _ sdk.Msg = &MsgUpdateParams{} _ sdk.Msg = &MsgRegisterERC20{} _ sdk.Msg = &MsgToggleConversion{} + _ sdk.Msg = &MsgMint{} + _ sdk.Msg = &MsgBurn{} + _ sdk.Msg = &MsgTransferOwnership{} _ sdk.HasValidateBasic = &MsgConvertERC20{} _ sdk.HasValidateBasic = &MsgConvertCoin{} _ sdk.HasValidateBasic = &MsgUpdateParams{} _ sdk.HasValidateBasic = &MsgRegisterERC20{} _ sdk.HasValidateBasic = &MsgToggleConversion{} + _ sdk.HasValidateBasic = &MsgMint{} + _ sdk.HasValidateBasic = &MsgBurn{} + _ sdk.HasValidateBasic = &MsgTransferOwnership{} ) const ( TypeMsgConvertERC20 = "convert_ERC20" TypeMsgConvertCoin = "convert_coin" + + TypeMsgMint = "mint" + TypeMsgBurn = "burn" + TypeMsgTransferOwnership = "transfer_ownership" + + AttributeKeyNewOwner = "new_owner" ) var MsgConvertERC20CustomGetSigner = txsigning.CustomGetSigner{ @@ -79,11 +91,6 @@ func (msg MsgConvertERC20) ValidateBasic() error { return nil } -// GetSignBytes encodes the message for signing -func (msg MsgConvertERC20) GetSignBytes() []byte { - return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) -} - // ValidateBasic does a sanity check of the provided data func (m *MsgUpdateParams) ValidateBasic() error { if _, err := sdk.AccAddressFromBech32(m.Authority); err != nil { @@ -92,11 +99,6 @@ func (m *MsgUpdateParams) ValidateBasic() error { return nil } -// GetSignBytes implements the LegacyMsg interface. -func (m MsgUpdateParams) GetSignBytes() []byte { - return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&m)) -} - // ValidateBasic does a sanity check of the provided data func (m *MsgRegisterERC20) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(m.Signer) @@ -145,7 +147,74 @@ func (msg MsgConvertCoin) ValidateBasic() error { return nil } -// GetSignBytes encodes the message for signing -func (msg MsgConvertCoin) GetSignBytes() []byte { - return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) +// ValidateBasic does a sanity check of the provided data +func (m *MsgTransferOwnership) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(m.Authority); err != nil { + return errorsmod.Wrap(err, "invalid authority address") + } + + if !common.IsHexAddress(m.Token) { + return errorsmod.Wrapf(errortypes.ErrInvalidAddress, "invalid ERC20 contract address %s", m.Token) + } + + if _, err := sdk.AccAddressFromBech32(m.NewOwner); err != nil { + return errorsmod.Wrap(err, "invalid new owner address") + } + + return nil +} + +// GetSignBytes implements the LegacyMsg interface. +func (m MsgTransferOwnership) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&m)) //nolint:staticcheck } + +// ValidateBasic does a sanity check of the provided data +func (m MsgMint) ValidateBasic() error { + if !common.IsHexAddress(m.ContractAddress) { + return errorsmod.Wrapf(errortypes.ErrInvalidAddress, "invalid contract hex address '%s'", m.ContractAddress) + } + + if !m.Amount.IsPositive() { + return errorsmod.Wrapf(errortypes.ErrInvalidCoins, "cannot mint a non-positive amount") + } + + if _, err := sdk.AccAddressFromBech32(m.Sender); err != nil { + return errorsmod.Wrap(err, "invalid sender address") + } + + if _, err := sdk.AccAddressFromBech32(m.To); err != nil { + return errorsmod.Wrap(err, "invalid receiver address") + } + + return nil +} + +// Route returns the message route for a MsgMint +func (m MsgMint) Route() string { return RouterKey } + +// Type returns the message type for a MsgMint +func (m MsgMint) Type() string { return TypeMsgMint } + +// ValidateBasic does a sanity check of the provided data +func (m MsgBurn) ValidateBasic() error { + if !common.IsHexAddress(m.ContractAddress) { + return errorsmod.Wrapf(errortypes.ErrInvalidAddress, "invalid contract hex address '%s'", m.ContractAddress) + } + + if !m.Amount.IsPositive() { + return errorsmod.Wrapf(errortypes.ErrInvalidCoins, "cannot burn a non-positive amount") + } + + if _, err := sdk.AccAddressFromBech32(m.Sender); err != nil { + return errorsmod.Wrap(err, "invalid sender address") + } + + return nil +} + +// Route returns the message route for a MsgBurn +func (m MsgBurn) Route() string { return RouterKey } + +// Type returns the message type for a MsgBurn +func (m MsgBurn) Type() string { return TypeMsgBurn } diff --git a/x/erc20/types/msg_test.go b/x/erc20/types/msg_test.go index 28b9c4ad9..9ff3aa2b2 100644 --- a/x/erc20/types/msg_test.go +++ b/x/erc20/types/msg_test.go @@ -25,16 +25,14 @@ func TestMsgsTestSuite(t *testing.T) { } func (suite *MsgsTestSuite) TestMsgConvertERC20Getters() { - msgInvalid := types.MsgConvertERC20{} msg := types.NewMsgConvertERC20( math.NewInt(100), - sdk.AccAddress(utiltx.GenerateAddress().Bytes()), + utiltx.GenerateAddress().Bytes(), utiltx.GenerateAddress(), utiltx.GenerateAddress(), ) suite.Require().Equal(types.RouterKey, msg.Route()) suite.Require().Equal(types.TypeMsgConvertERC20, msg.Type()) - suite.Require().NotNil(msgInvalid.GetSignBytes()) } func (suite *MsgsTestSuite) TestMsgConvertERC20New() { @@ -132,18 +130,16 @@ func (suite *MsgsTestSuite) TestMsgConvertERC20() { } func (suite *MsgsTestSuite) TestMsgConvertCoinGetters() { - msgInvalid := types.MsgConvertCoin{} msg := types.NewMsgConvertCoin( sdk.NewCoin( "atest", math.NewInt(100), ), utiltx.GenerateAddress(), - sdk.AccAddress(utiltx.GenerateAddress().Bytes()), + utiltx.GenerateAddress().Bytes(), ) suite.Require().Equal(types.RouterKey, msg.Route()) suite.Require().Equal(types.TypeMsgConvertCoin, msg.Type()) - suite.Require().NotNil(msgInvalid.GetSignBytes()) } func (suite *MsgsTestSuite) TestNewMsgConvertCoin() { @@ -279,3 +275,172 @@ func (suite *MsgsTestSuite) TestMsgUpdateValidateBasic() { }) } } + +func (suite *MsgsTestSuite) TestMsgMintValidateBasic() { + testcases := []struct { + name string + msgMint *types.MsgMint + expPass bool + }{ + { + "fail - invalid contract address", + &types.MsgMint{ + ContractAddress: "invalid", + }, + false, + }, + { + "fail - non-positive amount", + &types.MsgMint{ + ContractAddress: utiltx.GenerateAddress().String(), + Amount: math.NewInt(-1), + }, + false, + }, + { + "fail - invalid sender address", + &types.MsgMint{ + ContractAddress: utiltx.GenerateAddress().String(), + Amount: math.NewInt(100), + Sender: "invalid", + }, + false, + }, + { + "fail - invalid receiver address", + &types.MsgMint{ + ContractAddress: utiltx.GenerateAddress().String(), + Amount: math.NewInt(100), + Sender: sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + To: "invalid", + }, + false, + }, + { + "pass - valid msg", + &types.MsgMint{ + ContractAddress: utiltx.GenerateAddress().String(), + Amount: math.NewInt(100), + Sender: sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + To: sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + }, + true, + }, + } + + for _, tc := range testcases { + suite.Run(tc.name, func() { + err := tc.msgMint.ValidateBasic() + if tc.expPass { + suite.NoError(err) + } else { + suite.Error(err) + } + }) + } +} + +func (suite *MsgsTestSuite) TestMsgBurnValidateBasic() { + testcases := []struct { + name string + msgBurn *types.MsgBurn + expPass bool + }{ + { + "fail - invalid contract address", + &types.MsgBurn{ + ContractAddress: "invalid", + }, + false, + }, + { + "fail - non-positive amount", + &types.MsgBurn{ + ContractAddress: utiltx.GenerateAddress().String(), + Amount: math.NewInt(-1), + }, + false, + }, + { + "fail - invalid sender address", + &types.MsgBurn{ + ContractAddress: utiltx.GenerateAddress().String(), + Amount: math.NewInt(100), + Sender: "invalid", + }, + false, + }, + { + "pass - valid msg", + &types.MsgBurn{ + ContractAddress: utiltx.GenerateAddress().String(), + Amount: math.NewInt(100), + Sender: sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + }, + true, + }, + } + + for _, tc := range testcases { + suite.Run(tc.name, func() { + err := tc.msgBurn.ValidateBasic() + if tc.expPass { + suite.NoError(err) + } else { + suite.Error(err) + } + }) + } +} + +func (suite *MsgsTestSuite) TestMsgTransferOwnershipValidateBasic() { + testcases := []struct { + name string + msg *types.MsgTransferOwnership + expPass bool + }{ + { + "fail - invalid authority address", + &types.MsgTransferOwnership{ + Authority: "invalid", + }, + false, + }, + { + "fail - invalid contract address", + &types.MsgTransferOwnership{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + Token: "invalid", + }, + false, + }, + { + "fail - invalid new owner address", + &types.MsgTransferOwnership{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + NewOwner: "invalid", + }, + false, + }, + { + "pass - valid msg", + &types.MsgTransferOwnership{ + Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + NewOwner: sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + Token: utiltx.GenerateAddress().String(), + }, + true, + }, + } + + for _, tc := range testcases { + suite.Run(tc.name, func() { + err := tc.msg.ValidateBasic() + if tc.expPass { + suite.NoError(err) + } else { + suite.Error(err) + } + }) + } +} diff --git a/x/erc20/types/proposal_test.go b/x/erc20/types/proposal_test.go index 63137695d..c63533ba5 100644 --- a/x/erc20/types/proposal_test.go +++ b/x/erc20/types/proposal_test.go @@ -145,16 +145,16 @@ func (suite *ProposalTestSuite) TestRegisterERC20Proposal() { expectPass bool }{ // Valid tests - {msg: "Register token pair - valid pair enabled", title: "test", description: "test desc", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_MODULE}, expectPass: true}, - {msg: "Register token pair - valid pair dissabled", title: "test", description: "test desc", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", false, types.OWNER_MODULE}, expectPass: true}, + {msg: "Register token pair - valid pair enabled", title: "test", description: "test desc", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_MODULE, ""}, expectPass: true}, + {msg: "Register token pair - valid pair dissabled", title: "test", description: "test desc", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", false, types.OWNER_MODULE, ""}, expectPass: true}, // Missing params valid - {msg: "Register token pair - invalid missing title ", title: "", description: "test desc", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", false, types.OWNER_MODULE}, expectPass: false}, - {msg: "Register token pair - invalid missing description ", title: "test", description: "", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", false, types.OWNER_MODULE}, expectPass: false}, + {msg: "Register token pair - invalid missing title ", title: "", description: "test desc", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", false, types.OWNER_MODULE, ""}, expectPass: false}, + {msg: "Register token pair - invalid missing description ", title: "test", description: "", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", false, types.OWNER_MODULE, ""}, expectPass: false}, // Invalid address - {msg: "Register token pair - invalid address (no hex)", title: "test", description: "test desc", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19ZZ", "test", true, types.OWNER_MODULE}, expectPass: false}, - {msg: "Register token pair - invalid address (invalid length 1)", title: "test", description: "test desc", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19", "test", true, types.OWNER_MODULE}, expectPass: false}, - {msg: "Register token pair - invalid address (invalid length 2)", title: "test", description: "test desc", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb194FFF", "test", true, types.OWNER_MODULE}, expectPass: false}, - {msg: "Register token pair - invalid address (invalid prefix)", title: "test", description: "test desc", pair: types.TokenPair{"1x5dCA2483280D9727c80b5518faC4556617fb19F", "test", true, types.OWNER_MODULE}, expectPass: false}, + {msg: "Register token pair - invalid address (no hex)", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19ZZ", "test", true, types.OWNER_MODULE, ""}, expectPass: false}, + {msg: "Register token pair - invalid address (invalid length 1)", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19", "test", true, types.OWNER_MODULE, ""}, expectPass: false}, + {msg: "Register token pair - invalid address (invalid length 2)", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb194FFF", "test", true, types.OWNER_MODULE, ""}, expectPass: false}, + {msg: "pass", title: "test", description: "test desc", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_MODULE, ""}, expectPass: true}, } for i, tc := range testCases { diff --git a/x/erc20/types/query.pb.go b/x/erc20/types/query.pb.go index ac5fe18e8..5cbec4b02 100644 --- a/x/erc20/types/query.pb.go +++ b/x/erc20/types/query.pb.go @@ -313,6 +313,94 @@ func (m *QueryParamsResponse) GetParams() Params { return Params{} } +type QueryOwnerAddressRequest struct { + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` +} + +func (m *QueryOwnerAddressRequest) Reset() { *m = QueryOwnerAddressRequest{} } +func (m *QueryOwnerAddressRequest) String() string { return proto.CompactTextString(m) } +func (*QueryOwnerAddressRequest) ProtoMessage() {} +func (*QueryOwnerAddressRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f1630a6677a16bf4, []int{6} +} +func (m *QueryOwnerAddressRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryOwnerAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryOwnerAddressRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryOwnerAddressRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryOwnerAddressRequest.Merge(m, src) +} +func (m *QueryOwnerAddressRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryOwnerAddressRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryOwnerAddressRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryOwnerAddressRequest proto.InternalMessageInfo + +func (m *QueryOwnerAddressRequest) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +type QueryOwnerAddressResponse struct { + OwnerAddress string `protobuf:"bytes,1,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` +} + +func (m *QueryOwnerAddressResponse) Reset() { *m = QueryOwnerAddressResponse{} } +func (m *QueryOwnerAddressResponse) String() string { return proto.CompactTextString(m) } +func (*QueryOwnerAddressResponse) ProtoMessage() {} +func (*QueryOwnerAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f1630a6677a16bf4, []int{7} +} +func (m *QueryOwnerAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryOwnerAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryOwnerAddressResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryOwnerAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryOwnerAddressResponse.Merge(m, src) +} +func (m *QueryOwnerAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryOwnerAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryOwnerAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryOwnerAddressResponse proto.InternalMessageInfo + +func (m *QueryOwnerAddressResponse) GetOwnerAddress() string { + if m != nil { + return m.OwnerAddress + } + return "" +} + func init() { proto.RegisterType((*QueryTokenPairsRequest)(nil), "cosmos.evm.erc20.v1.QueryTokenPairsRequest") proto.RegisterType((*QueryTokenPairsResponse)(nil), "cosmos.evm.erc20.v1.QueryTokenPairsResponse") @@ -320,45 +408,53 @@ func init() { proto.RegisterType((*QueryTokenPairResponse)(nil), "cosmos.evm.erc20.v1.QueryTokenPairResponse") proto.RegisterType((*QueryParamsRequest)(nil), "cosmos.evm.erc20.v1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "cosmos.evm.erc20.v1.QueryParamsResponse") + proto.RegisterType((*QueryOwnerAddressRequest)(nil), "cosmos.evm.erc20.v1.QueryOwnerAddressRequest") + proto.RegisterType((*QueryOwnerAddressResponse)(nil), "cosmos.evm.erc20.v1.QueryOwnerAddressResponse") } func init() { proto.RegisterFile("cosmos/evm/erc20/v1/query.proto", fileDescriptor_f1630a6677a16bf4) } var fileDescriptor_f1630a6677a16bf4 = []byte{ - // 528 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0x41, 0x6b, 0x13, 0x41, - 0x14, 0xc7, 0x33, 0x2d, 0x2d, 0xe4, 0xe5, 0xe4, 0x34, 0x6a, 0x49, 0x75, 0x1b, 0xb7, 0x60, 0xc3, - 0xc6, 0xce, 0x98, 0xf4, 0x5c, 0x0f, 0x3d, 0xa8, 0x78, 0x8a, 0x41, 0x2f, 0x5e, 0x74, 0x36, 0x0c, - 0xeb, 0xa2, 0xbb, 0xb3, 0xdd, 0x99, 0x2c, 0x16, 0x11, 0xc4, 0x4f, 0xa0, 0x78, 0xf2, 0x1b, 0x78, - 0x12, 0xcf, 0x7e, 0x82, 0x1e, 0x0b, 0x5e, 0x3c, 0x89, 0x24, 0x82, 0x5f, 0x43, 0x76, 0x66, 0xb2, - 0xc9, 0xea, 0x4a, 0xe2, 0x25, 0xec, 0x3c, 0xfe, 0xef, 0xff, 0xff, 0xbd, 0x37, 0x43, 0x60, 0x77, - 0x24, 0x64, 0x24, 0x24, 0xe5, 0x59, 0x44, 0x79, 0x3a, 0xea, 0xdf, 0xa4, 0x59, 0x8f, 0x9e, 0x8c, - 0x79, 0x7a, 0x4a, 0x92, 0x54, 0x28, 0x81, 0xb7, 0x8c, 0x80, 0xf0, 0x2c, 0x22, 0x5a, 0x40, 0xb2, - 0x5e, 0xeb, 0x02, 0x8b, 0xc2, 0x58, 0x50, 0xfd, 0x6b, 0x74, 0x2d, 0xcf, 0x1a, 0xf9, 0x4c, 0x72, - 0x63, 0x40, 0xb3, 0x9e, 0xcf, 0x15, 0xeb, 0xd1, 0x84, 0x05, 0x61, 0xcc, 0x54, 0x28, 0x62, 0xab, - 0xad, 0x0c, 0x35, 0xe6, 0x46, 0x70, 0xad, 0x4a, 0x10, 0xf0, 0x98, 0xcb, 0x50, 0x5a, 0x49, 0x33, - 0x10, 0x81, 0xd0, 0x9f, 0x34, 0xff, 0xb2, 0xd5, 0x2b, 0x81, 0x10, 0xc1, 0x73, 0x4e, 0x59, 0x12, - 0x52, 0x16, 0xc7, 0x42, 0xe9, 0x58, 0xdb, 0xe3, 0x3e, 0x81, 0x4b, 0xf7, 0x73, 0xb2, 0x07, 0xe2, - 0x19, 0x8f, 0x07, 0x2c, 0x4c, 0xe5, 0x90, 0x9f, 0x8c, 0xb9, 0x54, 0xf8, 0x36, 0xc0, 0x9c, 0x72, - 0x1b, 0xb5, 0x51, 0xa7, 0xd1, 0xbf, 0x4e, 0xec, 0xe8, 0xf9, 0x48, 0xc4, 0xec, 0xc4, 0x8e, 0x44, - 0x06, 0x2c, 0xe0, 0xb6, 0x77, 0xb8, 0xd0, 0xe9, 0x7e, 0x42, 0x70, 0xf9, 0xaf, 0x08, 0x99, 0x88, - 0x58, 0x72, 0x7c, 0x0f, 0x1a, 0x2a, 0xaf, 0x3e, 0x4e, 0xf2, 0xf2, 0x36, 0x6a, 0xaf, 0x77, 0x1a, - 0x7d, 0x87, 0x54, 0xec, 0x97, 0x14, 0xdd, 0xc7, 0xf5, 0xb3, 0xef, 0xbb, 0xb5, 0x8f, 0xbf, 0x3e, - 0x7b, 0x68, 0x08, 0xaa, 0xf0, 0xc4, 0x77, 0x4a, 0xbc, 0x6b, 0x9a, 0x77, 0x7f, 0x29, 0xaf, 0x01, - 0x29, 0x01, 0x1f, 0xc0, 0xc5, 0x32, 0xef, 0x6c, 0x23, 0x4d, 0xd8, 0xd0, 0x79, 0x7a, 0x19, 0xf5, - 0xa1, 0x39, 0xb8, 0xfe, 0x9f, 0x1b, 0x2c, 0xa6, 0xbb, 0x0b, 0x30, 0x9f, 0xce, 0x6e, 0xf0, 0x3f, - 0x86, 0xab, 0x17, 0xc3, 0xb9, 0x4d, 0xc0, 0x3a, 0x63, 0xc0, 0x52, 0x16, 0xcd, 0x6e, 0xc8, 0x7d, - 0x08, 0x5b, 0xa5, 0xaa, 0x8d, 0xbd, 0x05, 0x9b, 0x89, 0xae, 0xd8, 0xc8, 0x9d, 0xca, 0x48, 0xd3, - 0xb4, 0x98, 0x67, 0xbb, 0xfa, 0x5f, 0xd6, 0x61, 0x43, 0xfb, 0xe2, 0x77, 0x08, 0x60, 0x7e, 0x6b, - 0xb8, 0x5b, 0x69, 0x54, 0xfd, 0x7c, 0x5a, 0x37, 0x56, 0x13, 0x1b, 0x66, 0xb7, 0xf3, 0xe6, 0xeb, - 0xcf, 0xf7, 0x6b, 0x2e, 0x6e, 0xd3, 0xaa, 0x67, 0xbe, 0xf0, 0x46, 0xf0, 0x07, 0x04, 0xf5, 0xc2, - 0x00, 0x7b, 0x2b, 0xa4, 0xcc, 0x88, 0xba, 0x2b, 0x69, 0x2d, 0xd0, 0xa1, 0x06, 0x3a, 0xc0, 0xdd, - 0x65, 0x40, 0xf4, 0xa5, 0x3e, 0x1c, 0x79, 0xde, 0x2b, 0xfc, 0x1a, 0xc1, 0xa6, 0xd9, 0x2b, 0xde, - 0xff, 0x77, 0x58, 0xe9, 0x12, 0x5b, 0x9d, 0xe5, 0x42, 0x8b, 0xb4, 0xa7, 0x91, 0xae, 0xe2, 0x9d, - 0x4a, 0x24, 0x73, 0x79, 0xc7, 0x47, 0x67, 0x13, 0x07, 0x9d, 0x4f, 0x1c, 0xf4, 0x63, 0xe2, 0xa0, - 0xb7, 0x53, 0xa7, 0x76, 0x3e, 0x75, 0x6a, 0xdf, 0xa6, 0x4e, 0xed, 0xd1, 0x5e, 0x10, 0xaa, 0xa7, - 0x63, 0x9f, 0x8c, 0x44, 0xb4, 0x68, 0xf0, 0xc2, 0x5a, 0xa8, 0xd3, 0x84, 0x4b, 0x7f, 0x53, 0xff, - 0x2b, 0x1c, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xe7, 0x87, 0x8b, 0x04, 0x05, 0x00, 0x00, + // 623 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xb3, 0x85, 0x46, 0xca, 0xa4, 0x08, 0xd8, 0x06, 0x08, 0x29, 0xb8, 0xc1, 0x91, 0x68, + 0x48, 0x88, 0xb7, 0x49, 0x2f, 0x5c, 0x8a, 0xa0, 0x12, 0x7f, 0xc4, 0x85, 0x10, 0xc1, 0x85, 0x4b, + 0xd9, 0xa4, 0x2b, 0x63, 0x81, 0xbd, 0xae, 0xed, 0x04, 0xaa, 0xaa, 0x12, 0xe2, 0x09, 0x40, 0x9c, + 0x78, 0x02, 0x38, 0x21, 0x1e, 0xa3, 0xc7, 0x4a, 0x5c, 0x38, 0x21, 0x94, 0x54, 0xe2, 0x35, 0x90, + 0x77, 0x37, 0x8e, 0x1d, 0x5c, 0x25, 0x5c, 0x2a, 0x7b, 0xfa, 0xcd, 0xf7, 0xfd, 0x66, 0x3c, 0x2d, + 0xac, 0xf6, 0xb8, 0x6f, 0x73, 0x9f, 0xb0, 0x81, 0x4d, 0x98, 0xd7, 0x6b, 0xad, 0x93, 0x41, 0x93, + 0xec, 0xf6, 0x99, 0xb7, 0x67, 0xb8, 0x1e, 0x0f, 0x38, 0x5e, 0x96, 0x02, 0x83, 0x0d, 0x6c, 0x43, + 0x08, 0x8c, 0x41, 0xb3, 0x74, 0x9e, 0xda, 0x96, 0xc3, 0x89, 0xf8, 0x29, 0x75, 0xa5, 0x9a, 0x32, + 0xea, 0x52, 0x9f, 0x49, 0x03, 0x32, 0x68, 0x76, 0x59, 0x40, 0x9b, 0xc4, 0xa5, 0xa6, 0xe5, 0xd0, + 0xc0, 0xe2, 0x8e, 0xd2, 0xa6, 0x86, 0x4a, 0x73, 0x29, 0xb8, 0x96, 0x26, 0x30, 0x99, 0xc3, 0x7c, + 0xcb, 0x57, 0x92, 0x82, 0xc9, 0x4d, 0x2e, 0x1e, 0x49, 0xf8, 0xa4, 0xaa, 0x57, 0x4c, 0xce, 0xcd, + 0xd7, 0x8c, 0x50, 0xd7, 0x22, 0xd4, 0x71, 0x78, 0x20, 0x62, 0x55, 0x8f, 0xfe, 0x02, 0x2e, 0x3e, + 0x09, 0xc9, 0x9e, 0xf2, 0x57, 0xcc, 0x69, 0x53, 0xcb, 0xf3, 0x3b, 0x6c, 0xb7, 0xcf, 0xfc, 0x00, + 0xdf, 0x07, 0x98, 0x50, 0x16, 0x51, 0x19, 0x55, 0xf3, 0xad, 0xeb, 0x86, 0x1a, 0x3d, 0x1c, 0xc9, + 0x90, 0x3b, 0x51, 0x23, 0x19, 0x6d, 0x6a, 0x32, 0xd5, 0xdb, 0x89, 0x75, 0xea, 0xdf, 0x10, 0x5c, + 0xfa, 0x27, 0xc2, 0x77, 0xb9, 0xe3, 0x33, 0xfc, 0x08, 0xf2, 0x41, 0x58, 0xdd, 0x76, 0xc3, 0x72, + 0x11, 0x95, 0x4f, 0x55, 0xf3, 0x2d, 0xcd, 0x48, 0xd9, 0xaf, 0x11, 0x75, 0x6f, 0xe5, 0x0e, 0x7f, + 0xad, 0x66, 0xbe, 0xfe, 0xf9, 0x5e, 0x43, 0x1d, 0x08, 0x22, 0x4f, 0xfc, 0x20, 0xc1, 0xbb, 0x20, + 0x78, 0xd7, 0x66, 0xf2, 0x4a, 0x90, 0x04, 0x70, 0x03, 0x2e, 0x24, 0x79, 0xc7, 0x1b, 0x29, 0xc0, + 0xa2, 0xc8, 0x13, 0xcb, 0xc8, 0x75, 0xe4, 0x8b, 0xde, 0x9d, 0xde, 0x60, 0x34, 0xdd, 0x43, 0x80, + 0xc9, 0x74, 0x6a, 0x83, 0xff, 0x31, 0x5c, 0x2e, 0x1a, 0x4e, 0x2f, 0x00, 0x16, 0x19, 0x6d, 0xea, + 0x51, 0x7b, 0xfc, 0x85, 0xf4, 0x67, 0xb0, 0x9c, 0xa8, 0xaa, 0xd8, 0xdb, 0x90, 0x75, 0x45, 0x45, + 0x45, 0xae, 0xa4, 0x46, 0xca, 0xa6, 0x78, 0x9e, 0xea, 0xd2, 0xef, 0x41, 0x51, 0xd8, 0x3e, 0x7e, + 0xe3, 0x30, 0xef, 0xee, 0xce, 0x8e, 0xc7, 0xfc, 0xe8, 0x28, 0x6e, 0xc0, 0xb9, 0x1e, 0x77, 0x02, + 0x8f, 0xf6, 0x82, 0x6d, 0x2a, 0x7f, 0xa5, 0xb6, 0x71, 0x76, 0x5c, 0x57, 0x1d, 0xfa, 0x1d, 0xb8, + 0x9c, 0x62, 0xa3, 0x18, 0x2b, 0x70, 0x86, 0x87, 0xf5, 0x29, 0x93, 0x25, 0x1e, 0x13, 0xb7, 0x8e, + 0x4f, 0xc3, 0xa2, 0xb0, 0xc0, 0x1f, 0x11, 0xc0, 0xe4, 0x7c, 0x70, 0x3d, 0x75, 0xa2, 0xf4, 0x3b, + 0x2e, 0xdd, 0x9c, 0x4f, 0x2c, 0xc1, 0xf4, 0xea, 0xfb, 0x1f, 0xc7, 0x9f, 0x16, 0x74, 0x5c, 0x26, + 0x69, 0x7f, 0x6f, 0xb1, 0x63, 0xc5, 0x9f, 0x11, 0xe4, 0x22, 0x03, 0x5c, 0x9b, 0x23, 0x65, 0x4c, + 0x54, 0x9f, 0x4b, 0xab, 0x80, 0x36, 0x04, 0x50, 0x03, 0xd7, 0x67, 0x01, 0x91, 0x7d, 0xf1, 0xb2, + 0x59, 0xab, 0x1d, 0xe0, 0x77, 0x08, 0xb2, 0xf2, 0x03, 0xe3, 0xb5, 0x93, 0xc3, 0x12, 0xd7, 0x54, + 0xaa, 0xce, 0x16, 0x2a, 0xa4, 0x8a, 0x40, 0xba, 0x8a, 0x57, 0x52, 0x91, 0xe4, 0x15, 0xe1, 0x2f, + 0x08, 0x96, 0xe2, 0x9f, 0x1e, 0x37, 0x4e, 0xf6, 0x4f, 0xb9, 0xb4, 0x92, 0x31, 0xaf, 0x5c, 0x41, + 0xdd, 0x12, 0x50, 0x2d, 0xbc, 0x1e, 0xd2, 0x84, 0x4c, 0x63, 0x9e, 0xc4, 0x9d, 0x91, 0xfd, 0xe9, + 0xf3, 0x3d, 0xd8, 0xda, 0x3c, 0x1c, 0x6a, 0xe8, 0x68, 0xa8, 0xa1, 0xdf, 0x43, 0x0d, 0x7d, 0x18, + 0x69, 0x99, 0xa3, 0x91, 0x96, 0xf9, 0x39, 0xd2, 0x32, 0xcf, 0x2b, 0xa6, 0x15, 0xbc, 0xec, 0x77, + 0x8d, 0x1e, 0xb7, 0xe3, 0xa3, 0xbe, 0x55, 0xe6, 0xc1, 0x9e, 0xcb, 0xfc, 0x6e, 0x56, 0xfc, 0x23, + 0xdd, 0xf8, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xbf, 0x38, 0xe3, 0xd0, 0x37, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -379,6 +475,8 @@ type QueryClient interface { TokenPair(ctx context.Context, in *QueryTokenPairRequest, opts ...grpc.CallOption) (*QueryTokenPairResponse, error) // Params retrieves the erc20 module params Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // OwnerAddress retrieves the owner address for a given ERC20 contract address + OwnerAddress(ctx context.Context, in *QueryOwnerAddressRequest, opts ...grpc.CallOption) (*QueryOwnerAddressResponse, error) } type queryClient struct { @@ -416,6 +514,15 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . return out, nil } +func (c *queryClient) OwnerAddress(ctx context.Context, in *QueryOwnerAddressRequest, opts ...grpc.CallOption) (*QueryOwnerAddressResponse, error) { + out := new(QueryOwnerAddressResponse) + err := c.cc.Invoke(ctx, "/cosmos.evm.erc20.v1.Query/OwnerAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // TokenPairs retrieves registered token pairs (mappings)x @@ -424,6 +531,8 @@ type QueryServer interface { TokenPair(context.Context, *QueryTokenPairRequest) (*QueryTokenPairResponse, error) // Params retrieves the erc20 module params Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // OwnerAddress retrieves the owner address for a given ERC20 contract address + OwnerAddress(context.Context, *QueryOwnerAddressRequest) (*QueryOwnerAddressResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -439,6 +548,9 @@ func (*UnimplementedQueryServer) TokenPair(ctx context.Context, req *QueryTokenP func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") } +func (*UnimplementedQueryServer) OwnerAddress(ctx context.Context, req *QueryOwnerAddressRequest) (*QueryOwnerAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OwnerAddress not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -498,6 +610,24 @@ func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Query_OwnerAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryOwnerAddressRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).OwnerAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.evm.erc20.v1.Query/OwnerAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).OwnerAddress(ctx, req.(*QueryOwnerAddressRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "cosmos.evm.erc20.v1.Query", HandlerType: (*QueryServer)(nil), @@ -514,6 +644,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "Params", Handler: _Query_Params_Handler, }, + { + MethodName: "OwnerAddress", + Handler: _Query_OwnerAddress_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "cosmos/evm/erc20/v1/query.proto", @@ -722,6 +856,66 @@ func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryOwnerAddressRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryOwnerAddressRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryOwnerAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryOwnerAddressResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryOwnerAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryOwnerAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.OwnerAddress) > 0 { + i -= len(m.OwnerAddress) + copy(dAtA[i:], m.OwnerAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.OwnerAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -809,6 +1003,32 @@ func (m *QueryParamsResponse) Size() (n int) { return n } +func (m *QueryOwnerAddressRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryOwnerAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.OwnerAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1319,6 +1539,170 @@ func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryOwnerAddressRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryOwnerAddressRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryOwnerAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryOwnerAddressResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryOwnerAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryOwnerAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OwnerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OwnerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/erc20/types/query.pb.gw.go b/x/erc20/types/query.pb.gw.go index 18dafd224..0e4962fa3 100644 --- a/x/erc20/types/query.pb.gw.go +++ b/x/erc20/types/query.pb.gw.go @@ -141,6 +141,60 @@ func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshal } +func request_Query_OwnerAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryOwnerAddressRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["contract_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contract_address") + } + + protoReq.ContractAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contract_address", err) + } + + msg, err := client.OwnerAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_OwnerAddress_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryOwnerAddressRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["contract_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "contract_address") + } + + protoReq.ContractAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "contract_address", err) + } + + msg, err := server.OwnerAddress(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -216,6 +270,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_OwnerAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_OwnerAddress_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_OwnerAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -317,6 +394,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_OwnerAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_OwnerAddress_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_OwnerAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -326,6 +423,8 @@ var ( pattern_Query_TokenPair_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 3, 0, 4, 1, 5, 5}, []string{"cosmos", "evm", "erc20", "v1", "token_pairs", "token"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "evm", "erc20", "v1", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_OwnerAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"evmos", "erc20", "v1", "owner_address", "contract_address"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -334,4 +433,6 @@ var ( forward_Query_TokenPair_0 = runtime.ForwardResponseMessage forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_OwnerAddress_0 = runtime.ForwardResponseMessage ) diff --git a/x/erc20/types/token_pair.go b/x/erc20/types/token_pair.go index 4da8ba4b4..3c361d9cc 100644 --- a/x/erc20/types/token_pair.go +++ b/x/erc20/types/token_pair.go @@ -49,6 +49,11 @@ func (tp TokenPair) GetERC20Contract() common.Address { return common.HexToAddress(tp.Erc20Address) } +// SetOwnerAddress sets the address of the owner of the ERC20 contract +func (tp *TokenPair) SetOwnerAddress(address string) { + tp.OwnerAddress = address +} + // Validate performs a stateless validation of a TokenPair func (tp TokenPair) Validate() error { if err := sdk.ValidateDenom(tp.Denom); err != nil { diff --git a/x/erc20/types/token_pair_test.go b/x/erc20/types/token_pair_test.go index e29ce121e..61b296767 100644 --- a/x/erc20/types/token_pair_test.go +++ b/x/erc20/types/token_pair_test.go @@ -59,10 +59,10 @@ func (suite *TokenPairTestSuite) TestTokenPair() { pair types.TokenPair expectPass bool }{ - {msg: "Register token pair - invalid address (no hex)", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19ZZ", "test", true, types.OWNER_MODULE}, expectPass: false}, - {msg: "Register token pair - invalid address (invalid length 1)", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19", "test", true, types.OWNER_MODULE}, expectPass: false}, - {msg: "Register token pair - invalid address (invalid length 2)", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb194FFF", "test", true, types.OWNER_MODULE}, expectPass: false}, - {msg: "pass", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_MODULE}, expectPass: true}, + {msg: "Register token pair - invalid address (no hex)", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19ZZ", "test", true, types.OWNER_MODULE, ""}, expectPass: false}, + {msg: "Register token pair - invalid address (invalid length 1)", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19", "test", true, types.OWNER_MODULE, ""}, expectPass: false}, + {msg: "Register token pair - invalid address (invalid length 2)", pair: types.TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb194FFF", "test", true, types.OWNER_MODULE, ""}, expectPass: false}, + {msg: "pass", pair: types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_MODULE, ""}, expectPass: true}, } for i, tc := range testCases { @@ -101,17 +101,17 @@ func (suite *TokenPairTestSuite) TestIsNativeCoin() { }{ { "no owner", - types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_UNSPECIFIED}, + types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_UNSPECIFIED, ""}, false, }, { "external ERC20 owner", - types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_EXTERNAL}, + types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_EXTERNAL, ""}, false, }, { "pass", - types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_MODULE}, + types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_MODULE, ""}, true, }, } @@ -134,17 +134,17 @@ func (suite *TokenPairTestSuite) TestIsNativeERC20() { }{ { "no owner", - types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_UNSPECIFIED}, + types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_UNSPECIFIED, ""}, false, }, { "module owner", - types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_MODULE}, + types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_MODULE, ""}, false, }, { "pass", - types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_EXTERNAL}, + types.TokenPair{utiltx.GenerateAddress().String(), "test", true, types.OWNER_EXTERNAL, ""}, true, }, } diff --git a/x/erc20/types/tx.pb.go b/x/erc20/types/tx.pb.go index 5e68426eb..112610bb0 100644 --- a/x/erc20/types/tx.pb.go +++ b/x/erc20/types/tx.pb.go @@ -527,6 +527,305 @@ func (m *MsgToggleConversionResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgToggleConversionResponse proto.InternalMessageInfo +// MsgTransferOwnership defines a Msg to transfer the ownership of the ERC20 +// token pair to the new owner +type MsgTransferOwnership struct { + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // token identifier can be either the hex contract address of the ERC20 or the + // Cosmos base denomination + Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` + // new_owner is the hex address of the new owner + NewOwner string `protobuf:"bytes,3,opt,name=new_owner,json=newOwner,proto3" json:"new_owner,omitempty"` +} + +func (m *MsgTransferOwnership) Reset() { *m = MsgTransferOwnership{} } +func (m *MsgTransferOwnership) String() string { return proto.CompactTextString(m) } +func (*MsgTransferOwnership) ProtoMessage() {} +func (*MsgTransferOwnership) Descriptor() ([]byte, []int) { + return fileDescriptor_e06c8e6992ada536, []int{10} +} +func (m *MsgTransferOwnership) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgTransferOwnership) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgTransferOwnership.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgTransferOwnership) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgTransferOwnership.Merge(m, src) +} +func (m *MsgTransferOwnership) XXX_Size() int { + return m.Size() +} +func (m *MsgTransferOwnership) XXX_DiscardUnknown() { + xxx_messageInfo_MsgTransferOwnership.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgTransferOwnership proto.InternalMessageInfo + +func (m *MsgTransferOwnership) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgTransferOwnership) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func (m *MsgTransferOwnership) GetNewOwner() string { + if m != nil { + return m.NewOwner + } + return "" +} + +// MsgTransferOwnershipResponse returns no fields +type MsgTransferOwnershipResponse struct { +} + +func (m *MsgTransferOwnershipResponse) Reset() { *m = MsgTransferOwnershipResponse{} } +func (m *MsgTransferOwnershipResponse) String() string { return proto.CompactTextString(m) } +func (*MsgTransferOwnershipResponse) ProtoMessage() {} +func (*MsgTransferOwnershipResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_e06c8e6992ada536, []int{11} +} +func (m *MsgTransferOwnershipResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgTransferOwnershipResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgTransferOwnershipResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgTransferOwnershipResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgTransferOwnershipResponse.Merge(m, src) +} +func (m *MsgTransferOwnershipResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgTransferOwnershipResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgTransferOwnershipResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgTransferOwnershipResponse proto.InternalMessageInfo + +// MsgMint defines a Msg to mint ERC20 tokens +type MsgMint struct { + // contract_address of an ERC20 token contract, that is registered in a token + // pair + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // amount of ERC20 tokens to mint + Amount cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=cosmossdk.io/math.Int" json:"amount"` + // to is the address to mint the tokens to + To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"` + // sender is the address of the sender + Sender string `protobuf:"bytes,4,opt,name=sender,proto3" json:"sender,omitempty"` +} + +func (m *MsgMint) Reset() { *m = MsgMint{} } +func (m *MsgMint) String() string { return proto.CompactTextString(m) } +func (*MsgMint) ProtoMessage() {} +func (*MsgMint) Descriptor() ([]byte, []int) { + return fileDescriptor_e06c8e6992ada536, []int{12} +} +func (m *MsgMint) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMint.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMint) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMint.Merge(m, src) +} +func (m *MsgMint) XXX_Size() int { + return m.Size() +} +func (m *MsgMint) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMint.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMint proto.InternalMessageInfo + +func (m *MsgMint) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *MsgMint) GetTo() string { + if m != nil { + return m.To + } + return "" +} + +func (m *MsgMint) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +type MsgMintResponse struct { +} + +func (m *MsgMintResponse) Reset() { *m = MsgMintResponse{} } +func (m *MsgMintResponse) String() string { return proto.CompactTextString(m) } +func (*MsgMintResponse) ProtoMessage() {} +func (*MsgMintResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_e06c8e6992ada536, []int{13} +} +func (m *MsgMintResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMintResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMintResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgMintResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMintResponse.Merge(m, src) +} +func (m *MsgMintResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgMintResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMintResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMintResponse proto.InternalMessageInfo + +// MsgBurn defines a Msg to burn ERC20 tokens +type MsgBurn struct { + // contract_address of an ERC20 token contract, that is registered in a token + // pair + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // amount of ERC20 tokens to burn + Amount cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=cosmossdk.io/math.Int" json:"amount"` + // sender is the address of the sender + Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` +} + +func (m *MsgBurn) Reset() { *m = MsgBurn{} } +func (m *MsgBurn) String() string { return proto.CompactTextString(m) } +func (*MsgBurn) ProtoMessage() {} +func (*MsgBurn) Descriptor() ([]byte, []int) { + return fileDescriptor_e06c8e6992ada536, []int{14} +} +func (m *MsgBurn) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgBurn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgBurn.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgBurn) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgBurn.Merge(m, src) +} +func (m *MsgBurn) XXX_Size() int { + return m.Size() +} +func (m *MsgBurn) XXX_DiscardUnknown() { + xxx_messageInfo_MsgBurn.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgBurn proto.InternalMessageInfo + +func (m *MsgBurn) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *MsgBurn) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +type MsgBurnResponse struct { +} + +func (m *MsgBurnResponse) Reset() { *m = MsgBurnResponse{} } +func (m *MsgBurnResponse) String() string { return proto.CompactTextString(m) } +func (*MsgBurnResponse) ProtoMessage() {} +func (*MsgBurnResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_e06c8e6992ada536, []int{15} +} +func (m *MsgBurnResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgBurnResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgBurnResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgBurnResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgBurnResponse.Merge(m, src) +} +func (m *MsgBurnResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgBurnResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgBurnResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgBurnResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgConvertERC20)(nil), "cosmos.evm.erc20.v1.MsgConvertERC20") proto.RegisterType((*MsgConvertERC20Response)(nil), "cosmos.evm.erc20.v1.MsgConvertERC20Response") @@ -538,62 +837,80 @@ func init() { proto.RegisterType((*MsgRegisterERC20Response)(nil), "cosmos.evm.erc20.v1.MsgRegisterERC20Response") proto.RegisterType((*MsgToggleConversion)(nil), "cosmos.evm.erc20.v1.MsgToggleConversion") proto.RegisterType((*MsgToggleConversionResponse)(nil), "cosmos.evm.erc20.v1.MsgToggleConversionResponse") + proto.RegisterType((*MsgTransferOwnership)(nil), "cosmos.evm.erc20.v1.MsgTransferOwnership") + proto.RegisterType((*MsgTransferOwnershipResponse)(nil), "cosmos.evm.erc20.v1.MsgTransferOwnershipResponse") + proto.RegisterType((*MsgMint)(nil), "cosmos.evm.erc20.v1.MsgMint") + proto.RegisterType((*MsgMintResponse)(nil), "cosmos.evm.erc20.v1.MsgMintResponse") + proto.RegisterType((*MsgBurn)(nil), "cosmos.evm.erc20.v1.MsgBurn") + proto.RegisterType((*MsgBurnResponse)(nil), "cosmos.evm.erc20.v1.MsgBurnResponse") } func init() { proto.RegisterFile("cosmos/evm/erc20/v1/tx.proto", fileDescriptor_e06c8e6992ada536) } var fileDescriptor_e06c8e6992ada536 = []byte{ - // 796 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcf, 0x4f, 0x13, 0x4d, - 0x18, 0xee, 0x42, 0x69, 0xbe, 0x0e, 0x7c, 0xc0, 0xb7, 0xf0, 0x41, 0x59, 0xf8, 0xca, 0xe7, 0xf2, - 0x43, 0xac, 0xb0, 0xdb, 0x16, 0x35, 0xb1, 0x89, 0x26, 0x96, 0x78, 0xf0, 0xd0, 0xc4, 0xac, 0x7a, - 0xf1, 0x42, 0xb6, 0xdb, 0xc9, 0xb0, 0x81, 0x9d, 0x69, 0x76, 0x86, 0x06, 0x6e, 0x86, 0xa3, 0x89, - 0x89, 0xc6, 0xbb, 0x89, 0x37, 0x8f, 0x1c, 0xfc, 0x03, 0x3c, 0x19, 0x8e, 0x44, 0x2f, 0xc6, 0x03, - 0x31, 0x60, 0xc2, 0xc1, 0x9b, 0x7f, 0x81, 0xd9, 0x99, 0xe9, 0xb2, 0x5d, 0xb6, 0xb6, 0xf1, 0xd2, - 0x74, 0xde, 0xf7, 0x79, 0xe7, 0x7d, 0x9e, 0xf7, 0xc7, 0x2c, 0x98, 0x73, 0x08, 0xf5, 0x08, 0x35, - 0x61, 0xcb, 0x33, 0xa1, 0xef, 0x94, 0x8b, 0x66, 0xab, 0x64, 0xb2, 0x3d, 0xa3, 0xe9, 0x13, 0x46, - 0xd4, 0x09, 0xe1, 0x35, 0x60, 0xcb, 0x33, 0xb8, 0xd7, 0x68, 0x95, 0xb4, 0x7f, 0x6c, 0xcf, 0xc5, - 0xc4, 0xe4, 0xbf, 0x02, 0xa7, 0xe5, 0xe5, 0x2d, 0x75, 0x9b, 0x42, 0xb3, 0x55, 0xaa, 0x43, 0x66, - 0x97, 0x4c, 0x87, 0xb8, 0x58, 0xfa, 0xaf, 0x24, 0x65, 0x41, 0x10, 0x43, 0xea, 0x52, 0x09, 0x99, - 0x96, 0x10, 0x8f, 0xa2, 0xc0, 0xe9, 0x51, 0x24, 0x1d, 0x33, 0xc2, 0xb1, 0xc9, 0x4f, 0xa6, 0x24, - 0x24, 0x5c, 0x93, 0x88, 0x20, 0x22, 0xec, 0xc1, 0x3f, 0x69, 0x9d, 0x43, 0x84, 0xa0, 0x1d, 0x68, - 0xda, 0x4d, 0xd7, 0xb4, 0x31, 0x26, 0xcc, 0x66, 0x2e, 0xc1, 0x32, 0x46, 0xff, 0xa9, 0x80, 0xb1, - 0x1a, 0x45, 0x1b, 0x04, 0xb7, 0xa0, 0xcf, 0xee, 0x5b, 0x1b, 0xe5, 0xa2, 0x7a, 0x0d, 0x8c, 0x3b, - 0x04, 0x33, 0xdf, 0x76, 0xd8, 0xa6, 0xdd, 0x68, 0xf8, 0x90, 0xd2, 0x9c, 0xf2, 0xbf, 0xb2, 0x92, - 0xb5, 0xc6, 0xda, 0xf6, 0x7b, 0xc2, 0xac, 0x56, 0x40, 0xc6, 0xf6, 0xc8, 0x2e, 0x66, 0xb9, 0x81, - 0x00, 0x50, 0xd5, 0x8f, 0x4e, 0xe6, 0x53, 0x5f, 0x4f, 0xe6, 0xff, 0x15, 0xc4, 0x68, 0x63, 0xdb, - 0x70, 0x89, 0xe9, 0xd9, 0x6c, 0xcb, 0x78, 0x80, 0xd9, 0xbb, 0xf3, 0xc3, 0x82, 0x62, 0xc9, 0x08, - 0xf5, 0x06, 0xf8, 0xcb, 0x87, 0x0e, 0x74, 0x5b, 0xd0, 0xcf, 0x0d, 0xf2, 0xe8, 0xdc, 0xa7, 0xf7, - 0x6b, 0x93, 0x52, 0x92, 0xcc, 0xf0, 0x88, 0xf9, 0x2e, 0x46, 0x56, 0x88, 0x54, 0xa7, 0x40, 0x86, - 0x42, 0xdc, 0x80, 0x7e, 0x2e, 0xcd, 0x29, 0xc9, 0x53, 0xa5, 0x70, 0x70, 0x7e, 0x58, 0x90, 0x87, - 0xe7, 0xe7, 0x87, 0x05, 0x2d, 0x52, 0xe3, 0x98, 0x40, 0x7d, 0x06, 0x4c, 0xc7, 0x4c, 0x16, 0xa4, - 0x4d, 0x82, 0x29, 0xd4, 0x3f, 0x2a, 0x60, 0xf4, 0xc2, 0xb7, 0x41, 0x5c, 0xac, 0xae, 0x83, 0x74, - 0xd0, 0x3b, 0x5e, 0x82, 0xe1, 0xf2, 0x8c, 0x21, 0x09, 0x06, 0xcd, 0x35, 0x64, 0x73, 0x8d, 0x00, - 0x58, 0x4d, 0x07, 0xe2, 0x2d, 0x0e, 0x56, 0xb5, 0x88, 0x38, 0x5e, 0x9a, 0x88, 0x84, 0x62, 0x28, - 0xa1, 0x97, 0xec, 0xb6, 0xb8, 0x52, 0x4c, 0x5c, 0x74, 0x80, 0xf6, 0xe4, 0x08, 0x75, 0xb2, 0xd6, - 0x73, 0x60, 0xaa, 0xd3, 0x12, 0x4a, 0xfc, 0x20, 0x5a, 0xfe, 0xa4, 0xd9, 0xb0, 0x19, 0x7c, 0x68, - 0xfb, 0xb6, 0x47, 0xd5, 0x5b, 0x20, 0x6b, 0xef, 0xb2, 0x2d, 0xe2, 0xbb, 0x6c, 0x5f, 0xf4, 0xfa, - 0x37, 0xac, 0x2e, 0xa0, 0xea, 0x5d, 0x90, 0x69, 0xf2, 0x1b, 0xb8, 0xc8, 0xe1, 0xf2, 0xac, 0x91, - 0xb0, 0x22, 0x86, 0x48, 0x52, 0xcd, 0x06, 0xf5, 0x91, 0x33, 0x20, 0xa2, 0x2a, 0x37, 0x03, 0x61, - 0x17, 0xf7, 0x05, 0xda, 0xf4, 0x64, 0x6d, 0x51, 0xba, 0xb2, 0x81, 0x51, 0x53, 0xa8, 0xee, 0xad, - 0x02, 0xc6, 0x6b, 0x14, 0x59, 0x10, 0xb9, 0x94, 0x41, 0x5f, 0x4c, 0x74, 0x50, 0x71, 0x17, 0x61, - 0xe8, 0xf7, 0xd4, 0x26, 0x71, 0xea, 0x32, 0x18, 0xe5, 0xa9, 0xe5, 0xfc, 0xc3, 0x40, 0xe0, 0xe0, - 0x4a, 0xd6, 0x8a, 0x59, 0x2b, 0xeb, 0xa2, 0x33, 0x3c, 0x28, 0x60, 0xbf, 0x90, 0xcc, 0xbe, 0x83, - 0x8e, 0xae, 0x81, 0x5c, 0xdc, 0x16, 0xf2, 0x7f, 0xa3, 0x80, 0x89, 0x1a, 0x45, 0x8f, 0x09, 0x42, - 0x3b, 0x50, 0xb4, 0x8f, 0xba, 0x04, 0xff, 0x71, 0x87, 0x26, 0xc1, 0x10, 0x23, 0xdb, 0x10, 0xcb, - 0x29, 0x14, 0x87, 0xca, 0xed, 0xcb, 0x75, 0x5f, 0x4e, 0x66, 0x1e, 0x27, 0xa2, 0xff, 0x07, 0x66, - 0x13, 0xcc, 0x6d, 0xfe, 0xe5, 0x1f, 0x69, 0x30, 0x58, 0xa3, 0x48, 0x7d, 0xa5, 0x80, 0x91, 0x8e, - 0x57, 0x65, 0x31, 0x71, 0x34, 0x62, 0x7b, 0xa8, 0xad, 0xf6, 0x83, 0x0a, 0x8b, 0xb5, 0x76, 0xf0, - 0xf9, 0xfb, 0xeb, 0x81, 0xab, 0xea, 0x92, 0x99, 0xfc, 0x6e, 0x9b, 0x8e, 0x88, 0xda, 0xe4, 0x36, - 0xf5, 0x85, 0x02, 0x86, 0xa3, 0x9b, 0xbd, 0xd0, 0x23, 0x59, 0x00, 0xd2, 0xae, 0xf7, 0x01, 0x0a, - 0x09, 0xad, 0x72, 0x42, 0xcb, 0xea, 0x62, 0x2f, 0x42, 0xfc, 0x91, 0xa8, 0x83, 0x91, 0x8e, 0x2d, - 0xec, 0x5a, 0xa2, 0x28, 0xaa, 0x7b, 0x89, 0x92, 0xf6, 0x41, 0x85, 0xe0, 0xef, 0xce, 0x5d, 0x58, - 0xea, 0x16, 0xde, 0x01, 0xd3, 0xd6, 0xfa, 0x82, 0x85, 0x69, 0x30, 0x18, 0xbf, 0x34, 0xb2, 0x2b, - 0xdd, 0xae, 0x88, 0x23, 0xb5, 0x62, 0xbf, 0xc8, 0x76, 0x3e, 0x6d, 0xe8, 0x59, 0xf0, 0x8e, 0x54, - 0xef, 0x1c, 0x9d, 0xe6, 0x95, 0xe3, 0xd3, 0xbc, 0xf2, 0xed, 0x34, 0xaf, 0xbc, 0x3c, 0xcb, 0xa7, - 0x8e, 0xcf, 0xf2, 0xa9, 0x2f, 0x67, 0xf9, 0xd4, 0xd3, 0x05, 0xe4, 0xb2, 0xad, 0xdd, 0xba, 0xe1, - 0x10, 0xcf, 0x4c, 0x98, 0x6c, 0xb6, 0xdf, 0x84, 0xb4, 0x9e, 0xe1, 0x1f, 0xc1, 0xf5, 0x5f, 0x01, - 0x00, 0x00, 0xff, 0xff, 0x3b, 0x2d, 0x64, 0x53, 0xf7, 0x07, 0x00, 0x00, + // 980 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0xcf, 0x6f, 0xdc, 0x44, + 0x14, 0x8e, 0x93, 0x6d, 0xda, 0x9d, 0x94, 0x34, 0x75, 0x43, 0xba, 0x71, 0xb6, 0x2e, 0x38, 0x69, + 0x48, 0x43, 0x63, 0x67, 0x37, 0x14, 0x89, 0x95, 0x40, 0x62, 0x23, 0x0e, 0x1c, 0x56, 0x20, 0x03, + 0x17, 0x2e, 0x91, 0xd7, 0x3b, 0x4c, 0xac, 0xd6, 0x33, 0xd6, 0xcc, 0x64, 0xd3, 0xdc, 0x50, 0x8f, + 0x48, 0x48, 0xad, 0xb8, 0x23, 0xb8, 0x71, 0xcc, 0x81, 0x3f, 0x80, 0x13, 0xaa, 0x38, 0x55, 0x70, + 0x41, 0x1c, 0x2a, 0x94, 0x20, 0xe5, 0xce, 0x5f, 0x80, 0xe6, 0x47, 0x1c, 0xdb, 0xb1, 0xb3, 0x0b, + 0x42, 0xbd, 0x44, 0xf1, 0x7b, 0xdf, 0x9b, 0xf7, 0x7d, 0xef, 0xbd, 0x79, 0xb3, 0xa0, 0x19, 0x12, + 0x16, 0x13, 0xe6, 0xc1, 0x61, 0xec, 0x41, 0x1a, 0xb6, 0x37, 0xbd, 0x61, 0xcb, 0xe3, 0x8f, 0xdc, + 0x84, 0x12, 0x4e, 0xcc, 0x1b, 0xca, 0xeb, 0xc2, 0x61, 0xec, 0x4a, 0xaf, 0x3b, 0x6c, 0x59, 0xd7, + 0x83, 0x38, 0xc2, 0xc4, 0x93, 0x7f, 0x15, 0xce, 0xb2, 0xf5, 0x29, 0xfd, 0x80, 0x41, 0x6f, 0xd8, + 0xea, 0x43, 0x1e, 0xb4, 0xbc, 0x90, 0x44, 0x58, 0xfb, 0x5f, 0x2f, 0xcb, 0x82, 0x20, 0x86, 0x2c, + 0x62, 0x1a, 0x72, 0x53, 0x43, 0x62, 0x86, 0x84, 0x33, 0x66, 0x48, 0x3b, 0x16, 0x95, 0x63, 0x47, + 0x7e, 0x79, 0x9a, 0x90, 0x72, 0xcd, 0x23, 0x82, 0x88, 0xb2, 0x8b, 0xff, 0xb4, 0xb5, 0x89, 0x08, + 0x41, 0x0f, 0xa1, 0x17, 0x24, 0x91, 0x17, 0x60, 0x4c, 0x78, 0xc0, 0x23, 0x82, 0x75, 0x8c, 0xf3, + 0xb7, 0x01, 0xae, 0xf5, 0x18, 0xda, 0x26, 0x78, 0x08, 0x29, 0xff, 0xc0, 0xdf, 0x6e, 0x6f, 0x9a, + 0x77, 0xc1, 0x5c, 0x48, 0x30, 0xa7, 0x41, 0xc8, 0x77, 0x82, 0xc1, 0x80, 0x42, 0xc6, 0x1a, 0xc6, + 0x6b, 0xc6, 0x5a, 0xdd, 0xbf, 0x76, 0x6a, 0x7f, 0x5f, 0x99, 0xcd, 0x0e, 0x98, 0x0e, 0x62, 0xb2, + 0x87, 0x79, 0x63, 0x52, 0x00, 0xba, 0xce, 0xb3, 0x17, 0xb7, 0x27, 0xfe, 0x78, 0x71, 0xfb, 0x55, + 0x45, 0x8c, 0x0d, 0x1e, 0xb8, 0x11, 0xf1, 0xe2, 0x80, 0xef, 0xba, 0x1f, 0x62, 0xfe, 0xc3, 0xc9, + 0xe1, 0xba, 0xe1, 0xeb, 0x08, 0xf3, 0x2d, 0x70, 0x85, 0xc2, 0x10, 0x46, 0x43, 0x48, 0x1b, 0x53, + 0x32, 0xba, 0xf1, 0xeb, 0x8f, 0x1b, 0xf3, 0x5a, 0x92, 0xce, 0xf0, 0x09, 0xa7, 0x11, 0x46, 0x7e, + 0x8a, 0x34, 0x17, 0xc0, 0x34, 0x83, 0x78, 0x00, 0x69, 0xa3, 0x26, 0x29, 0xe9, 0xaf, 0xce, 0xfa, + 0xe3, 0x93, 0xc3, 0x75, 0xfd, 0xf1, 0xd5, 0xc9, 0xe1, 0xba, 0x95, 0xa9, 0x71, 0x41, 0xa0, 0xb3, + 0x08, 0x6e, 0x16, 0x4c, 0x3e, 0x64, 0x09, 0xc1, 0x0c, 0x3a, 0x3f, 0x1b, 0x60, 0xf6, 0xcc, 0xb7, + 0x4d, 0x22, 0x6c, 0x6e, 0x81, 0x9a, 0xe8, 0x9d, 0x2c, 0xc1, 0x4c, 0x7b, 0xd1, 0xd5, 0x04, 0x45, + 0x73, 0x5d, 0xdd, 0x5c, 0x57, 0x00, 0xbb, 0x35, 0x21, 0xde, 0x97, 0x60, 0xd3, 0xca, 0x88, 0x93, + 0xa5, 0xc9, 0x48, 0xd8, 0x4c, 0x25, 0x8c, 0x92, 0x7d, 0x2a, 0xae, 0x55, 0x10, 0x97, 0x1d, 0xa0, + 0x47, 0x7a, 0x84, 0xf2, 0xac, 0x9d, 0x06, 0x58, 0xc8, 0x5b, 0x52, 0x89, 0x3f, 0xa9, 0x96, 0x7f, + 0x96, 0x0c, 0x02, 0x0e, 0x3f, 0x0e, 0x68, 0x10, 0x33, 0xf3, 0x6d, 0x50, 0x0f, 0xf6, 0xf8, 0x2e, + 0xa1, 0x11, 0x3f, 0x50, 0xbd, 0xbe, 0x80, 0xd5, 0x19, 0xd4, 0x7c, 0x0f, 0x4c, 0x27, 0xf2, 0x04, + 0x29, 0x72, 0xa6, 0xbd, 0xe4, 0x96, 0x5c, 0x11, 0x57, 0x25, 0xe9, 0xd6, 0x45, 0x7d, 0xf4, 0x0c, + 0xa8, 0xa8, 0xce, 0x7d, 0x21, 0xec, 0xec, 0x3c, 0xa1, 0xcd, 0x29, 0xd7, 0x96, 0xa5, 0xab, 0x1b, + 0x98, 0x35, 0xa5, 0xea, 0xbe, 0x37, 0xc0, 0x5c, 0x8f, 0x21, 0x1f, 0xa2, 0x88, 0x71, 0x48, 0xd5, + 0x44, 0x8b, 0x8a, 0x47, 0x08, 0x43, 0x3a, 0x52, 0x9b, 0xc6, 0x99, 0xab, 0x60, 0x56, 0xa6, 0xd6, + 0xf3, 0x0f, 0x85, 0xc0, 0xa9, 0xb5, 0xba, 0x5f, 0xb0, 0x76, 0xb6, 0x54, 0x67, 0x64, 0x90, 0x60, + 0xbf, 0x5c, 0xce, 0x3e, 0x47, 0xc7, 0xb1, 0x40, 0xa3, 0x68, 0x4b, 0xf9, 0x7f, 0x6b, 0x80, 0x1b, + 0x3d, 0x86, 0x3e, 0x25, 0x08, 0x3d, 0x84, 0xaa, 0x7d, 0x2c, 0x22, 0xf8, 0x3f, 0x77, 0x68, 0x1e, + 0x5c, 0xe2, 0xe4, 0x01, 0xc4, 0x7a, 0x0a, 0xd5, 0x47, 0xe7, 0x9d, 0xf3, 0x75, 0x5f, 0x2d, 0x67, + 0x5e, 0x24, 0xe2, 0xdc, 0x02, 0x4b, 0x25, 0xe6, 0x94, 0xff, 0x53, 0x03, 0xcc, 0x0b, 0x3f, 0x0d, + 0x30, 0xfb, 0x02, 0xd2, 0x8f, 0xf6, 0x31, 0xa4, 0x6c, 0x37, 0x4a, 0xfe, 0x5f, 0x01, 0xe6, 0x12, + 0xa8, 0x63, 0xb8, 0xbf, 0x43, 0xc4, 0xf1, 0xea, 0x1a, 0xf9, 0x57, 0x30, 0xdc, 0x97, 0xe9, 0x3a, + 0xb3, 0x79, 0x75, 0x8e, 0x0d, 0x9a, 0x65, 0x94, 0x52, 0xce, 0xdf, 0x19, 0xe0, 0x72, 0x8f, 0xa1, + 0x5e, 0x84, 0xf9, 0xbf, 0x59, 0x7e, 0xf7, 0x0b, 0xcb, 0xef, 0xd6, 0x85, 0xcb, 0x2f, 0xdd, 0x7b, + 0xb3, 0x60, 0x92, 0x13, 0xcd, 0x79, 0x92, 0x93, 0xca, 0x8d, 0x36, 0x93, 0xb9, 0xf4, 0xce, 0x75, + 0x79, 0x67, 0x05, 0xc3, 0x94, 0xf5, 0x13, 0xc5, 0xba, 0xbb, 0x47, 0xf1, 0x4b, 0x60, 0xbd, 0x90, + 0x5f, 0x5a, 0x17, 0xb1, 0x14, 0x8c, 0x4e, 0x59, 0xb6, 0x7f, 0xb9, 0x0c, 0xa6, 0x7a, 0x0c, 0x99, + 0x4f, 0x0d, 0x70, 0x35, 0xf7, 0xca, 0xac, 0x94, 0xae, 0x8a, 0xc2, 0x5e, 0xb6, 0xee, 0x8d, 0x83, + 0x4a, 0x4b, 0xb2, 0xf1, 0xf8, 0xb7, 0xbf, 0xbe, 0x99, 0x7c, 0xc3, 0xbc, 0xe3, 0x95, 0xbf, 0xe3, + 0x5e, 0xa8, 0xa2, 0x76, 0xa4, 0xcd, 0xfc, 0xda, 0x00, 0x33, 0xd9, 0x4d, 0xbf, 0x3c, 0x22, 0x99, + 0x00, 0x59, 0x6f, 0x8e, 0x01, 0x4a, 0x09, 0xdd, 0x93, 0x84, 0x56, 0xcd, 0x95, 0x51, 0x84, 0xe4, + 0xa3, 0xd1, 0x07, 0x57, 0x73, 0x5b, 0xb9, 0xb2, 0x44, 0x59, 0x54, 0x75, 0x89, 0xca, 0xf6, 0xa3, + 0x09, 0xc1, 0x2b, 0xf9, 0xdd, 0x78, 0xa7, 0x2a, 0x3c, 0x07, 0xb3, 0x36, 0xc6, 0x82, 0xa5, 0x69, + 0x30, 0x98, 0x3b, 0xb7, 0xc2, 0xd6, 0xaa, 0x8e, 0x28, 0x22, 0xad, 0xcd, 0x71, 0x91, 0x69, 0xbe, + 0x03, 0xb0, 0x78, 0x7a, 0xbf, 0xb7, 0xf5, 0xc0, 0x9f, 0xad, 0x9e, 0xbb, 0x95, 0xc7, 0x15, 0x57, + 0x82, 0xd5, 0x1a, 0x1b, 0x9a, 0xa6, 0x4e, 0x40, 0x4d, 0x6e, 0x8e, 0x66, 0x55, 0xa8, 0xf0, 0x5a, + 0x2b, 0x17, 0x79, 0xd3, 0x79, 0x59, 0x91, 0xf3, 0x62, 0x3b, 0xcd, 0xaa, 0x79, 0x89, 0x45, 0xa6, + 0x04, 0xd4, 0xe4, 0xad, 0xaf, 0xcc, 0x28, 0xbc, 0xd5, 0x19, 0xb3, 0xf7, 0x73, 0x74, 0xc6, 0xbe, + 0x38, 0xeb, 0xd2, 0x97, 0xe2, 0xd9, 0xee, 0xbe, 0xfb, 0xec, 0xc8, 0x36, 0x9e, 0x1f, 0xd9, 0xc6, + 0x9f, 0x47, 0xb6, 0xf1, 0xe4, 0xd8, 0x9e, 0x78, 0x7e, 0x6c, 0x4f, 0xfc, 0x7e, 0x6c, 0x4f, 0x7c, + 0xbe, 0x8c, 0x22, 0xbe, 0xbb, 0xd7, 0x77, 0x43, 0x12, 0x7b, 0x25, 0x0f, 0x09, 0x3f, 0x48, 0x20, + 0xeb, 0x4f, 0xcb, 0xdf, 0x9c, 0x5b, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x74, 0x49, 0xf4, 0x0d, + 0x66, 0x0b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -626,6 +943,13 @@ type MsgClient interface { // token pair conversion. The authority is hard-coded to the Cosmos SDK x/gov // module account ToggleConversion(ctx context.Context, in *MsgToggleConversion, opts ...grpc.CallOption) (*MsgToggleConversionResponse, error) + // TransferContractOwnership defines a Msg to transfer the ownership of the + // ERC20 token pair to the new owner + TransferContractOwnership(ctx context.Context, in *MsgTransferOwnership, opts ...grpc.CallOption) (*MsgTransferOwnershipResponse, error) + // Mint mints ERC20 tokens + Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) + // Burn burns ERC20 tokens + Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) } type msgClient struct { @@ -681,6 +1005,33 @@ func (c *msgClient) ToggleConversion(ctx context.Context, in *MsgToggleConversio return out, nil } +func (c *msgClient) TransferContractOwnership(ctx context.Context, in *MsgTransferOwnership, opts ...grpc.CallOption) (*MsgTransferOwnershipResponse, error) { + out := new(MsgTransferOwnershipResponse) + err := c.cc.Invoke(ctx, "/cosmos.evm.erc20.v1.Msg/TransferContractOwnership", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) { + out := new(MsgMintResponse) + err := c.cc.Invoke(ctx, "/cosmos.evm.erc20.v1.Msg/Mint", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) { + out := new(MsgBurnResponse) + err := c.cc.Invoke(ctx, "/cosmos.evm.erc20.v1.Msg/Burn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { // ConvertERC20 mints a native Cosmos coin representation of the ERC20 token @@ -701,6 +1052,13 @@ type MsgServer interface { // token pair conversion. The authority is hard-coded to the Cosmos SDK x/gov // module account ToggleConversion(context.Context, *MsgToggleConversion) (*MsgToggleConversionResponse, error) + // TransferContractOwnership defines a Msg to transfer the ownership of the + // ERC20 token pair to the new owner + TransferContractOwnership(context.Context, *MsgTransferOwnership) (*MsgTransferOwnershipResponse, error) + // Mint mints ERC20 tokens + Mint(context.Context, *MsgMint) (*MsgMintResponse, error) + // Burn burns ERC20 tokens + Burn(context.Context, *MsgBurn) (*MsgBurnResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -722,6 +1080,15 @@ func (*UnimplementedMsgServer) RegisterERC20(ctx context.Context, req *MsgRegist func (*UnimplementedMsgServer) ToggleConversion(ctx context.Context, req *MsgToggleConversion) (*MsgToggleConversionResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ToggleConversion not implemented") } +func (*UnimplementedMsgServer) TransferContractOwnership(ctx context.Context, req *MsgTransferOwnership) (*MsgTransferOwnershipResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TransferContractOwnership not implemented") +} +func (*UnimplementedMsgServer) Mint(ctx context.Context, req *MsgMint) (*MsgMintResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Mint not implemented") +} +func (*UnimplementedMsgServer) Burn(ctx context.Context, req *MsgBurn) (*MsgBurnResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Burn not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -817,6 +1184,60 @@ func _Msg_ToggleConversion_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _Msg_TransferContractOwnership_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgTransferOwnership) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).TransferContractOwnership(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.evm.erc20.v1.Msg/TransferContractOwnership", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).TransferContractOwnership(ctx, req.(*MsgTransferOwnership)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Mint_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgMint) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Mint(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.evm.erc20.v1.Msg/Mint", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Mint(ctx, req.(*MsgMint)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Burn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgBurn) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Burn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.evm.erc20.v1.Msg/Burn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Burn(ctx, req.(*MsgBurn)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "cosmos.evm.erc20.v1.Msg", HandlerType: (*MsgServer)(nil), @@ -841,6 +1262,18 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "ToggleConversion", Handler: _Msg_ToggleConversion_Handler, }, + { + MethodName: "TransferContractOwnership", + Handler: _Msg_TransferContractOwnership_Handler, + }, + { + MethodName: "Mint", + Handler: _Msg_Mint_Handler, + }, + { + MethodName: "Burn", + Handler: _Msg_Burn_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "cosmos/evm/erc20/v1/tx.proto", @@ -1178,10 +1611,224 @@ func (m *MsgToggleConversionResponse) MarshalToSizedBuffer(dAtA []byte) (int, er return len(dAtA) - i, nil } -func encodeVarintTx(dAtA []byte, offset int, v uint64) int { - offset -= sovTx(v) - base := offset - for v >= 1<<7 { +func (m *MsgTransferOwnership) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgTransferOwnership) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTransferOwnership) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.NewOwner) > 0 { + i -= len(m.NewOwner) + copy(dAtA[i:], m.NewOwner) + i = encodeVarintTx(dAtA, i, uint64(len(m.NewOwner))) + i-- + dAtA[i] = 0x1a + } + if len(m.Token) > 0 { + i -= len(m.Token) + copy(dAtA[i:], m.Token) + i = encodeVarintTx(dAtA, i, uint64(len(m.Token))) + i-- + dAtA[i] = 0x12 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgTransferOwnershipResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgTransferOwnershipResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTransferOwnershipResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgMint) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMint) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMint) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0x22 + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x1a + } + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMintResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgMintResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMintResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgBurn) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgBurn) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgBurn) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0x1a + } + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgBurnResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgBurnResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgBurnResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ @@ -1327,48 +1974,138 @@ func (m *MsgToggleConversionResponse) Size() (n int) { return n } -func sovTx(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 +func (m *MsgTransferOwnership) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Token) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.NewOwner) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n } -func sozTx(x uint64) (n int) { - return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + +func (m *MsgTransferOwnershipResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n } -func (m *MsgConvertERC20) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgConvertERC20: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgConvertERC20: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { + +func (m *MsgMint) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgMintResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgBurn) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgBurnResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgConvertERC20) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConvertERC20: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConvertERC20: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { return ErrIntOverflowTx } if iNdEx >= l { @@ -1430,7 +2167,533 @@ func (m *MsgConvertERC20) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConvertERC20Response) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConvertERC20Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConvertERC20Response: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConvertCoin) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConvertCoin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConvertCoin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Coin", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Coin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConvertCoinResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConvertCoinResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConvertCoinResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRegisterERC20) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRegisterERC20: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterERC20: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1458,11 +2721,11 @@ func (m *MsgConvertERC20) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Receiver = string(dAtA[iNdEx:postIndex]) + m.Signer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Erc20Addresses", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1490,7 +2753,7 @@ func (m *MsgConvertERC20) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Sender = string(dAtA[iNdEx:postIndex]) + m.Erc20Addresses = append(m.Erc20Addresses, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex default: iNdEx = preIndex @@ -1513,7 +2776,7 @@ func (m *MsgConvertERC20) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgConvertERC20Response) Unmarshal(dAtA []byte) error { +func (m *MsgRegisterERC20Response) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1536,10 +2799,10 @@ func (m *MsgConvertERC20Response) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgConvertERC20Response: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRegisterERC20Response: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgConvertERC20Response: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRegisterERC20Response: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -1563,7 +2826,7 @@ func (m *MsgConvertERC20Response) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgConvertCoin) Unmarshal(dAtA []byte) error { +func (m *MsgToggleConversion) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1586,48 +2849,15 @@ func (m *MsgConvertCoin) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgConvertCoin: wiretype end group for non-group") + return fmt.Errorf("proto: MsgToggleConversion: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgConvertCoin: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgToggleConversion: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Coin", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Coin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1655,11 +2885,11 @@ func (m *MsgConvertCoin) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Receiver = string(dAtA[iNdEx:postIndex]) + m.Authority = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1687,7 +2917,7 @@ func (m *MsgConvertCoin) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Sender = string(dAtA[iNdEx:postIndex]) + m.Token = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1710,7 +2940,7 @@ func (m *MsgConvertCoin) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgConvertCoinResponse) Unmarshal(dAtA []byte) error { +func (m *MsgToggleConversionResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1733,10 +2963,10 @@ func (m *MsgConvertCoinResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgConvertCoinResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgToggleConversionResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgConvertCoinResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgToggleConversionResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -1760,7 +2990,7 @@ func (m *MsgConvertCoinResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { +func (m *MsgTransferOwnership) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1783,10 +3013,10 @@ func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") + return fmt.Errorf("proto: MsgTransferOwnership: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgTransferOwnership: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1823,9 +3053,9 @@ func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -1835,24 +3065,55 @@ func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.Token = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewOwner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewOwner = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1875,7 +3136,7 @@ func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { +func (m *MsgTransferOwnershipResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1898,10 +3159,10 @@ func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateParamsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgTransferOwnershipResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgTransferOwnershipResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -1925,7 +3186,7 @@ func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRegisterERC20) Unmarshal(dAtA []byte) error { +func (m *MsgMint) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1948,15 +3209,15 @@ func (m *MsgRegisterERC20) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterERC20: wiretype end group for non-group") + return fmt.Errorf("proto: MsgMint: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterERC20: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgMint: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Signer", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1984,11 +3245,11 @@ func (m *MsgRegisterERC20) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Signer = string(dAtA[iNdEx:postIndex]) + m.ContractAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Erc20Addresses", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2016,7 +3277,73 @@ func (m *MsgRegisterERC20) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Erc20Addresses = append(m.Erc20Addresses, string(dAtA[iNdEx:postIndex])) + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -2039,7 +3366,7 @@ func (m *MsgRegisterERC20) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRegisterERC20Response) Unmarshal(dAtA []byte) error { +func (m *MsgMintResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2062,10 +3389,10 @@ func (m *MsgRegisterERC20Response) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterERC20Response: wiretype end group for non-group") + return fmt.Errorf("proto: MsgMintResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterERC20Response: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgMintResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -2089,7 +3416,7 @@ func (m *MsgRegisterERC20Response) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgToggleConversion) Unmarshal(dAtA []byte) error { +func (m *MsgBurn) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2112,15 +3439,15 @@ func (m *MsgToggleConversion) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgToggleConversion: wiretype end group for non-group") + return fmt.Errorf("proto: MsgBurn: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgToggleConversion: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgBurn: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2148,11 +3475,11 @@ func (m *MsgToggleConversion) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Authority = string(dAtA[iNdEx:postIndex]) + m.ContractAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -2180,7 +3507,41 @@ func (m *MsgToggleConversion) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Token = string(dAtA[iNdEx:postIndex]) + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -2203,7 +3564,7 @@ func (m *MsgToggleConversion) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgToggleConversionResponse) Unmarshal(dAtA []byte) error { +func (m *MsgBurnResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -2226,10 +3587,10 @@ func (m *MsgToggleConversionResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgToggleConversionResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgBurnResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgToggleConversionResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgBurnResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: diff --git a/x/erc20/types/tx.pb.gw.go b/x/erc20/types/tx.pb.gw.go index ea477d402..c7f36fdbc 100644 --- a/x/erc20/types/tx.pb.gw.go +++ b/x/erc20/types/tx.pb.gw.go @@ -105,6 +105,78 @@ func local_request_Msg_ConvertCoin_0(ctx context.Context, marshaler runtime.Mars } +var ( + filter_Msg_Mint_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_Mint_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgMint + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_Mint_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Mint(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_Mint_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgMint + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_Mint_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Mint(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Msg_Burn_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_Burn_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgBurn + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_Burn_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Burn(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_Burn_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgBurn + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_Burn_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Burn(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterMsgHandlerServer registers the http handlers for service Msg to "mux". // UnaryRPC :call MsgServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -157,6 +229,52 @@ func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server }) + mux.Handle("POST", pattern_Msg_Mint_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Msg_Mint_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_Mint_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_Msg_Burn_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Msg_Burn_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_Burn_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -238,6 +356,46 @@ func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client }) + mux.Handle("POST", pattern_Msg_Mint_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Msg_Mint_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_Mint_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_Msg_Burn_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Msg_Burn_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_Burn_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -245,10 +403,18 @@ var ( pattern_Msg_ConvertERC20_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "evm", "erc20", "v1", "tx", "convert_erc20"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Msg_ConvertCoin_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "evm", "erc20", "v1", "tx", "convert_coin"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Msg_Mint_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "evm", "erc20", "v1", "tx", "mint"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Msg_Burn_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "evm", "erc20", "v1", "tx", "burn"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( forward_Msg_ConvertERC20_0 = runtime.ForwardResponseMessage forward_Msg_ConvertCoin_0 = runtime.ForwardResponseMessage + + forward_Msg_Mint_0 = runtime.ForwardResponseMessage + + forward_Msg_Burn_0 = runtime.ForwardResponseMessage ) diff --git a/x/feemarket/module.go b/x/feemarket/module.go index 67557898d..9e78672cc 100644 --- a/x/feemarket/module.go +++ b/x/feemarket/module.go @@ -29,7 +29,7 @@ import ( const consensusVersion = 1 var ( - _ module.AppModule = AppModule{} + _ module.AppModule = AppModule{} //nolint:staticcheck // check against deprecated type _ module.AppModuleBasic = AppModuleBasic{} _ appmodule.HasEndBlocker = AppModule{} diff --git a/x/feemarket/types/msg.go b/x/feemarket/types/msg.go index 31b23e593..19a0cdd32 100644 --- a/x/feemarket/types/msg.go +++ b/x/feemarket/types/msg.go @@ -16,8 +16,3 @@ func (m *MsgUpdateParams) ValidateBasic() error { return m.Params.Validate() } - -// GetSignBytes implements the LegacyMsg interface. -func (m MsgUpdateParams) GetSignBytes() []byte { - return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&m)) -} diff --git a/x/ibc/callbacks/keeper/keeper.go b/x/ibc/callbacks/keeper/keeper.go index d12603e26..eee3e5d3c 100644 --- a/x/ibc/callbacks/keeper/keeper.go +++ b/x/ibc/callbacks/keeper/keeper.go @@ -12,6 +12,7 @@ import ( erc20types "github.com/cosmos/evm/x/erc20/types" "github.com/cosmos/evm/x/ibc/callbacks/types" evmante "github.com/cosmos/evm/x/vm/ante" + "github.com/cosmos/evm/x/vm/statedb" evmtypes "github.com/cosmos/evm/x/vm/types" callbacktypes "github.com/cosmos/ibc-go/v10/modules/apps/callbacks/types" transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" @@ -129,6 +130,7 @@ func (k ContractKeeper) IBCReceivePacketCallback( cachedCtx, writeFn := ctx.CacheContext() cachedCtx = evmante.BuildEvmExecutionCtx(cachedCtx). WithGasMeter(evmtypes.NewInfiniteGasMeterWithLimit(cbData.CommitGasLimit)) + stateDB := statedb.New(cachedCtx, k.evmKeeper, statedb.NewEmptyTxConfig()) // receiver := sdk.MustAccAddressFromBech32(data.Receiver) receiver, err := sdk.AccAddressFromBech32(data.Receiver) @@ -189,7 +191,7 @@ func (k ContractKeeper) IBCReceivePacketCallback( // Call the EVM with the remaining gas as the maximum gas limit. // Up to now, the remaining gas is equal to the callback gas limit set by the user. // NOTE: use the cached ctx for the EVM calls. - res, err := k.evmKeeper.CallEVM(cachedCtx, erc20.ABI, receiverHex, tokenPair.GetERC20Contract(), true, remainingGas, "approve", contractAddr, amountInt.BigInt()) + res, err := k.evmKeeper.CallEVM(cachedCtx, stateDB, erc20.ABI, receiverHex, tokenPair.GetERC20Contract(), true, false, remainingGas, "approve", contractAddr, amountInt.BigInt()) if err != nil { return errorsmod.Wrapf(types.ErrAllowanceFailed, "failed to set allowance: %v", err) } @@ -212,7 +214,7 @@ func (k ContractKeeper) IBCReceivePacketCallback( } // NOTE: use the cached ctx for the EVM calls. - res, err = k.evmKeeper.CallEVMWithData(cachedCtx, receiverHex, &contractAddr, cbData.Calldata, true, remainingGas) + res, err = k.evmKeeper.CallEVMWithData(cachedCtx, stateDB, receiverHex, &contractAddr, cbData.Calldata, true, false, remainingGas) if err != nil { return errorsmod.Wrapf(types.ErrEVMCallFailed, "EVM returned error: %s", err.Error()) } @@ -297,6 +299,7 @@ func (k ContractKeeper) IBCOnAcknowledgementPacketCallback( cachedCtx, writeFn := ctx.CacheContext() cachedCtx = evmante.BuildEvmExecutionCtx(cachedCtx). WithGasMeter(evmtypes.NewInfiniteGasMeterWithLimit(cbData.CommitGasLimit)) + stateDB := statedb.New(cachedCtx, k.evmKeeper, statedb.NewEmptyTxConfig()) if len(cbData.Calldata) != 0 { return errorsmod.Wrap(types.ErrInvalidCalldata, "acknowledgement callback data should not contain calldata") @@ -323,7 +326,7 @@ func (k ContractKeeper) IBCOnAcknowledgementPacketCallback( // Call the onPacketAcknowledgement function in the contract // NOTE: use the cached ctx for the EVM calls. - res, err := k.evmKeeper.CallEVM(cachedCtx, *abi, sender, contractAddr, true, math.NewIntFromUint64(cachedCtx.GasMeter().GasRemaining()).BigInt(), "onPacketAcknowledgement", + res, err := k.evmKeeper.CallEVM(cachedCtx, stateDB, *abi, sender, contractAddr, true, false, math.NewIntFromUint64(cachedCtx.GasMeter().GasRemaining()).BigInt(), "onPacketAcknowledgement", packet.GetSourceChannel(), packet.GetSourcePort(), packet.GetSequence(), packet.GetData(), acknowledgement) if err != nil { return errorsmod.Wrapf(types.ErrCallbackFailed, "EVM returned error: %s", err.Error()) @@ -397,6 +400,7 @@ func (k ContractKeeper) IBCOnTimeoutPacketCallback( cachedCtx, writeFn := ctx.CacheContext() cachedCtx = evmante.BuildEvmExecutionCtx(cachedCtx). WithGasMeter(evmtypes.NewInfiniteGasMeterWithLimit(cbData.CommitGasLimit)) + stateDB := statedb.New(cachedCtx, k.evmKeeper, statedb.NewEmptyTxConfig()) if len(cbData.Calldata) != 0 { return errorsmod.Wrap(types.ErrInvalidCalldata, "timeout callback data should not contain calldata") @@ -421,7 +425,7 @@ func (k ContractKeeper) IBCOnTimeoutPacketCallback( return err } - res, err := k.evmKeeper.CallEVM(ctx, *abi, sender, contractAddr, true, math.NewIntFromUint64(cachedCtx.GasMeter().GasRemaining()).BigInt(), "onPacketTimeout", + res, err := k.evmKeeper.CallEVM(ctx, stateDB, *abi, sender, contractAddr, true, false, math.NewIntFromUint64(cachedCtx.GasMeter().GasRemaining()).BigInt(), "onPacketTimeout", packet.GetSourceChannel(), packet.GetSourcePort(), packet.GetSequence(), packet.GetData()) if err != nil { return errorsmod.Wrapf(types.ErrCallbackFailed, "EVM returned error: %s", err.Error()) diff --git a/x/ibc/callbacks/types/expected_keepers.go b/x/ibc/callbacks/types/expected_keepers.go index bafdf9c3b..546a1c7ea 100644 --- a/x/ibc/callbacks/types/expected_keepers.go +++ b/x/ibc/callbacks/types/expected_keepers.go @@ -11,6 +11,8 @@ import ( "github.com/cosmos/evm/x/vm/statedb" evmtypes "github.com/cosmos/evm/x/vm/types" + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -22,11 +24,22 @@ type AccountKeeper interface { // EVMKeeper defines the expected EVM keeper interface used on erc20 type EVMKeeper interface { - CallEVM(ctx sdk.Context, abi abi.ABI, from, contract common.Address, commit bool, gasCap *big.Int, method string, args ...interface{}) (*evmtypes.MsgEthereumTxResponse, error) - CallEVMWithData(ctx sdk.Context, from common.Address, contract *common.Address, data []byte, commit bool, gasCap *big.Int) (*evmtypes.MsgEthereumTxResponse, error) + CallEVM(ctx sdk.Context, stateDB *statedb.StateDB, abi abi.ABI, from, contract common.Address, commit bool, callFromPrecompile bool, gasCap *big.Int, method string, args ...interface{}) (*evmtypes.MsgEthereumTxResponse, error) + CallEVMWithData(ctx sdk.Context, stateDB *statedb.StateDB, from common.Address, contract *common.Address, data []byte, commit bool, callFromPrecompile bool, gasCap *big.Int) (*evmtypes.MsgEthereumTxResponse, error) GetAccountOrEmpty(ctx sdk.Context, addr common.Address) statedb.Account GetAccount(ctx sdk.Context, addr common.Address) *statedb.Account IsContract(ctx sdk.Context, addr common.Address) bool + GetState(ctx sdk.Context, addr common.Address, key common.Hash) common.Hash + GetCode(ctx sdk.Context, codeHash common.Hash) []byte + GetCodeHash(ctx sdk.Context, addr common.Address) common.Hash + ForEachStorage(ctx sdk.Context, addr common.Address, cb func(key common.Hash, value common.Hash) bool) + SetAccount(ctx sdk.Context, addr common.Address, account statedb.Account) error + DeleteState(ctx sdk.Context, addr common.Address, key common.Hash) + SetState(ctx sdk.Context, addr common.Address, key common.Hash, value []byte) + DeleteCode(ctx sdk.Context, codeHash []byte) + SetCode(ctx sdk.Context, codeHash []byte, code []byte) + DeleteAccount(ctx sdk.Context, addr common.Address) error + KVStoreKeys() map[string]*storetypes.KVStoreKey } type ERC20Keeper interface { diff --git a/x/ibc/transfer/ibc_module.go b/x/ibc/transfer/ibc_module.go deleted file mode 100644 index 1d5a4a6c6..000000000 --- a/x/ibc/transfer/ibc_module.go +++ /dev/null @@ -1,22 +0,0 @@ -package transfer - -import ( - "github.com/cosmos/evm/x/ibc/transfer/keeper" - ibctransfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" - porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" -) - -var _ porttypes.IBCModule = IBCModule{} - -// IBCModule implements the ICS26 interface for transfer given the transfer keeper. -type IBCModule struct { - *ibctransfer.IBCModule -} - -// NewIBCModule creates a new IBCModule given the keeper -func NewIBCModule(k keeper.Keeper) IBCModule { - transferModule := ibctransfer.NewIBCModule(*k.Keeper) - return IBCModule{ - IBCModule: &transferModule, - } -} diff --git a/x/ibc/transfer/keeper/keeper.go b/x/ibc/transfer/keeper/keeper.go deleted file mode 100644 index 48b150803..000000000 --- a/x/ibc/transfer/keeper/keeper.go +++ /dev/null @@ -1,50 +0,0 @@ -package keeper - -import ( - "github.com/cosmos/evm/x/ibc/transfer/types" - "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" - transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" - porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" - - corestore "cosmossdk.io/core/store" - - "github.com/cosmos/cosmos-sdk/codec" -) - -// Keeper defines the modified IBC transfer keeper that embeds the original one. -// It also contains the bank keeper and the erc20 keeper to support ERC20 tokens -// to be sent via IBC. -type Keeper struct { - *keeper.Keeper - bankKeeper types.BankKeeper - erc20Keeper types.ERC20Keeper - accountKeeper types.AccountKeeper -} - -// NewKeeper creates a new IBC transfer Keeper instance -func NewKeeper( - cdc codec.BinaryCodec, - storeService corestore.KVStoreService, - - ics4Wrapper porttypes.ICS4Wrapper, - channelKeeper transfertypes.ChannelKeeper, - msgRouter transfertypes.MessageRouter, - authKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, - erc20Keeper types.ERC20Keeper, - authority string, -) Keeper { - // create the original IBC transfer keeper for embedding - transferKeeper := keeper.NewKeeper( - cdc, storeService, nil, - ics4Wrapper, channelKeeper, msgRouter, - authKeeper, bankKeeper, authority, - ) - - return Keeper{ - Keeper: &transferKeeper, - bankKeeper: bankKeeper, - erc20Keeper: erc20Keeper, - accountKeeper: authKeeper, - } -} diff --git a/x/ibc/transfer/keeper/msg_server.go b/x/ibc/transfer/keeper/msg_server.go deleted file mode 100644 index 337158397..000000000 --- a/x/ibc/transfer/keeper/msg_server.go +++ /dev/null @@ -1,117 +0,0 @@ -package keeper - -import ( - "context" - "strings" - - "github.com/ethereum/go-ethereum/common" - "github.com/hashicorp/go-metrics" - - erc20types "github.com/cosmos/evm/x/erc20/types" - "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" - - storetypes "cosmossdk.io/store/types" - - "github.com/cosmos/cosmos-sdk/telemetry" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var _ types.MsgServer = Keeper{} - -// Transfer defines a gRPC msg server method for the MsgTransfer message. -// This implementation overrides the default ICS20 transfer by converting -// the ERC20 tokens to their Cosmos representation if the token pair has been -// registered through governance. -// If user doesn't have enough balance of coin, it will attempt to convert -// ERC20 tokens to the coin denomination, and continue with a regular transfer. -func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - // Temporarily save the KV and transient KV gas config. To avoid extra costs for relayers - // these two gas config are replaced with empty one and should be restored before exiting this function. - kvGasCfg := ctx.KVGasConfig() - transientKVGasCfg := ctx.TransientKVGasConfig() - ctx = ctx. - WithKVGasConfig(storetypes.GasConfig{}). - WithTransientKVGasConfig(storetypes.GasConfig{}) - - defer func() { - // Return the KV gas config to initial values - ctx = ctx. - WithKVGasConfig(kvGasCfg). - WithTransientKVGasConfig(transientKVGasCfg) - }() - - // use native denom or contract address - denom := strings.TrimPrefix(msg.Token.Denom, erc20types.Erc20NativeCoinDenomPrefix) - - pairID := k.erc20Keeper.GetTokenPairID(ctx, denom) - if len(pairID) == 0 { - // no-op: token is not registered so we can proceed with regular transfer - return k.Keeper.Transfer(ctx, msg) - } - - pair, _ := k.erc20Keeper.GetTokenPair(ctx, pairID) - if !pair.Enabled { - // no-op: pair is not enabled so we can proceed with regular transfer - return k.Keeper.Transfer(ctx, msg) - } - - sender := sdk.MustAccAddressFromBech32(msg.Sender) - - if !k.erc20Keeper.IsERC20Enabled(ctx) { - // no-op: continue with regular transfer - return k.Keeper.Transfer(ctx, msg) - } - - // update the msg denom to the token pair denom - msg.Token.Denom = pair.Denom - - if !pair.IsNativeERC20() { - return k.Keeper.Transfer(ctx, msg) - } - // if the user has enough balance of the Cosmos representation, then we don't need to Convert - balance := k.bankKeeper.SpendableCoin(ctx, sender, pair.Denom) - if balance.Amount.GTE(msg.Token.Amount) { - - defer func() { - telemetry.IncrCounterWithLabels( - []string{"erc20", "ibc", "transfer", "total"}, - 1, - []metrics.Label{ - telemetry.NewLabel("denom", pair.Denom), - }, - ) - }() - - return k.Keeper.Transfer(ctx, msg) - } - - // Only convert if the pair is a native ERC20 - // only convert the remaining difference - difference := msg.Token.Amount.Sub(balance.Amount) - - msgConvertERC20 := erc20types.NewMsgConvertERC20( - difference, - sender, - pair.GetERC20Contract(), - common.BytesToAddress(sender.Bytes()), - ) - - // Use MsgConvertERC20 to convert the ERC20 to a Cosmos IBC Coin - if _, err := k.erc20Keeper.ConvertERC20(ctx, msgConvertERC20); err != nil { - return nil, err - } - - defer func() { - telemetry.IncrCounterWithLabels( - []string{"erc20", "ibc", "transfer", "total"}, - 1, - []metrics.Label{ - telemetry.NewLabel("denom", pair.Denom), - }, - ) - }() - - return k.Keeper.Transfer(ctx, msg) -} diff --git a/x/ibc/transfer/module.go b/x/ibc/transfer/module.go deleted file mode 100644 index bda640f07..000000000 --- a/x/ibc/transfer/module.go +++ /dev/null @@ -1,62 +0,0 @@ -package transfer - -import ( - "fmt" - - "github.com/cosmos/evm/x/ibc/transfer/keeper" - ibctransfer "github.com/cosmos/ibc-go/v10/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" - "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" - - "github.com/cosmos/cosmos-sdk/types/module" -) - -var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} -) - -// AppModuleBasic embeds the IBC Transfer AppModuleBasic -type AppModuleBasic struct { - *ibctransfer.AppModuleBasic -} - -// AppModule represents the AppModule for this module -type AppModule struct { - *ibctransfer.AppModule - keeper keeper.Keeper -} - -// NewAppModule creates a new 20-transfer module -func NewAppModule(k keeper.Keeper) AppModule { - am := ibctransfer.NewAppModule(*k.Keeper) - return AppModule{ - AppModule: &am, - keeper: k, - } -} - -// RegisterServices registers module services. -func (am AppModule) RegisterServices(cfg module.Configurator) { - // Override Transfer Msg Server - types.RegisterMsgServer(cfg.MsgServer(), am.keeper) - types.RegisterQueryServer(cfg.QueryServer(), am.keeper) - - m := ibctransferkeeper.NewMigrator(*am.keeper.Keeper) - - if err := cfg.RegisterMigration(types.ModuleName, 2, m.MigrateTotalEscrowForDenom); err != nil { - panic(fmt.Sprintf("failed to migrate transfer app from version 2 to 3: %v", err)) - } - - if err := cfg.RegisterMigration(types.ModuleName, 3, m.MigrateParams); err != nil { - panic(fmt.Errorf("failed to migrate transfer app version 3 to 4 (self-managed params migration): %v", err)) - } - - if err := cfg.RegisterMigration(types.ModuleName, 4, m.MigrateDenomMetadata); err != nil { - panic(fmt.Errorf("failed to migrate transfer app from version 4 to 5 (set denom metadata migration): %v", err)) - } - - if err := cfg.RegisterMigration(types.ModuleName, 5, m.MigrateDenomTraceToDenom); err != nil { - panic(fmt.Errorf("failed to migrate transfer app from version 5 to 6 (migrate DenomTrace to Denom): %v", err)) - } -} diff --git a/x/ibc/transfer/types/channels.go b/x/ibc/transfer/types/channels.go deleted file mode 100644 index 1316b848f..000000000 --- a/x/ibc/transfer/types/channels.go +++ /dev/null @@ -1,13 +0,0 @@ -package types - -// Osmosis channels -const ( - OsmosisTestnetChannelID = "channel-215" - OsmosisMainnetChannelID = "channel-0" -) - -// Stride channels -const ( - StrideTestnetChannelID = "channel-25" - StrideMainnetChannelID = "channel-25" -) diff --git a/x/ibc/transfer/types/interfaces.go b/x/ibc/transfer/types/interfaces.go deleted file mode 100644 index fa5d349f6..000000000 --- a/x/ibc/transfer/types/interfaces.go +++ /dev/null @@ -1,31 +0,0 @@ -package types - -import ( - "context" - - erc20types "github.com/cosmos/evm/x/erc20/types" - transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// AccountKeeper defines the expected interface needed to retrieve account info. -type AccountKeeper interface { - transfertypes.AccountKeeper - GetAccount(context.Context, sdk.AccAddress) sdk.AccountI -} - -// BankKeeper defines the expected interface needed to check balances and send coins. -type BankKeeper interface { - transfertypes.BankKeeper - GetBalance(ctx context.Context, addr sdk.AccAddress, denom string) sdk.Coin -} - -// ERC20Keeper defines the expected ERC20 keeper interface for supporting -// ERC20 token transfers via IBC. -type ERC20Keeper interface { - IsERC20Enabled(ctx sdk.Context) bool - GetTokenPairID(ctx sdk.Context, token string) []byte - GetTokenPair(ctx sdk.Context, id []byte) (erc20types.TokenPair, bool) - ConvertERC20(ctx context.Context, msg *erc20types.MsgConvertERC20) (*erc20types.MsgConvertERC20Response, error) -} diff --git a/x/ibc/transfer/v2/ibc_module.go b/x/ibc/transfer/v2/ibc_module.go deleted file mode 100644 index 06996dd90..000000000 --- a/x/ibc/transfer/v2/ibc_module.go +++ /dev/null @@ -1,22 +0,0 @@ -package v2 - -import ( - "github.com/cosmos/evm/x/ibc/transfer/keeper" - v2 "github.com/cosmos/ibc-go/v10/modules/apps/transfer/v2" - ibcapi "github.com/cosmos/ibc-go/v10/modules/core/api" -) - -var _ ibcapi.IBCModule = IBCModule{} - -// IBCModule implements the ICS26 interface for transfer given the transfer keeper. -type IBCModule struct { - *v2.IBCModule -} - -// NewIBCModule creates a new IBCModule given the keeper -func NewIBCModule(k keeper.Keeper) IBCModule { - transferModule := v2.NewIBCModule(*k.Keeper) - return IBCModule{ - IBCModule: transferModule, - } -} diff --git a/x/precisebank/module.go b/x/precisebank/module.go index 5da71ceb7..50da3777f 100644 --- a/x/precisebank/module.go +++ b/x/precisebank/module.go @@ -26,7 +26,7 @@ import ( const ConsensusVersion = 1 var ( - _ module.AppModule = AppModule{} + _ module.AppModule = AppModule{} //nolint:staticcheck // check against deprecated type _ module.AppModuleBasic = AppModuleBasic{} _ module.HasABCIGenesis = AppModule{} diff --git a/x/vm/keeper/call_evm.go b/x/vm/keeper/call_evm.go index 3f5b36c7a..2abe5bb7d 100644 --- a/x/vm/keeper/call_evm.go +++ b/x/vm/keeper/call_evm.go @@ -9,6 +9,7 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/cosmos/evm/server/config" + "github.com/cosmos/evm/x/vm/statedb" "github.com/cosmos/evm/x/vm/types" errorsmod "cosmossdk.io/errors" @@ -17,15 +18,9 @@ import ( ) // CallEVM performs a smart contract method call using given args. -func (k Keeper) CallEVM( - ctx sdk.Context, - abi abi.ABI, - from, contract common.Address, - commit bool, - gasCap *big.Int, - method string, - args ...interface{}, -) (*types.MsgEthereumTxResponse, error) { +// Note: if you call this from a precompile context, ensure that +// you use the existing stateDB. +func (k Keeper) CallEVM(ctx sdk.Context, stateDB *statedb.StateDB, abi abi.ABI, from, contract common.Address, commit, callFromPrecompile bool, gasCap *big.Int, method string, args ...interface{}) (*types.MsgEthereumTxResponse, error) { data, err := abi.Pack(method, args...) if err != nil { return nil, errorsmod.Wrap( @@ -34,7 +29,7 @@ func (k Keeper) CallEVM( ) } - resp, err := k.CallEVMWithData(ctx, from, &contract, data, commit, gasCap) + resp, err := k.CallEVMWithData(ctx, stateDB, from, &contract, data, commit, callFromPrecompile, gasCap) if err != nil { return resp, errorsmod.Wrapf(err, "contract call failed: method '%s', contract '%s'", method, contract) } @@ -42,14 +37,9 @@ func (k Keeper) CallEVM( } // CallEVMWithData performs a smart contract method call using contract data. -func (k Keeper) CallEVMWithData( - ctx sdk.Context, - from common.Address, - contract *common.Address, - data []byte, - commit bool, - gasCap *big.Int, -) (*types.MsgEthereumTxResponse, error) { +// Note: if you call this from a precompile context, ensure that +// you use the existing stateDB. +func (k Keeper) CallEVMWithData(ctx sdk.Context, stateDB *statedb.StateDB, from common.Address, contract *common.Address, data []byte, commit bool, callFromPrecompile bool, gasCap *big.Int) (*types.MsgEthereumTxResponse, error) { nonce, err := k.accountKeeper.GetSequence(ctx, from.Bytes()) if err != nil { return nil, err @@ -68,7 +58,7 @@ func (k Keeper) CallEVMWithData( AccessList: ethtypes.AccessList{}, } - res, err := k.ApplyMessage(ctx, msg, nil, commit, true) + res, err := k.ApplyMessage(ctx, stateDB, msg, nil, commit, callFromPrecompile, true) if err != nil { return nil, err } diff --git a/x/vm/keeper/grpc_query.go b/x/vm/keeper/grpc_query.go index 0e69e5ce0..0032b4b78 100644 --- a/x/vm/keeper/grpc_query.go +++ b/x/vm/keeper/grpc_query.go @@ -263,7 +263,8 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (*types.Ms txConfig := statedb.NewEmptyTxConfig() // pass false to not commit StateDB - res, err := k.ApplyMessageWithConfig(ctx, *msg, nil, false, cfg, txConfig, false, overrides) + stateDB := statedb.New(ctx, &k, txConfig) + res, err := k.ApplyMessageWithConfig(ctx, stateDB, *msg, nil, false, false, cfg, txConfig, false, overrides) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -403,7 +404,8 @@ func (k Keeper) EstimateGasInternal(c context.Context, req *types.EthCallRequest tmpCtx = buildTraceCtx(tmpCtx, msg.GasLimit) } // pass false to not commit StateDB - rsp, err = k.ApplyMessageWithConfig(tmpCtx, *msg, nil, false, cfg, txConfig, false, nil) + stateDB := statedb.New(tmpCtx, &k, txConfig) + rsp, err = k.ApplyMessageWithConfig(tmpCtx, stateDB, *msg, nil, false, false, cfg, txConfig, false, nil) if err != nil { if errors.Is(err, core.ErrIntrinsicGas) || errors.Is(err, core.ErrFloorDataGas) { return true, nil, nil // Special case, raise gas limit @@ -555,7 +557,8 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ ctx = buildTraceCtx(ctx, msg.GasLimit) // we ignore the error here. this endpoint, ideally, is called internally from the ETH backend, which will call this query // using all previous txs in the trace transaction's block. some of those _could_ be invalid transactions. - rsp, _ := k.ApplyMessageWithConfig(ctx, *msg, nil, true, cfg, txConfig, false, nil) + stateDB := statedb.New(ctx, &k, txConfig) + rsp, _ := k.ApplyMessageWithConfig(ctx, stateDB, *msg, nil, true, false, cfg, txConfig, false, nil) if rsp != nil { ctx.GasMeter().ConsumeGas(rsp.GasUsed, "evm predecessor tx") txConfig.LogIndex += uint(len(rsp.Logs)) @@ -833,7 +836,8 @@ func (k *Keeper) traceTxWithMsg( // Build EVM execution context ctx = buildTraceCtx(ctx, msg.GasLimit) - res, err := k.ApplyMessageWithConfig(ctx, *msg, tracer.Hooks, commitMessage, cfg, txConfig, false, nil) + stateDB := statedb.New(ctx, k, txConfig) + res, err := k.ApplyMessageWithConfig(ctx, stateDB, *msg, tracer.Hooks, commitMessage, false, cfg, txConfig, false, nil) if err != nil { return nil, 0, status.Error(codes.Internal, err.Error()) } diff --git a/x/vm/keeper/state_transition.go b/x/vm/keeper/state_transition.go index eb8975cf2..c9e7df65e 100644 --- a/x/vm/keeper/state_transition.go +++ b/x/vm/keeper/state_transition.go @@ -214,7 +214,8 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t tmpCtx, commitFn := ctx.CacheContext() // pass true to commit the StateDB - res, err := k.ApplyMessageWithConfig(tmpCtx, *msg, nil, true, cfg, txConfig, false, nil) + stateDB := statedb.New(tmpCtx, k, txConfig) + res, err := k.ApplyMessageWithConfig(tmpCtx, stateDB, *msg, nil, true, false, cfg, txConfig, false, nil) if err != nil { // when a transaction contains multiple msg, as long as one of the msg fails // all gas will be deducted. so is not msg.Gas() @@ -334,14 +335,16 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t } // ApplyMessage calls ApplyMessageWithConfig with an empty TxConfig. -func (k *Keeper) ApplyMessage(ctx sdk.Context, msg core.Message, tracer *tracing.Hooks, commit bool, internal bool) (*types.MsgEthereumTxResponse, error) { +// Note: if you call this from a precompile context, ensure that +// you use the existing stateDB. +func (k *Keeper) ApplyMessage(ctx sdk.Context, stateDB *statedb.StateDB, msg core.Message, tracer *tracing.Hooks, commit, callFromPrecompile, internal bool) (*types.MsgEthereumTxResponse, error) { cfg, err := k.EVMConfig(ctx, ctx.BlockHeader().ProposerAddress) if err != nil { return nil, errorsmod.Wrap(err, "failed to load evm config") } txConfig := statedb.NewEmptyTxConfig() - return k.ApplyMessageWithConfig(ctx, msg, tracer, commit, cfg, txConfig, internal, nil) + return k.ApplyMessageWithConfig(ctx, stateDB, msg, tracer, commit, callFromPrecompile, cfg, txConfig, internal, nil) } // ApplyMessageWithConfig computes the new state by applying the given message against the existing state. @@ -381,23 +384,15 @@ func (k *Keeper) ApplyMessage(ctx sdk.Context, msg core.Message, tracer *tracing // // # Commit parameter // -// If commit is true, the `StateDB` will be committed, otherwise discarded. -func (k *Keeper) ApplyMessageWithConfig( - ctx sdk.Context, - msg core.Message, - tracer *tracing.Hooks, - commit bool, - cfg *statedb.EVMConfig, - txConfig statedb.TxConfig, - internal bool, - overrides *rpctypes.StateOverride, -) (*types.MsgEthereumTxResponse, error) { +// If commit is true, the `StateDB` will be committed or flushed (if called from within a precompile), otherwise discarded. +func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, stateDB *statedb.StateDB, msg core.Message, tracer *tracing.Hooks, commit bool, callFromPrecompile bool, cfg *statedb.EVMConfig, txConfig statedb.TxConfig, internal bool, overrides *rpctypes.StateOverride) (*types.MsgEthereumTxResponse, error) { var ( ret []byte // return bytes from evm execution vmErr error // vm errors do not effect consensus and are therefore not assigned to err ) - - stateDB := statedb.New(ctx, k, txConfig) + if stateDB == nil { + return nil, types.ErrNilStateDB + } ethCfg := types.GetEthChainConfig() evm := k.NewEVMWithOverridePrecompiles(ctx, msg, cfg, tracer, stateDB, overrides == nil) // Gas limit suffices for the floor data cost (EIP-7623) @@ -455,7 +450,10 @@ func (k *Keeper) ApplyMessageWithConfig( // access list preparation is moved from ante handler to here, because it's needed when `ApplyMessage` is called // under contexts where ante handlers are not run, for example `eth_call` and `eth_estimateGas`. - stateDB.Prepare(rules, msg.From, common.Address{}, msg.To, evm.ActivePrecompiles(), msg.AccessList) + // If we're in a nested precompile scenario, then we don't want to prepare the stateDB a second time. + if !callFromPrecompile { + stateDB.Prepare(rules, msg.From, common.Address{}, msg.To, evm.ActivePrecompiles(), msg.AccessList) + } convertedValue, err := utils.Uint256FromBigInt(msg.Value) if err != nil { @@ -522,11 +520,18 @@ func (k *Keeper) ApplyMessageWithConfig( // The dirty states in `StateDB` is either committed or discarded after return if commit { - if err := stateDB.Commit(); err != nil { - return nil, errorsmod.Wrap(err, "failed to commit stateDB") + // In a precompile context, we never want to commit, as that will collapse the cache stack. + // Instead, we want to flush to the cacheCtx. + if callFromPrecompile { + if err := stateDB.FlushToCacheCtx(); err != nil { + return nil, errorsmod.Wrap(err, "failed to flush stateDB to cacheCtx") + } + } else { + if err := stateDB.Commit(); err != nil { + return nil, errorsmod.Wrap(err, "failed to commit stateDB") + } } } - // calculate a minimum amount of gas to be charged to sender if GasLimit // is considerably higher than GasUsed to stay more aligned with CometBFT gas mechanics // for more info https://github.com/evmos/ethermint/issues/1085 diff --git a/x/vm/statedb/balance_events_test.go b/x/vm/statedb/balance_events_test.go new file mode 100644 index 000000000..a50dbf202 --- /dev/null +++ b/x/vm/statedb/balance_events_test.go @@ -0,0 +1,113 @@ +package statedb + +import ( + "testing" + + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// mockSnapshotter is a simple mock implementation of the Snapshotter interface for testing. +type mockSnapshotter struct { + snapshots []int + current int +} + +func newMockSnapshotter() *mockSnapshotter { + return &mockSnapshotter{ + snapshots: []int{}, + current: 0, + } +} + +func (m *mockSnapshotter) Snapshot() int { + id := m.current + m.snapshots = append(m.snapshots, id) + m.current++ + return id +} + +func (m *mockSnapshotter) RevertToSnapshot(snapshot int) { + // Find the snapshot index + for i, s := range m.snapshots { + if s == snapshot { + m.snapshots = m.snapshots[:i+1] + m.current = snapshot + 1 + return + } + } +} + +// TestRevertToSnapshot_ProcessedEventsInvariant verifies the invariant: +// "After any revert, processedEventsCount <= current event count" +// This tests cacheCtx event manager behavior during EVM execution with precompile calls and reverts. +func TestRevertToSnapshot_ProcessedEventsInvariant(t *testing.T) { + // Test each revert scenario independently since reverting invalidates future snapshots + testCases := []struct { + name string + numPrecompiles int + revertToIndex int + expectedEvents int + }{ + {"revert to 5 precompile calls", 10, 5, 5}, + {"revert to 2 precompile calls", 10, 2, 2}, + {"revert to 0 precompile calls", 10, 0, 0}, + {"revert to 8 precompile calls", 10, 8, 8}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + mockSnap := newMockSnapshotter() + stateDB := &StateDB{ + validRevisions: []revision{}, + nextRevisionID: 0, + journal: newJournal(), + snapshotter: mockSnap, + } + + ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) + cacheCtx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) + stateDB.ctx = ctx + stateDB.cacheCtx = cacheCtx + stateDB.writeCache = func() {} // Simulate cache exists (after first precompile call) + + // Snapshot with 0 events (before any precompile calls) + snapshots := []int{stateDB.Snapshot()} + + // Simulate precompile calls - each emits an event + for i := 0; i < tc.numPrecompiles; i++ { + // Create multi-store snapshot for precompile journal entry + multiStoreSnapshot := mockSnap.Snapshot() + + // Add precompile journal entry (captures events before precompile) + err := stateDB.AddPrecompileFn(multiStoreSnapshot) + require.NoError(t, err) + + // Emit event during "precompile execution" + cacheCtx.EventManager().EmitEvent(sdk.NewEvent("test", sdk.NewAttribute("count", string(rune(i))))) + + // Update processed events count (simulates FlushToCacheCtx) + stateDB.processedEventsCount = len(cacheCtx.EventManager().Events()) + + // Take snapshot after precompile + snap := stateDB.Snapshot() + snapshots = append(snapshots, snap) + } + + // Revert to the target snapshot + stateDB.RevertToSnapshot(snapshots[tc.revertToIndex]) + + currentEventCount := len(cacheCtx.EventManager().Events()) + require.Equal(t, tc.expectedEvents, currentEventCount, "event count mismatch after revert") + + // Verify invariant: processedEventsCount <= current event count + require.LessOrEqual(t, stateDB.processedEventsCount, currentEventCount, + "processedEventsCount %d exceeds current event count %d", + stateDB.processedEventsCount, currentEventCount) + + require.Equal(t, tc.expectedEvents, stateDB.processedEventsCount, + "processedEventsCount should match expected event count") + }) + } +} diff --git a/x/vm/statedb/journal.go b/x/vm/statedb/journal.go index 3ae0817dd..a008ffe6b 100644 --- a/x/vm/statedb/journal.go +++ b/x/vm/statedb/journal.go @@ -144,8 +144,9 @@ type ( slot *common.Hash } precompileCallChange struct { - snapshot int - events sdk.Events + snapshot int + prevEvents sdk.Events + prevProcessedEventCount int } createContractChange struct { account *common.Address @@ -180,7 +181,13 @@ func (ch createContractChange) Dirtied() *common.Address { func (pc precompileCallChange) Revert(s *StateDB) { // rollback multi store from cache ctx to the previous // state stored in the snapshot - s.RevertMultiStore(pc.snapshot, pc.events) + s.RevertMultiStore(pc.snapshot) + + // Restore events to the state before this precompile call + s.cacheCtx.EventManager().OverrideEvents(pc.prevEvents) + + // Restore processed events counter + s.processedEventsCount = pc.prevProcessedEventCount } func (pc precompileCallChange) Dirtied() *common.Address { diff --git a/x/vm/statedb/statedb.go b/x/vm/statedb/statedb.go index 98185b60e..d10d1cd39 100644 --- a/x/vm/statedb/statedb.go +++ b/x/vm/statedb/statedb.go @@ -34,7 +34,6 @@ import ( type revision struct { id int journalIndex int - events sdk.Events } var _ vm.StateDB = &StateDB{} @@ -80,6 +79,12 @@ type StateDB struct { // The count of calls to precompiles precompileCallsCounter uint8 + + // processedEventsCount tracks how many events have been + // processed by BalanceHandler. Events are processed sequentially starting + // from index 0. Event counter tracks events to avoid having them reprocessed. + // On revert, this counter is rewound to the snapshot's event count. + processedEventsCount int } func (s *StateDB) CreateContract(address common.Address) { @@ -147,13 +152,14 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // New creates a new state from a given trie. func New(ctx sdk.Context, keeper Keeper, txConfig TxConfig) *StateDB { return &StateDB{ - keeper: keeper, - ctx: ctx, - stateObjects: make(map[common.Address]*stateObject), - journal: newJournal(), - accessList: newAccessList(), - transientStorage: newTransientStorage(), - txConfig: txConfig, + keeper: keeper, + ctx: ctx, + stateObjects: make(map[common.Address]*stateObject), + journal: newJournal(), + accessList: newAccessList(), + transientStorage: newTransientStorage(), + txConfig: txConfig, + processedEventsCount: len(ctx.EventManager().Events()), } } @@ -184,12 +190,8 @@ func (s *StateDB) MultiStoreSnapshot() int { return s.snapshotter.Snapshot() } -func (s *StateDB) RevertMultiStore(snapshot int, events sdk.Events) { +func (s *StateDB) RevertMultiStore(snapshot int) { s.snapshotter.RevertToSnapshot(snapshot) - s.writeCache = func() { - s.ctx.EventManager().EmitEvents(events) - s.cacheCtx.MultiStore().(storetypes.CacheMultiStore).Write() - } } // cache creates the stateDB cache context @@ -208,7 +210,8 @@ func (s *StateDB) cache() error { s.snapshotter = snapshotStore s.cacheCtx = s.cacheCtx.WithMultiStore(snapshotStore) s.writeCache = func() { - s.ctx.EventManager().EmitEvents(s.cacheCtx.EventManager().Events()) + eventsToEmit := s.cacheCtx.EventManager().Events() + s.ctx.EventManager().EmitEvents(eventsToEmit) s.cacheCtx.MultiStore().(storetypes.CacheMultiStore).Write() } @@ -433,10 +436,14 @@ func (s *StateDB) setStateObject(object *stateObject) { // AddPrecompileFn adds a precompileCall journal entry // with a snapshot of the multi-store and events previous // to the precompile call. -func (s *StateDB) AddPrecompileFn(snapshot int, events sdk.Events) error { +func (s *StateDB) AddPrecompileFn(snapshot int) error { + // Capture events before the precompile call + var prevEvents sdk.Events = s.cacheCtx.EventManager().Events() + s.journal.append(precompileCallChange{ - snapshot: snapshot, - events: events, + snapshot: snapshot, + prevEvents: prevEvents, + prevProcessedEventCount: s.processedEventsCount, }) s.precompileCallsCounter++ if s.precompileCallsCounter > types.MaxPrecompileCalls { @@ -445,6 +452,23 @@ func (s *StateDB) AddPrecompileFn(snapshot int, events sdk.Events) error { return nil } +// MarkEventProcessed records that the event at the given index +// has been seen by BalanceHandler. Events must be marked sequentially. +func (s *StateDB) MarkEventProcessed(idx int) { + // Events must be processed sequentially - idx should equal current count + if idx != s.processedEventsCount { + panic(fmt.Sprintf("balance events must be processed sequentially: expected %d, got %d", + s.processedEventsCount, idx)) + } + s.processedEventsCount++ +} + +// IsEventProcessed reports whether the event at idx has already been +// seen by a previous AfterBalanceChange invocation. +func (s *StateDB) IsEventProcessed(idx int) bool { + return idx < s.processedEventsCount +} + // AddBalance adds amount to the account associated with addr. func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int { stateObject := s.getOrNewStateObject(addr) @@ -664,7 +688,7 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre func (s *StateDB) Snapshot() int { id := s.nextRevisionID s.nextRevisionID++ - s.validRevisions = append(s.validRevisions, revision{id, s.journal.length(), s.ctx.EventManager().Events()}) + s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()}) return id } @@ -679,12 +703,8 @@ func (s *StateDB) RevertToSnapshot(revid int) { } snapshot := s.validRevisions[idx].journalIndex - // revert back to snapshotted events - eventManager := sdk.NewEventManager() - eventManager.EmitEvents(s.validRevisions[idx].events) - s.ctx = s.ctx.WithEventManager(eventManager) - // Replay the journal to undo changes and remove invalidated snapshots + // Event restoration is handled by precompileCallChange.Revert() s.journal.Revert(s, snapshot) s.validRevisions = s.validRevisions[:idx] } @@ -700,11 +720,19 @@ func (s *StateDB) Commit() error { return s.commitWithCtx(s.ctx) } -// CommitWithCacheCtx writes the dirty states to keeper using the cacheCtx. +// FlushToCacheCtx writes the dirty states to keeper using the cacheCtx. // This function is used before any precompile call to make sure the cacheCtx // is updated with the latest changes within the tx (StateDB's journal entries). -func (s *StateDB) CommitWithCacheCtx() error { - return s.commitWithCtx(s.cacheCtx) +func (s *StateDB) FlushToCacheCtx() error { + if err := s.commitWithCtx(s.cacheCtx); err != nil { + return err + } + + // Set counter to event count - all flushed events (from mint/burn during commit) are now accounted for. + // This prevents the balance handler from re-adding already flushed events. + s.processedEventsCount = len(s.cacheCtx.EventManager().Events()) + + return nil } // commitWithCtx writes the dirty states to keeper diff --git a/x/vm/statedb/statedb_test.go b/x/vm/statedb/statedb_test.go index 69bbddc2c..2e380cadc 100644 --- a/x/vm/statedb/statedb_test.go +++ b/x/vm/statedb/statedb_test.go @@ -58,7 +58,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().Empty(acct.Balance) suite.Require().False(acct.HasCodeHash()) - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db = statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) suite.Require().Equal(true, db.Exist(address)) suite.Require().Equal(true, db.Empty(address)) suite.Require().Equal(common.U2560, db.GetBalance(address)) @@ -81,7 +81,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().NoError(db.Commit()) // SelfDestruct - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) + db = statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), db.Keeper(), emptyTxConfig) suite.Require().False(db.HasSelfDestructed(address)) db.SelfDestruct(address) @@ -96,7 +96,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().NoError(db.Commit()) // not accessible from StateDB anymore - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) + db = statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), db.Keeper(), emptyTxConfig) suite.Require().False(db.Exist(address)) // and cleared in keeper too @@ -134,7 +134,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().NoError(db.Commit()) // not accessible from StateDB anymore - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) + db = statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), db.Keeper(), emptyTxConfig) suite.Require().False(db.Exist(address)) // and cleared in keeper too @@ -159,7 +159,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().NoError(db.Commit()) // SelfDestruct - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) + db = statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), db.Keeper(), emptyTxConfig) suite.Require().False(db.HasSelfDestructed(address)) _, _ = db.SelfDestruct6780(address) @@ -172,7 +172,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Require().NoError(db.Commit()) // Same-tx maintains state - db = statedb.New(sdk.Context{}, db.Keeper(), emptyTxConfig) + db = statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), db.Keeper(), emptyTxConfig) suite.Require().True(db.Exist(address)) suite.Require().False(db.HasSelfDestructed(address)) // but code and state are still accessible in dirty state @@ -193,7 +193,7 @@ func (suite *StateDBTestSuite) TestAccount() { suite.Run(tc.name, func() { ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) keeper := mocks.NewEVMKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) tc.malleate(ctx, db) }) } @@ -201,7 +201,7 @@ func (suite *StateDBTestSuite) TestAccount() { func (suite *StateDBTestSuite) TestAccountOverride() { keeper := mocks.NewEVMKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) // test balance carry over when overwritten amount := uint256.NewInt(1) @@ -233,7 +233,7 @@ func (suite *StateDBTestSuite) TestDBError() { }}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, mocks.NewEVMKeeper(), emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), mocks.NewEVMKeeper(), emptyTxConfig) tc.malleate(db) suite.Require().Error(db.Commit()) } @@ -267,7 +267,7 @@ func (suite *StateDBTestSuite) TestBalance() { suite.Run(tc.name, func() { ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) keeper := mocks.NewEVMKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) tc.malleate(db) // check dirty state @@ -322,7 +322,7 @@ func (suite *StateDBTestSuite) TestState() { suite.Run(tc.name, func() { ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager()) keeper := mocks.NewEVMKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) tc.malleate(db) suite.Require().NoError(db.Commit()) @@ -332,7 +332,7 @@ func (suite *StateDBTestSuite) TestState() { } // check ForEachStorage - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db = statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) collected := CollectContractStorage(db) if len(tc.expStates) > 0 { suite.Require().Equal(tc.expStates, collected) @@ -365,7 +365,7 @@ func (suite *StateDBTestSuite) TestCode() { for _, tc := range testCases { suite.Run(tc.name, func() { keeper := mocks.NewEVMKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) tc.malleate(db) // check dirty state @@ -376,7 +376,7 @@ func (suite *StateDBTestSuite) TestCode() { suite.Require().NoError(db.Commit()) // check again - db = statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db = statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) suite.Require().Equal(tc.expCode, db.GetCode(address)) suite.Require().Equal(len(tc.expCode), db.GetCodeSize(address)) suite.Require().Equal(tc.expCodeHash, db.GetCodeHash(address)) @@ -486,7 +486,7 @@ func (suite *StateDBTestSuite) TestNestedSnapshot() { } func (suite *StateDBTestSuite) TestInvalidSnapshotId() { - db := statedb.New(sdk.Context{}, mocks.NewEVMKeeper(), emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), mocks.NewEVMKeeper(), emptyTxConfig) suite.Require().Panics(func() { db.RevertToSnapshot(1) }) @@ -577,7 +577,7 @@ func (suite *StateDBTestSuite) TestAccessList() { } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, mocks.NewEVMKeeper(), emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), mocks.NewEVMKeeper(), emptyTxConfig) tc.malleate(db) } } @@ -589,7 +589,7 @@ func (suite *StateDBTestSuite) TestLog() { txHash, 1, 1, ) - db := statedb.New(sdk.Context{}, mocks.NewEVMKeeper(), txConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), mocks.NewEVMKeeper(), txConfig) data := []byte("hello world") db.AddLog(ðtypes.Log{ Address: address, @@ -639,7 +639,7 @@ func (suite *StateDBTestSuite) TestRefund() { }, 0, true}, } for _, tc := range testCases { - db := statedb.New(sdk.Context{}, mocks.NewEVMKeeper(), emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), mocks.NewEVMKeeper(), emptyTxConfig) if !tc.expPanic { tc.malleate(db) suite.Require().Equal(tc.expRefund, db.GetRefund()) @@ -660,7 +660,7 @@ func (suite *StateDBTestSuite) TestIterateStorage() { value2 := common.BigToHash(big.NewInt(4)) keeper := mocks.NewEVMKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) db.SetState(address, key1, value1) db.SetState(address, key2, value2) @@ -716,7 +716,7 @@ func (suite *StateDBTestSuite) TestSetStorage() { for _, tc := range testCases { suite.Run(tc.name, func() { keeper := mocks.NewEVMKeeper() - db := statedb.New(sdk.Context{}, keeper, emptyTxConfig) + db := statedb.New(sdk.Context{}.WithEventManager(sdk.NewEventManager()), keeper, emptyTxConfig) for k, v := range tc.prestate { db.SetState(contract, k, v) } diff --git a/x/vm/types/denom_config.go b/x/vm/types/denom_config.go index e3f0fac5b..e4bc839ba 100644 --- a/x/vm/types/denom_config.go +++ b/x/vm/types/denom_config.go @@ -97,7 +97,10 @@ func GetEVMCoinDisplayDenom() string { // setEVMCoinInfo allows to define denom and decimals of the coin used in the EVM. func setEVMCoinInfo(eci EvmCoinInfo) error { - if evmCoinInfo != nil { + if evmCoinInfo != nil && (evmCoinInfo.Denom != eci.Denom || + evmCoinInfo.ExtendedDenom != eci.ExtendedDenom || + evmCoinInfo.DisplayDenom != eci.DisplayDenom || + evmCoinInfo.Decimals != eci.Decimals) { return errors.New("EVM coin info already set") } diff --git a/x/vm/types/denom_config_testing.go b/x/vm/types/denom_config_testing.go index 9e731d7db..137d0dcf8 100644 --- a/x/vm/types/denom_config_testing.go +++ b/x/vm/types/denom_config_testing.go @@ -84,7 +84,10 @@ func GetEVMCoinDisplayDenom() string { // setTestingEVMCoinInfo allows to define denom and decimals of the coin used in the EVM. func setTestingEVMCoinInfo(eci EvmCoinInfo) error { - if testingEvmCoinInfo != nil { + if testingEvmCoinInfo != nil && (testingEvmCoinInfo.Denom != eci.Denom || + testingEvmCoinInfo.ExtendedDenom != eci.ExtendedDenom || + testingEvmCoinInfo.DisplayDenom != eci.DisplayDenom || + testingEvmCoinInfo.Decimals != eci.Decimals) { return errors.New("testing EVM coin info already set. Make sure you run the configurator's ResetTestConfig before trying to set a new evm coin info") } diff --git a/x/vm/types/errors.go b/x/vm/types/errors.go index aba448436..245b2d20d 100644 --- a/x/vm/types/errors.go +++ b/x/vm/types/errors.go @@ -32,6 +32,7 @@ const ( codeErrABIPack codeErrABIUnpack codeErrInvalidPreinstall + codeErrNilStateDB ) var ( @@ -94,6 +95,9 @@ var ( // RevertSelector is selector of ErrExecutionReverted RevertSelector = crypto.Keccak256([]byte("Error(string)"))[:4] + + // ErrNilStateDB + ErrNilStateDB = errorsmod.Register(ModuleName, codeErrNilStateDB, "stateDB cannot be nil") ) // RevertReasonBytes converts a message to ABI-encoded revert bytes. diff --git a/x/vm/types/msg.go b/x/vm/types/msg.go index 19bda468f..f4d7ff6e6 100644 --- a/x/vm/types/msg.go +++ b/x/vm/types/msg.go @@ -354,8 +354,3 @@ func (m *MsgUpdateParams) ValidateBasic() error { return m.Params.Validate() } - -// GetSignBytes implements the LegacyMsg interface. -func (m MsgUpdateParams) GetSignBytes() []byte { - return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&m)) -}