diff --git a/.github/workflows/eth_blocktests.yml b/.github/workflows/eth_blocktests.yml new file mode 100644 index 000000000..f85962665 --- /dev/null +++ b/.github/workflows/eth_blocktests.yml @@ -0,0 +1,53 @@ +name: ETH Blocktests + +on: + push: + branches: + - seiv2 + pull_request: + branches: + - seiv2 + +defaults: + run: + shell: bash + +env: + TOTAL_RUNNERS: 5 + +jobs: + runner-indexes: + runs-on: ubuntu-latest + name: Generate runner indexes + outputs: + json: ${{ steps.generate-index-list.outputs.json }} + steps: + - id: generate-index-list + run: | + MAX_INDEX=$((${{ env.TOTAL_RUNNERS }}-1)) + INDEX_LIST=$(seq 0 ${MAX_INDEX}) + INDEX_JSON=$(jq --null-input --compact-output '. |= [inputs]' <<< ${INDEX_LIST}) + echo "json=${INDEX_JSON}" >> $GITHUB_OUTPUT + + eth-blocktests: + name: "Run ETH Blocktests ${{ matrix.runner-index }}" + runs-on: ubuntu-latest + needs: runner-indexes + strategy: + fail-fast: false + matrix: + # generate runner index array from 0 to total-runners + runner-index: ${{fromJson(needs.runner-indexes.outputs.json)}} + steps: + - uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.21 + + - name: Clone ETH Blocktests + run: git clone https://github.com/ethereum/tests.git ethtests + + - name: "Run ETH Blocktest" + run: ./run_blocktests.sh ./ethtests/BlockchainTests/ ${{ matrix.runner-index }} ${{ env.TOTAL_RUNNERS }} diff --git a/app/antedecorators/priority.go b/app/antedecorators/priority.go index cb17f62bc..0fe7b287a 100644 --- a/app/antedecorators/priority.go +++ b/app/antedecorators/priority.go @@ -10,6 +10,8 @@ import ( const ( OraclePriority = math.MaxInt64 - 100 EVMAssociatePriority = math.MaxInt64 - 101 + // This is the max priority a non oracle or associate tx can take + MaxPriority = math.MaxInt64 - 1000 ) type PriorityDecorator struct{} @@ -27,9 +29,9 @@ func intMin(a, b int64) int64 { // Assigns higher priority to certain types of transactions including oracle func (pd PriorityDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { - // Cap priority to MAXINT64 - 1000 + // Cap priority // Use higher priorities for tiers including oracle tx's - priority := intMin(ctx.Priority(), math.MaxInt64-1000) + priority := intMin(ctx.Priority(), MaxPriority) if isOracleTx(tx) { priority = OraclePriority diff --git a/app/app.go b/app/app.go index ed48290c8..138791497 100644 --- a/app/app.go +++ b/app/app.go @@ -127,6 +127,7 @@ import ( evmante "github.com/sei-protocol/sei-chain/x/evm/ante" "github.com/sei-protocol/sei-chain/x/evm/blocktest" evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/querier" "github.com/sei-protocol/sei-chain/x/evm/replay" evmtracers "github.com/sei-protocol/sei-chain/x/evm/tracers" "github.com/sei-protocol/sei-chain/x/evm/tracing" @@ -595,11 +596,16 @@ func New( app.EvmKeeper = *evmkeeper.NewKeeper(keys[evmtypes.StoreKey], memKeys[evmtypes.MemStoreKey], app.GetSubspace(evmtypes.ModuleName), app.BankKeeper, &app.AccountKeeper, &app.StakingKeeper, - app.TransferKeeper) + app.TransferKeeper, wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper)) app.evmRPCConfig, err = evmrpc.ReadConfig(appOpts) if err != nil { panic(fmt.Sprintf("error reading EVM config due to %s", err)) } + evmQueryConfig, err := querier.ReadConfig(appOpts) + if err != nil { + panic(fmt.Sprintf("error reading evm query config due to %s", err)) + } + app.EvmKeeper.QueryConfig = &evmQueryConfig ethReplayConfig, err := replay.ReadConfig(appOpts) if err != nil { panic(fmt.Sprintf("error reading eth replay config due to %s", err)) @@ -658,7 +664,8 @@ func New( AddRoute(dexmoduletypes.RouterKey, dexmodule.NewProposalHandler(app.DexKeeper)). AddRoute(minttypes.RouterKey, mint.NewProposalHandler(app.MintKeeper)). AddRoute(tokenfactorytypes.RouterKey, tokenfactorymodule.NewProposalHandler(app.TokenFactoryKeeper)). - AddRoute(acltypes.ModuleName, aclmodule.NewProposalHandler(app.AccessControlKeeper)) + AddRoute(acltypes.ModuleName, aclmodule.NewProposalHandler(app.AccessControlKeeper)). + AddRoute(evmtypes.RouterKey, evm.NewProposalHandler(app.EvmKeeper)) if len(enabledProposals) != 0 { govRouter.AddRoute(wasm.RouterKey, wasm.NewWasmProposalHandler(app.WasmKeeper, enabledProposals)) } @@ -826,8 +833,8 @@ func New( oracletypes.ModuleName, tokenfactorytypes.ModuleName, epochmoduletypes.ModuleName, - evmtypes.ModuleName, wasm.ModuleName, + evmtypes.ModuleName, acltypes.ModuleName, // this line is used by starport scaffolding # stargate/app/initGenesis ) @@ -1463,6 +1470,7 @@ func (app *App) ProcessTXsWithOCC(ctx sdk.Context, txs [][]byte, typedTxs []sdk. GasUsed: r.Response.GasUsed, Events: r.Response.Events, Codespace: r.Response.Codespace, + EvmTxInfo: r.Response.EvmTxInfo, }) } diff --git a/app/eth_replay.go b/app/eth_replay.go index a16bae7ed..80b045068 100644 --- a/app/eth_replay.go +++ b/app/eth_replay.go @@ -6,10 +6,13 @@ import ( "fmt" "math/big" "path/filepath" + "strings" "time" "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethcore "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/tracing" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" @@ -89,6 +92,7 @@ func Replay(a *App) { a.Logger().Info(fmt.Sprintf("Verifying tx %s", tx.Hash().Hex())) if tx.To() != nil { a.EvmKeeper.VerifyBalance(ctx, *tx.To()) + a.EvmKeeper.VerifyState(ctx, *tx.To()) } a.EvmKeeper.VerifyTxResult(ctx, tx.Hash()) } @@ -133,18 +137,23 @@ func BlockTest(a *App, bt *ethtests.BlockTest) { for key, value := range genesisAccount.Storage { a.EvmKeeper.SetState(a.GetContextForDeliverTx([]byte{}), addr, key, value) } + params := a.EvmKeeper.GetParams(a.GetContextForDeliverTx([]byte{})) + params.MinimumFeePerGas = sdk.NewDecFromInt(sdk.NewInt(0)) + a.EvmKeeper.SetParams(a.GetContextForDeliverTx([]byte{}), params) } if len(bt.Json.Blocks) == 0 { panic("no blocks found") } + ethblocks := make([]*ethtypes.Block, 0) for i, btBlock := range bt.Json.Blocks { h := int64(i + 1) b, err := btBlock.Decode() if err != nil { panic(err) } + ethblocks = append(ethblocks, b) hash := make([]byte, 8) binary.BigEndian.PutUint64(hash, uint64(h)) _, err = a.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{ @@ -167,6 +176,15 @@ func BlockTest(a *App, bt *ethtests.BlockTest) { // Check post-state after all blocks are run ctx := a.GetCheckCtx() for addr, accountData := range bt.Json.Post { + if IsWithdrawalAddress(addr, ethblocks) { + fmt.Println("Skipping withdrawal address: ", addr) + continue + } + // Not checking compliance with EIP-4788 + if addr == params.BeaconRootsStorageAddress { + fmt.Println("Skipping beacon roots storage address: ", addr) + continue + } a.EvmKeeper.VerifyAccount(ctx, addr, accountData) fmt.Println("Successfully verified account: ", addr) } @@ -186,6 +204,9 @@ func encodeTx(tx *ethtypes.Transaction, txConfig client.TxConfig) []byte { txData, err = ethtx.NewBlobTx(tx) } if err != nil { + if strings.Contains(err.Error(), ethcore.ErrTipAboveFeeCap.Error()) { + return nil + } panic(err) } msg, err := evmtypes.NewMsgEVMTransaction(txData) @@ -202,3 +223,14 @@ func encodeTx(tx *ethtypes.Transaction, txConfig client.TxConfig) []byte { } return txbz } + +func IsWithdrawalAddress(addr common.Address, blocks []*ethtypes.Block) bool { + for _, block := range blocks { + for _, w := range block.Withdrawals() { + if w.Address == addr { + return true + } + } + } + return false +} diff --git a/app/upgrades.go b/app/upgrades.go index 2d31840ea..5ab0017cc 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -86,6 +86,7 @@ var upgradesList = []string{ "v4.1.5-evm-devnet", "v4.1.6-evm-devnet", "v4.1.7-evm-devnet", + "v4.1.8-evm-devnet", } // if there is an override list, use that instead, for integration tests diff --git a/cmd/seid/cmd/root.go b/cmd/seid/cmd/root.go index d63b62c1d..1d86266ad 100644 --- a/cmd/seid/cmd/root.go +++ b/cmd/seid/cmd/root.go @@ -39,6 +39,7 @@ import ( "github.com/sei-protocol/sei-chain/evmrpc" "github.com/sei-protocol/sei-chain/tools" "github.com/sei-protocol/sei-chain/x/evm/blocktest" + "github.com/sei-protocol/sei-chain/x/evm/querier" "github.com/sei-protocol/sei-chain/x/evm/replay" "github.com/spf13/cast" "github.com/spf13/cobra" @@ -378,6 +379,8 @@ func initAppConfig() (string, interface{}) { ETHReplay replay.Config `mapstructure:"eth_replay"` ETHBlockTest blocktest.Config `mapstructure:"eth_block_test"` + + EvmQuery querier.Config `mapstructure:"evm_query"` } // Optionally allow the chain developer to overwrite the SDK's default @@ -420,6 +423,7 @@ func initAppConfig() (string, interface{}) { EVM: evmrpc.DefaultConfig, ETHReplay: replay.DefaultConfig, ETHBlockTest: blocktest.DefaultConfig, + EvmQuery: querier.DefaultConfig, } customAppTemplate := serverconfig.DefaultConfigTemplate + ` @@ -496,6 +500,9 @@ eth_data_dir = "{{ .ETHReplay.EthDataDir }}" [eth_blocktest] eth_blocktest_enabled = {{ .ETHBlockTest.Enabled }} eth_blocktest_test_data_path = "{{ .ETHBlockTest.TestDataPath }}" + +[evm_query] +evm_query_gas_limit = {{ .EvmQuery.GasLimit }} ` return customAppTemplate, customAppConfig diff --git a/contracts/package-lock.json b/contracts/package-lock.json index cfd238f19..a4d1415c1 100644 --- a/contracts/package-lock.json +++ b/contracts/package-lock.json @@ -20,14 +20,14 @@ "@openzeppelin/hardhat-upgrades": "^3.0.2", "@openzeppelin/test-helpers": "^0.5.16", "dotenv": "^16.3.1", - "ethers": "^6.9.0", + "ethers": "^6.11.1", "hardhat": "^2.20.1" } }, "node_modules/@adraffy/ens-normalize": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", - "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", "dev": true }, "node_modules/@aws-crypto/sha256-js": { @@ -6942,9 +6942,9 @@ } }, "node_modules/ethers": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", - "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", + "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==", "dev": true, "funding": [ { @@ -6957,7 +6957,7 @@ } ], "dependencies": { - "@adraffy/ens-normalize": "1.10.0", + "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "18.15.13", @@ -14146,9 +14146,9 @@ }, "dependencies": { "@adraffy/ens-normalize": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", - "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", "dev": true }, "@aws-crypto/sha256-js": { @@ -19539,12 +19539,12 @@ } }, "ethers": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.10.0.tgz", - "integrity": "sha512-nMNwYHzs6V1FR3Y4cdfxSQmNgZsRj1RiTU25JwvnJLmyzw9z3SKxNc2XKDuiXXo/v9ds5Mp9m6HBabgYQQ26tA==", + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", + "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==", "dev": true, "requires": { - "@adraffy/ens-normalize": "1.10.0", + "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", "@types/node": "18.15.13", diff --git a/contracts/package.json b/contracts/package.json index 98d2f5bc8..38332f44e 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "@openzeppelin/hardhat-upgrades": "^3.0.2", "@openzeppelin/test-helpers": "^0.5.16", "dotenv": "^16.3.1", - "ethers": "^6.9.0", + "ethers": "^6.11.1", "hardhat": "^2.20.1" }, "dependencies": { diff --git a/contracts/src/CW721ERC721Pointer.sol b/contracts/src/CW721ERC721Pointer.sol index 21bc6a2b2..a8c614e18 100644 --- a/contracts/src/CW721ERC721Pointer.sol +++ b/contracts/src/CW721ERC721Pointer.sol @@ -87,6 +87,7 @@ contract CW721ERC721Pointer is ERC721 { if (to == address(0)) { revert ERC721InvalidReceiver(address(0)); } + require(from == ownerOf(tokenId), "`from` must be the owner"); string memory recipient = _formatPayload("recipient", _doubleQuotes(AddrPrecompile.getSeiAddr(to))); string memory tId = _formatPayload("token_id", _doubleQuotes(Strings.toString(tokenId))); string memory req = _curlyBrace(_formatPayload("transfer_nft", _curlyBrace(_join(recipient, tId, ",")))); diff --git a/contracts/src/WSEI.sol b/contracts/src/WSEI.sol new file mode 100644 index 000000000..02d9ec833 --- /dev/null +++ b/contracts/src/WSEI.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract WSEI { + string public name = "Wrapped Sei"; + string public symbol = "WSEI"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint wad); + event Transfer(address indexed src, address indexed dst, uint wad); + event Deposit(address indexed dst, uint wad); + event Withdrawal(address indexed src, uint wad); + + mapping (address => uint) public balanceOf; + mapping (address => mapping (address => uint)) public allowance; + + fallback() external payable { + deposit(); + } + receive() external payable { + deposit(); + } + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + function withdraw(uint wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + payable(msg.sender).transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint) { + return address(this).balance; + } + + function approve(address guy, uint wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint wad) + public + returns (bool) + { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != type(uint).max) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } +} diff --git a/contracts/test/CW721ERC721PointerTest.t.sol b/contracts/test/CW721ERC721PointerTest.t.sol index b7969583c..9c4602e7c 100644 --- a/contracts/test/CW721ERC721PointerTest.t.sol +++ b/contracts/test/CW721ERC721PointerTest.t.sol @@ -179,6 +179,21 @@ contract CW721ERC721PointerTest is Test { } function testTransferFrom() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"owner_of\":{\"token_id\":\"1\"}}")), + abi.encode("{\"owner\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}") + ); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytes(bytes,string)", bytes("{\"owner\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}"), "owner"), + abi.encode(bytes("sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe")) + ); + vm.mockCall( + ADDR_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("getEvmAddr(string)", "sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe"), + abi.encode(address(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)) + ); vm.mockCall( WASMD_PRECOMPILE_ADDRESS, abi.encodeWithSignature("execute(string,bytes,bytes)", MockCWContractAddress, bytes("{\"transfer_nft\":{\"recipient\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\",\"token_id\":\"1\"}}"), bytes("[]")), diff --git a/contracts/test/EVMCompatabilityTester.js b/contracts/test/EVMCompatabilityTester.js index be98b5468..16c2466d7 100644 --- a/contracts/test/EVMCompatabilityTester.js +++ b/contracts/test/EVMCompatabilityTester.js @@ -52,6 +52,7 @@ async function sendTx(sender, txn, responses) { responses.push({nonce: txn.nonce, response: txResponse}) } + describe("EVM Test", function () { describe("EVMCompatibilityTester", function () { @@ -234,6 +235,29 @@ describe("EVM Test", function () { expect(await evmTester.uint256Var()).to.equal(12345); }); + // this uses a newer version of ethers to attempt a blob transaction (different signer wallet) + it("should return an error for blobs", async function(){ + const key = "0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e" + const signer = new ethers.Wallet(key, ethers.provider); + const blobData = "BLOB"; + const blobDataBytes = ethers.toUtf8Bytes(blobData); + const blobHash = ethers.keccak256(blobDataBytes); + + const tx = { + type: 3, + to: owner.address, + value: ethers.parseEther("0.1"), + data: '0x', + maxFeePerGas: ethers.parseUnits('100', 'gwei'), + maxPriorityFeePerGas: ethers.parseUnits('1', 'gwei'), + gasLimit: 100000, + maxFeePerBlobGas: ethers.parseUnits('10', 'gwei'), + blobVersionedHashes: [blobHash], + } + + await expect(signer.sendTransaction(tx)).to.be.rejectedWith("unsupported transaction type"); + }) + it("Should trace a call with timestamp", async function () { await delay() const txResponse = await evmTester.setTimestamp(); diff --git a/contracts/test/EVMPrecompileTester.js b/contracts/test/EVMPrecompileTester.js index 4596802f0..3e6f3efaa 100644 --- a/contracts/test/EVMPrecompileTester.js +++ b/contracts/test/EVMPrecompileTester.js @@ -16,6 +16,8 @@ describe("EVM Test", function () { let signer2 before(async function() { contractAddress = readDeploymentOutput('erc20_deploy_addr.txt'); + console.log("ERC20 address is:"); + console.log(contractAddress); await sleep(1000); // Create a signer diff --git a/contracts/test/deploy_atom_erc20.sh b/contracts/test/deploy_atom_erc20.sh index ceed1766b..f5408f313 100644 --- a/contracts/test/deploy_atom_erc20.sh +++ b/contracts/test/deploy_atom_erc20.sh @@ -16,9 +16,11 @@ printf "12345678\n" | seid tx evm send $owner1 1000000000000000000 --from admin printf "12345678\n" | seid tx evm send $owner2 1000000000000000000 --from admin echo "Deploying ERC20 pointer contract for UATOM..." -deployment_output=$(printf "12345678\n" | seid tx evm deploy-erc20 uatom UATOM UATOM 6 --from admin --evm-rpc=$endpoint) +printf "12345678\n" | seid tx evm call-contract 0x000000000000000000000000000000000000100b c31d960f000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000057561746f6d000000000000000000000000000000000000000000000000000000 --from admin --evm-rpc=$endpoint +sleep 3 +pointer_output=$(seid q evm pointer NATIVE uatom --output json) -erc20_deploy_addr=$(echo "$deployment_output" | grep 'Deployed to:' | awk '{print $3}') +erc20_deploy_addr=$(echo "$pointer_output" | jq .pointer | tr -d '"') echo $erc20_deploy_addr > contracts/erc20_deploy_addr.txt # wait for deployment to finish on live chain diff --git a/docker/localnode/scripts/step2_genesis.sh b/docker/localnode/scripts/step2_genesis.sh index c4f54a3b6..0db68437e 100755 --- a/docker/localnode/scripts/step2_genesis.sh +++ b/docker/localnode/scripts/step2_genesis.sh @@ -33,6 +33,7 @@ override_genesis ".app_state[\"mint\"][\"params\"][\"token_release_schedule\"]=[ override_genesis '.app_state["auth"]["accounts"]=[]' override_genesis '.app_state["bank"]["balances"]=[]' override_genesis '.app_state["genutil"]["gen_txs"]=[]' +override_genesis '.app_state["bank"]["denom_metadata"]=[{"denom_units":[{"denom":"UATOM","exponent":6,"aliases":["UATOM"]}],"base":"uatom","display":"uatom","name":"UATOM","symbol":"UATOM"}]' # gov parameters override_genesis '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="usei"' diff --git a/evmrpc/association.go b/evmrpc/association.go index fc9555190..c3d14a937 100644 --- a/evmrpc/association.go +++ b/evmrpc/association.go @@ -98,7 +98,11 @@ func (t *AssociationAPI) GetSeiAddress(_ context.Context, ethAddress common.Addr func (t *AssociationAPI) GetEVMAddress(_ context.Context, seiAddress string) (result string, returnErr error) { startTime := time.Now() defer recordMetrics("sei_getEVMAddress", startTime, returnErr == nil) - ethAddress, found := t.keeper.GetEVMAddress(t.ctxProvider(LatestCtxHeight), sdk.MustAccAddressFromBech32(seiAddress)) + seiAddr, err := sdk.AccAddressFromBech32(seiAddress) + if err != nil { + return "", err + } + ethAddress, found := t.keeper.GetEVMAddress(t.ctxProvider(LatestCtxHeight), seiAddr) if !found { return "", fmt.Errorf("failed to find EVM address for %s", seiAddress) } diff --git a/evmrpc/block.go b/evmrpc/block.go index fc6b671a5..246d2726b 100644 --- a/evmrpc/block.go +++ b/evmrpc/block.go @@ -208,7 +208,7 @@ func EncodeTmBlock( "size": hexutil.Uint64(block.Block.Size()), "uncles": []common.Hash{}, // inapplicable to Sei "transactions": transactions, - "baseFeePerGas": (*hexutil.Big)(k.GetBaseFeePerGas(ctx).RoundInt().BigInt()), + "baseFeePerGas": (*hexutil.Big)(k.GetBaseFeePerGas(ctx).TruncateInt().BigInt()), } if fullTx { result["totalDifficulty"] = (*hexutil.Big)(big.NewInt(0)) // inapplicable to Sei diff --git a/evmrpc/info.go b/evmrpc/info.go index 6b268d805..e165cc3cf 100644 --- a/evmrpc/info.go +++ b/evmrpc/info.go @@ -78,11 +78,11 @@ func (i *InfoAPI) GasPrice(ctx context.Context) (result *hexutil.Big, returnErr } if len(feeHist.Reward) == 0 || len(feeHist.Reward[0]) == 0 { // if there is no EVM tx in the most recent block, return the minimum fee param - return (*hexutil.Big)(i.keeper.GetMinimumFeePerGas(i.ctxProvider(LatestCtxHeight)).RoundInt().BigInt()), nil + return (*hexutil.Big)(i.keeper.GetMinimumFeePerGas(i.ctxProvider(LatestCtxHeight)).TruncateInt().BigInt()), nil } return (*hexutil.Big)(new(big.Int).Add( feeHist.Reward[0][0].ToInt(), - i.keeper.GetBaseFeePerGas(i.ctxProvider(LatestCtxHeight)).RoundInt().BigInt(), + i.keeper.GetBaseFeePerGas(i.ctxProvider(LatestCtxHeight)).TruncateInt().BigInt(), )), nil } diff --git a/go.mod b/go.mod index f94efbe60..a5c04de9f 100644 --- a/go.mod +++ b/go.mod @@ -346,10 +346,10 @@ require ( replace ( github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.1.0 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 - github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.2.80-0.20240329180032-8b8b5739ef96 + github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.2.80-seiv2 github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.9 github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.0 - github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-9.0.20240327165640-6ab0d196bac6 + github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-13 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.33 // Latest goleveldb is broken, we have to stick to this version diff --git a/go.sum b/go.sum index b1a210ada..55dc77b06 100644 --- a/go.sum +++ b/go.sum @@ -1343,12 +1343,12 @@ github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod github.com/securego/gosec/v2 v2.11.0 h1:+PDkpzR41OI2jrw1q6AdXZCbsNGNGT7pQjal0H0cArI= github.com/securego/gosec/v2 v2.11.0/go.mod h1:SX8bptShuG8reGC0XS09+a4H2BoWSJi+fscA+Pulbpo= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= -github.com/sei-protocol/go-ethereum v1.13.5-sei-9.0.20240327165640-6ab0d196bac6 h1:AU9VAvZsTGibuzzVmoX3taGOWjPJJct5ypXDg6vKKu0= -github.com/sei-protocol/go-ethereum v1.13.5-sei-9.0.20240327165640-6ab0d196bac6/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= +github.com/sei-protocol/go-ethereum v1.13.5-sei-13 h1:ied1MMoqJyTEPvT7AtJeVTn3bEuwksInfvyXxp2siLw= +github.com/sei-protocol/go-ethereum v1.13.5-sei-13/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA= github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= -github.com/sei-protocol/sei-cosmos v0.2.80-0.20240329180032-8b8b5739ef96 h1:IrNlnSd2ebm4K6/e3iUaRC0nRKJIBG2GigpLdW3Ame0= -github.com/sei-protocol/sei-cosmos v0.2.80-0.20240329180032-8b8b5739ef96/go.mod h1:ib/gp0gCxN7FXUZ40j5+x8BeyoI7AcX+rTvf53JoDsY= +github.com/sei-protocol/sei-cosmos v0.2.80-seiv2 h1:stu0hTZmQWvewzr/y40iZrKsKHFuCXFKNEJGsgivvL4= +github.com/sei-protocol/sei-cosmos v0.2.80-seiv2/go.mod h1:ib/gp0gCxN7FXUZ40j5+x8BeyoI7AcX+rTvf53JoDsY= github.com/sei-protocol/sei-db v0.0.33 h1:TspNkw/lW7fubR0TsOpmJdzWiLecMDOS5DAxFNQXQ6M= github.com/sei-protocol/sei-db v0.0.33/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= diff --git a/integration_test/seidb/state_store_test.yaml b/integration_test/seidb/state_store_test.yaml index 3c96f1064..829d79587 100644 --- a/integration_test/seidb/state_store_test.yaml +++ b/integration_test/seidb/state_store_test.yaml @@ -39,19 +39,19 @@ verifiers: # Verify number of wasm codes at each height - type: eval - expr: BEGINNING_LIST_CODE_LENGTH == 0 + expr: BEGINNING_LIST_CODE_LENGTH == 2 - type: eval - expr: FIRST_SET_LIST_CODE_LENGTH == 10 + expr: FIRST_SET_LIST_CODE_LENGTH == 12 - type: eval - expr: FIRST_SET_LIST_CODE_LENGTH_REVERSE == 10 + expr: FIRST_SET_LIST_CODE_LENGTH_REVERSE == 12 - type: eval - expr: SECOND_SET_LIST_CODE_LENGTH == 20 + expr: SECOND_SET_LIST_CODE_LENGTH == 22 - type: eval - expr: SECOND_SET_LIST_CODE_LENGTH_REVERSE == 20 + expr: SECOND_SET_LIST_CODE_LENGTH_REVERSE == 22 - type: eval - expr: THIRD_SET_LIST_CODE_LENGTH == 30 + expr: THIRD_SET_LIST_CODE_LENGTH == 32 - type: eval - expr: THIRD_SET_LIST_CODE_LENGTH_REVERSE == 30 + expr: THIRD_SET_LIST_CODE_LENGTH_REVERSE == 32 - name: Test state store historical data checking specific wasm codes inputs: @@ -59,19 +59,19 @@ - cmd: tail -1 integration_test/contracts/wasm_first_set_block_height.txt env: FIRST_SET_BLOCK_HEIGHT # Get code id from first contract returned at first set height in forward order (0) - - cmd: seid q wasm list-code --count-total --limit 400 --height $FIRST_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[0].code_id" + - cmd: seid q wasm list-code --count-total --limit 400 --height $FIRST_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[3].code_id" env: FIRST_ID_FIRST_SET # Get creator from first contract returned at first set height in forward order - - cmd: seid q wasm list-code --count-total --limit 400 --height $FIRST_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[0].creator" + - cmd: seid q wasm list-code --count-total --limit 400 --height $FIRST_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[3].creator" env: FIRST_CREATOR_FIRST_SET # Get height from second set - cmd: tail -1 integration_test/contracts/wasm_second_set_block_height.txt env: SECOND_SET_BLOCK_HEIGHT # Get code id from first contract returned at second set height in reverse order (200) - - cmd: seid q wasm list-code --reverse --count-total --limit 400 --height $SECOND_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[0].code_id" + - cmd: seid q wasm list-code --reverse --count-total --limit 400 --height $SECOND_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[3].code_id" env: SECOND_ID_FIRST_SET # Get creator from second contract returned at second set height in reverse order - - cmd: seid q wasm list-code --reverse --count-total --limit 400 --height $SECOND_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[0].creator" + - cmd: seid q wasm list-code --reverse --count-total --limit 400 --height $SECOND_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[3].creator" env: FIRST_CREATOR_SECOND_SET # Get creator id - cmd: tail -1 integration_test/contracts/wasm_creator_id.txt @@ -85,9 +85,9 @@ # Verify correct code ids # NOTE: Since chain is continually running / stateful, may have remove - type: eval - expr: FIRST_ID_FIRST_SET == 1 + expr: FIRST_ID_FIRST_SET == 4 - type: eval - expr: SECOND_ID_FIRST_SET == 20 + expr: SECOND_ID_FIRST_SET == 19 - name: Test state store iteration through tokenfactory denoms inputs: diff --git a/occ_tests/messages/test_msgs.go b/occ_tests/messages/test_msgs.go index 0a7f88536..a9f3c2d2a 100644 --- a/occ_tests/messages/test_msgs.go +++ b/occ_tests/messages/test_msgs.go @@ -2,13 +2,17 @@ package messages import ( "fmt" + "math/big" "github.com/CosmWasm/wasmd/x/wasm" - sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/sei-protocol/sei-chain/occ_tests/utils" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" ) const instantiateMsg = `{"whitelist": ["sei1h9yjz89tl0dl6zu65dpxcqnxfhq60wxx8s5kag"], @@ -34,38 +38,98 @@ const instantiateMsg = `{"whitelist": ["sei1h9yjz89tl0dl6zu65dpxcqnxfhq60wxx8s5k "maintenance":"0.06" }}` -func WasmInstantiate(tCtx *utils.TestContext, count int) []sdk.Msg { - var msgs []sdk.Msg +func WasmInstantiate(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage for i := 0; i < count; i++ { - msgs = append(msgs, &wasm.MsgInstantiateContract{ - Sender: tCtx.TestAccounts[0].AccountAddress.String(), - Admin: tCtx.TestAccounts[1].AccountAddress.String(), - CodeID: tCtx.CodeID, - Label: fmt.Sprintf("test-%d", i), - Msg: []byte(instantiateMsg), - Funds: utils.Funds(100000), + msgs = append(msgs, &utils.TestMessage{ + Msg: &wasm.MsgInstantiateContract{ + Sender: tCtx.TestAccounts[0].AccountAddress.String(), + Admin: tCtx.TestAccounts[1].AccountAddress.String(), + CodeID: tCtx.CodeID, + Label: fmt.Sprintf("test-%d", i), + Msg: []byte(instantiateMsg), + Funds: utils.Funds(100000), + }, + Type: "WasmInstantitate", }) } return msgs } -func BankTransfer(tCtx *utils.TestContext, count int) []sdk.Msg { - var msgs []sdk.Msg +// EVMTransferNonConflicting generates a list of EVM transfer messages that do not conflict with each other +// each message will have a brand new address +func EVMTransferNonConflicting(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage for i := 0; i < count; i++ { - msgs = append(msgs, banktypes.NewMsgSend(tCtx.TestAccounts[0].AccountAddress, tCtx.TestAccounts[1].AccountAddress, utils.Funds(int64(i+1)))) + testAcct := utils.NewSigner() + msgs = append(msgs, evmTransfer(testAcct, testAcct.EvmAddress, "EVMTransferNonConflicting")) } return msgs } -func GovernanceSubmitProposal(tCtx *utils.TestContext, count int) []sdk.Msg { - var msgs []sdk.Msg +// EVMTransferConflicting generates a list of EVM transfer messages to the same address +func EVMTransferConflicting(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage + for i := 0; i < count; i++ { + testAcct := utils.NewSigner() + msgs = append(msgs, evmTransfer(testAcct, tCtx.TestAccounts[0].EvmAddress, "EVMTransferConflicting")) + } + return msgs +} + +// EVMTransferNonConflicting generates a list of EVM transfer messages that do not conflict with each other +// each message will have a brand new address +func evmTransfer(testAcct utils.TestAcct, to common.Address, scenario string) *utils.TestMessage { + signedTx, err := ethtypes.SignTx(ethtypes.NewTx(ðtypes.DynamicFeeTx{ + GasFeeCap: new(big.Int).SetUint64(1000000000000), + GasTipCap: new(big.Int).SetUint64(1000000000000), + Gas: 21000, + ChainID: big.NewInt(1), + To: &to, + Value: big.NewInt(1), + Nonce: 0, + }), testAcct.EvmSigner, testAcct.EvmPrivateKey) + + if err != nil { + panic(err) + } + + txData, err := ethtx.NewTxDataFromTx(signedTx) + if err != nil { + panic(err) + } + + msg, err := types.NewMsgEVMTransaction(txData) + if err != nil { + panic(err) + } + + return &utils.TestMessage{ + Msg: msg, + IsEVM: true, + EVMSigner: testAcct, + Type: scenario, + } +} + +func BankTransfer(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage + for i := 0; i < count; i++ { + msg := banktypes.NewMsgSend(tCtx.TestAccounts[0].AccountAddress, tCtx.TestAccounts[1].AccountAddress, utils.Funds(int64(i+1))) + msgs = append(msgs, &utils.TestMessage{Msg: msg, Type: "BankTransfer"}) + } + return msgs +} + +func GovernanceSubmitProposal(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage for i := 0; i < count; i++ { content := govtypes.NewTextProposal(fmt.Sprintf("Proposal %d", i), "test", true) mp, err := govtypes.NewMsgSubmitProposalWithExpedite(content, utils.Funds(10000), tCtx.TestAccounts[0].AccountAddress, true) if err != nil { panic(err) } - msgs = append(msgs, mp) + msgs = append(msgs, &utils.TestMessage{Msg: mp, Type: "GovernanceSubmitProposal"}) } return msgs } diff --git a/occ_tests/occ_test.go b/occ_tests/occ_test.go index 91b034ea8..ff5cb3c0c 100644 --- a/occ_tests/occ_test.go +++ b/occ_tests/occ_test.go @@ -106,12 +106,12 @@ func TestParallelTransactions(t *testing.T) { runs int shuffle bool before func(tCtx *utils.TestContext) - txs func(tCtx *utils.TestContext) []sdk.Msg + txs func(tCtx *utils.TestContext) []*utils.TestMessage }{ { name: "Test wasm instantiations", runs: runs, - txs: func(tCtx *utils.TestContext) []sdk.Msg { + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { return utils.JoinMsgs( messages.WasmInstantiate(tCtx, 10), ) @@ -120,7 +120,7 @@ func TestParallelTransactions(t *testing.T) { { name: "Test bank transfer", runs: runs, - txs: func(tCtx *utils.TestContext) []sdk.Msg { + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { return utils.JoinMsgs( messages.BankTransfer(tCtx, 2), ) @@ -129,21 +129,41 @@ func TestParallelTransactions(t *testing.T) { { name: "Test governance proposal", runs: runs, - txs: func(tCtx *utils.TestContext) []sdk.Msg { + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { return utils.JoinMsgs( messages.GovernanceSubmitProposal(tCtx, 10), ) }, }, + { + name: "Test evm transfers non-conflicting", + runs: runs, + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { + return utils.JoinMsgs( + messages.EVMTransferNonConflicting(tCtx, 10), + ) + }, + }, + { + name: "Test evm transfers conflicting", + runs: runs, + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { + return utils.JoinMsgs( + messages.EVMTransferConflicting(tCtx, 10), + ) + }, + }, { name: "Test combinations", runs: runs, shuffle: true, - txs: func(tCtx *utils.TestContext) []sdk.Msg { + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { return utils.JoinMsgs( messages.WasmInstantiate(tCtx, 10), messages.BankTransfer(tCtx, 10), messages.GovernanceSubmitProposal(tCtx, 10), + messages.EVMTransferConflicting(tCtx, 10), + messages.EVMTransferNonConflicting(tCtx, 10), ) }, }, @@ -178,8 +198,8 @@ func TestParallelTransactions(t *testing.T) { require.NoError(t, pErr, tt.name) require.Len(t, pResults, len(txs)) - assertEqualEvents(t, sEvts, pEvts, tt.name) assertExecTxResultCode(t, sResults, pResults, 0, tt.name) + assertEqualEvents(t, sEvts, pEvts, tt.name) assertEqualExecTxResults(t, sResults, pResults, tt.name) assertEqualState(t, sCtx.Ctx, pCtx.Ctx, tt.name) } diff --git a/occ_tests/utils/utils.go b/occ_tests/utils/utils.go index 7b671ed80..4b20702ef 100644 --- a/occ_tests/utils/utils.go +++ b/occ_tests/utils/utils.go @@ -2,6 +2,9 @@ package utils import ( "context" + "crypto/ecdsa" + "encoding/hex" + "math/big" "math/rand" "os" "testing" @@ -20,14 +23,19 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx/signing" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/cosmos/cosmos-sdk/x/auth/tx" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/sei-protocol/sei-chain/app" + utils2 "github.com/sei-protocol/sei-chain/utils" dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" dextypes "github.com/sei-protocol/sei-chain/x/dex/types" dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" + types2 "github.com/sei-protocol/sei-chain/x/evm/types" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" ) @@ -38,6 +46,13 @@ var ignoredStoreKeys = map[string]struct{}{ "deferredcache": {}, } +type TestMessage struct { + Msg sdk.Msg + Type string + EVMSigner TestAcct + IsEVM bool +} + type TestContext struct { Ctx sdk.Context CodeID uint64 @@ -52,6 +67,9 @@ type TestAcct struct { AccountAddress sdk.AccAddress PrivateKey cryptotypes.PrivKey PublicKey cryptotypes.PubKey + EvmAddress common.Address + EvmSigner ethtypes.Signer + EvmPrivateKey *ecdsa.PrivateKey } func NewTestAccounts(count int) []TestAcct { @@ -66,11 +84,20 @@ func NewSigner() TestAcct { priv1, pubKey, acct := testdata.KeyTestPubAddr() val := addressToValAddress(acct) + pvKeyHex := hex.EncodeToString(priv1.Bytes()) + key, _ := crypto.HexToECDSA(pvKeyHex) + ethCfg := types2.DefaultChainConfig().EthereumConfig(big.NewInt(1)) + signer := ethtypes.MakeSigner(ethCfg, utils2.Big1, 1) + address := crypto.PubkeyToAddress(key.PublicKey) + return TestAcct{ ValidatorAddress: val, AccountAddress: acct, PrivateKey: priv1, PublicKey: pubKey, + EvmAddress: address, + EvmSigner: signer, + EvmPrivateKey: key, } } @@ -130,14 +157,15 @@ func NewTestContext(t *testing.T, testAccts []TestAcct, blockTime time.Time, wor } } -func toTxBytes(testCtx *TestContext, msgs []sdk.Msg) [][]byte { +func toTxBytes(testCtx *TestContext, msgs []*TestMessage) [][]byte { txs := make([][]byte, 0, len(msgs)) tc := app.MakeEncodingConfig().TxConfig priv := testCtx.TestAccounts[0].PrivateKey acct := testCtx.TestApp.AccountKeeper.GetAccount(testCtx.Ctx, testCtx.TestAccounts[0].AccountAddress) - for _, m := range msgs { + for _, tm := range msgs { + m := tm.Msg a, err := codectypes.NewAnyWithValue(m) if err != nil { panic(err) @@ -157,6 +185,25 @@ func toTxBytes(testCtx *TestContext, msgs []sdk.Msg) [][]byte { }, }) + if tm.IsEVM { + amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000000000000000000)), sdk.NewCoin("uusdc", sdk.NewInt(1000000000000000))) + + // fund account so it has funds + if err := testCtx.TestApp.BankKeeper.MintCoins(testCtx.Ctx, minttypes.ModuleName, amounts); err != nil { + panic(err) + } + if err := testCtx.TestApp.BankKeeper.SendCoinsFromModuleToAccount(testCtx.Ctx, minttypes.ModuleName, tm.EVMSigner.AccountAddress, amounts); err != nil { + panic(err) + } + + b, err := tc.TxEncoder()(tBuilder.GetTx()) + if err != nil { + panic(err) + } + txs = append(txs, b) + continue + } + err = tBuilder.SetSignatures(signing.SignatureV2{ PubKey: priv.PubKey(), Data: &signing.SingleSignatureData{ @@ -202,16 +249,16 @@ func toTxBytes(testCtx *TestContext, msgs []sdk.Msg) [][]byte { } // RunWithOCC runs the given messages with OCC enabled, number of workers is configured via context -func RunWithOCC(testCtx *TestContext, msgs []sdk.Msg) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { +func RunWithOCC(testCtx *TestContext, msgs []*TestMessage) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { return runTxs(testCtx, msgs, true) } // RunWithoutOCC runs the given messages without OCC enabled -func RunWithoutOCC(testCtx *TestContext, msgs []sdk.Msg) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { +func RunWithoutOCC(testCtx *TestContext, msgs []*TestMessage) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { return runTxs(testCtx, msgs, false) } -func runTxs(testCtx *TestContext, msgs []sdk.Msg, occ bool) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { +func runTxs(testCtx *TestContext, msgs []*TestMessage, occ bool) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { app.EnableOCC = occ txs := toTxBytes(testCtx, msgs) req := &types.RequestFinalizeBlock{ @@ -222,16 +269,16 @@ func runTxs(testCtx *TestContext, msgs []sdk.Msg, occ bool) ([]types.Event, []*t return testCtx.TestApp.ProcessBlock(testCtx.Ctx, txs, req, req.DecidedLastCommit) } -func JoinMsgs(msgsList ...[]sdk.Msg) []sdk.Msg { - var result []sdk.Msg - for _, msgs := range msgsList { - result = append(result, msgs...) +func JoinMsgs(msgsList ...[]*TestMessage) []*TestMessage { + var result []*TestMessage + for _, testMsg := range msgsList { + result = append(result, testMsg...) } return result } -func Shuffle(msgs []sdk.Msg) []sdk.Msg { - result := make([]sdk.Msg, 0, len(msgs)) +func Shuffle(msgs []*TestMessage) []*TestMessage { + result := make([]*TestMessage, 0, len(msgs)) for _, i := range rand.Perm(len(msgs)) { result = append(result, msgs[i]) } diff --git a/precompiles/addr/addr.go b/precompiles/addr/addr.go index ac1c80513..f78a33453 100644 --- a/precompiles/addr/addr.go +++ b/precompiles/addr/addr.go @@ -70,12 +70,15 @@ func NewPrecompile(evmKeeper pcommon.EVMKeeper) (*Precompile, error) { // RequiredGas returns the required bare minimum gas to execute the precompile. func (p Precompile) RequiredGas(input []byte) uint64 { - methodID := input[:4] + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } method, err := p.ABI.MethodById(methodID) if err != nil { // This should never happen since this method is going to fail during Run - return 0 + return pcommon.UnknownMethodCallGas } return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) @@ -85,7 +88,7 @@ func (p Precompile) Address() common.Address { return p.address } -func (p Precompile) Run(evm *vm.EVM, _ common.Address, input []byte, value *big.Int) (bz []byte, err error) { +func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err @@ -101,16 +104,31 @@ func (p Precompile) Run(evm *vm.EVM, _ common.Address, input []byte, value *big. } func (p Precompile) getSeiAddr(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 1) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + seiAddrStr := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[0].(common.Address)).String() return method.Outputs.Pack(seiAddrStr) } func (p Precompile) getEvmAddr(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 1) - evmAddr := p.evmKeeper.GetEVMAddressFromBech32OrDefault(ctx, args[0].(string)) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + + evmAddr, err := p.evmKeeper.GetEVMAddressFromBech32OrDefault(ctx, args[0].(string)) + if err != nil { + return nil, err + } return method.Outputs.Pack(evmAddr) } diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index 9d312d178..9fff25eed 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -101,12 +101,15 @@ func NewPrecompile(bankKeeper pcommon.BankKeeper, evmKeeper pcommon.EVMKeeper) ( // RequiredGas returns the required bare minimum gas to execute the precompile. func (p Precompile) RequiredGas(input []byte) uint64 { - methodID := input[:4] + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } method, err := p.ABI.MethodById(methodID) if err != nil { // This should never happen since this method is going to fail during Run - return 0 + return pcommon.UnknownMethodCallGas } return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) @@ -116,7 +119,7 @@ func (p Precompile) Address() common.Address { return p.address } -func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value *big.Int) (bz []byte, err error) { +func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err @@ -124,13 +127,9 @@ func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value switch method.Name { case SendMethod: - if err := p.validateCaller(ctx, caller); err != nil { - return nil, err - } - return p.send(ctx, method, args, value) + return p.send(ctx, caller, method, args, value, readOnly) case SendNativeMethod: - // TODO: Add validation on caller separate from validation above - return p.sendNative(ctx, method, args, caller, value) + return p.sendNative(ctx, method, args, caller, callingContract, value, readOnly) case BalanceMethod: return p.balance(ctx, method, args, value) case NameMethod: @@ -145,21 +144,25 @@ func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value return } -func (p Precompile) validateCaller(ctx sdk.Context, caller common.Address) error { - codeHash := p.evmKeeper.GetCodeHash(ctx, caller) - if p.evmKeeper.IsCodeHashWhitelistedForBankSend(ctx, codeHash) { - return nil +func (p Precompile) send(ctx sdk.Context, caller common.Address, method *abi.Method, args []interface{}, value *big.Int, readOnly bool) ([]byte, error) { + if readOnly { + return nil, errors.New("cannot call send from staticcall") + } + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err } - return fmt.Errorf("caller %s with code hash %s is not whitelisted for arbitrary bank send", caller.Hex(), codeHash.Hex()) -} -func (p Precompile) send(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 4) + if err := pcommon.ValidateArgsLength(args, 4); err != nil { + return nil, err + } denom := args[2].(string) if denom == "" { return nil, errors.New("invalid denom") } + pointer, _, exists := p.evmKeeper.GetERC20NativePointer(ctx, denom) + if !exists || pointer.Cmp(caller) != 0 { + return nil, fmt.Errorf("only pointer %s can send %s but got %s", pointer.Hex(), denom, caller.Hex()) + } amount := args[3].(*big.Int) if amount.Cmp(utils.Big0) == 0 { // short circuit @@ -182,8 +185,16 @@ func (p Precompile) send(ctx sdk.Context, method *abi.Method, args []interface{} return method.Outputs.Pack(true) } -func (p Precompile) sendNative(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address, value *big.Int) ([]byte, error) { - pcommon.AssertArgsLength(args, 1) +func (p Precompile) sendNative(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address, callingContract common.Address, value *big.Int, readOnly bool) ([]byte, error) { + if readOnly { + return nil, errors.New("cannot call sendNative from staticcall") + } + if caller.Cmp(callingContract) != 0 { + return nil, errors.New("cannot delegatecall sendNative") + } + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } if value == nil || value.Sign() == 0 { return nil, errors.New("set `value` field to non-zero to send") } @@ -234,7 +245,11 @@ func (p Precompile) sendNative(ctx sdk.Context, method *abi.Method, args []inter hooks.OnBalanceChange(caller, oldBalance, newBalance, tracing.BalanceChangeTransfer) // Receiver received wei from the sender address - evmReceiverAddr := p.evmKeeper.GetEVMAddressFromBech32OrDefault(ctx, receiverAddr) + evmReceiverAddr, err := p.evmKeeper.GetEVMAddressFromBech32OrDefault(ctx, receiverAddr) + if err != nil { + panic(fmt.Errorf("failed to get evm address from bech32, this shouldn't happen because SendCoinsAndWei worked: %w", err)) + } + newBalance = p.bankKeeper.GetWeiBalance(ctx, receiverSeiAddr).BigInt() oldBalance = new(big.Int).Sub(newBalance, wei.BigInt()) @@ -245,8 +260,13 @@ func (p Precompile) sendNative(ctx sdk.Context, method *abi.Method, args []inter } func (p Precompile) balance(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 2) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } addr, err := p.accAddressFromArg(ctx, args[0]) if err != nil { @@ -261,8 +281,13 @@ func (p Precompile) balance(ctx sdk.Context, method *abi.Method, args []interfac } func (p Precompile) name(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 1) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } denom := args[0].(string) metadata, found := p.bankKeeper.GetDenomMetaData(ctx, denom) @@ -273,8 +298,13 @@ func (p Precompile) name(ctx sdk.Context, method *abi.Method, args []interface{} } func (p Precompile) symbol(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 1) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } denom := args[0].(string) metadata, found := p.bankKeeper.GetDenomMetaData(ctx, denom) @@ -285,14 +315,22 @@ func (p Precompile) symbol(ctx sdk.Context, method *abi.Method, args []interface } func (p Precompile) decimals(_ sdk.Context, method *abi.Method, _ []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - // all native tokens are integer-based + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + // all native tokens are integer-based, returns decimals for microdenom (usei) return method.Outputs.Pack(uint8(0)) } func (p Precompile) totalSupply(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 1) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } denom := args[0].(string) coin := p.bankKeeper.GetSupply(ctx, denom) diff --git a/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go index 6ac3454f6..c4a16dd8b 100644 --- a/precompiles/bank/bank_test.go +++ b/precompiles/bank/bank_test.go @@ -2,7 +2,9 @@ package bank_test import ( "encoding/hex" + "fmt" "math/big" + "strings" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -53,7 +55,7 @@ func TestRun(t *testing.T) { require.Nil(t, err) args, err := send.Inputs.Pack(senderEVMAddr, evmAddr, "usei", big.NewInt(25)) require.Nil(t, err) - _, err = p.Run(&evm, senderEVMAddr, append(p.SendID, args...), nil) // should error because address is not whitelisted + _, err = p.Run(&evm, senderEVMAddr, senderEVMAddr, append(p.SendID, args...), nil, false) // should error because address is not whitelisted require.NotNil(t, err) // Precompile sendNative test error @@ -63,19 +65,19 @@ func TestRun(t *testing.T) { argsNativeError, err := sendNative.Inputs.Pack(seiAddrString) require.Nil(t, err) // 0 amount disallowed - _, err = p.Run(&evm, senderEVMAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(0)) + _, err = p.Run(&evm, senderEVMAddr, senderEVMAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(0), false) require.NotNil(t, err) argsNativeError, err = sendNative.Inputs.Pack("") require.Nil(t, err) - _, err = p.Run(&evm, senderEVMAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(100)) + _, err = p.Run(&evm, senderEVMAddr, senderEVMAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(100), false) require.NotNil(t, err) argsNativeError, err = sendNative.Inputs.Pack("invalidaddr") require.Nil(t, err) - _, err = p.Run(&evm, senderEVMAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(100)) + _, err = p.Run(&evm, senderEVMAddr, senderEVMAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(100), false) require.NotNil(t, err) argsNativeError, err = sendNative.Inputs.Pack(senderAddr.String()) require.Nil(t, err) - _, err = p.Run(&evm, evmAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(100)) + _, err = p.Run(&evm, evmAddr, evmAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(100), false) require.NotNil(t, err) // Send native 10_000_000_000_100, split into 10 usei 100wei @@ -106,18 +108,54 @@ func TestRun(t *testing.T) { req, err := types.NewMsgEVMTransaction(txwrapper) require.Nil(t, err) + // send the transaction msgServer := keeper.NewMsgServerImpl(k) ante.Preprocess(ctx, req) + ctx = ctx.WithEventManager(sdk.NewEventManager()) res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) require.Nil(t, err) require.Empty(t, res.VmError) + evts := ctx.EventManager().ABCIEvents() + + for _, evt := range evts { + var lines []string + for _, attr := range evt.Attributes { + lines = append(lines, fmt.Sprintf("%s=%s", string(attr.Key), string(attr.Value))) + } + fmt.Printf("type=%s\t%s\n", evt.Type, strings.Join(lines, "\t")) + } + + var expectedEvts sdk.Events = []sdk.Event{ + // gas is sent from sender + banktypes.NewCoinSpentEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(2)))), + // sender sends coin to the receiver + banktypes.NewCoinSpentEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))), + banktypes.NewCoinReceivedEvent(seiAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))), + sdk.NewEvent( + banktypes.EventTypeTransfer, + sdk.NewAttribute(banktypes.AttributeKeyRecipient, seiAddr.String()), + sdk.NewAttribute(banktypes.AttributeKeySender, senderAddr.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, sdk.NewCoin("usei", sdk.NewInt(10)).String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(banktypes.AttributeKeySender, senderAddr.String()), + ), + // gas refund to the sender + banktypes.NewCoinReceivedEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1)))), + // tip is paid to the validator + banktypes.NewCoinReceivedEvent(sdk.MustAccAddressFromBech32("sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqqlve8dv"), sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(0)))), + } + + require.EqualValues(t, expectedEvts.ToABCIEvents(), evts) + // Use precompile balance to verify sendNative usei amount succeeded balance, err := p.ABI.MethodById(p.BalanceID) require.Nil(t, err) args, err = balance.Inputs.Pack(evmAddr, "usei") require.Nil(t, err) - precompileRes, err := p.Run(&evm, common.Address{}, append(p.BalanceID, args...), nil) + precompileRes, err := p.Run(&evm, common.Address{}, common.Address{}, append(p.BalanceID, args...), nil, false) require.Nil(t, err) is, err := balance.Outputs.Unpack(precompileRes) require.Nil(t, err) @@ -127,15 +165,15 @@ func TestRun(t *testing.T) { require.Equal(t, big.NewInt(100), weiBalance.BigInt()) // Verify errors properly raised on bank balance calls with incorrect inputs - _, err = p.Run(&evm, common.Address{}, append(p.BalanceID, args[:1]...), nil) + _, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.BalanceID, args[:1]...), nil, false) require.NotNil(t, err) args, err = balance.Inputs.Pack(evmAddr, "") require.Nil(t, err) - _, err = p.Run(&evm, common.Address{}, append(p.BalanceID, args...), nil) + _, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.BalanceID, args...), nil, false) require.NotNil(t, err) // invalid input - _, err = p.Run(&evm, common.Address{}, []byte{1, 2, 3, 4}, nil) + _, err = p.Run(&evm, common.Address{}, common.Address{}, []byte{1, 2, 3, 4}, nil, false) require.NotNil(t, err) } @@ -152,7 +190,7 @@ func TestMetadata(t *testing.T) { require.Nil(t, err) args, err := name.Inputs.Pack("usei") require.Nil(t, err) - res, err := p.Run(&evm, common.Address{}, append(p.NameID, args...), nil) + res, err := p.Run(&evm, common.Address{}, common.Address{}, append(p.NameID, args...), nil, false) require.Nil(t, err) outputs, err := name.Outputs.Unpack(res) require.Nil(t, err) @@ -162,7 +200,7 @@ func TestMetadata(t *testing.T) { require.Nil(t, err) args, err = symbol.Inputs.Pack("usei") require.Nil(t, err) - res, err = p.Run(&evm, common.Address{}, append(p.SymbolID, args...), nil) + res, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.SymbolID, args...), nil, false) require.Nil(t, err) outputs, err = symbol.Outputs.Unpack(res) require.Nil(t, err) @@ -172,7 +210,7 @@ func TestMetadata(t *testing.T) { require.Nil(t, err) args, err = decimal.Inputs.Pack("usei") require.Nil(t, err) - res, err = p.Run(&evm, common.Address{}, append(p.DecimalsID, args...), nil) + res, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.DecimalsID, args...), nil, false) require.Nil(t, err) outputs, err = decimal.Outputs.Unpack(res) require.Nil(t, err) @@ -182,7 +220,7 @@ func TestMetadata(t *testing.T) { require.Nil(t, err) args, err = supply.Inputs.Pack("usei") require.Nil(t, err) - res, err = p.Run(&evm, common.Address{}, append(p.SupplyID, args...), nil) + res, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.SupplyID, args...), nil, false) require.Nil(t, err) outputs, err = supply.Outputs.Unpack(res) require.Nil(t, err) @@ -196,7 +234,7 @@ func TestRequiredGas(t *testing.T) { balanceRequiredGas := p.RequiredGas(p.BalanceID) require.Equal(t, uint64(1000), balanceRequiredGas) // invalid method - require.Equal(t, uint64(0), p.RequiredGas([]byte{1, 1, 1, 1})) + require.Equal(t, uint64(3000), p.RequiredGas([]byte{1, 1, 1, 1})) } func TestAddress(t *testing.T) { diff --git a/precompiles/common/expected_keepers.go b/precompiles/common/expected_keepers.go index f1ec4cfa5..f0525a1b2 100644 --- a/precompiles/common/expected_keepers.go +++ b/precompiles/common/expected_keepers.go @@ -25,12 +25,16 @@ type EVMKeeper interface { GetSeiAddress(sdk.Context, common.Address) (sdk.AccAddress, bool) GetSeiAddressOrDefault(ctx sdk.Context, evmAddress common.Address) sdk.AccAddress GetEVMAddress(sdk.Context, sdk.AccAddress) (common.Address, bool) - GetEVMAddressFromBech32OrDefault(ctx sdk.Context, seiAddress string) common.Address + GetEVMAddressFromBech32OrDefault(ctx sdk.Context, seiAddress string) (common.Address, error) GetCodeHash(sdk.Context, common.Address) common.Hash - IsCodeHashWhitelistedForDelegateCall(ctx sdk.Context, h common.Hash) bool - IsCodeHashWhitelistedForBankSend(ctx sdk.Context, h common.Hash) bool GetPriorityNormalizer(ctx sdk.Context) sdk.Dec GetBaseDenom(ctx sdk.Context) string + SetERC20NativePointer(ctx sdk.Context, token string, addr common.Address) error + GetERC20NativePointer(ctx sdk.Context, token string) (addr common.Address, version uint16, exists bool) + SetERC20CW20Pointer(ctx sdk.Context, cw20Address string, addr common.Address) error + GetERC20CW20Pointer(ctx sdk.Context, cw20Address string) (addr common.Address, version uint16, exists bool) + SetERC721CW721Pointer(ctx sdk.Context, cw721Address string, addr common.Address) error + GetERC721CW721Pointer(ctx sdk.Context, cw721Address string) (addr common.Address, version uint16, exists bool) } type OracleKeeper interface { diff --git a/precompiles/common/precompiles.go b/precompiles/common/precompiles.go index 6cdc89216..5a38be8d9 100644 --- a/precompiles/common/precompiles.go +++ b/precompiles/common/precompiles.go @@ -8,11 +8,12 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/sei-protocol/sei-chain/x/evm/state" ) +const UnknownMethodCallGas uint64 = 3000 + type Contexter interface { Ctx() sdk.Context } @@ -36,7 +37,10 @@ func (p Precompile) Prepare(evm *vm.EVM, input []byte) (sdk.Context, *abi.Method if !ok { return sdk.Context{}, nil, nil, errors.New("cannot get context from EVM") } - methodID := input[:4] + methodID, err := ExtractMethodID(input) + if err != nil { + return sdk.Context{}, nil, nil, err + } method, err := p.ABI.MethodById(methodID) if err != nil { return sdk.Context{}, nil, nil, err @@ -51,16 +55,20 @@ func (p Precompile) Prepare(evm *vm.EVM, input []byte) (sdk.Context, *abi.Method return ctxer.Ctx(), method, args, nil } -func AssertArgsLength(args []interface{}, length int) { +func ValidateArgsLength(args []interface{}, length int) error { if len(args) != length { - panic(fmt.Sprintf("expected %d arguments but got %d", length, len(args))) + return fmt.Errorf("expected %d arguments but got %d", length, len(args)) } + + return nil } -func AssertNonPayable(value *big.Int) { +func ValidateNonPayable(value *big.Int) error { if value != nil && value.Sign() != 0 { - panic("sending funds to a non-payable function") + return errors.New("sending funds to a non-payable function") } + + return nil } func HandlePaymentUsei(ctx sdk.Context, precompileAddr sdk.AccAddress, payer sdk.AccAddress, value *big.Int, bankKeeper BankKeeper) (sdk.Coin, error) { @@ -70,7 +78,8 @@ func HandlePaymentUsei(ctx sdk.Context, precompileAddr sdk.AccAddress, payer sdk } coin := sdk.NewCoin(sdk.MustGetBaseDenom(), usei) // refund payer because the following precompile logic will debit the payments from payer's account - if err := bankKeeper.SendCoins(ctx, precompileAddr, payer, sdk.NewCoins(coin)); err != nil { + // this creates a new event manager to avoid surfacing these as cosmos events + if err := bankKeeper.SendCoins(ctx.WithEventManager(sdk.NewEventManager()), precompileAddr, payer, sdk.NewCoins(coin)); err != nil { return sdk.Coin{}, err } return coin, nil @@ -79,26 +88,28 @@ func HandlePaymentUsei(ctx sdk.Context, precompileAddr sdk.AccAddress, payer sdk func HandlePaymentUseiWei(ctx sdk.Context, precompileAddr sdk.AccAddress, payer sdk.AccAddress, value *big.Int, bankKeeper BankKeeper) (sdk.Int, sdk.Int, error) { usei, wei := state.SplitUseiWeiAmount(value) // refund payer because the following precompile logic will debit the payments from payer's account - if err := bankKeeper.SendCoinsAndWei(ctx, precompileAddr, payer, usei, wei); err != nil { + // this creates a new event manager to avoid surfacing these as cosmos events + if err := bankKeeper.SendCoinsAndWei(ctx.WithEventManager(sdk.NewEventManager()), precompileAddr, payer, usei, wei); err != nil { return sdk.Int{}, sdk.Int{}, err } return usei, wei, nil } +/* +* +sei gas = evm gas * multiplier +sei gas price = fee / sei gas = fee / (evm gas * multiplier) = evm gas / multiplier +*/ func GetRemainingGas(ctx sdk.Context, evmKeeper EVMKeeper) uint64 { gasMultipler := evmKeeper.GetPriorityNormalizer(ctx) seiGasRemaining := ctx.GasMeter().Limit() - ctx.GasMeter().GasConsumedToLimit() - return new(big.Int).Mul(new(big.Int).SetUint64(seiGasRemaining), gasMultipler.RoundInt().BigInt()).Uint64() + return sdk.NewDecFromInt(sdk.NewIntFromUint64(seiGasRemaining)).Quo(gasMultipler).TruncateInt().Uint64() } -func ValidateCaller(ctx sdk.Context, evmKeeper EVMKeeper, caller common.Address, callingContract common.Address) error { - if caller == callingContract { - // not a delegate call - return nil - } - codeHash := evmKeeper.GetCodeHash(ctx, callingContract) - if evmKeeper.IsCodeHashWhitelistedForDelegateCall(ctx, codeHash) { - return nil +func ExtractMethodID(input []byte) ([]byte, error) { + // Check if the input has at least the length needed for methodID + if len(input) < 4 { + return nil, errors.New("input too short to extract method ID") } - return fmt.Errorf("calling contract %s with code hash %s is not whitelisted for delegate calls", callingContract.Hex(), codeHash.Hex()) + return input[:4], nil } diff --git a/precompiles/common/precompiles_test.go b/precompiles/common/precompiles_test.go index f02caf1db..588039714 100644 --- a/precompiles/common/precompiles_test.go +++ b/precompiles/common/precompiles_test.go @@ -8,14 +8,20 @@ import ( "github.com/stretchr/testify/require" ) -func TestAssertArgsLength(t *testing.T) { - require.NotPanics(t, func() { common.AssertArgsLength(nil, 0) }) - require.NotPanics(t, func() { common.AssertArgsLength([]interface{}{1, ""}, 2) }) - require.Panics(t, func() { common.AssertArgsLength([]interface{}{""}, 2) }) +func TestValidateArgsLength(t *testing.T) { + err := common.ValidateArgsLength(nil, 0) + require.Nil(t, err) + err = common.ValidateArgsLength([]interface{}{1, ""}, 2) + require.Nil(t, err) + err = common.ValidateArgsLength([]interface{}{""}, 2) + require.NotNil(t, err) } -func TestAssertNonPayable(t *testing.T) { - require.NotPanics(t, func() { common.AssertNonPayable(nil) }) - require.NotPanics(t, func() { common.AssertNonPayable(big.NewInt(0)) }) - require.Panics(t, func() { common.AssertNonPayable(big.NewInt(1)) }) +func TestValidteNonPayable(t *testing.T) { + err := common.ValidateNonPayable(nil) + require.Nil(t, err) + err = common.ValidateNonPayable(big.NewInt(0)) + require.Nil(t, err) + err = common.ValidateNonPayable(big.NewInt(1)) + require.NotNil(t, err) } diff --git a/precompiles/distribution/distribution.go b/precompiles/distribution/distribution.go index 1465b1e7e..d93e5683c 100644 --- a/precompiles/distribution/distribution.go +++ b/precompiles/distribution/distribution.go @@ -76,25 +76,36 @@ func NewPrecompile(distrKeeper pcommon.DistributionKeeper, evmKeeper pcommon.EVM // RequiredGas returns the required bare minimum gas to execute the precompile. func (p Precompile) RequiredGas(input []byte) uint64 { - methodID := input[:4] + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } if bytes.Equal(methodID, p.SetWithdrawAddrID) { return 30000 } else if bytes.Equal(methodID, p.WithdrawDelegationRewardsID) { return 50000 } - panic("unknown method") + + // This should never happen since this is going to fail during Run + return pcommon.UnknownMethodCallGas } func (p Precompile) Address() common.Address { return p.address } -func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value *big.Int) (bz []byte, err error) { +func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + if readOnly { + return nil, errors.New("cannot call distr precompile from staticcall") + } ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err } + if caller.Cmp(callingContract) != 0 { + return nil, errors.New("cannot delegatecall distr") + } switch method.Name { case SetWithdrawAddressMethod: @@ -106,8 +117,13 @@ func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value } func (p Precompile) setWithdrawAddress(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 1) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } delegator := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) withdrawAddr, err := p.accAddressFromArg(ctx, args[0]) if err != nil { @@ -121,8 +137,13 @@ func (p Precompile) setWithdrawAddress(ctx sdk.Context, method *abi.Method, call } func (p Precompile) withdrawDelegationRewards(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 1) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } delegator := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) validator, err := sdk.ValAddressFromBech32(args[0].(string)) if err != nil { diff --git a/precompiles/gov/gov.go b/precompiles/gov/gov.go index ea372d21f..86ec7e3bd 100644 --- a/precompiles/gov/gov.go +++ b/precompiles/gov/gov.go @@ -79,25 +79,36 @@ func NewPrecompile(govKeeper pcommon.GovKeeper, evmKeeper pcommon.EVMKeeper, ban // RequiredGas returns the required bare minimum gas to execute the precompile. func (p Precompile) RequiredGas(input []byte) uint64 { - methodID := input[:4] + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } if bytes.Equal(methodID, p.VoteID) { return 30000 } else if bytes.Equal(methodID, p.DepositID) { return 30000 } - panic("unknown method") + + // This should never happen since this is going to fail during Run + return pcommon.UnknownMethodCallGas } func (p Precompile) Address() common.Address { return p.address } -func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value *big.Int) (bz []byte, err error) { +func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + if readOnly { + return nil, errors.New("cannot call gov precompile from staticcall") + } ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err } + if caller.Cmp(callingContract) != 0 { + return nil, errors.New("cannot delegatecall gov") + } switch method.Name { case VoteMethod: @@ -109,8 +120,13 @@ func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value } func (p Precompile) vote(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 2) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } voter := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) proposalID := args[0].(uint64) voteOption := args[1].(int32) @@ -122,7 +138,9 @@ func (p Precompile) vote(ctx sdk.Context, method *abi.Method, caller common.Addr } func (p Precompile) deposit(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertArgsLength(args, 1) + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } depositor := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) proposalID := args[0].(uint64) if value == nil || value.Sign() == 0 { diff --git a/precompiles/ibc/ibc.go b/precompiles/ibc/ibc.go index cbef49748..7fdb9f9d9 100644 --- a/precompiles/ibc/ibc.go +++ b/precompiles/ibc/ibc.go @@ -9,12 +9,13 @@ import ( "github.com/cosmos/cosmos-sdk/types/bech32" - "github.com/sei-protocol/sei-chain/precompiles/wasmd" + "github.com/sei-protocol/sei-chain/utils" sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" ) @@ -28,6 +29,7 @@ const ( ) var _ vm.PrecompiledContract = &Precompile{} +var _ vm.DynamicGasPrecompiledContract = &Precompile{} // Embed abi json file to the executable binary. Needed when importing as dependency. // @@ -78,30 +80,36 @@ func NewPrecompile(transferKeeper pcommon.TransferKeeper, evmKeeper pcommon.EVMK // RequiredGas returns the required bare minimum gas to execute the precompile. func (p Precompile) RequiredGas(input []byte) uint64 { - methodID := input[:4] + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } method, err := p.ABI.MethodById(methodID) if err != nil { // This should never happen since this method is going to fail during Run - return 0 + return pcommon.UnknownMethodCallGas } return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) } -func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int) (ret []byte, remainingGas uint64, err error) { +func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, _ *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if readOnly { + return nil, 0, errors.New("cannot call IBC precompile from staticcall") + } ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, 0, err } - if err = pcommon.ValidateCaller(ctx, p.evmKeeper, caller, callingContract); err != nil { - return nil, 0, err + if caller.Cmp(callingContract) != 0 { + return nil, 0, errors.New("cannot delegatecall IBC") } gasMultiplier := p.evmKeeper.GetPriorityNormalizer(ctx) - gasLimitBigInt := new(big.Int).Mul(new(big.Int).SetUint64(suppliedGas), gasMultiplier.RoundInt().BigInt()) - if gasLimitBigInt.Cmp(wasmd.MaxUint64BigInt) > 0 { - gasLimitBigInt = wasmd.MaxUint64BigInt + gasLimitBigInt := new(big.Int).Mul(new(big.Int).SetUint64(suppliedGas), gasMultiplier.TruncateInt().BigInt()) + if gasLimitBigInt.Cmp(utils.BigMaxU64) > 0 { + gasLimitBigInt = utils.BigMaxU64 } ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimitBigInt.Uint64())) @@ -112,7 +120,7 @@ func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, calli return } -func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value *big.Int) (bz []byte, err error) { +func (p Precompile) Run(*vm.EVM, common.Address, common.Address, []byte, *big.Int, bool) (bz []byte, err error) { panic("static gas Run is not implemented for dynamic gas precompile") } @@ -125,7 +133,11 @@ func (p Precompile) transfer(ctx sdk.Context, method *abi.Method, args []interfa return } }() - pcommon.AssertArgsLength(args, 8) + + if err := pcommon.ValidateArgsLength(args, 8); err != nil { + rerr = err + return + } senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) if !ok { rerr = errors.New("caller is not a valid SEI address") diff --git a/precompiles/ibc/ibc_test.go b/precompiles/ibc/ibc_test.go index f408a40ee..12579cc99 100644 --- a/precompiles/ibc/ibc_test.go +++ b/precompiles/ibc/ibc_test.go @@ -2,6 +2,10 @@ package ibc_test import ( "errors" + "math/big" + "reflect" + "testing" + sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" "github.com/ethereum/go-ethereum/common" @@ -12,9 +16,6 @@ import ( "github.com/sei-protocol/sei-chain/x/evm/state" "github.com/stretchr/testify/require" tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" - "math/big" - "reflect" - "testing" ) type MockTransferKeeper struct{} @@ -109,7 +110,7 @@ func TestPrecompile_Run(t *testing.T) { args: args{caller: senderEvmAddress, callingContract: common.Address{}, input: commonArgs.input, suppliedGas: 1000000, value: nil}, wantBz: nil, wantErr: true, - wantErrMsg: "calling contract 0x0000000000000000000000000000000000000000 with code hash 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is not whitelisted for delegate calls", + wantErrMsg: "cannot delegatecall IBC", }, { name: "failed transfer: empty sourcePort", @@ -222,7 +223,7 @@ func TestPrecompile_Run(t *testing.T) { tt.args.input.sourcePort, tt.args.input.sourceChannel, tt.args.input.denom, tt.args.input.amount, tt.args.input.revisionNumber, tt.args.input.revisionHeight, tt.args.input.timeoutTimestamp) require.Nil(t, err) - gotBz, gotRemainingGas, err := p.RunAndCalculateGas(&evm, tt.args.caller, tt.args.callingContract, append(p.TransferID, inputs...), tt.args.suppliedGas, tt.args.value) + gotBz, gotRemainingGas, err := p.RunAndCalculateGas(&evm, tt.args.caller, tt.args.callingContract, append(p.TransferID, inputs...), tt.args.suppliedGas, tt.args.value, nil, false) if (err != nil) != tt.wantErr { t.Errorf("Run() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/precompiles/json/json.go b/precompiles/json/json.go index 1a3d5eb4c..3712bc292 100644 --- a/precompiles/json/json.go +++ b/precompiles/json/json.go @@ -4,6 +4,7 @@ import ( "bytes" "embed" gjson "encoding/json" + "errors" "fmt" "math/big" "strings" @@ -73,6 +74,9 @@ func NewPrecompile() (*Precompile, error) { // RequiredGas returns the required bare minimum gas to execute the precompile. func (p Precompile) RequiredGas(input []byte) uint64 { + if len(input) < 4 { + return pcommon.UnknownMethodCallGas + } return uint64(GasCostPerByte * (len(input) - 4)) } @@ -84,7 +88,7 @@ func (p Precompile) Address() common.Address { return p.address } -func (p Precompile) Run(evm *vm.EVM, _ common.Address, input []byte, value *big.Int) (bz []byte, err error) { +func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err @@ -101,6 +105,11 @@ func (p Precompile) Run(evm *vm.EVM, _ common.Address, input []byte, value *big. if err != nil { return nil, err } + + if uint_.BitLen() > 256 { + return nil, errors.New("value does not fit in 32 bytes") + } + uint_.FillBytes(byteArr) return byteArr, nil } @@ -108,8 +117,13 @@ func (p Precompile) Run(evm *vm.EVM, _ common.Address, input []byte, value *big. } func (p Precompile) extractAsBytes(_ sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 2) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } // type assertion will always succeed because it's already validated in p.Prepare call in Run() bz := args[0].([]byte) @@ -131,12 +145,17 @@ func (p Precompile) extractAsBytes(_ sdk.Context, method *abi.Method, args []int } func (p Precompile) extractAsBytesList(_ sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 2) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } // type assertion will always succeed because it's already validated in p.Prepare call in Run() bz := args[0].([]byte) - decoded := map[string][]gjson.RawMessage{} + decoded := map[string]gjson.RawMessage{} if err := gjson.Unmarshal(bz, &decoded); err != nil { return nil, err } @@ -145,13 +164,22 @@ func (p Precompile) extractAsBytesList(_ sdk.Context, method *abi.Method, args [ if !ok { return nil, fmt.Errorf("input does not contain key %s", key) } + decodedResult := []gjson.RawMessage{} + if err := gjson.Unmarshal(result, &decodedResult); err != nil { + return nil, err + } - return method.Outputs.Pack(utils.Map(result, func(r gjson.RawMessage) []byte { return []byte(r) })) + return method.Outputs.Pack(utils.Map(decodedResult, func(r gjson.RawMessage) []byte { return []byte(r) })) } func (p Precompile) ExtractAsUint256(_ sdk.Context, _ *abi.Method, args []interface{}, value *big.Int) (*big.Int, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 2) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } // type assertion will always succeed because it's already validated in p.Prepare call in Run() bz := args[0].([]byte) diff --git a/precompiles/json/json_test.go b/precompiles/json/json_test.go index 80710c75a..f4688e416 100644 --- a/precompiles/json/json_test.go +++ b/precompiles/json/json_test.go @@ -41,7 +41,7 @@ func TestExtractAsBytes(t *testing.T) { args, err := method.Inputs.Pack(test.body, "key") require.Nil(t, err) input := append(p.ExtractAsBytesID, args...) - res, err := p.Run(evm, common.Address{}, input, nil) + res, err := p.Run(evm, common.Address{}, common.Address{}, input, nil, true) require.Nil(t, err) output, err := method.Outputs.Unpack(res) require.Nil(t, err) @@ -63,23 +63,23 @@ func TestExtractAsBytesList(t *testing.T) { expectedOutput [][]byte }{ { - []byte("{\"key\":[]}"), + []byte("{\"key\":[],\"key2\":1}"), [][]byte{}, }, { - []byte("{\"key\":[1,2,3]}"), + []byte("{\"key\":[1,2,3],\"key2\":1}"), [][]byte{[]byte("1"), []byte("2"), []byte("3")}, }, { - []byte("{\"key\":[\"1\", \"2\"]}"), + []byte("{\"key\":[\"1\", \"2\"],\"key2\":1}"), [][]byte{[]byte("\"1\""), []byte("\"2\"")}, }, { - []byte("{\"key\":[{\"nested\":1}, {\"nested\":2}]}"), + []byte("{\"key\":[{\"nested\":1}, {\"nested\":2}],\"key2\":1}"), [][]byte{[]byte("{\"nested\":1}"), []byte("{\"nested\":2}")}, }, } { args, err := method.Inputs.Pack(test.body, "key") require.Nil(t, err) input := append(p.ExtractAsBytesListID, args...) - res, err := p.Run(evm, common.Address{}, input, nil) + res, err := p.Run(evm, common.Address{}, common.Address{}, input, nil, true) require.Nil(t, err) output, err := method.Outputs.Unpack(res) require.Nil(t, err) @@ -113,7 +113,7 @@ func TestExtractAsUint256(t *testing.T) { args, err := method.Inputs.Pack(test.body, "key") require.Nil(t, err) input := append(p.ExtractAsUint256ID, args...) - res, err := p.Run(evm, common.Address{}, input, nil) + res, err := p.Run(evm, common.Address{}, common.Address{}, input, nil, true) require.Nil(t, err) output, err := method.Outputs.Unpack(res) require.Nil(t, err) diff --git a/precompiles/oracle/oracle.go b/precompiles/oracle/oracle.go index fbe18402e..06f1dd60a 100644 --- a/precompiles/oracle/oracle.go +++ b/precompiles/oracle/oracle.go @@ -95,12 +95,15 @@ func NewPrecompile(oracleKeeper pcommon.OracleKeeper, evmKeeper pcommon.EVMKeepe // RequiredGas returns the required bare minimum gas to execute the precompile. func (p Precompile) RequiredGas(input []byte) uint64 { - methodID := input[:4] + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } method, err := p.ABI.MethodById(methodID) if err != nil { // This should never happen since this method is going to fail during Run - return 0 + return pcommon.UnknownMethodCallGas } return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) @@ -110,7 +113,7 @@ func (p Precompile) Address() common.Address { return p.address } -func (p Precompile) Run(evm *vm.EVM, _ common.Address, input []byte, value *big.Int) (bz []byte, err error) { +func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err @@ -126,8 +129,13 @@ func (p Precompile) Run(evm *vm.EVM, _ common.Address, input []byte, value *big. } func (p Precompile) getExchangeRates(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 0) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 0); err != nil { + return nil, err + } exchangeRates := []DenomOracleExchangeRatePair{} p.oracleKeeper.IterateBaseExchangeRates(ctx, func(denom string, rate types.OracleExchangeRate) (stop bool) { exchangeRates = append(exchangeRates, DenomOracleExchangeRatePair{Denom: denom, OracleExchangeRateVal: OracleExchangeRate{ExchangeRate: rate.ExchangeRate.String(), LastUpdate: rate.LastUpdate.String(), LastUpdateTimestamp: rate.LastUpdateTimestamp}}) @@ -138,8 +146,13 @@ func (p Precompile) getExchangeRates(ctx sdk.Context, method *abi.Method, args [ } func (p Precompile) getOracleTwaps(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 1) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } lookbackSeconds := args[0].(uint64) twaps, err := p.oracleKeeper.CalculateTwaps(ctx, lookbackSeconds) if err != nil { diff --git a/precompiles/oracle/oracle_test.go b/precompiles/oracle/oracle_test.go index 7fdddece4..5b86bc2b6 100644 --- a/precompiles/oracle/oracle_test.go +++ b/precompiles/oracle/oracle_test.go @@ -38,7 +38,7 @@ func TestGetExchangeRate(t *testing.T) { query, err := p.ABI.MethodById(p.GetExchangeRatesId) require.Nil(t, err) - precompileRes, err := p.Run(&evm, common.Address{}, p.GetExchangeRatesId, nil) + precompileRes, err := p.Run(&evm, common.Address{}, common.Address{}, p.GetExchangeRatesId, nil, true) require.Nil(t, err) exchangeRates, err := query.Outputs.Unpack(precompileRes) require.Nil(t, err) @@ -114,7 +114,7 @@ func TestGetOracleTwaps(t *testing.T) { require.Nil(t, err) args, err := query.Inputs.Pack(uint64(3600)) require.Nil(t, err) - precompileRes, err := p.Run(&evm, common.Address{}, append(p.GetOracleTwapsId, args...), nil) + precompileRes, err := p.Run(&evm, common.Address{}, common.Address{}, append(p.GetOracleTwapsId, args...), nil, true) require.Nil(t, err) twap, err := query.Outputs.Unpack(precompileRes) require.Nil(t, err) diff --git a/precompiles/pointer/Pointer.sol b/precompiles/pointer/Pointer.sol new file mode 100644 index 000000000..d85893949 --- /dev/null +++ b/precompiles/pointer/Pointer.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant POINTER_PRECOMPILE_ADDRESS = 0x000000000000000000000000000000000000100b; + +IPointer constant POINTER_CONTRACT = IPointer(POINTER_PRECOMPILE_ADDRESS); + +interface IPointer { + function addNativePointer( + string memory token + ) payable external returns (address ret); + + function addCW20Pointer( + string memory cwAddr + ) payable external returns (address ret); + + function addCW721Pointer( + string memory cwAddr + ) payable external returns (address ret); +} diff --git a/precompiles/pointer/abi.json b/precompiles/pointer/abi.json new file mode 100644 index 000000000..8fb8238da --- /dev/null +++ b/precompiles/pointer/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"cwAddr","type":"string"}],"name":"addCW20Pointer","outputs":[{"internalType":"address","name":"ret","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"cwAddr","type":"string"}],"name":"addCW721Pointer","outputs":[{"internalType":"address","name":"ret","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"token","type":"string"}],"name":"addNativePointer","outputs":[{"internalType":"address","name":"ret","type":"address"}],"stateMutability":"payable","type":"function"}] \ No newline at end of file diff --git a/precompiles/pointer/pointer.go b/precompiles/pointer/pointer.go new file mode 100644 index 000000000..8fb594b84 --- /dev/null +++ b/precompiles/pointer/pointer.go @@ -0,0 +1,279 @@ +package pointer + +import ( + "bytes" + "embed" + "encoding/json" + "errors" + "fmt" + "math" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethabi "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +const ( + AddNativePointer = "addNativePointer" + AddCW20Pointer = "addCW20Pointer" + AddCW721Pointer = "addCW721Pointer" +) + +const PointerAddress = "0x000000000000000000000000000000000000100b" + +var _ vm.PrecompiledContract = &Precompile{} +var _ vm.DynamicGasPrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +type Precompile struct { + pcommon.Precompile + evmKeeper pcommon.EVMKeeper + bankKeeper pcommon.BankKeeper + wasmdKeeper pcommon.WasmdViewKeeper + address common.Address + + AddNativePointerID []byte + AddCW20PointerID []byte + AddCW721PointerID []byte +} + +func NewPrecompile(evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper, wasmdKeeper pcommon.WasmdViewKeeper) (*Precompile, error) { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + return nil, fmt.Errorf("error loading the pointer ABI %s", err) + } + + newAbi, err := ethabi.JSON(bytes.NewReader(abiBz)) + if err != nil { + return nil, err + } + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + evmKeeper: evmKeeper, + bankKeeper: bankKeeper, + wasmdKeeper: wasmdKeeper, + address: common.HexToAddress(PointerAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case AddNativePointer: + p.AddNativePointerID = m.ID + case AddCW20Pointer: + p.AddCW20PointerID = m.ID + case AddCW721Pointer: + p.AddCW721PointerID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + // gas is calculated dynamically + return pcommon.UnknownMethodCallGas +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, _ *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if readOnly { + return nil, 0, errors.New("cannot call pointer precompile from staticcall") + } + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, 0, err + } + if caller.Cmp(callingContract) != 0 { + return nil, 0, errors.New("cannot delegatecall pointer") + } + + switch method.Name { + case AddNativePointer: + return p.AddNative(ctx, method, caller, args, value, evm, suppliedGas) + case AddCW20Pointer: + return p.AddCW20(ctx, method, caller, args, value, evm, suppliedGas) + case AddCW721Pointer: + return p.AddCW721(ctx, method, caller, args, value, evm, suppliedGas) + default: + err = fmt.Errorf("unknown method %s", method.Name) + } + return +} + +func (p Precompile) Run(*vm.EVM, common.Address, common.Address, []byte, *big.Int, bool) ([]byte, error) { + panic("static gas Run is not implemented for dynamic gas precompile") +} + +func (p Precompile) AddNative(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, 0, err + } + token := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC20NativePointer(ctx, token) + if exists && existingVersion >= native.CurrentVersion { + return nil, 0, fmt.Errorf("pointer at %s with version %d exists when trying to set pointer for version %d", existingAddr.Hex(), existingVersion, native.CurrentVersion) + } + metadata, metadataExists := p.bankKeeper.GetDenomMetaData(ctx, token) + if !metadataExists { + return nil, 0, fmt.Errorf("denom %s does not have metadata stored and thus can only have its pointer set through gov proposal", token) + } + name := metadata.Name + symbol := metadata.Symbol + var decimals uint8 + for _, denomUnit := range metadata.DenomUnits { + if denomUnit.Exponent > uint32(decimals) && denomUnit.Exponent <= math.MaxUint8 { + decimals = uint8(denomUnit.Exponent) + name = denomUnit.Denom + symbol = denomUnit.Denom + if len(denomUnit.Aliases) > 0 { + name = denomUnit.Aliases[0] + } + } + } + constructorArguments := []interface{}{ + token, name, symbol, decimals, + } + + packedArgs, err := native.GetParsedABI().Pack("", constructorArguments...) + if err != nil { + panic(err) + } + bin := append(native.GetBin(), packedArgs...) + if value == nil { + value = utils.Big0 + } + ret, contractAddr, remainingGas, err := evm.Create(vm.AccountRef(caller), bin, suppliedGas, value) + if err != nil { + return + } + err = p.evmKeeper.SetERC20NativePointer(ctx, token, contractAddr) + if err != nil { + return + } + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "native"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, contractAddr.Hex()), sdk.NewAttribute(types.AttributeKeyPointee, token), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", native.CurrentVersion)))) + ret, err = method.Outputs.Pack(contractAddr) + return +} + +func (p Precompile) AddCW20(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, 0, err + } + cwAddr := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC20CW20Pointer(ctx, cwAddr) + if exists && existingVersion >= cw20.CurrentVersion { + return nil, 0, fmt.Errorf("pointer at %s with version %d exists when trying to set pointer for version %d", existingAddr.Hex(), existingVersion, cw20.CurrentVersion) + } + cwAddress, err := sdk.AccAddressFromBech32(cwAddr) + if err != nil { + return nil, 0, err + } + res, err := p.wasmdKeeper.QuerySmart(ctx, cwAddress, []byte("{\"token_info\":{}}")) + if err != nil { + return nil, 0, err + } + formattedRes := map[string]interface{}{} + if err := json.Unmarshal(res, &formattedRes); err != nil { + return nil, 0, err + } + name := formattedRes["name"].(string) + symbol := formattedRes["symbol"].(string) + constructorArguments := []interface{}{ + cwAddr, name, symbol, + } + + packedArgs, err := cw20.GetParsedABI().Pack("", constructorArguments...) + if err != nil { + panic(err) + } + bin := append(cw20.GetBin(), packedArgs...) + if value == nil { + value = utils.Big0 + } + ret, contractAddr, remainingGas, err := evm.Create(vm.AccountRef(caller), bin, suppliedGas, value) + if err != nil { + return + } + err = p.evmKeeper.SetERC20CW20Pointer(ctx, cwAddr, contractAddr) + if err != nil { + return + } + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "cw20"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, contractAddr.Hex()), sdk.NewAttribute(types.AttributeKeyPointee, cwAddr), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", cw20.CurrentVersion)))) + ret, err = method.Outputs.Pack(contractAddr) + return +} + +func (p Precompile) AddCW721(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, 0, err + } + cwAddr := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC721CW721Pointer(ctx, cwAddr) + if exists && existingVersion >= cw721.CurrentVersion { + return nil, 0, fmt.Errorf("pointer at %s with version %d exists when trying to set pointer for version %d", existingAddr.Hex(), existingVersion, cw721.CurrentVersion) + } + cwAddress, err := sdk.AccAddressFromBech32(cwAddr) + if err != nil { + return nil, 0, err + } + res, err := p.wasmdKeeper.QuerySmart(ctx, cwAddress, []byte("{\"contract_info\":{}}")) + if err != nil { + return nil, 0, err + } + formattedRes := map[string]interface{}{} + if err := json.Unmarshal(res, &formattedRes); err != nil { + return nil, 0, err + } + name := formattedRes["name"].(string) + symbol := formattedRes["symbol"].(string) + constructorArguments := []interface{}{ + cwAddr, name, symbol, + } + + packedArgs, err := cw721.GetParsedABI().Pack("", constructorArguments...) + if err != nil { + panic(err) + } + bin := append(cw721.GetBin(), packedArgs...) + if value == nil { + value = utils.Big0 + } + ret, contractAddr, remainingGas, err := evm.Create(vm.AccountRef(caller), bin, suppliedGas, value) + if err != nil { + return + } + err = p.evmKeeper.SetERC721CW721Pointer(ctx, cwAddr, contractAddr) + if err != nil { + return + } + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "cw721"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, contractAddr.Hex()), sdk.NewAttribute(types.AttributeKeyPointee, cwAddr), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", cw721.CurrentVersion)))) + ret, err = method.Outputs.Pack(contractAddr) + return +} diff --git a/precompiles/pointer/pointer_test.go b/precompiles/pointer/pointer_test.go new file mode 100644 index 000000000..f621a66c3 --- /dev/null +++ b/precompiles/pointer/pointer_test.go @@ -0,0 +1,83 @@ +package pointer_test + +import ( + "testing" + "time" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/app" + "github.com/sei-protocol/sei-chain/precompiles/pointer" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestAddNative(t *testing.T) { + testApp := app.Setup(false, false) + p, err := pointer.NewPrecompile(&testApp.EvmKeeper, testApp.BankKeeper, testApp.WasmKeeper) + require.Nil(t, err) + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + _, caller := testkeeper.MockAddressPair() + suppliedGas := uint64(10000000) + cfg := types.DefaultChainConfig().EthereumConfig(testApp.EvmKeeper.ChainID(ctx)) + + // token has no metadata + m, err := p.ABI.MethodById(p.AddNativePointerID) + require.Nil(t, err) + args, err := m.Inputs.Pack("test") + require.Nil(t, err) + statedb := state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + blockCtx, _ := testApp.EvmKeeper.GetVMBlockContext(ctx, core.GasPool(suppliedGas)) + evm := vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, cfg, vm.Config{}) + _, g, err := p.RunAndCalculateGas(evm, caller, caller, append(p.AddNativePointerID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + _, _, exists := testApp.EvmKeeper.GetERC20NativePointer(statedb.Ctx(), "test") + require.False(t, exists) + + // token has metadata + testApp.BankKeeper.SetDenomMetaData(ctx, banktypes.Metadata{ + Base: "test", + Name: "base_name", + Symbol: "base_symbol", + DenomUnits: []*banktypes.DenomUnit{{ + Exponent: 6, + Denom: "denom", + Aliases: []string{"DENOM"}, + }}, + }) + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, cfg, vm.Config{}) + ret, g, err := p.RunAndCalculateGas(evm, caller, caller, append(p.AddNativePointerID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + require.Equal(t, uint64(8907806), g) + outputs, err := m.Outputs.Unpack(ret) + require.Nil(t, err) + addr := outputs[0].(common.Address) + pointerAddr, version, exists := testApp.EvmKeeper.GetERC20NativePointer(statedb.Ctx(), "test") + require.Equal(t, addr, pointerAddr) + require.Equal(t, native.CurrentVersion, version) + require.True(t, exists) + hasRegisteredEvent := false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + require.Equal(t, types.EventTypePointerRegistered, e.Type) + require.Equal(t, "native", string(e.Attributes[0].Value)) + } + require.True(t, hasRegisteredEvent) + + // pointer already exists + statedb = state.NewDBImpl(statedb.Ctx(), &testApp.EvmKeeper, true) + evm = vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, cfg, vm.Config{}) + _, g, err = p.RunAndCalculateGas(evm, caller, caller, append(p.AddNativePointerID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) +} diff --git a/precompiles/pointerview/Pointerview.sol b/precompiles/pointerview/Pointerview.sol new file mode 100644 index 000000000..497c977fd --- /dev/null +++ b/precompiles/pointerview/Pointerview.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant POINTERVIEW_PRECOMPILE_ADDRESS = 0x000000000000000000000000000000000000100A; + +IPointerview constant POINTERVIEW_CONTRACT = IPointerview(POINTERVIEW_PRECOMPILE_ADDRESS); + +interface IPointerview { + function getNativePointer( + string memory token + ) view external returns (address addr, uint16 version, bool exists); + + function getCW20Pointer( + string memory cwAddr + ) view external returns (address addr, uint16 version, bool exists); + + function getCW721Pointer( + string memory cwAddr + ) view external returns (address addr, uint16 version, bool exists); +} diff --git a/precompiles/pointerview/abi.json b/precompiles/pointerview/abi.json new file mode 100644 index 000000000..a469eff12 --- /dev/null +++ b/precompiles/pointerview/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"cwAddr","type":"string"}],"name":"getCW20Pointer","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"cwAddr","type":"string"}],"name":"getCW721Pointer","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"token","type":"string"}],"name":"getNativePointer","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/pointerview/pointerview.go b/precompiles/pointerview/pointerview.go new file mode 100644 index 000000000..acbc97561 --- /dev/null +++ b/precompiles/pointerview/pointerview.go @@ -0,0 +1,125 @@ +package pointerview + +import ( + "bytes" + "embed" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" +) + +const ( + GetNativePointer = "getNativePointer" + GetCW20Pointer = "getCW20Pointer" + GetCW721Pointer = "getCW721Pointer" +) + +const PointerViewAddress = "0x000000000000000000000000000000000000100A" + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +type Precompile struct { + pcommon.Precompile + evmKeeper pcommon.EVMKeeper + address common.Address + + GetNativePointerID []byte + GetCW20PointerID []byte + GetCW721PointerID []byte +} + +func NewPrecompile(evmKeeper pcommon.EVMKeeper) (*Precompile, error) { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + return nil, fmt.Errorf("error loading the pointer ABI %s", err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + return nil, err + } + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + evmKeeper: evmKeeper, + address: common.HexToAddress(PointerViewAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case GetNativePointer: + p.GetNativePointerID = m.ID + case GetCW20Pointer: + p.GetCW20PointerID = m.ID + case GetCW721Pointer: + p.GetCW721PointerID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + return 2000 +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, _ *big.Int, _ bool) (ret []byte, err error) { + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, err + } + + switch method.Name { + case GetNativePointer: + return p.GetNative(ctx, method, args) + case GetCW20Pointer: + return p.GetCW20(ctx, method, args) + case GetCW721Pointer: + return p.GetCW721(ctx, method, args) + default: + err = fmt.Errorf("unknown method %s", method.Name) + } + return +} + +func (p Precompile) GetNative(ctx sdk.Context, method *abi.Method, args []interface{}) (ret []byte, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + token := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC20NativePointer(ctx, token) + return method.Outputs.Pack(existingAddr, existingVersion, exists) +} + +func (p Precompile) GetCW20(ctx sdk.Context, method *abi.Method, args []interface{}) (ret []byte, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + addr := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC20CW20Pointer(ctx, addr) + return method.Outputs.Pack(existingAddr, existingVersion, exists) +} + +func (p Precompile) GetCW721(ctx sdk.Context, method *abi.Method, args []interface{}) (ret []byte, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + addr := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC721CW721Pointer(ctx, addr) + return method.Outputs.Pack(existingAddr, existingVersion, exists) +} diff --git a/precompiles/pointerview/pointerview_test.go b/precompiles/pointerview/pointerview_test.go new file mode 100644 index 000000000..ad6d28bff --- /dev/null +++ b/precompiles/pointerview/pointerview_test.go @@ -0,0 +1,67 @@ +package pointerview_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/precompiles/pointerview" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/stretchr/testify/require" +) + +func TestPointerView(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + p, err := pointerview.NewPrecompile(k) + require.Nil(t, err) + _, pointer := testkeeper.MockAddressPair() + k.SetERC20NativePointer(ctx, "test", pointer) + k.SetERC20CW20Pointer(ctx, "test", pointer) + k.SetERC721CW721Pointer(ctx, "test", pointer) + m, err := p.ABI.MethodById(p.GetNativePointerID) + require.Nil(t, err) + ret, err := p.GetNative(ctx, m, []interface{}{"test"}) + require.Nil(t, err) + outputs, err := m.Outputs.Unpack(ret) + require.Nil(t, err) + require.Equal(t, pointer, outputs[0].(common.Address)) + require.Equal(t, native.CurrentVersion, outputs[1].(uint16)) + require.True(t, outputs[2].(bool)) + ret, err = p.GetNative(ctx, m, []interface{}{"test2"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.False(t, outputs[2].(bool)) + + m, err = p.ABI.MethodById(p.GetCW20PointerID) + require.Nil(t, err) + ret, err = p.GetCW20(ctx, m, []interface{}{"test"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.Equal(t, pointer, outputs[0].(common.Address)) + require.Equal(t, cw20.CurrentVersion, outputs[1].(uint16)) + require.True(t, outputs[2].(bool)) + ret, err = p.GetCW20(ctx, m, []interface{}{"test2"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.False(t, outputs[2].(bool)) + + m, err = p.ABI.MethodById(p.GetCW721PointerID) + require.Nil(t, err) + ret, err = p.GetCW721(ctx, m, []interface{}{"test"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.Equal(t, pointer, outputs[0].(common.Address)) + require.Equal(t, cw721.CurrentVersion, outputs[1].(uint16)) + require.True(t, outputs[2].(bool)) + ret, err = p.GetCW721(ctx, m, []interface{}{"test2"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.False(t, outputs[2].(bool)) +} diff --git a/precompiles/setup.go b/precompiles/setup.go index c72869fac..a0908d496 100644 --- a/precompiles/setup.go +++ b/precompiles/setup.go @@ -13,6 +13,8 @@ import ( "github.com/sei-protocol/sei-chain/precompiles/ibc" "github.com/sei-protocol/sei-chain/precompiles/json" "github.com/sei-protocol/sei-chain/precompiles/oracle" + "github.com/sei-protocol/sei-chain/precompiles/pointer" + "github.com/sei-protocol/sei-chain/precompiles/pointerview" "github.com/sei-protocol/sei-chain/precompiles/staking" "github.com/sei-protocol/sei-chain/precompiles/wasmd" ) @@ -81,6 +83,16 @@ func InitializePrecompiles( return err } addPrecompileToVM(ibcp, ibcp.Address()) + pointerp, err := pointer.NewPrecompile(evmKeeper, bankKeeper, wasmdViewKeeper) + if err != nil { + return err + } + addPrecompileToVM(pointerp, pointerp.Address()) + pointerviewp, err := pointerview.NewPrecompile(evmKeeper) + if err != nil { + return err + } + addPrecompileToVM(pointerviewp, pointerviewp.Address()) Initialized = true return nil } diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index 7115fec03..1c96a5666 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -84,7 +84,10 @@ func NewPrecompile(stakingKeeper pcommon.StakingKeeper, evmKeeper pcommon.EVMKee // RequiredGas returns the required bare minimum gas to execute the precompile. func (p Precompile) RequiredGas(input []byte) uint64 { - methodID := input[:4] + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } if bytes.Equal(methodID, p.DelegateID) { return 50000 @@ -93,18 +96,26 @@ func (p Precompile) RequiredGas(input []byte) uint64 { } else if bytes.Equal(methodID, p.UndelegateID) { return 50000 } - panic("unknown method") + + // This should never happen since this is going to fail during Run + return pcommon.UnknownMethodCallGas } func (p Precompile) Address() common.Address { return p.address } -func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value *big.Int) (bz []byte, err error) { +func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + if readOnly { + return nil, errors.New("cannot call staking precompile from staticcall") + } ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err } + if caller.Cmp(callingContract) != 0 { + return nil, errors.New("cannot delegatecall staking") + } switch method.Name { case DelegateMethod: @@ -118,7 +129,9 @@ func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte, value } func (p Precompile) delegate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertArgsLength(args, 1) + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } // if delegator is associated, then it must have Account set already // if delegator is not associated, then it can't delegate anyway (since // there is no good way to merge delegations if it becomes associated) @@ -146,8 +159,13 @@ func (p Precompile) delegate(ctx sdk.Context, method *abi.Method, caller common. } func (p Precompile) redelegate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 3) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 3); err != nil { + return nil, err + } delegator, associated := p.evmKeeper.GetSeiAddress(ctx, caller) if !associated { return nil, fmt.Errorf("redelegator %s is not associated/doesn't have an Account set yet", caller.Hex()) @@ -168,8 +186,13 @@ func (p Precompile) redelegate(ctx sdk.Context, method *abi.Method, caller commo } func (p Precompile) undelegate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 2) + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } delegator, associated := p.evmKeeper.GetSeiAddress(ctx, caller) if !associated { return nil, fmt.Errorf("undelegator %s is not associated/doesn't have an Account set yet", caller.Hex()) diff --git a/precompiles/wasmd/wasmd.go b/precompiles/wasmd/wasmd.go index c817f2576..25ceee5ab 100644 --- a/precompiles/wasmd/wasmd.go +++ b/precompiles/wasmd/wasmd.go @@ -6,15 +6,16 @@ import ( "encoding/json" "errors" "fmt" - "math" "math/big" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/utils" ) const ( @@ -26,14 +27,13 @@ const ( const WasmdAddress = "0x0000000000000000000000000000000000001002" var _ vm.PrecompiledContract = &Precompile{} +var _ vm.DynamicGasPrecompiledContract = &Precompile{} // Embed abi json file to the executable binary. Needed when importing as dependency. // //go:embed abi.json var f embed.FS -var MaxUint64BigInt = new(big.Int).SetUint64(math.MaxUint64) - type Precompile struct { pcommon.Precompile evmKeeper pcommon.EVMKeeper @@ -83,12 +83,15 @@ func NewPrecompile(evmKeeper pcommon.EVMKeeper, wasmdKeeper pcommon.WasmdKeeper, // RequiredGas returns the required bare minimum gas to execute the precompile. func (p Precompile) RequiredGas(input []byte) uint64 { - methodID := input[:4] + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } method, err := p.ABI.MethodById(methodID) if err != nil { // This should never happen since this method is going to fail during Run - return 0 + return pcommon.UnknownMethodCallGas } return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) @@ -109,18 +112,15 @@ func (p Precompile) Address() common.Address { return p.address } -func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { +func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, logger *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, 0, err } - if err := pcommon.ValidateCaller(ctx, p.evmKeeper, caller, callingContract); err != nil { - return nil, 0, err - } gasMultipler := p.evmKeeper.GetPriorityNormalizer(ctx) - gasLimitBigInt := new(big.Int).Mul(new(big.Int).SetUint64(suppliedGas), gasMultipler.RoundInt().BigInt()) - if gasLimitBigInt.Cmp(MaxUint64BigInt) > 0 { - gasLimitBigInt = MaxUint64BigInt + gasLimitBigInt := sdk.NewDecFromInt(sdk.NewIntFromUint64(suppliedGas)).Mul(gasMultipler).TruncateInt().BigInt() + if gasLimitBigInt.Cmp(utils.BigMaxU64) > 0 { + gasLimitBigInt = utils.BigMaxU64 } ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimitBigInt.Uint64())) @@ -130,20 +130,20 @@ func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, calli switch method.Name { case InstantiateMethod: - return p.instantiate(ctx, method, caller, args, value) + return p.instantiate(ctx, method, caller, callingContract, args, value, readOnly) case ExecuteMethod: - return p.execute(ctx, method, caller, args, value) + return p.execute(ctx, method, caller, callingContract, args, value, readOnly) case QueryMethod: return p.query(ctx, method, args, value) } return } -func (p Precompile) Run(*vm.EVM, common.Address, []byte, *big.Int) ([]byte, error) { +func (p Precompile) Run(*vm.EVM, common.Address, common.Address, []byte, *big.Int, bool) ([]byte, error) { panic("static gas Run is not implemented for dynamic gas precompile") } -func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) (ret []byte, remainingGas uint64, rerr error) { +func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool) (ret []byte, remainingGas uint64, rerr error) { defer func() { if err := recover(); err != nil { ret = nil @@ -152,7 +152,18 @@ func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller comm return } }() - pcommon.AssertArgsLength(args, 5) + if readOnly { + rerr = errors.New("cannot call instantiate from staticcall") + return + } + if err := pcommon.ValidateArgsLength(args, 5); err != nil { + rerr = err + return + } + if caller.Cmp(callingContract) != 0 { + rerr = errors.New("cannot delegatecall instantiate") + return + } // type assertion will always succeed because it's already validated in p.Prepare call in Run() codeID := args[0].(uint64) @@ -171,6 +182,7 @@ func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller comm label := args[3].(string) coins := sdk.NewCoins() coinsBz := args[4].([]byte) + if err := json.Unmarshal(coinsBz, &coins); err != nil { rerr = err return @@ -179,6 +191,22 @@ func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller comm rerr = errors.New("deposit of usei must be done through the `value` field") return } + + // Run basic validation, can also just expose validateLabel and validate validateWasmCode in sei-wasmd + msgInstantiate := wasmtypes.MsgInstantiateContract{ + Sender: creatorAddr.String(), + CodeID: codeID, + Label: label, + Funds: coins, + Msg: msg, + Admin: adminAddrStr, + } + + if err := msgInstantiate.ValidateBasic(); err != nil { + rerr = err + return + } + if value != nil { coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), creatorAddr, value, p.bankKeeper) if err != nil { @@ -198,7 +226,7 @@ func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller comm return } -func (p Precompile) execute(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) (ret []byte, remainingGas uint64, rerr error) { +func (p Precompile) execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool) (ret []byte, remainingGas uint64, rerr error) { defer func() { if err := recover(); err != nil { ret = nil @@ -207,10 +235,24 @@ func (p Precompile) execute(ctx sdk.Context, method *abi.Method, caller common.A return } }() - pcommon.AssertArgsLength(args, 3) + if readOnly { + rerr = errors.New("cannot call execute from staticcall") + return + } + if err := pcommon.ValidateArgsLength(args, 3); err != nil { + rerr = err + return + } // type assertion will always succeed because it's already validated in p.Prepare call in Run() contractAddrStr := args[0].(string) + if caller.Cmp(callingContract) != 0 { + erc20pointer, _, erc20exists := p.evmKeeper.GetERC20CW20Pointer(ctx, contractAddrStr) + erc721pointer, _, erc721exists := p.evmKeeper.GetERC721CW721Pointer(ctx, contractAddrStr) + if (!erc20exists || erc20pointer.Cmp(callingContract) != 0) && (!erc721exists || erc721pointer.Cmp(callingContract) != 0) { + return nil, 0, fmt.Errorf("%s is not a pointer of %s", callingContract.Hex(), contractAddrStr) + } + } // addresses will be sent in Sei format contractAddr, err := sdk.AccAddressFromBech32(contractAddrStr) if err != nil { @@ -229,6 +271,19 @@ func (p Precompile) execute(ctx sdk.Context, method *abi.Method, caller common.A rerr = errors.New("deposit of usei must be done through the `value` field") return } + // Run basic validation, can also just expose validateLabel and validate validateWasmCode in sei-wasmd + msgExecute := wasmtypes.MsgExecuteContract{ + Sender: senderAddr.String(), + Contract: contractAddr.String(), + Msg: msg, + Funds: coins, + } + + if err := msgExecute.ValidateBasic(); err != nil { + rerr = err + return + } + if value != nil { coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), senderAddr, value, p.bankKeeper) if err != nil { @@ -256,8 +311,15 @@ func (p Precompile) query(ctx sdk.Context, method *abi.Method, args []interface{ return } }() - pcommon.AssertNonPayable(value) - pcommon.AssertArgsLength(args, 2) + if err := pcommon.ValidateNonPayable(value); err != nil { + rerr = err + return + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + rerr = err + return + } contractAddrStr := args[0].(string) // addresses will be sent in Sei format @@ -267,6 +329,13 @@ func (p Precompile) query(ctx sdk.Context, method *abi.Method, args []interface{ return } req := args[1].([]byte) + + rawContractMessage := wasmtypes.RawContractMessage(req) + if err := rawContractMessage.ValidateBasic(); err != nil { + rerr = err + return + } + res, err := p.wasmdViewKeeper.QuerySmart(ctx, contractAddr, req) if err != nil { rerr = err diff --git a/precompiles/wasmd/wasmd_test.go b/precompiles/wasmd/wasmd_test.go index 74cc79a6b..926a007b1 100644 --- a/precompiles/wasmd/wasmd_test.go +++ b/precompiles/wasmd/wasmd_test.go @@ -25,7 +25,7 @@ func TestRequiredGas(t *testing.T) { require.Equal(t, uint64(2000), p.RequiredGas(p.ExecuteID)) require.Equal(t, uint64(2000), p.RequiredGas(p.InstantiateID)) require.Equal(t, uint64(1000), p.RequiredGas(p.QueryID)) - require.Equal(t, uint64(0), p.RequiredGas([]byte{15, 15, 15, 15})) // invalid method + require.Equal(t, uint64(3000), p.RequiredGas([]byte{15, 15, 15, 15})) // invalid method } func TestAddress(t *testing.T) { @@ -63,12 +63,12 @@ func TestInstantiate(t *testing.T) { StateDB: statedb, } suppliedGas := uint64(1000000) - res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, nil, nil) + res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, nil, nil, false) require.Nil(t, err) outputs, err := instantiateMethod.Outputs.Unpack(res) require.Nil(t, err) require.Equal(t, 2, len(outputs)) - require.Equal(t, "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m", outputs[0].(string)) + require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) require.Empty(t, outputs[1].([]byte)) require.Equal(t, uint64(902898), g) @@ -80,16 +80,16 @@ func TestInstantiate(t *testing.T) { "test", amtsbz, ) - _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, nil, nil) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) require.Equal(t, uint64(0), g) // bad inputs badArgs, _ := instantiateMethod.Inputs.Pack(codeID, "not bech32", []byte("{}"), "test", amtsbz) - _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, badArgs...), suppliedGas, nil, nil) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, badArgs...), suppliedGas, nil, nil, false) require.NotNil(t, err) badArgs, _ = instantiateMethod.Inputs.Pack(codeID, mockAddr.String(), []byte("{}"), "test", []byte("bad coins")) - _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, badArgs...), suppliedGas, nil, nil) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, badArgs...), suppliedGas, nil, nil, false) require.NotNil(t, err) } @@ -125,14 +125,14 @@ func TestExecute(t *testing.T) { } suppliedGas := uint64(1000000) testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) - _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) // used coins instead of `value` to send usei to the contract amtsbz, err = sdk.NewCoins().MarshalJSON() require.Nil(t, err) args, err = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) require.Nil(t, err) - res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil) + res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) require.Nil(t, err) outputs, err := executeMethod.Outputs.Unpack(res) require.Nil(t, err) @@ -143,29 +143,28 @@ func TestExecute(t *testing.T) { // allowed delegatecall contractAddrAllowed := common.BytesToAddress([]byte("contractA")) - testApp.EvmKeeper.SetCode(ctx, contractAddrAllowed, []byte("allowed")) - testApp.EvmKeeper.AddCodeHashWhitelistedForDelegateCall(ctx, testApp.EvmKeeper.GetCodeHash(ctx, contractAddrAllowed)) - _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrAllowed, append(p.ExecuteID, args...), suppliedGas, nil, nil) + testApp.EvmKeeper.SetERC20CW20Pointer(ctx, contractAddr.String(), contractAddrAllowed) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrAllowed, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.Nil(t, err) // disallowed delegatecall contractAddrDisallowed := common.BytesToAddress([]byte("contractB")) - _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrDisallowed, append(p.ExecuteID, args...), suppliedGas, nil, nil) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrDisallowed, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) // bad contract address args, _ = executeMethod.Inputs.Pack(mockAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) - _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) require.Equal(t, uint64(0), g) // bad inputs args, _ = executeMethod.Inputs.Pack("not bech32", []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) - _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) require.Equal(t, uint64(0), g) args, _ = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), []byte("bad coins")) - _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) require.Equal(t, uint64(0), g) } @@ -193,7 +192,7 @@ func TestQuery(t *testing.T) { StateDB: statedb, } suppliedGas := uint64(1000000) - res, g, err := p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.QueryID, args...), suppliedGas, nil, nil) + res, g, err := p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.QueryID, args...), suppliedGas, nil, nil, false) require.Nil(t, err) outputs, err := queryMethod.Outputs.Unpack(res) require.Nil(t, err) @@ -203,17 +202,17 @@ func TestQuery(t *testing.T) { // bad contract address args, _ = queryMethod.Inputs.Pack(mockAddr.String(), []byte("{\"info\":{}}")) - _, g, err = p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.ExecuteID, args...), suppliedGas, nil, nil) + _, g, err = p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) require.Equal(t, uint64(0), g) // bad input args, _ = queryMethod.Inputs.Pack("not bech32", []byte("{\"info\":{}}")) - _, g, err = p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.ExecuteID, args...), suppliedGas, nil, nil) + _, g, err = p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) require.Equal(t, uint64(0), g) args, _ = queryMethod.Inputs.Pack(contractAddr.String(), []byte("{\"bad\":{}}")) - _, g, err = p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.ExecuteID, args...), suppliedGas, nil, nil) + _, g, err = p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) require.Equal(t, uint64(0), g) } diff --git a/proto/evm/enums.proto b/proto/evm/enums.proto new file mode 100644 index 000000000..fefdee9ab --- /dev/null +++ b/proto/evm/enums.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +enum PointerType { + ERC20 = 0; + ERC721 = 1; + NATIVE = 2; + CW20 = 3; + CW721 = 4; + } \ No newline at end of file diff --git a/proto/evm/gov.proto b/proto/evm/gov.proto new file mode 100644 index 000000000..0425df2de --- /dev/null +++ b/proto/evm/gov.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +message AddERCNativePointerProposal { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; + string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; + string token = 3 [(gogoproto.moretags) = "yaml:\"token\""]; + string pointer = 4 [(gogoproto.moretags) = "yaml:\"pointer\""]; + uint32 version = 5 [(gogoproto.moretags) = "yaml:\"version\""]; +} + +message AddERCCW20PointerProposal { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; + string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; + string pointee = 3 [(gogoproto.moretags) = "yaml:\"pointee\""]; + string pointer = 4 [(gogoproto.moretags) = "yaml:\"pointer\""]; + uint32 version = 5 [(gogoproto.moretags) = "yaml:\"version\""]; +} + +message AddERCCW721PointerProposal { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; + string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; + string pointee = 3 [(gogoproto.moretags) = "yaml:\"pointee\""]; + string pointer = 4 [(gogoproto.moretags) = "yaml:\"pointer\""]; + uint32 version = 5 [(gogoproto.moretags) = "yaml:\"version\""]; +} diff --git a/proto/evm/query.proto b/proto/evm/query.proto index 6f8117097..6f90daa9b 100644 --- a/proto/evm/query.proto +++ b/proto/evm/query.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package seiprotocol.seichain.evm; import "google/api/annotations.proto"; +import "evm/enums.proto"; option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; @@ -18,6 +19,10 @@ service Query { rpc StaticCall(QueryStaticCallRequest) returns (QueryStaticCallResponse) { option (google.api.http).get = "/sei-protocol/seichain/evm/static_call"; } + + rpc Pointer(QueryPointerRequest) returns (QueryPointerResponse) { + option (google.api.http).get = "/sei-protocol/seichain/evm/pointer"; + } } message QuerySeiAddressByEVMAddressRequest { @@ -46,3 +51,14 @@ message QueryStaticCallRequest { message QueryStaticCallResponse { bytes data = 1; } + +message QueryPointerRequest { + PointerType pointer_type = 1; + string pointee = 2; +} + +message QueryPointerResponse { + string pointer = 1; + uint32 version = 2; + bool exists = 3; +} diff --git a/proto/evm/tx.proto b/proto/evm/tx.proto index 35e6852dc..03eaa8ce9 100644 --- a/proto/evm/tx.proto +++ b/proto/evm/tx.proto @@ -4,12 +4,14 @@ package seiprotocol.seichain.evm; import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; import "cosmos/base/v1beta1/coin.proto"; +import "evm/enums.proto"; option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; service Msg { rpc EVMTransaction(MsgEVMTransaction) returns (MsgEVMTransactionResponse); rpc Send(MsgSend) returns (MsgSendResponse); + rpc RegisterPointer(MsgRegisterPointer) returns (MsgRegisterPointerResponse); } message MsgEVMTransaction { @@ -53,3 +55,13 @@ message MsgSend { } message MsgSendResponse {} + +message MsgRegisterPointer { + string sender = 1; + PointerType pointer_type = 2; + string erc_address = 3; +} + +message MsgRegisterPointerResponse { + string pointer_address = 1; +} diff --git a/run_blocktests.sh b/run_blocktests.sh new file mode 100755 index 000000000..05367f6d5 --- /dev/null +++ b/run_blocktests.sh @@ -0,0 +1,101 @@ +#!/bin/bash + +set -e + +# mode options are list, run, or all +block_tests_path=$1 +runner_index=$2 +runner_total=$3 + +if [ -z "$runner_index" ]; then + runner_index=0 + runner_total=1 +fi + +echo $mode +echo $block_tests_path + +# Define an array of test directories to run +declare -a test_path_run_list=( + # run all valid block tests + "ValidBlocks/" + + # run only certain invalid block tests + "InvalidBlocks/bcEIP1559/" + "InvalidBlocks/bcStateTests/" +) + +# Define an array of tests to skip +declare -a test_name_skip_list=( + # valid block tests + "DelegateCallSpam" # passes, but takes super long + "blockhashTests" # failing + "blockhashNonConstArg" # failing + "BLOCKHASH_Bounds" # failing + "logRevert" # uses an invalid opcode (0xBA) + "blockWithAllTransactionTypes" # recently started failing + + # invalid block tests - state tests + "gasLimitTooHigh" # block header gas limit doesn't apply to us + "transactionFromSelfDestructedContract" # failing + + # InvaldBlockTests/bcEIP1559 + "badUncles" # reorgs don't apply to us + "checkGasLimit" # not sure what issue is +) + +# list out all paths to json files starting from the block_tests_dir +block_tests=$(find "$block_tests_path" -name "*.json" | sort) + +i=0 + +# for each json file, run the block test +for test_path in $block_tests; do + test_name=$(basename "$test_path" .json) + match_found=false + + # Iterate through the test_path_run_list to check for a match + for run_path in "${test_path_run_list[@]}"; do + if [[ "$test_path" == *"$run_path"* ]]; then + match_found=true + break + fi + done + + # Skip the test if no match is found + if [ "$match_found" = false ]; then + continue + fi + + echo "test file: $test_path" + echo "test dir: $test_path" + + # Check if the test name is in the skip list + if printf '%s\n' "${test_name_skip_list[@]}" | grep -qx "$test_name"; then + echo "Skipping test in skip list: $test_path" + continue + fi + + # Check if "${test_name}_Cancun" is not in the test file + if ! grep -q "${test_name}_Cancun" "$test_path"; then + echo "Skipping test due to missing Cancun tag: $test_path" + continue + fi + + if [ $((i % runner_total)) -ne $runner_index ]; then + i=$((i+1)) + runner_id=$((i % runner_total)) + echo "Skipping test not in runner index: $test_path, runner index: $runner_id" + continue + fi + + i=$((i+1)) + + echo -e "\n*********************************************************\n" + echo "Running block test: $test_path" + echo "test name: ${test_name}_Cancun" + echo -e "\n*********************************************************\n" + rm -r ~/.sei || true + NO_RUN=1 ./scripts/initialize_local_chain.sh + seid blocktest --block-test $test_path --test-name "${test_name}_Cancun" +done diff --git a/scripts/initialize_local_chain.sh b/scripts/initialize_local_chain.sh index f283f23ea..350f161eb 100755 --- a/scripts/initialize_local_chain.sh +++ b/scripts/initialize_local_chain.sh @@ -60,6 +60,7 @@ cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["whitelist"] cat ~/.sei/config/genesis.json | jq '.app_state["distribution"]["params"]["community_tax"]="0.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="35000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.app_state["staking"]["params"]["max_voting_power_ratio"]="1.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json +cat ~/.sei/config/genesis.json | jq '.app_state["bank"]["denom_metadata"]=[{"denom_units":[{"denom":"UATOM","exponent":6,"aliases":["UATOM"]}],"base":"uatom","display":"uatom","name":"UATOM","symbol":"UATOM"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json # Use the Python command to get the dates START_DATE=$($PYTHON_CMD -c "from datetime import datetime; print(datetime.now().strftime('%Y-%m-%d'))") @@ -111,16 +112,10 @@ fi ~/go/bin/seid config keyring-backend test -fund() { - echo "Initializing chain..." - sleep 3 # Wait for chain to be ready instead... - ~/go/bin/seid tx evm send 0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 100000000000000000 --from admin -} - -sd 'occ-enabled =.*' 'occ-enabled = true' "$APP_PATH" -sd '\[evm\]' "[evm]\nlive_evm_tracer = \"firehose\"\nlive_evm_tracer_chain_id = 713715" "$APP_PATH" - -fund & +if [ $NO_RUN = 1 ]; then + echo "No run flag set, exiting without starting the chain" + exit 0 +fi # start the chain with log tracing GORACE="log_path=/tmp/race/seid_race" ~/go/bin/seid start --trace --chain-id sei-chain --log_level warn diff --git a/testutil/keeper/evm.go b/testutil/keeper/evm.go index a71647038..d5449ad59 100644 --- a/testutil/keeper/evm.go +++ b/testutil/keeper/evm.go @@ -3,6 +3,7 @@ package keeper import ( "encoding/hex" "sync" + "time" "github.com/cosmos/cosmos-sdk/crypto/hd" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -51,7 +52,7 @@ func MockEVMKeeperWithPrecompiles() (*evmkeeper.Keeper, sdk.Context) { func MockEVMKeeper() (*evmkeeper.Keeper, sdk.Context) { testApp := app.Setup(false, false) - ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockHeight(8) + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockHeight(8).WithBlockTime(time.Now()) k := testApp.EvmKeeper k.InitGenesis(ctx, *evmtypes.DefaultGenesis()) diff --git a/utils/constants.go b/utils/constants.go index 36232c00f..f25c156e1 100644 --- a/utils/constants.go +++ b/utils/constants.go @@ -14,5 +14,6 @@ var Big8 = big.NewInt(8) var Big27 = big.NewInt(27) var Big35 = big.NewInt(35) var BigMaxI64 = big.NewInt(math.MaxInt64) +var BigMaxU64 = new(big.Int).SetUint64(math.MaxUint64) var Sdk0 = sdk.NewInt(0) diff --git a/x/dex/keeper/msgserver/msg_server_register_contract_test.go b/x/dex/keeper/msgserver/msg_server_register_contract_test.go index 415087eeb..9b989ed79 100644 --- a/x/dex/keeper/msgserver/msg_server_register_contract_test.go +++ b/x/dex/keeper/msgserver/msg_server_register_contract_test.go @@ -22,7 +22,7 @@ import ( ) const ( - TestContractA = "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m" + TestContractA = "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n" TestContractB = "sei1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrqms7u8a" TestContractC = "sei1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3shh3qfl" TestContractD = "sei1up07dctjqud4fns75cnpejr4frmjtddzsmwgcktlyxd4zekhwecqghxqcp" diff --git a/x/evm/ante/basic.go b/x/evm/ante/basic.go index ab0b1fe3c..e9db85dca 100644 --- a/x/evm/ante/basic.go +++ b/x/evm/ante/basic.go @@ -23,9 +23,6 @@ func NewBasicDecorator() *BasicDecorator { // cherrypicked from go-ethereum:txpool:ValidateTransaction func (gl BasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { - if !ctx.IsCheckTx() { - return next(ctx, tx, simulate) - } msg := evmtypes.MustGetEVMTransactionMessage(tx) etx, _ := msg.AsTransaction() @@ -45,29 +42,35 @@ func (gl BasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, n return ctx, sdkerrors.ErrOutOfGas } - // Ensure blob transactions have valid commitments if etx.Type() == ethtypes.BlobTxType { - sidecar := etx.BlobTxSidecar() - if sidecar == nil { - return ctx, fmt.Errorf("missing sidecar in blob transaction") - } - // Ensure the number of items in the blob transaction and various side - // data match up before doing any expensive validations - hashes := etx.BlobHashes() - if len(hashes) == 0 { - return ctx, fmt.Errorf("blobless blob transaction") - } - if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob { - return ctx, fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) - } - if err := validateBlobSidecar(hashes, sidecar); err != nil { - return ctx, err - } + return ctx, sdkerrors.ErrUnsupportedTxType } + //TODO: support blobs (leaving this commented out) + // Ensure blob transactions have valid commitments + //if etx.Type() == ethtypes.BlobTxType { + // sidecar := etx.BlobTxSidecar() + // if sidecar == nil { + // return ctx, fmt.Errorf("missing sidecar in blob transaction") + // } + // // Ensure the number of items in the blob transaction and various side + // // data match up before doing any expensive validations + // hashes := etx.BlobHashes() + // if len(hashes) == 0 { + // return ctx, fmt.Errorf("blobless blob transaction") + // } + // if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob { + // return ctx, fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) + // } + // if err := validateBlobSidecar(hashes, sidecar); err != nil { + // return ctx, err + // } + //} + return next(ctx, tx, simulate) } +//nolint:deadcode func validateBlobSidecar(hashes []common.Hash, sidecar *ethtypes.BlobTxSidecar) error { if len(sidecar.Blobs) != len(hashes) { return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sidecar.Blobs), len(hashes)) diff --git a/x/evm/ante/basic_test.go b/x/evm/ante/basic_test.go index 80ec510e1..c7d5255f0 100644 --- a/x/evm/ante/basic_test.go +++ b/x/evm/ante/basic_test.go @@ -20,8 +20,7 @@ func TestBasicDecorator(t *testing.T) { ctx, err := a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { return ctx, nil }) - require.Nil(t, err) // is not checktx - ctx = ctx.WithIsCheckTx(true) + require.NotNil(t, err) // expect out of gas err dataTooLarge := make([]byte, params.MaxInitCodeSize+1) for i := 0; i <= params.MaxInitCodeSize; i++ { dataTooLarge[i] = 1 @@ -53,21 +52,5 @@ func TestBasicDecorator(t *testing.T) { return ctx, nil }) require.NotNil(t, err) - require.Contains(t, err.Error(), "missing sidecar in blob transaction") - - msg, _ = types.NewMsgEVMTransaction(ðtx.BlobTx{GasLimit: 21000, Sidecar: ðtx.BlobTxSidecar{}}) - ctx, err = a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { - return ctx, nil - }) - require.NotNil(t, err) - require.Contains(t, err.Error(), "blobless blob transaction") - - msg, _ = types.NewMsgEVMTransaction(ðtx.BlobTx{GasLimit: 21000, Sidecar: ðtx.BlobTxSidecar{}, BlobHashes: [][]byte{ - {}, {}, {}, {}, {}, {}, {}, - }}) - ctx, err = a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { - return ctx, nil - }) - require.NotNil(t, err) - require.Contains(t, err.Error(), "too many blobs in transaction") + require.Error(t, err, sdkerrors.ErrUnsupportedTxType) } diff --git a/x/evm/ante/fee.go b/x/evm/ante/fee.go index 48328b82d..a3210b3f2 100644 --- a/x/evm/ante/fee.go +++ b/x/evm/ante/fee.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/sei-protocol/sei-chain/app/antedecorators" "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/x/evm/derived" evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" @@ -72,20 +73,20 @@ func (fc EVMFeeCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b // fee per gas to be burnt func (fc EVMFeeCheckDecorator) getBaseFee(ctx sdk.Context) *big.Int { - return fc.evmKeeper.GetBaseFeePerGas(ctx).RoundInt().BigInt() + return fc.evmKeeper.GetBaseFeePerGas(ctx).TruncateInt().BigInt() } // lowest allowed fee per gas func (fc EVMFeeCheckDecorator) getMinimumFee(ctx sdk.Context) *big.Int { - return fc.evmKeeper.GetMinimumFeePerGas(ctx).RoundInt().BigInt() + return fc.evmKeeper.GetMinimumFeePerGas(ctx).TruncateInt().BigInt() } // CalculatePriority returns a priority based on the effective gas price of the transaction func (fc EVMFeeCheckDecorator) CalculatePriority(ctx sdk.Context, txData ethtx.TxData) *big.Int { gp := txData.EffectiveGasPrice(utils.Big0) - priority := new(big.Int).Quo(gp, fc.evmKeeper.GetPriorityNormalizer(ctx).RoundInt().BigInt()) - if priority.Cmp(utils.BigMaxI64) > 0 { - priority = utils.BigMaxI64 + priority := sdk.NewDecFromBigInt(gp).Quo(fc.evmKeeper.GetPriorityNormalizer(ctx)).TruncateInt().BigInt() + if priority.Cmp(big.NewInt(antedecorators.MaxPriority)) > 0 { + priority = big.NewInt(antedecorators.MaxPriority) } return priority } diff --git a/x/evm/ante/fee_test.go b/x/evm/ante/fee_test.go index a7de56bfe..4fcb3572b 100644 --- a/x/evm/ante/fee_test.go +++ b/x/evm/ante/fee_test.go @@ -11,6 +11,7 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/holiman/uint256" + "github.com/sei-protocol/sei-chain/app/antedecorators" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/ante" "github.com/sei-protocol/sei-chain/x/evm/state" @@ -60,7 +61,7 @@ func TestEVMFeeCheckDecoratorCancun(t *testing.T) { }) require.NotNil(t, err) - txData.GasFeeCap = k.GetMinimumFeePerGas(ctx).RoundInt().BigInt() + txData.GasFeeCap = k.GetMinimumFeePerGas(ctx).TruncateInt().BigInt() tx, err = ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) require.Nil(t, err) typedTx, err = ethtx.NewDynamicFeeTx(tx) @@ -178,6 +179,7 @@ func TestCalculatePriorityScenarios(t *testing.T) { _1_1gwei := big.NewInt(1100000000000) _2gwei := big.NewInt(200000000000) maxInt := big.NewInt(math.MaxInt64) + maxPriority := big.NewInt(antedecorators.MaxPriority) scenarios := []struct { name string @@ -236,7 +238,7 @@ func TestCalculatePriorityScenarios(t *testing.T) { GasTipCap: new(big.Int).Add(maxInt, big.NewInt(1)), Value: big.NewInt(1000000000), }, - expectedPriority: maxInt, + expectedPriority: maxPriority, }, { name: "LegacyTx has priority with gas price", diff --git a/x/evm/ante/gas.go b/x/evm/ante/gas.go index 17f528443..5a04f2f51 100644 --- a/x/evm/ante/gas.go +++ b/x/evm/ante/gas.go @@ -23,6 +23,6 @@ func (gl GasLimitDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool } adjustedGasLimit := gl.evmKeeper.GetPriorityNormalizer(ctx).MulInt64(int64(txData.GetGas())) - ctx = ctx.WithGasMeter(sdk.NewGasMeter(adjustedGasLimit.RoundInt().Uint64())) + ctx = ctx.WithGasMeter(sdk.NewGasMeter(adjustedGasLimit.TruncateInt().Uint64())) return next(ctx, tx, simulate) } diff --git a/x/evm/ante/preprocess.go b/x/evm/ante/preprocess.go index a609293e9..0d5ad21de 100644 --- a/x/evm/ante/preprocess.go +++ b/x/evm/ante/preprocess.go @@ -71,6 +71,8 @@ func (p *EVMPreprocessDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate // check if the account has enough balance (without charging) baseDenom := p.evmKeeper.GetBaseDenom(ctx) seiBalance := p.evmKeeper.BankKeeper().GetBalance(ctx, seiAddr, baseDenom).Amount + // no need to get wei balance here since the sei address is not used directly in EVM and thus does not + // contain any wei, so any wei balance in `sdk.AccAddress(evmAddr[:])` would not add up to 1usei anyway. castBalance := p.evmKeeper.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), baseDenom).Amount if new(big.Int).Add(seiBalance.BigInt(), castBalance.BigInt()).Cmp(new(big.Int).SetUint64(BalanceThreshold)) < 0 { return ctx, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "account needs to have at least 1Sei to force association") diff --git a/x/evm/artifacts/cw20/artifacts.go b/x/evm/artifacts/cw20/artifacts.go index 9d8092ad1..073971723 100644 --- a/x/evm/artifacts/cw20/artifacts.go +++ b/x/evm/artifacts/cw20/artifacts.go @@ -5,8 +5,13 @@ import ( "embed" "encoding/hex" "fmt" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" ) +const CurrentVersion uint16 = 1 + //go:embed CW20ERC20Pointer.abi //go:embed CW20ERC20Pointer.bin //go:embed legacy.bin @@ -14,6 +19,7 @@ var f embed.FS var cachedBin []byte var cachedLegacyBin []byte +var cachedABI *abi.ABI func GetABI() []byte { bz, err := f.ReadFile("CW20ERC20Pointer.abi") @@ -23,6 +29,18 @@ func GetABI() []byte { return bz } +func GetParsedABI() *abi.ABI { + if cachedABI != nil { + return cachedABI + } + parsedABI, err := abi.JSON(strings.NewReader(string(GetABI()))) + if err != nil { + panic(err) + } + cachedABI = &parsedABI + return cachedABI +} + func GetBin() []byte { if cachedBin != nil { return cachedBin diff --git a/x/evm/artifacts/cw721/CW721ERC721Pointer.bin b/x/evm/artifacts/cw721/CW721ERC721Pointer.bin index c5dc1ca79..700510ae7 100644 --- a/x/evm/artifacts/cw721/CW721ERC721Pointer.bin +++ b/x/evm/artifacts/cw721/CW721ERC721Pointer.bin @@ -1 +1 @@ -608060405234801562000010575f80fd5b5060405162003be638038062003be68339818101604052810190620000369190620002c3565b8181815f9081620000489190620005b0565b5080600190816200005a9190620005b0565b50505061100260075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100360085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100460095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260069081620001349190620005b0565b5050505062000694565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200019f8262000157565b810181811067ffffffffffffffff82111715620001c157620001c062000167565b5b80604052505050565b5f620001d56200013e565b9050620001e3828262000194565b919050565b5f67ffffffffffffffff82111562000205576200020462000167565b5b620002108262000157565b9050602081019050919050565b5f5b838110156200023c5780820151818401526020810190506200021f565b5f8484015250505050565b5f6200025d6200025784620001e8565b620001ca565b9050828152602081018484840111156200027c576200027b62000153565b5b620002898482856200021d565b509392505050565b5f82601f830112620002a857620002a76200014f565b5b8151620002ba84826020860162000247565b91505092915050565b5f805f60608486031215620002dd57620002dc62000147565b5b5f84015167ffffffffffffffff811115620002fd57620002fc6200014b565b5b6200030b8682870162000291565b935050602084015167ffffffffffffffff8111156200032f576200032e6200014b565b5b6200033d8682870162000291565b925050604084015167ffffffffffffffff8111156200036157620003606200014b565b5b6200036f8682870162000291565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620003c857607f821691505b602082108103620003de57620003dd62000383565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004427fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000405565b6200044e868362000405565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000498620004926200048c8462000466565b6200046f565b62000466565b9050919050565b5f819050919050565b620004b38362000478565b620004cb620004c2826200049f565b84845462000411565b825550505050565b5f90565b620004e1620004d3565b620004ee818484620004a8565b505050565b5b818110156200051557620005095f82620004d7565b600181019050620004f4565b5050565b601f82111562000564576200052e81620003e4565b6200053984620003f6565b8101602085101562000549578190505b620005616200055885620003f6565b830182620004f3565b50505b505050565b5f82821c905092915050565b5f620005865f198460080262000569565b1980831691505092915050565b5f620005a0838362000575565b9150826002028217905092915050565b620005bb8262000379565b67ffffffffffffffff811115620005d757620005d662000167565b5b620005e38254620003b0565b620005f082828562000519565b5f60209050601f83116001811462000626575f841562000611578287015190505b6200061d858262000593565b8655506200068c565b601f1984166200063686620003e4565b5f5b828110156200065f5784890151825560018201915060208501945060208101905062000638565b868310156200067f57848901516200067b601f89168262000575565b8355505b6001600288020188555050505b505050505050565b61354480620006a25f395ff3fe608060405234801561000f575f80fd5b5060043610610109575f3560e01c806370a08231116100a0578063c2aed3021161006f578063c2aed302146102b3578063c87b56dd146102d1578063de4725cc14610301578063e985e9c51461031f578063f00b02551461034f57610109565b806370a082311461022d57806395d89b411461025d578063a22cb4651461027b578063b88d4fde1461029757610109565b806323b872dd116100dc57806323b872dd146101a757806342842e0e146101c35780635c4aead7146101df5780636352211e146101fd57610109565b806301ffc9a71461010d57806306fdde031461013d578063081812fc1461015b578063095ea7b31461018b575b5f80fd5b610127600480360381019061012291906123ea565b61036d565b604051610134919061242f565b60405180910390f35b61014561044e565b60405161015291906124d2565b60405180910390f35b61017560048036038101906101709190612525565b6104dd565b604051610182919061258f565b60405180910390f35b6101a560048036038101906101a091906125d2565b610837565b005b6101c160048036038101906101bc9190612610565b610a73565b005b6101dd60048036038101906101d89190612610565b610d18565b005b6101e7610d37565b6040516101f491906124d2565b60405180910390f35b61021760048036038101906102129190612525565b610dc3565b604051610224919061258f565b60405180910390f35b61024760048036038101906102429190612660565b61104d565b604051610254919061269a565b60405180910390f35b610265611343565b60405161027291906124d2565b60405180910390f35b610295600480360381019061029091906126dd565b6113d3565b005b6102b160048036038101906102ac9190612847565b6115d6565b005b6102bb6115f3565b6040516102c89190612922565b60405180910390f35b6102eb60048036038101906102e69190612525565b611618565b6040516102f891906124d2565b60405180910390f35b610309611815565b604051610316919061295b565b60405180910390f35b61033960048036038101906103349190612974565b61183a565b604051610346919061242f565b60405180910390f35b610357611c74565b60405161036491906129d2565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061043757507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610447575061044682611c99565b5b9050919050565b60605f805461045c90612a18565b80601f016020809104026020016040519081016040528092919081815260200182805461048890612a18565b80156104d35780601f106104aa576101008083540402835291602001916104d3565b820191905f5260205f20905b8154815290600101906020018083116104b657829003601f168201915b5050505050905090565b5f8061052e6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061052961052486611d02565b611dcc565b611e14565b90505f61058061057b6040518060400160405280600981526020017f617070726f76616c73000000000000000000000000000000000000000000000081525061057685611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016105e0929190612b2d565b5f60405180830381865afa1580156105fa573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106229190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b815260040161067f9190612c61565b5f60405180830381865afa158015610699573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106c19190612d76565b90505f8151111561082a575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5835f8151811061071d5761071c612dbd565b5b60200260200101516040518263ffffffff1660e01b81526004016107419190612e34565b5f60405180830381865afa15801561075b573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906107839190612bd0565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b81526004016107df91906124d2565b602060405180830381865afa1580156107fa573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061081e9190612e7b565b95505050505050610832565b5f9450505050505b919050565b5f61091a6040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061091560095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b81526004016108ce919061258f565b5f60405180830381865afa1580156108e8573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906109109190612f44565b611dcc565b611e14565b90505f61096c6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061096761096286611d02565b611dcc565b611e14565b90505f6109fd6109f86040518060400160405280600781526020017f617070726f7665000000000000000000000000000000000000000000000000008152506109f36109ee87876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611eae565b611e66565b611e14565b611e66565b9050610a0881611efc565b50838573ffffffffffffffffffffffffffffffffffffffff16610a2a86610dc3565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ae3575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ada919061258f565b60405180910390fd5b5f610bc66040518060400160405280600981526020017f726563697069656e740000000000000000000000000000000000000000000000815250610bc160095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401610b7a919061258f565b5f60405180830381865afa158015610b94573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610bbc9190612f44565b611dcc565b611e14565b90505f610c186040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610c13610c0e86611d02565b611dcc565b611e14565b90505f610ca9610ca46040518060400160405280600c81526020017f7472616e736665725f6e66740000000000000000000000000000000000000000815250610c9f610c9a87876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611eae565b611e66565b611e14565b611e66565b9050610cb481611efc565b50838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b610d3283838360405180602001604052805f8152506115d6565b505050565b60068054610d4490612a18565b80601f0160208091040260200160405190810160405280929190818152602001828054610d7090612a18565b8015610dbb5780601f10610d9257610100808354040283529160200191610dbb565b820191905f5260205f20905b815481529060010190602001808311610d9e57829003601f168201915b505050505081565b5f80610e146040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610e0f610e0a86611d02565b611dcc565b611e14565b90505f610e66610e616040518060400160405280600881526020017f6f776e65725f6f66000000000000000000000000000000000000000000000000815250610e5c85611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401610ec6929190612b2d565b5f60405180830381865afa158015610ee0573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610f089190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b8152600401610f659190612fd5565b5f60405180830381865afa158015610f7f573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610fa79190612bd0565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b815260040161100391906124d2565b602060405180830381865afa15801561101e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110429190612e7b565b945050505050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110be575f6040517f89c62b640000000000000000000000000000000000000000000000000000000081526004016110b5919061258f565b60405180910390fd5b5f6111a16040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061119c60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401611155919061258f565b5f60405180830381865afa15801561116f573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906111979190612f44565b611dcc565b611e14565b90505f6111f36111ee6040518060400160405280600681526020017f746f6b656e7300000000000000000000000000000000000000000000000000008152506111e985611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401611253929190612b2d565b5f60405180830381865afa15801561126d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906112959190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b81526004016112f29190613052565b5f60405180830381865afa15801561130c573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906113349190612d76565b90508051945050505050919050565b60606001805461135290612a18565b80601f016020809104026020016040519081016040528092919081815260200182805461137e90612a18565b80156113c95780601f106113a0576101008083540402835291602001916113c9565b820191905f5260205f20905b8154815290600101906020018083116113ac57829003601f168201915b5050505050905090565b5f6114be6114b96040518060400160405280600881526020017f6f70657261746f720000000000000000000000000000000000000000000000008152506114b460095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161146d919061258f565b5f60405180830381865afa158015611487573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906114af9190612f44565b611dcc565b611e14565b611e66565b9050811561151b5761151561151061150b6040518060400160405280600b81526020017f617070726f76655f616c6c00000000000000000000000000000000000000000081525084611e14565b611e66565b611efc565b5061156c565b61156a6115656115606040518060400160405280600a81526020017f7265766f6b655f616c6c0000000000000000000000000000000000000000000081525084611e14565b611e66565b611efc565b505b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31846040516115c9919061242f565b60405180910390a3505050565b6115e1848484610a73565b6115ed8484848461207a565b50505050565b60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606061162382610dc3565b505f6116746040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061166f61166a86611d02565b611dcc565b611e14565b90505f6116c66116c16040518060400160405280600881526020017f6e66745f696e666f0000000000000000000000000000000000000000000000008152506116bc85611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401611726929190612b2d565b5f60405180830381865afa158015611740573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906117689190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b81526004016117c591906130cf565b5f60405180830381865afa1580156117df573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906118079190612bd0565b905080945050505050919050565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f8061191e6040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061191960095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b81526004016118d2919061258f565b5f60405180830381865afa1580156118ec573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906119149190612f44565b611dcc565b611e14565b90505f61197061196b6040518060400160405280600d81526020017f616c6c5f6f70657261746f72730000000000000000000000000000000000000081525061196685611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016119d0929190612b2d565b5f60405180830381865afa1580156119ea573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611a129190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b8152600401611a6f919061314c565b5f60405180830381865afa158015611a89573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611ab19190612d76565b90505f5b8151811015611c65575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5848481518110611b0f57611b0e612dbd565b5b60200260200101516040518263ffffffff1660e01b8152600401611b339190612e34565b5f60405180830381865afa158015611b4d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611b759190612bd0565b90508773ffffffffffffffffffffffffffffffffffffffff1660095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539836040518263ffffffff1660e01b8152600401611be891906124d2565b602060405180830381865afa158015611c03573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c279190612e7b565b73ffffffffffffffffffffffffffffffffffffffff1603611c515760019650505050505050611c6e565b508080611c5d906131ac565b915050611ab5565b505f9450505050505b92915050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60605f6001611d108461222c565b0190505f8167ffffffffffffffff811115611d2e57611d2d612723565b5b6040519080825280601f01601f191660200182016040528015611d605781602001600182028036833780820191505090505b5090505f82602001820190505b600115611dc1578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581611db657611db56131f3565b5b0494505f8503611d6d575b819350505050919050565b606081604051602001611ddf9190613280565b604051602081830303815290604052604051602001611dfe91906132a5565b6040516020818303038152906040529050919050565b6060611e5e611e2284611dcc565b836040518060400160405280600181526020017f3a00000000000000000000000000000000000000000000000000000000000000815250611eae565b905092915050565b606081604051602001611e7991906132f0565b604051602081830303815290604052604051602001611e98919061333b565b6040516020818303038152906040529050919050565b6060838284604051602001611ec4929190613360565b604051602081830303815290604052604051602001611ee4929190613360565b60405160208183030381529060405290509392505050565b60605f8061100273ffffffffffffffffffffffffffffffffffffffff166006856040518060400160405280600281526020017f5b5d000000000000000000000000000000000000000000000000000000000000815250604051602401611f6493929190613383565b6040516020818303038152906040527f44d227ae000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051611fee9190613407565b5f60405180830381855af49150503d805f8114612026576040519150601f19603f3d011682016040523d82523d5f602084013e61202b565b606091505b509150915081612070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161206790613467565b60405180910390fd5b8092505050919050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b1115612226578273ffffffffffffffffffffffffffffffffffffffff1663150b7a026120bd61237d565b8685856040518563ffffffff1660e01b81526004016120df9493929190613485565b6020604051808303815f875af192505050801561211a57506040513d601f19601f8201168201806040525081019061211791906134e3565b60015b61219b573d805f8114612148576040519150601f19603f3d011682016040523d82523d5f602084013e61214d565b606091505b505f81510361219357836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161218a919061258f565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461222457836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161221b919061258f565b60405180910390fd5b505b50505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612288577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161227e5761227d6131f3565b5b0492506040810190505b6d04ee2d6d415b85acef810000000083106122c5576d04ee2d6d415b85acef810000000083816122bb576122ba6131f3565b5b0492506020810190505b662386f26fc1000083106122f457662386f26fc1000083816122ea576122e96131f3565b5b0492506010810190505b6305f5e100831061231d576305f5e1008381612313576123126131f3565b5b0492506008810190505b6127108310612342576127108381612338576123376131f3565b5b0492506004810190505b60648310612365576064838161235b5761235a6131f3565b5b0492506002810190505b600a8310612374576001810190505b80915050919050565b5f33905090565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6123c981612395565b81146123d3575f80fd5b50565b5f813590506123e4816123c0565b92915050565b5f602082840312156123ff576123fe61238d565b5b5f61240c848285016123d6565b91505092915050565b5f8115159050919050565b61242981612415565b82525050565b5f6020820190506124425f830184612420565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561247f578082015181840152602081019050612464565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6124a482612448565b6124ae8185612452565b93506124be818560208601612462565b6124c78161248a565b840191505092915050565b5f6020820190508181035f8301526124ea818461249a565b905092915050565b5f819050919050565b612504816124f2565b811461250e575f80fd5b50565b5f8135905061251f816124fb565b92915050565b5f6020828403121561253a5761253961238d565b5b5f61254784828501612511565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61257982612550565b9050919050565b6125898161256f565b82525050565b5f6020820190506125a25f830184612580565b92915050565b6125b18161256f565b81146125bb575f80fd5b50565b5f813590506125cc816125a8565b92915050565b5f80604083850312156125e8576125e761238d565b5b5f6125f5858286016125be565b925050602061260685828601612511565b9150509250929050565b5f805f606084860312156126275761262661238d565b5b5f612634868287016125be565b9350506020612645868287016125be565b925050604061265686828701612511565b9150509250925092565b5f602082840312156126755761267461238d565b5b5f612682848285016125be565b91505092915050565b612694816124f2565b82525050565b5f6020820190506126ad5f83018461268b565b92915050565b6126bc81612415565b81146126c6575f80fd5b50565b5f813590506126d7816126b3565b92915050565b5f80604083850312156126f3576126f261238d565b5b5f612700858286016125be565b9250506020612711858286016126c9565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6127598261248a565b810181811067ffffffffffffffff8211171561277857612777612723565b5b80604052505050565b5f61278a612384565b90506127968282612750565b919050565b5f67ffffffffffffffff8211156127b5576127b4612723565b5b6127be8261248a565b9050602081019050919050565b828183375f83830152505050565b5f6127eb6127e68461279b565b612781565b9050828152602081018484840111156128075761280661271f565b5b6128128482856127cb565b509392505050565b5f82601f83011261282e5761282d61271b565b5b813561283e8482602086016127d9565b91505092915050565b5f805f806080858703121561285f5761285e61238d565b5b5f61286c878288016125be565b945050602061287d878288016125be565b935050604061288e87828801612511565b925050606085013567ffffffffffffffff8111156128af576128ae612391565b5b6128bb8782880161281a565b91505092959194509250565b5f819050919050565b5f6128ea6128e56128e084612550565b6128c7565b612550565b9050919050565b5f6128fb826128d0565b9050919050565b5f61290c826128f1565b9050919050565b61291c81612902565b82525050565b5f6020820190506129355f830184612913565b92915050565b5f612945826128f1565b9050919050565b6129558161293b565b82525050565b5f60208201905061296e5f83018461294c565b92915050565b5f806040838503121561298a5761298961238d565b5b5f612997858286016125be565b92505060206129a8858286016125be565b9150509250929050565b5f6129bc826128f1565b9050919050565b6129cc816129b2565b82525050565b5f6020820190506129e55f8301846129c3565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680612a2f57607f821691505b602082108103612a4257612a416129eb565b5b50919050565b5f819050815f5260205f209050919050565b5f8154612a6681612a18565b612a708186612452565b9450600182165f8114612a8a5760018114612aa057612ad2565b60ff198316865281151560200286019350612ad2565b612aa985612a48565b5f5b83811015612aca57815481890152600182019150602081019050612aab565b808801955050505b50505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f612aff82612adb565b612b098185612ae5565b9350612b19818560208601612462565b612b228161248a565b840191505092915050565b5f6040820190508181035f830152612b458185612a5a565b90508181036020830152612b598184612af5565b90509392505050565b5f612b74612b6f8461279b565b612781565b905082815260208101848484011115612b9057612b8f61271f565b5b612b9b848285612462565b509392505050565b5f82601f830112612bb757612bb661271b565b5b8151612bc7848260208601612b62565b91505092915050565b5f60208284031215612be557612be461238d565b5b5f82015167ffffffffffffffff811115612c0257612c01612391565b5b612c0e84828501612ba3565b91505092915050565b7f617070726f76616c7300000000000000000000000000000000000000000000005f82015250565b5f612c4b600983612452565b9150612c5682612c17565b602082019050919050565b5f6040820190508181035f830152612c798184612af5565b90508181036020830152612c8c81612c3f565b905092915050565b5f67ffffffffffffffff821115612cae57612cad612723565b5b602082029050602081019050919050565b5f80fd5b5f612cd5612cd084612c94565b612781565b90508083825260208201905060208402830185811115612cf857612cf7612cbf565b5b835b81811015612d3f57805167ffffffffffffffff811115612d1d57612d1c61271b565b5b808601612d2a8982612ba3565b85526020850194505050602081019050612cfa565b5050509392505050565b5f82601f830112612d5d57612d5c61271b565b5b8151612d6d848260208601612cc3565b91505092915050565b5f60208284031215612d8b57612d8a61238d565b5b5f82015167ffffffffffffffff811115612da857612da7612391565b5b612db484828501612d49565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f7370656e646572000000000000000000000000000000000000000000000000005f82015250565b5f612e1e600783612452565b9150612e2982612dea565b602082019050919050565b5f6040820190508181035f830152612e4c8184612af5565b90508181036020830152612e5f81612e12565b905092915050565b5f81519050612e75816125a8565b92915050565b5f60208284031215612e9057612e8f61238d565b5b5f612e9d84828501612e67565b91505092915050565b5f67ffffffffffffffff821115612ec057612ebf612723565b5b612ec98261248a565b9050602081019050919050565b5f612ee8612ee384612ea6565b612781565b905082815260208101848484011115612f0457612f0361271f565b5b612f0f848285612462565b509392505050565b5f82601f830112612f2b57612f2a61271b565b5b8151612f3b848260208601612ed6565b91505092915050565b5f60208284031215612f5957612f5861238d565b5b5f82015167ffffffffffffffff811115612f7657612f75612391565b5b612f8284828501612f17565b91505092915050565b7f6f776e65720000000000000000000000000000000000000000000000000000005f82015250565b5f612fbf600583612452565b9150612fca82612f8b565b602082019050919050565b5f6040820190508181035f830152612fed8184612af5565b9050818103602083015261300081612fb3565b905092915050565b7f746f6b656e7300000000000000000000000000000000000000000000000000005f82015250565b5f61303c600683612452565b915061304782613008565b602082019050919050565b5f6040820190508181035f83015261306a8184612af5565b9050818103602083015261307d81613030565b905092915050565b7f746f6b656e5f75726900000000000000000000000000000000000000000000005f82015250565b5f6130b9600983612452565b91506130c482613085565b602082019050919050565b5f6040820190508181035f8301526130e78184612af5565b905081810360208301526130fa816130ad565b905092915050565b7f6f70657261746f727300000000000000000000000000000000000000000000005f82015250565b5f613136600983612452565b915061314182613102565b602082019050919050565b5f6040820190508181035f8301526131648184612af5565b905081810360208301526131778161312a565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6131b6826124f2565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036131e8576131e761317f565b5b600182019050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f81905092915050565b5f61323482612448565b61323e8185613220565b935061324e818560208601612462565b80840191505092915050565b7f2200000000000000000000000000000000000000000000000000000000000000815250565b5f61328b828461322a565b91506132968261325a565b60018201915081905092915050565b5f6132af8261325a565b6001820191506132bf828461322a565b915081905092915050565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b5f6132fb828461322a565b9150613306826132ca565b60018201915081905092915050565b7f7b00000000000000000000000000000000000000000000000000000000000000815250565b5f61334582613315565b600182019150613355828461322a565b915081905092915050565b5f61336b828561322a565b9150613377828461322a565b91508190509392505050565b5f6060820190508181035f83015261339b8186612a5a565b905081810360208301526133af8185612af5565b905081810360408301526133c38184612af5565b9050949350505050565b5f81905092915050565b5f6133e182612adb565b6133eb81856133cd565b93506133fb818560208601612462565b80840191505092915050565b5f61341282846133d7565b915081905092915050565b7f436f736d5761736d2065786563757465206661696c65640000000000000000005f82015250565b5f613451601783612452565b915061345c8261341d565b602082019050919050565b5f6020820190508181035f83015261347e81613445565b9050919050565b5f6080820190506134985f830187612580565b6134a56020830186612580565b6134b2604083018561268b565b81810360608301526134c48184612af5565b905095945050505050565b5f815190506134dd816123c0565b92915050565b5f602082840312156134f8576134f761238d565b5b5f613505848285016134cf565b9150509291505056fea2646970667358221220e5f30d268a1c1cbd830f6459bc10d756e5d2c01715cdaf7b88d3731c44af5bb164736f6c63430008150033 \ No newline at end of file +608060405234801562000010575f80fd5b5060405162003cc638038062003cc68339818101604052810190620000369190620002c3565b8181815f9081620000489190620005b0565b5080600190816200005a9190620005b0565b50505061100260075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100360085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100460095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260069081620001349190620005b0565b5050505062000694565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200019f8262000157565b810181811067ffffffffffffffff82111715620001c157620001c062000167565b5b80604052505050565b5f620001d56200013e565b9050620001e3828262000194565b919050565b5f67ffffffffffffffff82111562000205576200020462000167565b5b620002108262000157565b9050602081019050919050565b5f5b838110156200023c5780820151818401526020810190506200021f565b5f8484015250505050565b5f6200025d6200025784620001e8565b620001ca565b9050828152602081018484840111156200027c576200027b62000153565b5b620002898482856200021d565b509392505050565b5f82601f830112620002a857620002a76200014f565b5b8151620002ba84826020860162000247565b91505092915050565b5f805f60608486031215620002dd57620002dc62000147565b5b5f84015167ffffffffffffffff811115620002fd57620002fc6200014b565b5b6200030b8682870162000291565b935050602084015167ffffffffffffffff8111156200032f576200032e6200014b565b5b6200033d8682870162000291565b925050604084015167ffffffffffffffff8111156200036157620003606200014b565b5b6200036f8682870162000291565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620003c857607f821691505b602082108103620003de57620003dd62000383565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004427fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000405565b6200044e868362000405565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000498620004926200048c8462000466565b6200046f565b62000466565b9050919050565b5f819050919050565b620004b38362000478565b620004cb620004c2826200049f565b84845462000411565b825550505050565b5f90565b620004e1620004d3565b620004ee818484620004a8565b505050565b5b818110156200051557620005095f82620004d7565b600181019050620004f4565b5050565b601f82111562000564576200052e81620003e4565b6200053984620003f6565b8101602085101562000549578190505b620005616200055885620003f6565b830182620004f3565b50505b505050565b5f82821c905092915050565b5f620005865f198460080262000569565b1980831691505092915050565b5f620005a0838362000575565b9150826002028217905092915050565b620005bb8262000379565b67ffffffffffffffff811115620005d757620005d662000167565b5b620005e38254620003b0565b620005f082828562000519565b5f60209050601f83116001811462000626575f841562000611578287015190505b6200061d858262000593565b8655506200068c565b601f1984166200063686620003e4565b5f5b828110156200065f5784890151825560018201915060208501945060208101905062000638565b868310156200067f57848901516200067b601f89168262000575565b8355505b6001600288020188555050505b505050505050565b61362480620006a25f395ff3fe608060405234801561000f575f80fd5b5060043610610109575f3560e01c806370a08231116100a0578063c2aed3021161006f578063c2aed302146102b3578063c87b56dd146102d1578063de4725cc14610301578063e985e9c51461031f578063f00b02551461034f57610109565b806370a082311461022d57806395d89b411461025d578063a22cb4651461027b578063b88d4fde1461029757610109565b806323b872dd116100dc57806323b872dd146101a757806342842e0e146101c35780635c4aead7146101df5780636352211e146101fd57610109565b806301ffc9a71461010d57806306fdde031461013d578063081812fc1461015b578063095ea7b31461018b575b5f80fd5b61012760048036038101906101229190612462565b61036d565b60405161013491906124a7565b60405180910390f35b61014561044e565b604051610152919061254a565b60405180910390f35b6101756004803603810190610170919061259d565b6104dd565b6040516101829190612607565b60405180910390f35b6101a560048036038101906101a0919061264a565b610837565b005b6101c160048036038101906101bc9190612688565b610a73565b005b6101dd60048036038101906101d89190612688565b610d8e565b005b6101e7610dad565b6040516101f4919061254a565b60405180910390f35b6102176004803603810190610212919061259d565b610e39565b6040516102249190612607565b60405180910390f35b610247600480360381019061024291906126d8565b6110c3565b6040516102549190612712565b60405180910390f35b6102656113b9565b604051610272919061254a565b60405180910390f35b61029560048036038101906102909190612755565b611449565b005b6102b160048036038101906102ac91906128bf565b61164c565b005b6102bb611671565b6040516102c8919061299a565b60405180910390f35b6102eb60048036038101906102e6919061259d565b611696565b6040516102f8919061254a565b60405180910390f35b610309611893565b60405161031691906129d3565b60405180910390f35b610339600480360381019061033491906129ec565b6118b8565b60405161034691906124a7565b60405180910390f35b610357611cf2565b6040516103649190612a4a565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061043757507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610447575061044682611d17565b5b9050919050565b60605f805461045c90612a90565b80601f016020809104026020016040519081016040528092919081815260200182805461048890612a90565b80156104d35780601f106104aa576101008083540402835291602001916104d3565b820191905f5260205f20905b8154815290600101906020018083116104b657829003601f168201915b5050505050905090565b5f8061052e6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061052961052486611d80565b611e4a565b611e92565b90505f61058061057b6040518060400160405280600981526020017f617070726f76616c73000000000000000000000000000000000000000000000081525061057685611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016105e0929190612ba5565b5f60405180830381865afa1580156105fa573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106229190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b815260040161067f9190612cd9565b5f60405180830381865afa158015610699573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106c19190612dee565b90505f8151111561082a575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5835f8151811061071d5761071c612e35565b5b60200260200101516040518263ffffffff1660e01b81526004016107419190612eac565b5f60405180830381865afa15801561075b573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906107839190612c48565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b81526004016107df919061254a565b602060405180830381865afa1580156107fa573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061081e9190612ef3565b95505050505050610832565b5f9450505050505b919050565b5f61091a6040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061091560095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b81526004016108ce9190612607565b5f60405180830381865afa1580156108e8573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906109109190612fbc565b611e4a565b611e92565b90505f61096c6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061096761096286611d80565b611e4a565b611e92565b90505f6109fd6109f86040518060400160405280600781526020017f617070726f7665000000000000000000000000000000000000000000000000008152506109f36109ee87876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611f2c565b611ee4565b611e92565b611ee4565b9050610a0881611f7a565b50838573ffffffffffffffffffffffffffffffffffffffff16610a2a86610e39565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ae3575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ada9190612607565b60405180910390fd5b610aec81610e39565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610b59576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b509061304d565b60405180910390fd5b5f610c3c6040518060400160405280600981526020017f726563697069656e740000000000000000000000000000000000000000000000815250610c3760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401610bf09190612607565b5f60405180830381865afa158015610c0a573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610c329190612fbc565b611e4a565b611e92565b90505f610c8e6040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610c89610c8486611d80565b611e4a565b611e92565b90505f610d1f610d1a6040518060400160405280600c81526020017f7472616e736665725f6e66740000000000000000000000000000000000000000815250610d15610d1087876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611f2c565b611ee4565b611e92565b611ee4565b9050610d2a81611f7a565b50838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b610da883838360405180602001604052805f81525061164c565b505050565b60068054610dba90612a90565b80601f0160208091040260200160405190810160405280929190818152602001828054610de690612a90565b8015610e315780601f10610e0857610100808354040283529160200191610e31565b820191905f5260205f20905b815481529060010190602001808311610e1457829003601f168201915b505050505081565b5f80610e8a6040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610e85610e8086611d80565b611e4a565b611e92565b90505f610edc610ed76040518060400160405280600881526020017f6f776e65725f6f66000000000000000000000000000000000000000000000000815250610ed285611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401610f3c929190612ba5565b5f60405180830381865afa158015610f56573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610f7e9190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b8152600401610fdb91906130b5565b5f60405180830381865afa158015610ff5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061101d9190612c48565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b8152600401611079919061254a565b602060405180830381865afa158015611094573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110b89190612ef3565b945050505050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611134575f6040517f89c62b6400000000000000000000000000000000000000000000000000000000815260040161112b9190612607565b60405180910390fd5b5f6112176040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061121260095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b81526004016111cb9190612607565b5f60405180830381865afa1580156111e5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061120d9190612fbc565b611e4a565b611e92565b90505f6112696112646040518060400160405280600681526020017f746f6b656e73000000000000000000000000000000000000000000000000000081525061125f85611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016112c9929190612ba5565b5f60405180830381865afa1580156112e3573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061130b9190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b81526004016113689190613132565b5f60405180830381865afa158015611382573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906113aa9190612dee565b90508051945050505050919050565b6060600180546113c890612a90565b80601f01602080910402602001604051908101604052809291908181526020018280546113f490612a90565b801561143f5780601f106114165761010080835404028352916020019161143f565b820191905f5260205f20905b81548152906001019060200180831161142257829003601f168201915b5050505050905090565b5f61153461152f6040518060400160405280600881526020017f6f70657261746f7200000000000000000000000000000000000000000000000081525061152a60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b81526004016114e39190612607565b5f60405180830381865afa1580156114fd573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906115259190612fbc565b611e4a565b611e92565b611ee4565b905081156115915761158b6115866115816040518060400160405280600b81526020017f617070726f76655f616c6c00000000000000000000000000000000000000000081525084611e92565b611ee4565b611f7a565b506115e2565b6115e06115db6115d66040518060400160405280600a81526020017f7265766f6b655f616c6c0000000000000000000000000000000000000000000081525084611e92565b611ee4565b611f7a565b505b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318460405161163f91906124a7565b60405180910390a3505050565b611657848484610a73565b61166b6116626120f8565b858585856120ff565b50505050565b60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606116a182610e39565b505f6116f26040518060400160405280600881526020017f746f6b656e5f69640000000000000000000000000000000000000000000000008152506116ed6116e886611d80565b611e4a565b611e92565b90505f61174461173f6040518060400160405280600881526020017f6e66745f696e666f00000000000000000000000000000000000000000000000081525061173a85611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016117a4929190612ba5565b5f60405180830381865afa1580156117be573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906117e69190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b815260040161184391906131af565b5f60405180830381865afa15801561185d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906118859190612c48565b905080945050505050919050565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f8061199c6040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061199760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b81526004016119509190612607565b5f60405180830381865afa15801561196a573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906119929190612fbc565b611e4a565b611e92565b90505f6119ee6119e96040518060400160405280600d81526020017f616c6c5f6f70657261746f7273000000000000000000000000000000000000008152506119e485611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401611a4e929190612ba5565b5f60405180830381865afa158015611a68573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611a909190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b8152600401611aed919061322c565b5f60405180830381865afa158015611b07573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611b2f9190612dee565b90505f5b8151811015611ce3575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5848481518110611b8d57611b8c612e35565b5b60200260200101516040518263ffffffff1660e01b8152600401611bb19190612eac565b5f60405180830381865afa158015611bcb573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611bf39190612c48565b90508773ffffffffffffffffffffffffffffffffffffffff1660095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539836040518263ffffffff1660e01b8152600401611c66919061254a565b602060405180830381865afa158015611c81573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ca59190612ef3565b73ffffffffffffffffffffffffffffffffffffffff1603611ccf5760019650505050505050611cec565b508080611cdb9061328c565b915050611b33565b505f9450505050505b92915050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60605f6001611d8e846122ab565b0190505f8167ffffffffffffffff811115611dac57611dab61279b565b5b6040519080825280601f01601f191660200182016040528015611dde5781602001600182028036833780820191505090505b5090505f82602001820190505b600115611e3f578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581611e3457611e336132d3565b5b0494505f8503611deb575b819350505050919050565b606081604051602001611e5d9190613360565b604051602081830303815290604052604051602001611e7c9190613385565b6040516020818303038152906040529050919050565b6060611edc611ea084611e4a565b836040518060400160405280600181526020017f3a00000000000000000000000000000000000000000000000000000000000000815250611f2c565b905092915050565b606081604051602001611ef791906133d0565b604051602081830303815290604052604051602001611f16919061341b565b6040516020818303038152906040529050919050565b6060838284604051602001611f42929190613440565b604051602081830303815290604052604051602001611f62929190613440565b60405160208183030381529060405290509392505050565b60605f8061100273ffffffffffffffffffffffffffffffffffffffff166006856040518060400160405280600281526020017f5b5d000000000000000000000000000000000000000000000000000000000000815250604051602401611fe293929190613463565b6040516020818303038152906040527f44d227ae000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161206c91906134e7565b5f60405180830381855af49150503d805f81146120a4576040519150601f19603f3d011682016040523d82523d5f602084013e6120a9565b606091505b5091509150816120ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120e590613547565b60405180910390fd5b8092505050919050565b5f33905090565b5f8373ffffffffffffffffffffffffffffffffffffffff163b11156122a4578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02868685856040518563ffffffff1660e01b815260040161215d9493929190613565565b6020604051808303815f875af192505050801561219857506040513d601f19601f8201168201806040525081019061219591906135c3565b60015b612219573d805f81146121c6576040519150601f19603f3d011682016040523d82523d5f602084013e6121cb565b606091505b505f81510361221157836040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016122089190612607565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146122a257836040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016122999190612607565b60405180910390fd5b505b5050505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612307577a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083816122fd576122fc6132d3565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612344576d04ee2d6d415b85acef8100000000838161233a576123396132d3565b5b0492506020810190505b662386f26fc10000831061237357662386f26fc100008381612369576123686132d3565b5b0492506010810190505b6305f5e100831061239c576305f5e1008381612392576123916132d3565b5b0492506008810190505b61271083106123c15761271083816123b7576123b66132d3565b5b0492506004810190505b606483106123e457606483816123da576123d96132d3565b5b0492506002810190505b600a83106123f3576001810190505b80915050919050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6124418161240d565b811461244b575f80fd5b50565b5f8135905061245c81612438565b92915050565b5f6020828403121561247757612476612405565b5b5f6124848482850161244e565b91505092915050565b5f8115159050919050565b6124a18161248d565b82525050565b5f6020820190506124ba5f830184612498565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156124f75780820151818401526020810190506124dc565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61251c826124c0565b61252681856124ca565b93506125368185602086016124da565b61253f81612502565b840191505092915050565b5f6020820190508181035f8301526125628184612512565b905092915050565b5f819050919050565b61257c8161256a565b8114612586575f80fd5b50565b5f8135905061259781612573565b92915050565b5f602082840312156125b2576125b1612405565b5b5f6125bf84828501612589565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6125f1826125c8565b9050919050565b612601816125e7565b82525050565b5f60208201905061261a5f8301846125f8565b92915050565b612629816125e7565b8114612633575f80fd5b50565b5f8135905061264481612620565b92915050565b5f80604083850312156126605761265f612405565b5b5f61266d85828601612636565b925050602061267e85828601612589565b9150509250929050565b5f805f6060848603121561269f5761269e612405565b5b5f6126ac86828701612636565b93505060206126bd86828701612636565b92505060406126ce86828701612589565b9150509250925092565b5f602082840312156126ed576126ec612405565b5b5f6126fa84828501612636565b91505092915050565b61270c8161256a565b82525050565b5f6020820190506127255f830184612703565b92915050565b6127348161248d565b811461273e575f80fd5b50565b5f8135905061274f8161272b565b92915050565b5f806040838503121561276b5761276a612405565b5b5f61277885828601612636565b925050602061278985828601612741565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6127d182612502565b810181811067ffffffffffffffff821117156127f0576127ef61279b565b5b80604052505050565b5f6128026123fc565b905061280e82826127c8565b919050565b5f67ffffffffffffffff82111561282d5761282c61279b565b5b61283682612502565b9050602081019050919050565b828183375f83830152505050565b5f61286361285e84612813565b6127f9565b90508281526020810184848401111561287f5761287e612797565b5b61288a848285612843565b509392505050565b5f82601f8301126128a6576128a5612793565b5b81356128b6848260208601612851565b91505092915050565b5f805f80608085870312156128d7576128d6612405565b5b5f6128e487828801612636565b94505060206128f587828801612636565b935050604061290687828801612589565b925050606085013567ffffffffffffffff81111561292757612926612409565b5b61293387828801612892565b91505092959194509250565b5f819050919050565b5f61296261295d612958846125c8565b61293f565b6125c8565b9050919050565b5f61297382612948565b9050919050565b5f61298482612969565b9050919050565b6129948161297a565b82525050565b5f6020820190506129ad5f83018461298b565b92915050565b5f6129bd82612969565b9050919050565b6129cd816129b3565b82525050565b5f6020820190506129e65f8301846129c4565b92915050565b5f8060408385031215612a0257612a01612405565b5b5f612a0f85828601612636565b9250506020612a2085828601612636565b9150509250929050565b5f612a3482612969565b9050919050565b612a4481612a2a565b82525050565b5f602082019050612a5d5f830184612a3b565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680612aa757607f821691505b602082108103612aba57612ab9612a63565b5b50919050565b5f819050815f5260205f209050919050565b5f8154612ade81612a90565b612ae881866124ca565b9450600182165f8114612b025760018114612b1857612b4a565b60ff198316865281151560200286019350612b4a565b612b2185612ac0565b5f5b83811015612b4257815481890152600182019150602081019050612b23565b808801955050505b50505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f612b7782612b53565b612b818185612b5d565b9350612b918185602086016124da565b612b9a81612502565b840191505092915050565b5f6040820190508181035f830152612bbd8185612ad2565b90508181036020830152612bd18184612b6d565b90509392505050565b5f612bec612be784612813565b6127f9565b905082815260208101848484011115612c0857612c07612797565b5b612c138482856124da565b509392505050565b5f82601f830112612c2f57612c2e612793565b5b8151612c3f848260208601612bda565b91505092915050565b5f60208284031215612c5d57612c5c612405565b5b5f82015167ffffffffffffffff811115612c7a57612c79612409565b5b612c8684828501612c1b565b91505092915050565b7f617070726f76616c7300000000000000000000000000000000000000000000005f82015250565b5f612cc36009836124ca565b9150612cce82612c8f565b602082019050919050565b5f6040820190508181035f830152612cf18184612b6d565b90508181036020830152612d0481612cb7565b905092915050565b5f67ffffffffffffffff821115612d2657612d2561279b565b5b602082029050602081019050919050565b5f80fd5b5f612d4d612d4884612d0c565b6127f9565b90508083825260208201905060208402830185811115612d7057612d6f612d37565b5b835b81811015612db757805167ffffffffffffffff811115612d9557612d94612793565b5b808601612da28982612c1b565b85526020850194505050602081019050612d72565b5050509392505050565b5f82601f830112612dd557612dd4612793565b5b8151612de5848260208601612d3b565b91505092915050565b5f60208284031215612e0357612e02612405565b5b5f82015167ffffffffffffffff811115612e2057612e1f612409565b5b612e2c84828501612dc1565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f7370656e646572000000000000000000000000000000000000000000000000005f82015250565b5f612e966007836124ca565b9150612ea182612e62565b602082019050919050565b5f6040820190508181035f830152612ec48184612b6d565b90508181036020830152612ed781612e8a565b905092915050565b5f81519050612eed81612620565b92915050565b5f60208284031215612f0857612f07612405565b5b5f612f1584828501612edf565b91505092915050565b5f67ffffffffffffffff821115612f3857612f3761279b565b5b612f4182612502565b9050602081019050919050565b5f612f60612f5b84612f1e565b6127f9565b905082815260208101848484011115612f7c57612f7b612797565b5b612f878482856124da565b509392505050565b5f82601f830112612fa357612fa2612793565b5b8151612fb3848260208601612f4e565b91505092915050565b5f60208284031215612fd157612fd0612405565b5b5f82015167ffffffffffffffff811115612fee57612fed612409565b5b612ffa84828501612f8f565b91505092915050565b7f6066726f6d60206d75737420626520746865206f776e657200000000000000005f82015250565b5f6130376018836124ca565b915061304282613003565b602082019050919050565b5f6020820190508181035f8301526130648161302b565b9050919050565b7f6f776e65720000000000000000000000000000000000000000000000000000005f82015250565b5f61309f6005836124ca565b91506130aa8261306b565b602082019050919050565b5f6040820190508181035f8301526130cd8184612b6d565b905081810360208301526130e081613093565b905092915050565b7f746f6b656e7300000000000000000000000000000000000000000000000000005f82015250565b5f61311c6006836124ca565b9150613127826130e8565b602082019050919050565b5f6040820190508181035f83015261314a8184612b6d565b9050818103602083015261315d81613110565b905092915050565b7f746f6b656e5f75726900000000000000000000000000000000000000000000005f82015250565b5f6131996009836124ca565b91506131a482613165565b602082019050919050565b5f6040820190508181035f8301526131c78184612b6d565b905081810360208301526131da8161318d565b905092915050565b7f6f70657261746f727300000000000000000000000000000000000000000000005f82015250565b5f6132166009836124ca565b9150613221826131e2565b602082019050919050565b5f6040820190508181035f8301526132448184612b6d565b905081810360208301526132578161320a565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6132968261256a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036132c8576132c761325f565b5b600182019050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f81905092915050565b5f613314826124c0565b61331e8185613300565b935061332e8185602086016124da565b80840191505092915050565b7f2200000000000000000000000000000000000000000000000000000000000000815250565b5f61336b828461330a565b91506133768261333a565b60018201915081905092915050565b5f61338f8261333a565b60018201915061339f828461330a565b915081905092915050565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b5f6133db828461330a565b91506133e6826133aa565b60018201915081905092915050565b7f7b00000000000000000000000000000000000000000000000000000000000000815250565b5f613425826133f5565b600182019150613435828461330a565b915081905092915050565b5f61344b828561330a565b9150613457828461330a565b91508190509392505050565b5f6060820190508181035f83015261347b8186612ad2565b9050818103602083015261348f8185612b6d565b905081810360408301526134a38184612b6d565b9050949350505050565b5f81905092915050565b5f6134c182612b53565b6134cb81856134ad565b93506134db8185602086016124da565b80840191505092915050565b5f6134f282846134b7565b915081905092915050565b7f436f736d5761736d2065786563757465206661696c65640000000000000000005f82015250565b5f6135316017836124ca565b915061353c826134fd565b602082019050919050565b5f6020820190508181035f83015261355e81613525565b9050919050565b5f6080820190506135785f8301876125f8565b61358560208301866125f8565b6135926040830185612703565b81810360608301526135a48184612b6d565b905095945050505050565b5f815190506135bd81612438565b92915050565b5f602082840312156135d8576135d7612405565b5b5f6135e5848285016135af565b9150509291505056fea2646970667358221220a2c419c1e43b74d07c7e3f63d55af936cde414fdc186470d597ab1da5b53412e64736f6c63430008150033 \ No newline at end of file diff --git a/x/evm/artifacts/cw721/artifacts.go b/x/evm/artifacts/cw721/artifacts.go index 27d37be4d..18e5f812a 100644 --- a/x/evm/artifacts/cw721/artifacts.go +++ b/x/evm/artifacts/cw721/artifacts.go @@ -5,8 +5,13 @@ import ( "embed" "encoding/hex" "fmt" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" ) +const CurrentVersion uint16 = 2 + //go:embed CW721ERC721Pointer.abi //go:embed CW721ERC721Pointer.bin //go:embed legacy.bin @@ -14,6 +19,7 @@ var f embed.FS var cachedBin []byte var cachedLegacyBin []byte +var cachedABI *abi.ABI func GetABI() []byte { bz, err := f.ReadFile("CW721ERC721Pointer.abi") @@ -23,6 +29,18 @@ func GetABI() []byte { return bz } +func GetParsedABI() *abi.ABI { + if cachedABI != nil { + return cachedABI + } + parsedABI, err := abi.JSON(strings.NewReader(string(GetABI()))) + if err != nil { + panic(err) + } + cachedABI = &parsedABI + return cachedABI +} + func GetBin() []byte { if cachedBin != nil { return cachedBin diff --git a/x/evm/artifacts/erc20/artifacts.go b/x/evm/artifacts/erc20/artifacts.go new file mode 100644 index 000000000..9e964cbec --- /dev/null +++ b/x/evm/artifacts/erc20/artifacts.go @@ -0,0 +1,22 @@ +package erc20 + +import "embed" + +const CurrentVersion uint16 = 1 + +//go:embed cwerc20.wasm +var f embed.FS + +var cachedBin []byte + +func GetBin() []byte { + if cachedBin != nil { + return cachedBin + } + bz, err := f.ReadFile("cwerc20.wasm") + if err != nil { + panic("failed to read ERC20 wrapper contract wasm") + } + cachedBin = bz + return bz +} diff --git a/x/evm/artifacts/erc20/cwerc20.wasm b/x/evm/artifacts/erc20/cwerc20.wasm new file mode 100644 index 000000000..aac641633 Binary files /dev/null and b/x/evm/artifacts/erc20/cwerc20.wasm differ diff --git a/x/evm/artifacts/erc721/artifacts.go b/x/evm/artifacts/erc721/artifacts.go new file mode 100644 index 000000000..b542ee3b4 --- /dev/null +++ b/x/evm/artifacts/erc721/artifacts.go @@ -0,0 +1,22 @@ +package erc721 + +import "embed" + +const CurrentVersion uint16 = 1 + +//go:embed cwerc721.wasm +var f embed.FS + +var cachedBin []byte + +func GetBin() []byte { + if cachedBin != nil { + return cachedBin + } + bz, err := f.ReadFile("cwerc721.wasm") + if err != nil { + panic("failed to read ERC721 wrapper contract wasm") + } + cachedBin = bz + return bz +} diff --git a/x/evm/artifacts/erc721/cwerc721.wasm b/x/evm/artifacts/erc721/cwerc721.wasm new file mode 100644 index 000000000..318ada77b Binary files /dev/null and b/x/evm/artifacts/erc721/cwerc721.wasm differ diff --git a/x/evm/artifacts/native/artifacts.go b/x/evm/artifacts/native/artifacts.go index d624097d9..801f66f45 100644 --- a/x/evm/artifacts/native/artifacts.go +++ b/x/evm/artifacts/native/artifacts.go @@ -5,13 +5,19 @@ import ( "embed" "encoding/hex" "fmt" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" ) +const CurrentVersion uint16 = 1 + //go:embed NativeSeiTokensERC20.abi //go:embed NativeSeiTokensERC20.bin var f embed.FS var cachedBin []byte +var cachedABI *abi.ABI func GetABI() []byte { bz, err := f.ReadFile("NativeSeiTokensERC20.abi") @@ -21,6 +27,18 @@ func GetABI() []byte { return bz } +func GetParsedABI() *abi.ABI { + if cachedABI != nil { + return cachedABI + } + parsedABI, err := abi.JSON(strings.NewReader(string(GetABI()))) + if err != nil { + panic(err) + } + cachedABI = &parsedABI + return cachedABI +} + func GetBin() []byte { if cachedBin != nil { return cachedBin diff --git a/x/evm/artifacts/native/artifacts_test.go b/x/evm/artifacts/native/artifacts_test.go index 17876eceb..46451776c 100644 --- a/x/evm/artifacts/native/artifacts_test.go +++ b/x/evm/artifacts/native/artifacts_test.go @@ -69,6 +69,7 @@ func TestSimple(t *testing.T) { require.Nil(t, err) require.NotNil(t, receipt) require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) + k.SetERC20NativePointer(ctx, "test", common.HexToAddress(receipt.ContractAddress)) // send transaction to the contract contractAddr := common.HexToAddress(receipt.ContractAddress) diff --git a/x/evm/artifacts/utils/utils.go b/x/evm/artifacts/utils/utils.go new file mode 100644 index 000000000..c75eeb861 --- /dev/null +++ b/x/evm/artifacts/utils/utils.go @@ -0,0 +1,15 @@ +package utils + +import "encoding/binary" + +func GetVersionBz(version uint16) []byte { + res := make([]byte, 2) + binary.BigEndian.PutUint16(res, version) + return res +} + +func GetCodeIDBz(codeID uint64) []byte { + res := make([]byte, 8) + binary.BigEndian.PutUint64(res, codeID) + return res +} diff --git a/x/evm/artifacts/wsei/WSEI.abi b/x/evm/artifacts/wsei/WSEI.abi new file mode 100644 index 000000000..e8a5861f2 --- /dev/null +++ b/x/evm/artifacts/wsei/WSEI.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guy","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/x/evm/artifacts/wsei/WSEI.bin b/x/evm/artifacts/wsei/WSEI.bin new file mode 100644 index 000000000..471d4c80c --- /dev/null +++ b/x/evm/artifacts/wsei/WSEI.bin @@ -0,0 +1 @@ +60806040526040518060400160405280600b81526020017f57726170706564205365690000000000000000000000000000000000000000008152505f908162000049919062000323565b506040518060400160405280600481526020017f57534549000000000000000000000000000000000000000000000000000000008152506001908162000090919062000323565b50601260025f6101000a81548160ff021916908360ff160217905550348015620000b8575f80fd5b5062000407565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200013b57607f821691505b602082108103620001515762000150620000f6565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620001b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000178565b620001c1868362000178565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200020b62000205620001ff84620001d9565b620001e2565b620001d9565b9050919050565b5f819050919050565b6200022683620001eb565b6200023e620002358262000212565b84845462000184565b825550505050565b5f90565b6200025462000246565b620002618184846200021b565b505050565b5b8181101562000288576200027c5f826200024a565b60018101905062000267565b5050565b601f821115620002d757620002a18162000157565b620002ac8462000169565b81016020851015620002bc578190505b620002d4620002cb8562000169565b83018262000266565b50505b505050565b5f82821c905092915050565b5f620002f95f1984600802620002dc565b1980831691505092915050565b5f620003138383620002e8565b9150826002028217905092915050565b6200032e82620000bf565b67ffffffffffffffff8111156200034a5762000349620000c9565b5b62000356825462000123565b620003638282856200028c565b5f60209050601f83116001811462000399575f841562000384578287015190505b62000390858262000306565b865550620003ff565b601f198416620003a98662000157565b5f5b82811015620003d257848901518255600182019150602085019450602081019050620003ab565b86831015620003f25784890151620003ee601f891682620002e8565b8355505b6001600288020188555050505b505050505050565b610e5680620004155f395ff3fe60806040526004361061009f575f3560e01c8063313ce56711610063578063313ce567146101ac57806370a08231146101d657806395d89b4114610212578063a9059cbb1461023c578063d0e30db014610278578063dd62ed3e14610282576100ae565b806306fdde03146100b8578063095ea7b3146100e257806318160ddd1461011e57806323b872dd146101485780632e1a7d4d14610184576100ae565b366100ae576100ac6102be565b005b6100b66102be565b005b3480156100c3575f80fd5b506100cc610361565b6040516100d99190610ace565b60405180910390f35b3480156100ed575f80fd5b5061010860048036038101906101039190610b7f565b6103ec565b6040516101159190610bd7565b60405180910390f35b348015610129575f80fd5b506101326104d9565b60405161013f9190610bff565b60405180910390f35b348015610153575f80fd5b5061016e60048036038101906101699190610c18565b6104e0565b60405161017b9190610bd7565b60405180910390f35b34801561018f575f80fd5b506101aa60048036038101906101a59190610c68565b61082c565b005b3480156101b7575f80fd5b506101c061095d565b6040516101cd9190610cae565b60405180910390f35b3480156101e1575f80fd5b506101fc60048036038101906101f79190610cc7565b61096f565b6040516102099190610bff565b60405180910390f35b34801561021d575f80fd5b50610226610984565b6040516102339190610ace565b60405180910390f35b348015610247575f80fd5b50610262600480360381019061025d9190610b7f565b610a10565b60405161026f9190610bd7565b60405180910390f35b6102806102be565b005b34801561028d575f80fd5b506102a860048036038101906102a39190610cf2565b610a24565b6040516102b59190610bff565b60405180910390f35b3460035f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461030a9190610d5d565b925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040516103579190610bff565b60405180910390a2565b5f805461036d90610dbd565b80601f016020809104026020016040519081016040528092919081815260200182805461039990610dbd565b80156103e45780601f106103bb576101008083540402835291602001916103e4565b820191905f5260205f20905b8154815290600101906020018083116103c757829003601f168201915b505050505081565b5f8160045f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516104c79190610bff565b60405180910390a36001905092915050565b5f47905090565b5f8160035f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054101561052a575f80fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141580156105fe57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60045f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205414155b15610716578160045f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541015610687575f80fd5b8160045f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461070e9190610ded565b925050819055505b8160035f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546107629190610ded565b925050819055508160035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546107b59190610d5d565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516108199190610bff565b60405180910390a3600190509392505050565b8060035f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541015610875575f80fd5b8060035f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546108c19190610ded565b925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f1935050505015801561090b573d5f803e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65826040516109529190610bff565b60405180910390a250565b60025f9054906101000a900460ff1681565b6003602052805f5260405f205f915090505481565b6001805461099190610dbd565b80601f01602080910402602001604051908101604052809291908181526020018280546109bd90610dbd565b8015610a085780601f106109df57610100808354040283529160200191610a08565b820191905f5260205f20905b8154815290600101906020018083116109eb57829003601f168201915b505050505081565b5f610a1c3384846104e0565b905092915050565b6004602052815f5260405f20602052805f5260405f205f91509150505481565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610a7b578082015181840152602081019050610a60565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610aa082610a44565b610aaa8185610a4e565b9350610aba818560208601610a5e565b610ac381610a86565b840191505092915050565b5f6020820190508181035f830152610ae68184610a96565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610b1b82610af2565b9050919050565b610b2b81610b11565b8114610b35575f80fd5b50565b5f81359050610b4681610b22565b92915050565b5f819050919050565b610b5e81610b4c565b8114610b68575f80fd5b50565b5f81359050610b7981610b55565b92915050565b5f8060408385031215610b9557610b94610aee565b5b5f610ba285828601610b38565b9250506020610bb385828601610b6b565b9150509250929050565b5f8115159050919050565b610bd181610bbd565b82525050565b5f602082019050610bea5f830184610bc8565b92915050565b610bf981610b4c565b82525050565b5f602082019050610c125f830184610bf0565b92915050565b5f805f60608486031215610c2f57610c2e610aee565b5b5f610c3c86828701610b38565b9350506020610c4d86828701610b38565b9250506040610c5e86828701610b6b565b9150509250925092565b5f60208284031215610c7d57610c7c610aee565b5b5f610c8a84828501610b6b565b91505092915050565b5f60ff82169050919050565b610ca881610c93565b82525050565b5f602082019050610cc15f830184610c9f565b92915050565b5f60208284031215610cdc57610cdb610aee565b5b5f610ce984828501610b38565b91505092915050565b5f8060408385031215610d0857610d07610aee565b5b5f610d1585828601610b38565b9250506020610d2685828601610b38565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610d6782610b4c565b9150610d7283610b4c565b9250828201905080821115610d8a57610d89610d30565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610dd457607f821691505b602082108103610de757610de6610d90565b5b50919050565b5f610df782610b4c565b9150610e0283610b4c565b9250828203905081811115610e1a57610e19610d30565b5b9291505056fea26469706673582212209760e9f7136a7937f92559eee60462de4e4979de76e9753a09c73876151b049864736f6c63430008150033 \ No newline at end of file diff --git a/x/evm/artifacts/wsei/artifacts.go b/x/evm/artifacts/wsei/artifacts.go new file mode 100644 index 000000000..fda3b85c4 --- /dev/null +++ b/x/evm/artifacts/wsei/artifacts.go @@ -0,0 +1,54 @@ +package wsei + +import ( + "embed" + "encoding/hex" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +const CurrentVersion uint16 = 1 + +//go:embed WSEI.abi +//go:embed WSEI.bin +var f embed.FS + +var cachedBin []byte +var cachedABI *abi.ABI + +func GetABI() []byte { + bz, err := f.ReadFile("WSEI.abi") + if err != nil { + panic("failed to read WSEI contract ABI") + } + return bz +} + +func GetParsedABI() *abi.ABI { + if cachedABI != nil { + return cachedABI + } + parsedABI, err := abi.JSON(strings.NewReader(string(GetABI()))) + if err != nil { + panic(err) + } + cachedABI = &parsedABI + return cachedABI +} + +func GetBin() []byte { + if cachedBin != nil { + return cachedBin + } + code, err := f.ReadFile("WSEI.bin") + if err != nil { + panic("failed to read WSEI contract binary") + } + bz, err := hex.DecodeString(string(code)) + if err != nil { + panic("failed to decode WSEI contract binary") + } + cachedBin = bz + return bz +} diff --git a/x/evm/client/cli/gov_tx.go b/x/evm/client/cli/gov_tx.go new file mode 100644 index 000000000..40b475768 --- /dev/null +++ b/x/evm/client/cli/gov_tx.go @@ -0,0 +1,175 @@ +package cli + +import ( + "strconv" + "strings" + + "github.com/sei-protocol/sei-chain/x/evm/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/spf13/cobra" +) + +func NewAddERCNativePointerProposalTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "add-erc-native-pointer title description token version deposit [pointer address]", + Args: cobra.RangeArgs(5, 6), + Short: "Submit an add ERC-native pointer proposal", + Long: strings.TrimSpace(` + Submit a proposal to register an ERC pointer contract address for a native token. + Not specifying the pointer address means a proposal that deletes the existing pointer. + `), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + version, err := strconv.ParseUint(args[3], 10, 16) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(args[4]) + if err != nil { + return err + } + var pointer string + if len(args) == 6 { + pointer = args[5] + } + + // Convert proposal to RegisterPairsProposal Type + from := clientCtx.GetFromAddress() + + content := types.AddERCNativePointerProposal{ + Title: args[0], + Description: args[1], + Token: args[2], + Version: uint32(version), + Pointer: pointer, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, from) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func NewAddERCCW20PointerProposalTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "add-erc-cw20-pointer title description cw20address version deposit [pointer address]", + Args: cobra.RangeArgs(5, 6), + Short: "Submit an add ERC-CW20 pointer proposal", + Long: strings.TrimSpace(` + Submit a proposal to register an ERC pointer contract address for a CW20 token. + Not specifying the pointer address means a proposal that deletes the existing pointer. + `), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + version, err := strconv.ParseUint(args[3], 10, 16) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(args[4]) + if err != nil { + return err + } + var pointer string + if len(args) == 6 { + pointer = args[5] + } + + // Convert proposal to RegisterPairsProposal Type + from := clientCtx.GetFromAddress() + + content := types.AddERCCW20PointerProposal{ + Title: args[0], + Description: args[1], + Pointee: args[2], + Version: uint32(version), + Pointer: pointer, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, from) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func NewAddERCCW721PointerProposalTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "add-erc-cw721-pointer title description cw721address version deposit [pointer address]", + Args: cobra.RangeArgs(5, 6), + Short: "Submit an add ERC-CW721 pointer proposal", + Long: strings.TrimSpace(` + Submit a proposal to register an ERC pointer contract address for a CW721 token. + Not specifying the pointer address means a proposal that deletes the existing pointer. + `), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + version, err := strconv.ParseUint(args[3], 10, 16) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(args[4]) + if err != nil { + return err + } + var pointer string + if len(args) == 6 { + pointer = args[5] + } + + // Convert proposal to RegisterPairsProposal Type + from := clientCtx.GetFromAddress() + + content := types.AddERCCW721PointerProposal{ + Title: args[0], + Description: args[1], + Pointee: args[2], + Version: uint32(version), + Pointer: pointer, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, from) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/evm/client/cli/query.go b/x/evm/client/cli/query.go index 7d76198d2..084f4a725 100644 --- a/x/evm/client/cli/query.go +++ b/x/evm/client/cli/query.go @@ -43,6 +43,7 @@ func GetQueryCmd(_ string) *cobra.Command { cmd.AddCommand(CmdQueryERC721Payload()) cmd.AddCommand(CmdQueryERC20()) cmd.AddCommand(CmdQueryPayload()) + cmd.AddCommand(CmdQueryPointer()) return cmd } @@ -339,3 +340,29 @@ func CmdQueryERC721Payload() *cobra.Command { return cmd } + +func CmdQueryPointer() *cobra.Command { + cmd := &cobra.Command{ + Use: "pointer [type] [pointee]", + Short: "get pointer address of the specified type (one of [NATIVE, CW20, CW721, ERC20, ERC721]) and pointee", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Pointer(context.Background(), &types.QueryPointerRequest{ + PointerType: types.PointerType(types.PointerType_value[args[0]]), Pointee: args[1], + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/evm/client/cli/tx.go b/x/evm/client/cli/tx.go index c94cb99ba..0de934f06 100644 --- a/x/evm/client/cli/tx.go +++ b/x/evm/client/cli/tx.go @@ -14,7 +14,6 @@ import ( "strconv" "strings" - ethabi "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" @@ -35,6 +34,7 @@ import ( "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/wsei" "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" ) @@ -42,6 +42,7 @@ import ( const ( FlagGasFeeCap = "gas-fee-cap" FlagGas = "gas-limit" + FlagValue = "value" FlagRPC = "evm-rpc" FlagNonce = "nonce" ) @@ -62,9 +63,13 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(CmdDeployErcCw20()) cmd.AddCommand(CmdCallContract()) cmd.AddCommand(CmdDeployErcCw721()) + cmd.AddCommand(CmdDeployWSEI()) cmd.AddCommand(CmdERC20Send()) cmd.AddCommand(CmdDelegate()) cmd.AddCommand(NativeSendTxCmd()) + cmd.AddCommand(NewAddERCNativePointerProposalTxCmd()) + cmd.AddCommand(NewAddERCCW20PointerProposalTxCmd()) + cmd.AddCommand(NewAddERCCW721PointerProposalTxCmd()) return cmd } @@ -239,17 +244,11 @@ func CmdDeployErc20() *cobra.Command { } bytecode := native.GetBin() - abi := native.GetABI() - parsedABI, err := ethabi.JSON(strings.NewReader(string(abi))) - if err != nil { - fmt.Println("failed at parsing abi") - return err - } constructorArguments := []interface{}{ denom, name, symbol, uint8(decimal), } - packedArgs, err := parsedABI.Pack("", constructorArguments...) + packedArgs, err := native.GetParsedABI().Pack("", constructorArguments...) if err != nil { return err } @@ -325,17 +324,11 @@ func CmdDeployErcCw20() *cobra.Command { } bytecode := cw20.GetBin() - abi := cw20.GetABI() - parsedABI, err := ethabi.JSON(strings.NewReader(string(abi))) - if err != nil { - fmt.Println("failed at parsing abi") - return err - } constructorArguments := []interface{}{ args[0], args[1], args[2], } - packedArgs, err := parsedABI.Pack("", constructorArguments...) + packedArgs, err := cw20.GetParsedABI().Pack("", constructorArguments...) if err != nil { return err } @@ -411,17 +404,11 @@ func CmdDeployErcCw721() *cobra.Command { } bytecode := cw721.GetBin() - abi := cw721.GetABI() - parsedABI, err := ethabi.JSON(strings.NewReader(string(abi))) - if err != nil { - fmt.Println("failed at parsing abi") - return err - } constructorArguments := []interface{}{ args[0], args[1], args[2], } - packedArgs, err := parsedABI.Pack("", constructorArguments...) + packedArgs, err := cw721.GetParsedABI().Pack("", constructorArguments...) if err != nil { return err } @@ -516,12 +503,17 @@ func CmdCallContract() *cobra.Command { } } + value, err := cmd.Flags().GetUint64(FlagValue) + if err != nil { + return err + } + txData, err := getTxData(cmd) if err != nil { return err } txData.Nonce = nonce - txData.Value = utils.Big0 + txData.Value = big.NewInt(int64(value)) txData.Data = payload txData.To = &contract @@ -537,6 +529,7 @@ func CmdCallContract() *cobra.Command { cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") cmd.Flags().Uint64(FlagGas, 7000000, "Gas limit for the transaction") + cmd.Flags().Uint64(FlagValue, 0, "Value for the transaction") cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") flags.AddTxFlagsToCmd(cmd) @@ -678,6 +671,72 @@ func CmdDelegate() *cobra.Command { return cmd } +func CmdDeployWSEI() *cobra.Command { + cmd := &cobra.Command{ + Use: "deploy-wsei --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Short: "Deploy ERC20 contract for a native Sei token", + Long: "", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) (err error) { + contractData := wsei.GetBin() + + key, err := getPrivateKey(cmd) + if err != nil { + return err + } + + rpc, err := cmd.Flags().GetString(FlagRPC) + if err != nil { + return err + } + var nonce uint64 + if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { + nonce = uint64(n) + } else { + nonce, err = getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + } + + txData, err := getTxData(cmd) + if err != nil { + return err + } + txData.Nonce = nonce + txData.Value = utils.Big0 + txData.Data = contractData + + resp, err := sendTx(txData, rpc, key) + if err != nil { + return err + } + + senderAddr := crypto.PubkeyToAddress(key.PublicKey) + data, err := rlp.EncodeToBytes([]interface{}{senderAddr, nonce}) + if err != nil { + return err + } + hash := crypto.Keccak256Hash(data) + contractAddress := hash.Bytes()[12:] + contractAddressHex := hex.EncodeToString(contractAddress) + + fmt.Println("Deployer:", senderAddr) + fmt.Println("Deployed to:", fmt.Sprintf("0x%s", contractAddressHex)) + fmt.Println("Transaction hash:", resp.Hex()) + return nil + }, + } + + cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") + cmd.Flags().Uint64(FlagGas, 5000000, "Gas limit for the transaction") + cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + func getPrivateKey(cmd *cobra.Command) (*ecdsa.PrivateKey, error) { clientCtx, err := client.GetClientTxContext(cmd) if err != nil { diff --git a/x/evm/client/wasm/query.go b/x/evm/client/wasm/query.go index 77418f40a..8e94e306b 100644 --- a/x/evm/client/wasm/query.go +++ b/x/evm/client/wasm/query.go @@ -23,7 +23,10 @@ func NewEVMQueryHandler(k *keeper.Keeper) *EVMQueryHandler { } func (h *EVMQueryHandler) HandleStaticCall(ctx sdk.Context, from string, to string, data []byte) ([]byte, error) { - fromAddr := sdk.MustAccAddressFromBech32(from) + fromAddr, err := sdk.AccAddressFromBech32(from) + if err != nil { + return nil, err + } var toAddr *common.Address if to != "" { toSeiAddr := common.HexToAddress(to) @@ -37,7 +40,10 @@ func (h *EVMQueryHandler) HandleERC20TransferPayload(ctx sdk.Context, recipient if err != nil { return nil, err } - evmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, recipient) + evmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, recipient) + if err != nil { + return nil, err + } bz, err := abi.Pack("transfer", evmAddr, amount.BigInt()) if err != nil { return nil, err @@ -186,8 +192,14 @@ func (h *EVMQueryHandler) HandleERC721TransferPayload(ctx sdk.Context, from stri if err != nil { return nil, err } - fromEvmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, from) - toEvmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, recipient) + fromEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, from) + if err != nil { + return nil, err + } + toEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, recipient) + if err != nil { + return nil, err + } t, ok := sdk.NewIntFromString(tokenId) if !ok { return nil, errors.New("invalid token ID for ERC20, must be a big Int") @@ -202,8 +214,12 @@ func (h *EVMQueryHandler) HandleERC721TransferPayload(ctx sdk.Context, from stri func (h *EVMQueryHandler) HandleERC721ApprovePayload(ctx sdk.Context, spender string, tokenId string) ([]byte, error) { spenderEvmAddr := common.Address{} // empty address if approval should be revoked (i.e. spender string is empty) + var err error if spender != "" { - spenderEvmAddr = h.k.GetEVMAddressFromBech32OrDefault(ctx, spender) + spenderEvmAddr, err = h.k.GetEVMAddressFromBech32OrDefault(ctx, spender) + if err != nil { + return nil, err + } } abi, err := cw721.Cw721MetaData.GetAbi() if err != nil { @@ -222,7 +238,10 @@ func (h *EVMQueryHandler) HandleERC721ApprovePayload(ctx sdk.Context, spender st } func (h *EVMQueryHandler) HandleERC721SetApprovalAllPayload(ctx sdk.Context, to string, approved bool) ([]byte, error) { - evmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, to) + evmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, to) + if err != nil { + return nil, err + } abi, err := cw721.Cw721MetaData.GetAbi() if err != nil { return nil, err @@ -240,8 +259,14 @@ func (h *EVMQueryHandler) HandleERC20TransferFromPayload(ctx sdk.Context, owner if err != nil { return nil, err } - ownerEvmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, owner) - recipientEvmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, recipient) + ownerEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, owner) + if err != nil { + return nil, err + } + recipientEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, recipient) + if err != nil { + return nil, err + } bz, err := abi.Pack("transferFrom", ownerEvmAddr, recipientEvmAddr, amount.BigInt()) if err != nil { return nil, err @@ -255,7 +280,10 @@ func (h *EVMQueryHandler) HandleERC20ApprovePayload(ctx sdk.Context, spender str if err != nil { return nil, err } - spenderEvmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, spender) + spenderEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, spender) + if err != nil { + return nil, err + } bz, err := abi.Pack("approve", spenderEvmAddr, amount.BigInt()) if err != nil { @@ -267,11 +295,17 @@ func (h *EVMQueryHandler) HandleERC20ApprovePayload(ctx sdk.Context, spender str func (h *EVMQueryHandler) HandleERC20Allowance(ctx sdk.Context, contractAddress string, owner string, spender string) ([]byte, error) { // Get the evm address of the owner - ownerAddr := sdk.MustAccAddressFromBech32(owner) + ownerAddr, err := sdk.AccAddressFromBech32(owner) + if err != nil { + return nil, err + } ownerEvmAddr := h.k.GetEVMAddressOrDefault(ctx, ownerAddr) // Get the evm address of spender - spenderEvmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, spender) + spenderEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, spender) + if err != nil { + return nil, err + } // Fetch the contract ABI contract := common.HexToAddress(contractAddress) @@ -341,8 +375,14 @@ func (h *EVMQueryHandler) HandleERC721IsApprovedForAll(ctx sdk.Context, caller s if err != nil { return nil, err } - ownerEvmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, owner) - operatorEvmAddr := h.k.GetEVMAddressFromBech32OrDefault(ctx, operator) + ownerEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, owner) + if err != nil { + return nil, err + } + operatorEvmAddr, err := h.k.GetEVMAddressFromBech32OrDefault(ctx, operator) + if err != nil { + return nil, err + } contract := common.HexToAddress(contractAddress) abi, err := cw721.Cw721MetaData.GetAbi() if err != nil { diff --git a/x/evm/gov.go b/x/evm/gov.go new file mode 100644 index 000000000..879f2fa5d --- /dev/null +++ b/x/evm/gov.go @@ -0,0 +1,46 @@ +package evm + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func HandleAddERCNativePointerProposal(ctx sdk.Context, k *keeper.Keeper, p *types.AddERCNativePointerProposal) error { + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "native"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, p.Pointer), sdk.NewAttribute(types.AttributeKeyPointee, p.Token), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", p.Version)))) + if p.Pointer == "" { + k.DeleteERC20NativePointer(ctx, p.Token, uint16(p.Version)) + return nil + } + return k.SetERC20NativePointerWithVersion(ctx, p.Token, common.HexToAddress(p.Pointer), uint16(p.Version)) +} + +func HandleAddERCCW20PointerProposal(ctx sdk.Context, k *keeper.Keeper, p *types.AddERCCW20PointerProposal) error { + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "cw20"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, p.Pointer), sdk.NewAttribute(types.AttributeKeyPointee, p.Pointee), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", p.Version)))) + if p.Pointer == "" { + k.DeleteERC20CW20Pointer(ctx, p.Pointee, uint16(p.Version)) + return nil + } + return k.SetERC20CW20PointerWithVersion(ctx, p.Pointee, common.HexToAddress(p.Pointer), uint16(p.Version)) +} + +func HandleAddERCCW721PointerProposal(ctx sdk.Context, k *keeper.Keeper, p *types.AddERCCW721PointerProposal) error { + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "cw721"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, p.Pointer), sdk.NewAttribute(types.AttributeKeyPointee, p.Pointee), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", p.Version)))) + if p.Pointer == "" { + k.DeleteERC721CW721Pointer(ctx, p.Pointee, uint16(p.Version)) + return nil + } + return k.SetERC721CW721PointerWithVersion(ctx, p.Pointee, common.HexToAddress(p.Pointer), uint16(p.Version)) +} diff --git a/x/evm/gov_test.go b/x/evm/gov_test.go new file mode 100644 index 000000000..355403742 --- /dev/null +++ b/x/evm/gov_test.go @@ -0,0 +1,106 @@ +package evm_test + +import ( + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestAddERCNativePointerProposals(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, pointer1 := testkeeper.MockAddressPair() + _, pointer2 := testkeeper.MockAddressPair() + require.Nil(t, evm.HandleAddERCNativePointerProposal(ctx, k, &types.AddERCNativePointerProposal{ + Token: "test", + Version: 1, + Pointer: pointer1.Hex(), + })) + addr, ver, exists := k.GetERC20NativePointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) + require.Nil(t, evm.HandleAddERCNativePointerProposal(ctx, k, &types.AddERCNativePointerProposal{ + Token: "test", + Version: 2, + Pointer: pointer2.Hex(), + })) + addr, ver, exists = k.GetERC20NativePointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(2), ver) + require.Equal(t, addr, pointer2) + require.Nil(t, evm.HandleAddERCNativePointerProposal(ctx, k, &types.AddERCNativePointerProposal{ + Token: "test", + Version: 2, + })) + addr, ver, exists = k.GetERC20NativePointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) +} + +func TestAddERCCW20PointerProposals(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, pointer1 := testkeeper.MockAddressPair() + _, pointer2 := testkeeper.MockAddressPair() + require.Nil(t, evm.HandleAddERCCW20PointerProposal(ctx, k, &types.AddERCCW20PointerProposal{ + Pointee: "test", + Version: 1, + Pointer: pointer1.Hex(), + })) + addr, ver, exists := k.GetERC20CW20Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) + require.Nil(t, evm.HandleAddERCCW20PointerProposal(ctx, k, &types.AddERCCW20PointerProposal{ + Pointee: "test", + Version: 2, + Pointer: pointer2.Hex(), + })) + addr, ver, exists = k.GetERC20CW20Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(2), ver) + require.Equal(t, addr, pointer2) + require.Nil(t, evm.HandleAddERCCW20PointerProposal(ctx, k, &types.AddERCCW20PointerProposal{ + Pointee: "test", + Version: 2, + })) + addr, ver, exists = k.GetERC20CW20Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) +} + +func TestAddERCCW721PointerProposals(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, pointer1 := testkeeper.MockAddressPair() + _, pointer2 := testkeeper.MockAddressPair() + require.Nil(t, evm.HandleAddERCCW721PointerProposal(ctx, k, &types.AddERCCW721PointerProposal{ + Pointee: "test", + Version: 1, + Pointer: pointer1.Hex(), + })) + addr, ver, exists := k.GetERC721CW721Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) + require.Nil(t, evm.HandleAddERCCW721PointerProposal(ctx, k, &types.AddERCCW721PointerProposal{ + Pointee: "test", + Version: 2, + Pointer: pointer2.Hex(), + })) + addr, ver, exists = k.GetERC721CW721Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(2), ver) + require.Equal(t, addr, pointer2) + require.Nil(t, evm.HandleAddERCCW721PointerProposal(ctx, k, &types.AddERCCW721PointerProposal{ + Pointee: "test", + Version: 2, + })) + addr, ver, exists = k.GetERC721CW721Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) +} diff --git a/x/evm/handler.go b/x/evm/handler.go index eeaf2ab45..f610540ec 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -29,3 +30,18 @@ func NewHandler(k *keeper.Keeper) sdk.Handler { } } } + +func NewProposalHandler(k keeper.Keeper) govtypes.Handler { + return func(ctx sdk.Context, content govtypes.Content) error { + switch c := content.(type) { + case *types.AddERCNativePointerProposal: + return HandleAddERCNativePointerProposal(ctx, &k, c) + case *types.AddERCCW20PointerProposal: + return HandleAddERCCW20PointerProposal(ctx, &k, c) + case *types.AddERCCW721PointerProposal: + return HandleAddERCCW721PointerProposal(ctx, &k, c) + default: + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized evm proposal content type: %T", c) + } + } +} diff --git a/x/evm/keeper/address.go b/x/evm/keeper/address.go index e91d70267..0049ca711 100644 --- a/x/evm/keeper/address.go +++ b/x/evm/keeper/address.go @@ -13,6 +13,11 @@ func (k *Keeper) SetAddressMapping(ctx sdk.Context, seiAddress sdk.AccAddress, e if !k.accountKeeper.HasAccount(ctx, seiAddress) { k.accountKeeper.SetAccount(ctx, k.accountKeeper.NewAccountWithAddress(ctx, seiAddress)) } + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeAddressAssociated, + sdk.NewAttribute(types.AttributeKeySeiAddress, seiAddress.String()), + sdk.NewAttribute(types.AttributeKeyEvmAddress, evmAddress.Hex()), + )) } func (k *Keeper) DeleteAddressMapping(ctx sdk.Context, seiAddress sdk.AccAddress, evmAddress common.Address) { @@ -40,8 +45,12 @@ func (k *Keeper) GetEVMAddressOrDefault(ctx sdk.Context, seiAddress sdk.AccAddre return common.BytesToAddress(seiAddress) } -func (k *Keeper) GetEVMAddressFromBech32OrDefault(ctx sdk.Context, seiAddress string) common.Address { - return k.GetEVMAddressOrDefault(ctx, sdk.MustAccAddressFromBech32(seiAddress)) +func (k *Keeper) GetEVMAddressFromBech32OrDefault(ctx sdk.Context, seiAddress string) (common.Address, error) { + seiAddr, err := sdk.AccAddressFromBech32(seiAddress) + if err != nil { + return common.Address{}, err + } + return k.GetEVMAddressOrDefault(ctx, seiAddr), nil } func (k *Keeper) GetSeiAddress(ctx sdk.Context, evmAddress common.Address) (sdk.AccAddress, bool) { diff --git a/x/evm/keeper/evm.go b/x/evm/keeper/evm.go index 692247359..ae64cd5ba 100644 --- a/x/evm/keeper/evm.go +++ b/x/evm/keeper/evm.go @@ -23,7 +23,11 @@ func (k *Keeper) HandleInternalEVMCall(ctx sdk.Context, req *types.MsgInternalEV addr := common.HexToAddress(req.To) to = &addr } - ret, err := k.CallEVM(ctx, sdk.MustAccAddressFromBech32(req.Sender), to, req.Value, req.Data) + senderAddr, err := sdk.AccAddressFromBech32(req.Sender) + if err != nil { + return nil, err + } + ret, err := k.CallEVM(ctx, senderAddr, to, req.Value, req.Data) if err != nil { return nil, err } @@ -40,7 +44,11 @@ func (k *Keeper) HandleInternalEVMDelegateCall(ctx sdk.Context, req *types.MsgIn to = &addr } zeroInt := sdk.ZeroInt() - ret, err := k.CallEVM(ctx, sdk.MustAccAddressFromBech32(req.Sender), to, &zeroInt, req.Data) + senderAddr, err := sdk.AccAddressFromBech32(req.Sender) + if err != nil { + return nil, err + } + ret, err := k.CallEVM(ctx, senderAddr, to, &zeroInt, req.Data) if err != nil { return nil, err } @@ -52,7 +60,6 @@ func (k *Keeper) CallEVM(ctx sdk.Context, from sdk.AccAddress, to *common.Addres if err != nil { return nil, err } - var createdContractAddress common.Address defer func() { if finalizer != nil { if err := finalizer(); err != nil { @@ -60,16 +67,12 @@ func (k *Keeper) CallEVM(ctx sdk.Context, from sdk.AccAddress, to *common.Addres return } } - if reterr == nil && to == nil { - k.AddToWhitelistIfApplicable(ctx, data, createdContractAddress) - } }() var f EVMCallFunc if to == nil { // contract creation f = func(caller vm.ContractRef, _ *common.Address, input []byte, gas uint64, value *big.Int) ([]byte, uint64, error) { - ret, ca, leftoverGas, err := evm.Create(caller, input, gas, value) - createdContractAddress = ca + ret, _, leftoverGas, err := evm.Create(caller, input, gas, value) return ret, leftoverGas, err } } else { @@ -97,8 +100,8 @@ func (k *Keeper) callEVM(ctx sdk.Context, from sdk.AccAddress, to *common.Addres // infinite gas meter (used in queries) seiGasRemaining = math.MaxUint64 } - multiplier := k.GetPriorityNormalizer(ctx).RoundInt().BigInt() - evmGasRemaining := new(big.Int).Quo(new(big.Int).SetUint64(seiGasRemaining), multiplier) + multiplier := k.GetPriorityNormalizer(ctx) + evmGasRemaining := sdk.NewDecFromInt(sdk.NewIntFromUint64(seiGasRemaining)).Quo(multiplier).TruncateInt().BigInt() if evmGasRemaining.Cmp(MaxUint64BigInt) > 0 { evmGasRemaining = MaxUint64BigInt } @@ -107,7 +110,7 @@ func (k *Keeper) callEVM(ctx sdk.Context, from sdk.AccAddress, to *common.Addres value = val.BigInt() } ret, leftoverGas, err := f(vm.AccountRef(sender), to, data, evmGasRemaining.Uint64(), value) - ctx.GasMeter().ConsumeGas(ctx.GasMeter().Limit()-new(big.Int).Mul(new(big.Int).SetUint64(leftoverGas), multiplier).Uint64(), "call EVM") + ctx.GasMeter().ConsumeGas(ctx.GasMeter().Limit()-sdk.NewDecFromInt(sdk.NewIntFromUint64(leftoverGas)).Mul(multiplier).TruncateInt().Uint64(), "call EVM") if err != nil { return nil, err } diff --git a/x/evm/keeper/evm_test.go b/x/evm/keeper/evm_test.go index 4ecd5e3e9..940e246ec 100644 --- a/x/evm/keeper/evm_test.go +++ b/x/evm/keeper/evm_test.go @@ -59,6 +59,7 @@ func TestInternalCall(t *testing.T) { contractAddr := crypto.CreateAddress(senderEvmAddr, 0) require.NotEmpty(t, k.GetCode(ctx, contractAddr)) require.Equal(t, ret.Data, k.GetCode(ctx, contractAddr)) + k.SetERC20NativePointer(ctx, "test", contractAddr) receiverAddr, evmAddr := testkeeper.MockAddressPair() k.SetAddressMapping(ctx, receiverAddr, evmAddr) diff --git a/x/evm/keeper/genesis.go b/x/evm/keeper/genesis.go index 99e554496..dc46d5ac7 100644 --- a/x/evm/keeper/genesis.go +++ b/x/evm/keeper/genesis.go @@ -3,6 +3,7 @@ package keeper import ( "fmt" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" @@ -13,6 +14,9 @@ import ( "github.com/ethereum/go-ethereum/trie/triedb/hashdb" "github.com/ethereum/go-ethereum/trie/triedb/pathdb" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + artifactsutils "github.com/sei-protocol/sei-chain/x/evm/artifacts/utils" "github.com/sei-protocol/sei-chain/x/evm/types" ) @@ -31,6 +35,24 @@ func (k *Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { k.SetAddressMapping(ctx, sdk.MustAccAddressFromBech32(addr.SeiAddress), common.HexToAddress(addr.EthAddress)) } + erc20CodeID, err := k.wasmKeeper.Create(ctx, k.accountKeeper.GetModuleAddress(types.ModuleName), erc20.GetBin(), nil) + if err != nil { + panic(err) + } + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW20ERC20Prefix).Set( + artifactsutils.GetVersionBz(erc20.CurrentVersion), + artifactsutils.GetCodeIDBz(erc20CodeID), + ) + + erc721CodeID, err := k.wasmKeeper.Create(ctx, k.accountKeeper.GetModuleAddress(types.ModuleName), erc721.GetBin(), nil) + if err != nil { + panic(err) + } + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW721ERC721Prefix).Set( + artifactsutils.GetVersionBz(erc721.CurrentVersion), + artifactsutils.GetCodeIDBz(erc721CodeID), + ) + if k.EthReplayConfig.Enabled && !ethReplayInitialied { header := k.OpenEthDatabase() params := k.GetParams(ctx) diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index c4369002f..3c0905ef0 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -41,7 +41,11 @@ func (q Querier) EVMAddressBySeiAddress(c context.Context, req *types.QueryEVMAd if req.SeiAddress == "" { return nil, sdkerrors.ErrInvalidRequest } - addr, found := q.Keeper.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(req.SeiAddress)) + seiAddr, err := sdk.AccAddressFromBech32(req.SeiAddress) + if err != nil { + return nil, err + } + addr, found := q.Keeper.GetEVMAddress(ctx, seiAddr) if !found { return &types.QueryEVMAddressBySeiAddressResponse{Associated: false}, nil } @@ -54,6 +58,9 @@ func (q Querier) StaticCall(c context.Context, req *types.QueryStaticCallRequest if req.To == "" { return nil, errors.New("cannot use static call to create contracts") } + if ctx.GasMeter().Limit() == 0 { + ctx = ctx.WithGasMeter(sdk.NewGasMeter(q.QueryConfig.GasLimit)) + } to := common.HexToAddress(req.To) res, err := q.Keeper.StaticCallEVM(ctx, q.Keeper.AccountKeeper().GetModuleAddress(types.ModuleName), &to, req.Data) if err != nil { @@ -61,3 +68,46 @@ func (q Querier) StaticCall(c context.Context, req *types.QueryStaticCallRequest } return &types.QueryStaticCallResponse{Data: res}, nil } + +func (q Querier) Pointer(c context.Context, req *types.QueryPointerRequest) (*types.QueryPointerResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + switch req.PointerType { + case types.PointerType_NATIVE: + p, v, e := q.Keeper.GetERC20NativePointer(ctx, req.Pointee) + return &types.QueryPointerResponse{ + Pointer: p.Hex(), + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_CW20: + p, v, e := q.Keeper.GetERC20CW20Pointer(ctx, req.Pointee) + return &types.QueryPointerResponse{ + Pointer: p.Hex(), + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_CW721: + p, v, e := q.Keeper.GetERC721CW721Pointer(ctx, req.Pointee) + return &types.QueryPointerResponse{ + Pointer: p.Hex(), + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_ERC20: + p, v, e := q.Keeper.GetCW20ERC20Pointer(ctx, common.HexToAddress(req.Pointee)) + return &types.QueryPointerResponse{ + Pointer: p.String(), + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_ERC721: + p, v, e := q.Keeper.GetCW721ERC721Pointer(ctx, common.HexToAddress(req.Pointee)) + return &types.QueryPointerResponse{ + Pointer: p.String(), + Version: uint32(v), + Exists: e, + }, nil + default: + return nil, errors.ErrUnsupported + } +} diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go new file mode 100644 index 000000000..5df048043 --- /dev/null +++ b/x/evm/keeper/grpc_query_test.go @@ -0,0 +1,47 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestQueryPointer(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + seiAddr1, evmAddr1 := testkeeper.MockAddressPair() + seiAddr2, evmAddr2 := testkeeper.MockAddressPair() + seiAddr3, evmAddr3 := testkeeper.MockAddressPair() + seiAddr4, evmAddr4 := testkeeper.MockAddressPair() + seiAddr5, evmAddr5 := testkeeper.MockAddressPair() + goCtx := sdk.WrapSDKContext(ctx) + k.SetERC20NativePointer(ctx, seiAddr1.String(), evmAddr1) + k.SetERC20CW20Pointer(ctx, seiAddr2.String(), evmAddr2) + k.SetERC721CW721Pointer(ctx, seiAddr3.String(), evmAddr3) + k.SetCW20ERC20Pointer(ctx, evmAddr4, seiAddr4.String()) + k.SetCW721ERC721Pointer(ctx, evmAddr5, seiAddr5.String()) + q := keeper.Querier{k} + res, err := q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_NATIVE, Pointee: seiAddr1.String()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: evmAddr1.Hex(), Version: uint32(native.CurrentVersion), Exists: true}, *res) + res, err = q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_CW20, Pointee: seiAddr2.String()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: evmAddr2.Hex(), Version: uint32(cw20.CurrentVersion), Exists: true}, *res) + res, err = q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_CW721, Pointee: seiAddr3.String()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: evmAddr3.Hex(), Version: uint32(cw721.CurrentVersion), Exists: true}, *res) + res, err = q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_ERC20, Pointee: evmAddr4.Hex()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: seiAddr4.String(), Version: uint32(erc20.CurrentVersion), Exists: true}, *res) + res, err = q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_ERC721, Pointee: evmAddr5.Hex()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: seiAddr5.String(), Version: uint32(erc721.CurrentVersion), Exists: true}, *res) +} diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 8d729e703..92f98af7c 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -11,6 +11,7 @@ import ( "sort" "sync" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" @@ -32,6 +33,7 @@ import ( "github.com/sei-protocol/sei-chain/utils" "github.com/sei-protocol/sei-chain/x/evm/blocktest" + "github.com/sei-protocol/sei-chain/x/evm/querier" "github.com/sei-protocol/sei-chain/x/evm/replay" "github.com/sei-protocol/sei-chain/x/evm/state" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -49,6 +51,7 @@ type Keeper struct { accountKeeper *authkeeper.AccountKeeper stakingKeeper *stakingkeeper.Keeper transferKeeper ibctransferkeeper.Keeper + wasmKeeper *wasmkeeper.PermissionedKeeper cachedFeeCollectorAddressMtx *sync.RWMutex cachedFeeCollectorAddress *common.Address @@ -56,6 +59,8 @@ type Keeper struct { pendingTxs map[string][]*PendingTx keyToNonce map[tmtypes.TxKey]*AddressNoncePair + QueryConfig *querier.Config + // only used during ETH replay. Not used in chain critical path. EthClient *ethclient.Client EthReplayConfig replay.Config @@ -76,6 +81,7 @@ type EvmTxDeferredInfo struct { TxHash common.Hash TxBloom ethtypes.Bloom Surplus sdk.Int + Error string } type AddressNoncePair struct { @@ -109,7 +115,7 @@ func (ctx *ReplayChainContext) GetHeader(hash common.Hash, number uint64) *ethty func NewKeeper( storeKey sdk.StoreKey, memStoreKey sdk.StoreKey, paramstore paramtypes.Subspace, bankKeeper bankkeeper.Keeper, accountKeeper *authkeeper.AccountKeeper, stakingKeeper *stakingkeeper.Keeper, - transferKeeper ibctransferkeeper.Keeper) *Keeper { + transferKeeper ibctransferkeeper.Keeper, wasmKeeper *wasmkeeper.PermissionedKeeper) *Keeper { if !paramstore.HasKeyTable() { paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) } @@ -121,6 +127,7 @@ func NewKeeper( accountKeeper: accountKeeper, stakingKeeper: stakingKeeper, transferKeeper: transferKeeper, + wasmKeeper: wasmKeeper, pendingTxs: make(map[string][]*PendingTx), nonceMx: &sync.RWMutex{}, cachedFeeCollectorAddressMtx: &sync.RWMutex{}, @@ -138,6 +145,10 @@ func (k *Keeper) BankKeeper() bankkeeper.Keeper { return k.bankKeeper } +func (k *Keeper) WasmKeeper() *wasmkeeper.PermissionedKeeper { + return k.wasmKeeper +} + func (k *Keeper) GetStoreKey() sdk.StoreKey { return k.storeKey } @@ -170,16 +181,25 @@ func (k *Keeper) GetVMBlockContext(ctx sdk.Context, gp core.GasPool) (*vm.BlockC return nil, err } rh := common.BytesToHash(r) + + txfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { + if IsPayablePrecompile(&recipient) { + state.TransferWithoutEvents(db, sender, recipient, amount) + } else { + core.Transfer(db, sender, recipient, amount) + } + } + return &vm.BlockContext{ CanTransfer: core.CanTransfer, - Transfer: core.Transfer, + Transfer: txfer, GetHash: k.GetHashFn(ctx), Coinbase: coinbase, GasLimit: gp.Gas(), BlockNumber: big.NewInt(ctx.BlockHeight()), Time: uint64(ctx.BlockHeader().Time.Unix()), - Difficulty: utils.Big0, // only needed for PoW - BaseFee: k.GetBaseFeePerGas(ctx).RoundInt().BigInt(), // feemarket not enabled + Difficulty: utils.Big0, // only needed for PoW + BaseFee: k.GetBaseFeePerGas(ctx).TruncateInt().BigInt(), // feemarket not enabled Random: &rh, }, nil } @@ -212,7 +232,7 @@ func (k *Keeper) GetEVMTxDeferredInfo(ctx sdk.Context) (res []EvmTxDeferredInfo) ctx.Logger().Error(fmt.Sprintf("getting invalid tx index in EVM deferred info: %d, num of txs: %d", txIdx, len(k.txResults))) return true } - if k.txResults[txIdx].Code == 0 { + if k.txResults[txIdx].Code == 0 || value.(*EvmTxDeferredInfo).Error != "" { res = append(res, *(value.(*EvmTxDeferredInfo))) } return true @@ -230,6 +250,14 @@ func (k *Keeper) AppendToEvmTxDeferredInfo(ctx sdk.Context, bloom ethtypes.Bloom }) } +func (k *Keeper) AppendErrorToEvmTxDeferredInfo(ctx sdk.Context, txHash common.Hash, err string) { + k.deferredInfo.Store(ctx.TxIndex(), &EvmTxDeferredInfo{ + TxIndx: ctx.TxIndex(), + TxHash: txHash, + Error: err, + }) +} + func (k *Keeper) ClearEVMTxDeferredInfo() { k.deferredInfo = &sync.Map{} } @@ -411,8 +439,12 @@ func (k *Keeper) GetBaseFee(ctx sdk.Context) *big.Int { return k.ReplayBlock.Header_.BaseFee } if k.EthBlockTestConfig.Enabled { - block := k.BlockTest.Json.Blocks[ctx.BlockHeight()-1] - return block.BlockHeader.BaseFeePerGas + bb := k.BlockTest.Json.Blocks[ctx.BlockHeight()-1] + b, err := bb.Decode() + if err != nil { + panic(err) + } + return b.Header_.BaseFee } return nil } @@ -450,27 +482,21 @@ func (k *Keeper) getInt64State(ctx sdk.Context, key []byte) int64 { } func (k *Keeper) getBlockTestBlockCtx(ctx sdk.Context) (*vm.BlockContext, error) { - btBlock := k.BlockTest.Json.Blocks[ctx.BlockHeight()-1] - btHeader := btBlock.BlockHeader - header := ðtypes.Header{ - ParentHash: btHeader.ParentHash, - UncleHash: btHeader.UncleHash, - Coinbase: btHeader.Coinbase, - Root: btHeader.StateRoot, - TxHash: btHeader.TransactionsTrie, - ReceiptHash: btHeader.ReceiptTrie, - Bloom: btHeader.Bloom, - Difficulty: btHeader.Difficulty, - Number: new(big.Int).Set(btHeader.Number), - GasLimit: btHeader.GasLimit, - GasUsed: btHeader.GasUsed, - Time: btHeader.Timestamp, - Extra: btHeader.ExtraData, - MixDigest: btHeader.MixHash, - Nonce: btHeader.Nonce, - BaseFee: btHeader.BaseFeePerGas, + bb := k.BlockTest.Json.Blocks[ctx.BlockHeight()-1] + b, err := bb.Decode() + if err != nil { + return nil, err + } + header := b.Header_ + getHash := func(height uint64) common.Hash { + height = height + 1 + for i := 0; i < len(k.BlockTest.Json.Blocks); i++ { + if k.BlockTest.Json.Blocks[i].BlockHeader.Number.Uint64() == height { + return k.BlockTest.Json.Blocks[i].BlockHeader.Hash + } + } + panic(fmt.Sprintf("block hash not found for height %d", height)) } - getHash := core.GetHashFn(header, &ReplayChainContext{ethClient: k.EthClient}) var ( baseFee *big.Int blobBaseFee *big.Int @@ -481,6 +507,8 @@ func (k *Keeper) getBlockTestBlockCtx(ctx sdk.Context) (*vm.BlockContext, error) } if header.ExcessBlobGas != nil { blobBaseFee = eip4844.CalcBlobFee(*header.ExcessBlobGas) + } else { + blobBaseFee = eip4844.CalcBlobFee(0) } if header.Difficulty.Cmp(common.Big0) == 0 { random = &header.MixDigest diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index ab00adb83..691909a44 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -2,12 +2,15 @@ package keeper import ( "context" + "encoding/binary" + "encoding/json" "fmt" "math" "math/big" "runtime/debug" "github.com/armon/go-metrics" + "github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" @@ -19,6 +22,9 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + artifactsutils "github.com/sei-protocol/sei-chain/x/evm/artifacts/utils" "github.com/sei-protocol/sei-chain/x/evm/state" evmtracers "github.com/sei-protocol/sei-chain/x/evm/tracers" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -75,6 +81,7 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT debug.PrintStack() ctx.Logger().Error(fmt.Sprintf("EVM PANIC: %s", pe)) telemetry.IncrCounter(1, types.ModuleName, "panics") + server.AppendErrorToEvmTxDeferredInfo(ctx, tx.Hash(), fmt.Sprintf("%s", pe)) panic(pe) } @@ -136,9 +143,6 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT bloom := ethtypes.Bloom{} bloom.SetBytes(receipt.LogsBloom) server.AppendToEvmTxDeferredInfo(ctx, bloom, tx.Hash(), surplus) - if serverRes.VmError == "" && tx.To() == nil { - server.AddToWhitelistIfApplicable(ctx, tx.Data(), common.HexToAddress(receipt.ContractAddress)) - } // GasUsed in serverRes is in EVM's gas unit, not Sei's gas unit. // PriorityNormalizer is the coefficient that's used to adjust EVM @@ -146,7 +150,7 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT // to Sei transactions' priority, which is based on gas limit in // Sei unit, so we use the same coefficient to convert gas unit here. adjustedGasUsed := server.GetPriorityNormalizer(ctx).MulInt64(int64(serverRes.GasUsed)) - originalGasMeter.ConsumeGas(adjustedGasUsed.RoundInt().Uint64(), "evm transaction") + originalGasMeter.ConsumeGas(adjustedGasUsed.TruncateInt().Uint64(), "evm transaction") }() st := core.NewStateTransition(evmInstance, emsg, &gp) @@ -284,6 +288,66 @@ func (server msgServer) Send(goCtx context.Context, msg *types.MsgSend) (*types. return &types.MsgSendResponse{}, nil } +func (server msgServer) RegisterPointer(goCtx context.Context, msg *types.MsgRegisterPointer) (*types.MsgRegisterPointerResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + var existingPointer sdk.AccAddress + var existingVersion uint16 + var currentVersion uint16 + var exists bool + switch msg.PointerType { + case types.PointerType_ERC20: + currentVersion = erc20.CurrentVersion + existingPointer, existingVersion, exists = server.GetCW20ERC20Pointer(ctx, common.HexToAddress(msg.ErcAddress)) + case types.PointerType_ERC721: + currentVersion = erc721.CurrentVersion + existingPointer, existingVersion, exists = server.GetCW721ERC721Pointer(ctx, common.HexToAddress(msg.ErcAddress)) + default: + panic("unknown pointer type") + } + if exists && existingVersion >= currentVersion { + return nil, fmt.Errorf("pointer %s already registered at version %d", existingPointer.String(), existingVersion) + } + store := server.PrefixStore(ctx, types.PointerCWCodePrefix) + payload := map[string]interface{}{} + switch msg.PointerType { + case types.PointerType_ERC20: + store = prefix.NewStore(store, types.PointerCW20ERC20Prefix) + payload["erc20_address"] = msg.ErcAddress + case types.PointerType_ERC721: + store = prefix.NewStore(store, types.PointerCW721ERC721Prefix) + payload["erc721_address"] = msg.ErcAddress + default: + panic("unknown pointer type") + } + codeID := binary.BigEndian.Uint64(store.Get(artifactsutils.GetVersionBz(currentVersion))) + bz, err := json.Marshal(payload) + if err != nil { + return nil, err + } + moduleAcct := server.accountKeeper.GetModuleAddress(types.ModuleName) + pointerAddr, _, err := server.wasmKeeper.Instantiate(ctx, codeID, moduleAcct, moduleAcct, bz, fmt.Sprintf("Pointer of %s", msg.ErcAddress), sdk.NewCoins()) + if err != nil { + return nil, err + } + switch msg.PointerType { + case types.PointerType_ERC20: + err = server.SetCW20ERC20Pointer(ctx, common.HexToAddress(msg.ErcAddress), pointerAddr.String()) + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "erc20"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, pointerAddr.String()), sdk.NewAttribute(types.AttributeKeyPointee, msg.ErcAddress), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", erc20.CurrentVersion)))) + case types.PointerType_ERC721: + err = server.SetCW721ERC721Pointer(ctx, common.HexToAddress(msg.ErcAddress), pointerAddr.String()) + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "erc721"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, pointerAddr.String()), sdk.NewAttribute(types.AttributeKeyPointee, msg.ErcAddress), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", erc721.CurrentVersion)))) + default: + panic("unknown pointer type") + } + return &types.MsgRegisterPointerResponse{PointerAddress: pointerAddr.String()}, err +} + func (server msgServer) getEthReceipt(ctx sdk.Context, tx *ethtypes.Transaction, msg *core.Message, response *types.MsgEVMTransactionResponse, stateDB *state.DBImpl) *ethtypes.Receipt { ethLogs := stateDB.GetAllLogs() receipt := ðtypes.Receipt{ diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index a2007f9cf..6dfc66605 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -16,6 +16,8 @@ import ( "github.com/sei-protocol/sei-chain/example/contracts/simplestorage" testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/state" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -300,8 +302,7 @@ func TestEVMPrecompiles(t *testing.T) { require.Nil(t, err) require.NotNil(t, receipt) require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) - codeHash := k.GetCodeHash(ctx, common.HexToAddress(receipt.ContractAddress)) - k.AddCodeHashWhitelistedForBankSend(ctx, codeHash) + k.SetERC20NativePointer(ctx, k.GetBaseDenom(ctx), common.HexToAddress(receipt.ContractAddress)) // call sendall addr1, evmAddr1 := testkeeper.MockAddressPair() @@ -456,3 +457,85 @@ func TestSend(t *testing.T) { require.Equal(t, sdk.NewInt(500000), k.BankKeeper().GetBalance(ctx, seiFrom, "usei").Amount) require.Equal(t, sdk.NewInt(500000), k.BankKeeper().GetBalance(ctx, seiTo, "usei").Amount) } + +func TestRegisterPointer(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + sender, _ := testkeeper.MockAddressPair() + _, pointee := testkeeper.MockAddressPair() + res, err := keeper.NewMsgServerImpl(k).RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: sender.String(), + PointerType: types.PointerType_ERC20, + ErcAddress: pointee.Hex(), + }) + require.Nil(t, err) + pointer, version, exists := k.GetCW20ERC20Pointer(ctx, pointee) + require.True(t, exists) + require.Equal(t, erc20.CurrentVersion, version) + require.Equal(t, pointer.String(), res.PointerAddress) + hasRegisteredEvent := false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + require.Equal(t, types.EventTypePointerRegistered, e.Type) + require.Equal(t, "erc20", string(e.Attributes[0].Value)) + } + require.True(t, hasRegisteredEvent) + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + // already exists + _, err = keeper.NewMsgServerImpl(k).RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: sender.String(), + PointerType: types.PointerType_ERC20, + ErcAddress: pointee.Hex(), + }) + require.NotNil(t, err) + hasRegisteredEvent = false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + } + require.False(t, hasRegisteredEvent) + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + res, err = keeper.NewMsgServerImpl(k).RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: sender.String(), + PointerType: types.PointerType_ERC721, + ErcAddress: pointee.Hex(), + }) + require.Nil(t, err) + pointer, version, exists = k.GetCW721ERC721Pointer(ctx, pointee) + require.True(t, exists) + require.Equal(t, erc721.CurrentVersion, version) + require.Equal(t, pointer.String(), res.PointerAddress) + hasRegisteredEvent = false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + require.Equal(t, types.EventTypePointerRegistered, e.Type) + require.Equal(t, "erc721", string(e.Attributes[0].Value)) + } + require.True(t, hasRegisteredEvent) + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + // already exists + _, err = keeper.NewMsgServerImpl(k).RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: sender.String(), + PointerType: types.PointerType_ERC721, + ErcAddress: pointee.Hex(), + }) + require.NotNil(t, err) + hasRegisteredEvent = false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + } + require.False(t, hasRegisteredEvent) +} diff --git a/x/evm/keeper/pointer.go b/x/evm/keeper/pointer.go new file mode 100644 index 000000000..e87192834 --- /dev/null +++ b/x/evm/keeper/pointer.go @@ -0,0 +1,132 @@ +package keeper + +import ( + "encoding/binary" + "fmt" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func (k *Keeper) SetERC20NativePointer(ctx sdk.Context, token string, addr common.Address) error { + return k.SetPointerInfo(ctx, types.PointerERC20NativeKey(token), addr[:], native.CurrentVersion) +} + +func (k *Keeper) SetERC20NativePointerWithVersion(ctx sdk.Context, token string, addr common.Address, version uint16) error { + return k.SetPointerInfo(ctx, types.PointerERC20NativeKey(token), addr[:], version) +} + +func (k *Keeper) GetERC20NativePointer(ctx sdk.Context, token string) (addr common.Address, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerERC20NativeKey(token)) + if exists { + addr = common.BytesToAddress(addrBz) + } + return +} + +func (k *Keeper) DeleteERC20NativePointer(ctx sdk.Context, token string, version uint16) { + k.DeletePointerInfo(ctx, types.PointerERC20NativeKey(token), version) +} + +func (k *Keeper) SetERC20CW20Pointer(ctx sdk.Context, cw20Address string, addr common.Address) error { + return k.SetPointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), addr[:], cw20.CurrentVersion) +} + +func (k *Keeper) SetERC20CW20PointerWithVersion(ctx sdk.Context, cw20Address string, addr common.Address, version uint16) error { + return k.SetPointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), addr[:], version) +} + +func (k *Keeper) GetERC20CW20Pointer(ctx sdk.Context, cw20Address string) (addr common.Address, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerERC20CW20Key(cw20Address)) + if exists { + addr = common.BytesToAddress(addrBz) + } + return +} + +func (k *Keeper) DeleteERC20CW20Pointer(ctx sdk.Context, cw20Address string, version uint16) { + k.DeletePointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), version) +} + +func (k *Keeper) SetERC721CW721Pointer(ctx sdk.Context, cw721Address string, addr common.Address) error { + return k.SetPointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), addr[:], cw721.CurrentVersion) +} + +func (k *Keeper) SetERC721CW721PointerWithVersion(ctx sdk.Context, cw721Address string, addr common.Address, version uint16) error { + return k.SetPointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), addr[:], version) +} + +func (k *Keeper) GetERC721CW721Pointer(ctx sdk.Context, cw721Address string) (addr common.Address, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerERC721CW721Key(cw721Address)) + if exists { + addr = common.BytesToAddress(addrBz) + } + return +} + +func (k *Keeper) DeleteERC721CW721Pointer(ctx sdk.Context, cw721Address string, version uint16) { + k.DeletePointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), version) +} + +func (k *Keeper) SetCW20ERC20Pointer(ctx sdk.Context, erc20Address common.Address, addr string) error { + return k.SetPointerInfo(ctx, types.PointerCW20ERC20Key(erc20Address), []byte(addr), erc20.CurrentVersion) +} + +func (k *Keeper) GetCW20ERC20Pointer(ctx sdk.Context, erc20Address common.Address) (addr sdk.AccAddress, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerCW20ERC20Key(erc20Address)) + if exists { + addr = sdk.MustAccAddressFromBech32(string(addrBz)) + } + return +} + +func (k *Keeper) SetCW721ERC721Pointer(ctx sdk.Context, erc721Address common.Address, addr string) error { + return k.SetPointerInfo(ctx, types.PointerCW721ERC721Key(erc721Address), []byte(addr), erc721.CurrentVersion) +} + +func (k *Keeper) GetCW721ERC721Pointer(ctx sdk.Context, erc721Address common.Address) (addr sdk.AccAddress, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerCW721ERC721Key(erc721Address)) + if exists { + addr = sdk.MustAccAddressFromBech32(string(addrBz)) + } + return +} + +func (k *Keeper) GetPointerInfo(ctx sdk.Context, pref []byte) (addr []byte, version uint16, exists bool) { + store := prefix.NewStore(ctx.KVStore(k.GetStoreKey()), pref) + iter := store.ReverseIterator(nil, nil) + defer iter.Close() + exists = iter.Valid() + if !exists { + return + } + version = binary.BigEndian.Uint16(iter.Key()) + addr = iter.Value() + return +} + +func (k *Keeper) SetPointerInfo(ctx sdk.Context, pref []byte, addr []byte, version uint16) error { + existingAddr, existingVersion, exists := k.GetPointerInfo(ctx, pref) + if exists && existingVersion >= version { + return fmt.Errorf("pointer at %s with version %d exists when trying to set pointer for version %d", string(existingAddr), existingVersion, version) + } + store := prefix.NewStore(ctx.KVStore(k.GetStoreKey()), pref) + versionBz := make([]byte, 2) + binary.BigEndian.PutUint16(versionBz, version) + store.Set(versionBz, addr) + return nil +} + +func (k *Keeper) DeletePointerInfo(ctx sdk.Context, pref []byte, version uint16) { + store := prefix.NewStore(ctx.KVStore(k.GetStoreKey()), pref) + versionBz := make([]byte, 2) + binary.BigEndian.PutUint16(versionBz, version) + store.Delete(versionBz) +} diff --git a/x/evm/keeper/pointer_test.go b/x/evm/keeper/pointer_test.go new file mode 100644 index 000000000..e4048af69 --- /dev/null +++ b/x/evm/keeper/pointer_test.go @@ -0,0 +1,21 @@ +package keeper_test + +import ( + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/stretchr/testify/require" +) + +func TestSetPointer(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, pointer := testkeeper.MockAddressPair() + cw20, _ := testkeeper.MockAddressPair() + cw721, _ := testkeeper.MockAddressPair() + require.Nil(t, k.SetERC20NativePointer(ctx, "test", pointer)) + require.NotNil(t, k.SetERC20NativePointer(ctx, "test", pointer)) // already set + require.Nil(t, k.SetERC20CW20Pointer(ctx, cw20.String(), pointer)) + require.NotNil(t, k.SetERC20CW20Pointer(ctx, cw20.String(), pointer)) // already set + require.Nil(t, k.SetERC721CW721Pointer(ctx, cw721.String(), pointer)) + require.NotNil(t, k.SetERC721CW721Pointer(ctx, cw721.String(), pointer)) // already set +} diff --git a/x/evm/keeper/precompile.go b/x/evm/keeper/precompile.go new file mode 100644 index 000000000..c2a8b5119 --- /dev/null +++ b/x/evm/keeper/precompile.go @@ -0,0 +1,24 @@ +package keeper + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/precompiles/bank" + "github.com/sei-protocol/sei-chain/precompiles/gov" + "github.com/sei-protocol/sei-chain/precompiles/staking" +) + +// add any payable precompiles here +// these will suppress transfer events to/from the precompile address +var payablePrecompiles = map[string]struct{}{ + bank.BankAddress: {}, + staking.StakingAddress: {}, + gov.GovAddress: {}, +} + +func IsPayablePrecompile(addr *common.Address) bool { + if addr == nil { + return false + } + _, ok := payablePrecompiles[addr.Hex()] + return ok +} diff --git a/x/evm/keeper/precompile_test.go b/x/evm/keeper/precompile_test.go new file mode 100644 index 000000000..956f5cb95 --- /dev/null +++ b/x/evm/keeper/precompile_test.go @@ -0,0 +1,29 @@ +package keeper_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + "github.com/sei-protocol/sei-chain/precompiles/bank" + "github.com/sei-protocol/sei-chain/precompiles/gov" + "github.com/sei-protocol/sei-chain/precompiles/staking" + "github.com/sei-protocol/sei-chain/testutil/keeper" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" +) + +func toAddr(addr string) *common.Address { + ca := common.HexToAddress(addr) + return &ca +} + +func TestIsPayablePrecompile(t *testing.T) { + _, evmAddr := keeper.MockAddressPair() + require.False(t, evmkeeper.IsPayablePrecompile(&evmAddr)) + require.False(t, evmkeeper.IsPayablePrecompile(nil)) + + require.True(t, evmkeeper.IsPayablePrecompile(toAddr(bank.BankAddress))) + require.True(t, evmkeeper.IsPayablePrecompile(toAddr(staking.StakingAddress))) + require.True(t, evmkeeper.IsPayablePrecompile(toAddr(gov.GovAddress))) +} diff --git a/x/evm/keeper/replay.go b/x/evm/keeper/replay.go index 1b2720e1a..c202b38ed 100644 --- a/x/evm/keeper/replay.go +++ b/x/evm/keeper/replay.go @@ -9,6 +9,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "github.com/sei-protocol/sei-chain/x/evm/types" ) func (k *Keeper) VerifyBalance(ctx sdk.Context, addr common.Address) { @@ -87,3 +88,19 @@ func (k *Keeper) VerifyAccount(ctx sdk.Context, addr common.Address, accountData panic(fmt.Sprintf("nonce mismatch for address %s: expected %d, got %d", addr.Hex(), nonce, k.GetNonce(ctx, addr))) } } + +func (k *Keeper) VerifyState(ctx sdk.Context, addr common.Address) { + store := k.PrefixStore(ctx, types.StateKey(addr)) + iter := store.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + key := common.BytesToHash(iter.Key()) + ethVal, err := k.EthClient.StorageAt(ctx.Context(), addr, key, k.ReplayBlock.Number()) + if err != nil { + panic(err) + } + if !bytes.Equal(iter.Value(), ethVal) { + panic(fmt.Sprintf("state mismatch for address %s hash %s: expected %X but got %X", addr.Hex(), key.Hex(), ethVal, iter.Value())) + } + } +} diff --git a/x/evm/keeper/whitelist.go b/x/evm/keeper/whitelist.go index deade054b..5e85bfbf4 100644 --- a/x/evm/keeper/whitelist.go +++ b/x/evm/keeper/whitelist.go @@ -2,66 +2,10 @@ package keeper import ( "bytes" - "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" - "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" - "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" - "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" - "github.com/sei-protocol/sei-chain/x/evm/types" ) -func (k *Keeper) AddToWhitelistIfApplicable(ctx sdk.Context, data []byte, contractAddress common.Address) { - if native.IsCodeFromBin(data) { - codeHash := k.GetCodeHash(ctx, contractAddress) - if (codeHash != common.Hash{}) { - k.AddCodeHashWhitelistedForBankSend(ctx, codeHash) - } - return - } - if cw20.IsCodeFromBin(data) || cw721.IsCodeFromBin(data) { - codeHash := k.GetCodeHash(ctx, contractAddress) - if (codeHash != common.Hash{}) { - k.AddCodeHashWhitelistedForDelegateCall(ctx, codeHash) - } - return - } -} - -func (k *Keeper) IsCodeHashWhitelistedForBankSend(ctx sdk.Context, h common.Hash) bool { - if w := k.GetCodeHashWhitelistedForBankSend(ctx); w != nil { - return w.IsHashInWhiteList(h) - } - return false -} - -func (k *Keeper) AddCodeHashWhitelistedForBankSend(ctx sdk.Context, h common.Hash) { - store := ctx.KVStore(k.storeKey) - w := k.GetCodeHashWhitelistedForBankSend(ctx) - if w == nil { - w = &types.Whitelist{Hashes: []string{h.Hex()}} - } else if !w.IsHashInWhiteList(h) { - w.Hashes = append(w.Hashes, h.Hex()) - } - bz, _ := w.Marshal() - store.Set(types.WhitelistedCodeHashesForBankSendPrefix, bz) -} - -func (k *Keeper) GetCodeHashWhitelistedForBankSend(ctx sdk.Context) *types.Whitelist { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.WhitelistedCodeHashesForBankSendPrefix) - if bz == nil { - return &types.Whitelist{Hashes: []string{}} - } - w := &types.Whitelist{} - if err := w.Unmarshal(bz); err != nil { - ctx.Logger().Error(fmt.Sprintf("error parsing code hash whitelist for bank send: %s", err)) - return nil - } - return w -} - func (k *Keeper) IsCWCodeHashWhitelistedForEVMDelegateCall(ctx sdk.Context, h []byte) bool { for _, w := range k.WhitelistedCwCodeHashesForDelegateCall(ctx) { if bytes.Equal(w, h) { @@ -70,36 +14,3 @@ func (k *Keeper) IsCWCodeHashWhitelistedForEVMDelegateCall(ctx sdk.Context, h [] } return false } - -func (k *Keeper) IsCodeHashWhitelistedForDelegateCall(ctx sdk.Context, h common.Hash) bool { - if w := k.GetCodeHashWhitelistedForDelegateCall(ctx); w != nil { - return w.IsHashInWhiteList(h) - } - return false -} - -func (k *Keeper) AddCodeHashWhitelistedForDelegateCall(ctx sdk.Context, h common.Hash) { - store := ctx.KVStore(k.storeKey) - w := k.GetCodeHashWhitelistedForDelegateCall(ctx) - if w == nil { - w = &types.Whitelist{Hashes: []string{h.Hex()}} - } else if !w.IsHashInWhiteList(h) { - w.Hashes = append(w.Hashes, h.Hex()) - } - bz, _ := w.Marshal() - store.Set(types.WhitelistedCodeHashesForDelegateCallPrefix, bz) -} - -func (k *Keeper) GetCodeHashWhitelistedForDelegateCall(ctx sdk.Context) *types.Whitelist { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.WhitelistedCodeHashesForDelegateCallPrefix) - if bz == nil { - return &types.Whitelist{Hashes: []string{}} - } - w := &types.Whitelist{} - if err := w.Unmarshal(bz); err != nil { - ctx.Logger().Error(fmt.Sprintf("error parsing code hash whitelist for delegate call: %s", err)) - return nil - } - return w -} diff --git a/x/evm/keeper/whitelist_test.go b/x/evm/keeper/whitelist_test.go deleted file mode 100644 index 89a2a1087..000000000 --- a/x/evm/keeper/whitelist_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package keeper_test - -import ( - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/stretchr/testify/require" -) - -func TestBankSendWhitelist(t *testing.T) { - k, ctx := keeper.MockEVMKeeper() - wl := k.GetCodeHashWhitelistedForBankSend(ctx) - require.Empty(t, wl.Hashes) - k.AddCodeHashWhitelistedForBankSend(ctx, common.BytesToHash([]byte("a"))) - require.True(t, k.IsCodeHashWhitelistedForBankSend(ctx, common.BytesToHash([]byte("a")))) - require.False(t, k.IsCodeHashWhitelistedForBankSend(ctx, common.BytesToHash([]byte("b")))) -} - -func TestDelegateCallWhitelist(t *testing.T) { - k, ctx := keeper.MockEVMKeeper() - wl := k.GetCodeHashWhitelistedForDelegateCall(ctx) - require.Empty(t, wl.Hashes) - k.AddCodeHashWhitelistedForDelegateCall(ctx, common.BytesToHash([]byte("a"))) - require.True(t, k.IsCodeHashWhitelistedForDelegateCall(ctx, common.BytesToHash([]byte("a")))) - require.False(t, k.IsCodeHashWhitelistedForDelegateCall(ctx, common.BytesToHash([]byte("b")))) -} diff --git a/x/evm/migrations/store_cw_pointer_code.go b/x/evm/migrations/store_cw_pointer_code.go new file mode 100644 index 000000000..2e188ec24 --- /dev/null +++ b/x/evm/migrations/store_cw_pointer_code.go @@ -0,0 +1,32 @@ +package migrations + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + artifactsutils "github.com/sei-protocol/sei-chain/x/evm/artifacts/utils" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func StoreCWPointerCode(ctx sdk.Context, k *keeper.Keeper) error { + erc20CodeID, err := k.WasmKeeper().Create(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), erc20.GetBin(), nil) + if err != nil { + panic(err) + } + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW20ERC20Prefix).Set( + artifactsutils.GetVersionBz(erc20.CurrentVersion), + artifactsutils.GetCodeIDBz(erc20CodeID), + ) + + erc721CodeID, err := k.WasmKeeper().Create(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), erc721.GetBin(), nil) + if err != nil { + panic(err) + } + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW721ERC721Prefix).Set( + artifactsutils.GetVersionBz(erc721.CurrentVersion), + artifactsutils.GetCodeIDBz(erc721CodeID), + ) + return nil +} diff --git a/x/evm/module.go b/x/evm/module.go index 83ab304a7..9e8625eef 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -3,14 +3,16 @@ package evm import ( "encoding/json" "fmt" + "math" "math/big" // this line is used by starport scaffolding # 1 "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/tracing" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/tests" + "github.com/ethereum/go-ethereum/core/vm" "github.com/gorilla/mux" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" @@ -141,6 +143,10 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { _ = cfg.RegisterMigration(types.ModuleName, 3, func(ctx sdk.Context) error { return migrations.AddNewParamsAndSetAllToDefaults(ctx, am.keeper) }) + + _ = cfg.RegisterMigration(types.ModuleName, 4, func(ctx sdk.Context) error { + return migrations.StoreCWPointerCode(ctx, am.keeper) + }) } // RegisterInvariants registers the capability module's invariants. @@ -165,14 +171,30 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 4 } +func (AppModule) ConsensusVersion() uint64 { return 5 } // BeginBlock executes all ABCI BeginBlock logic respective to the capability module. -func (am AppModule) BeginBlock(sdk.Context, abci.RequestBeginBlock) { +func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { // clear tx responses from last block am.keeper.SetTxResults([]*abci.ExecTxResult{}) // clear the TxDeferredInfo am.keeper.ClearEVMTxDeferredInfo() + // mock beacon root if replaying + if am.keeper.EthReplayConfig.Enabled { + if beaconRoot := am.keeper.ReplayBlock.BeaconRoot(); beaconRoot != nil { + blockCtx, err := am.keeper.GetVMBlockContext(ctx, core.GasPool(math.MaxUint64)) + if err != nil { + panic(err) + } + statedb := state.NewDBImpl(ctx, am.keeper, false) + vmenv := vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, types.DefaultChainConfig().EthereumConfig(am.keeper.ChainID(ctx)), vm.Config{}) + core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + _, err = statedb.Finalize() + if err != nil { + panic(err) + } + } + } } // EndBlock executes all ABCI EndBlock logic respective to the evm module. It @@ -181,22 +203,13 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val var coinbase sdk.AccAddress if am.keeper.EthBlockTestConfig.Enabled { blocks := am.keeper.BlockTest.Json.Blocks - var block *tests.BtBlock - for i, b := range blocks { - if b.BlockHeader.Number.Uint64() == uint64(ctx.BlockHeight()) { - block = &blocks[i] - } - } - if block == nil { - panic(fmt.Sprintf("block not found at height %d", ctx.BlockHeight())) - } - coinbase = am.keeper.GetSeiAddressOrDefault(ctx, block.BlockHeader.Coinbase) - } else if am.keeper.EthReplayConfig.Enabled { - block, err := am.keeper.EthClient.BlockByNumber(ctx.Context(), big.NewInt(ctx.BlockHeight()+am.keeper.GetReplayInitialHeight(ctx))) + block, err := blocks[ctx.BlockHeight()-1].Decode() if err != nil { - panic(fmt.Sprintf("error getting block at height %d", ctx.BlockHeight()+am.keeper.GetReplayInitialHeight(ctx))) + panic(err) } coinbase = am.keeper.GetSeiAddressOrDefault(ctx, block.Header_.Coinbase) + } else if am.keeper.EthReplayConfig.Enabled { + coinbase = am.keeper.GetSeiAddressOrDefault(ctx, am.keeper.ReplayBlock.Header_.Coinbase) am.keeper.SetReplayedHeight(ctx) } else { coinbase = am.keeper.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName) @@ -206,6 +219,14 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val denom := am.keeper.GetBaseDenom(ctx) surplus := utils.Sdk0 for _, deferredInfo := range evmTxDeferredInfoList { + if deferredInfo.Error != "" { + _ = am.keeper.SetReceipt(ctx, deferredInfo.TxHash, &types.Receipt{ + TxHashHex: deferredInfo.TxHash.Hex(), + TransactionIndex: uint32(deferredInfo.TxIndx), + VmError: deferredInfo.Error, + }) + continue + } idx := deferredInfo.TxIndx coinbaseAddress := state.GetCoinbaseAddress(idx) balance := am.keeper.BankKeeper().GetBalance(ctx, coinbaseAddress, denom) diff --git a/x/evm/module_test.go b/x/evm/module_test.go index ea9dd2b25..108603d85 100644 --- a/x/evm/module_test.go +++ b/x/evm/module_test.go @@ -65,4 +65,13 @@ func TestABCI(t *testing.T) { m.EndBlock(ctx, abci.RequestEndBlock{}) require.Equal(t, uint64(1), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), "usei").Amount.Uint64()) require.Equal(t, uint64(2), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName), "usei").Amount.Uint64()) + + // third block + m.BeginBlock(ctx, abci.RequestBeginBlock{}) + k.AppendErrorToEvmTxDeferredInfo(ctx.WithTxIndex(0), common.Hash{1}, "test error") + k.SetTxResults([]*abci.ExecTxResult{{Code: 1}}) + m.EndBlock(ctx, abci.RequestEndBlock{}) + receipt, err := k.GetReceipt(ctx, common.Hash{1}) + require.Nil(t, err) + require.Equal(t, receipt.VmError, "test error") } diff --git a/x/evm/querier/config.go b/x/evm/querier/config.go new file mode 100644 index 000000000..8997594e2 --- /dev/null +++ b/x/evm/querier/config.go @@ -0,0 +1,29 @@ +package querier + +import ( + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/spf13/cast" +) + +type Config struct { + GasLimit uint64 `mapstructure:"evm_query_gas_limit"` +} + +var DefaultConfig = Config{ + GasLimit: 300000, +} + +const ( + flagGasLimit = "evm_query.evm_query_gas_limit" +) + +func ReadConfig(opts servertypes.AppOptions) (Config, error) { + cfg := DefaultConfig // copy + var err error + if v := opts.Get(flagGasLimit); v != nil { + if cfg.GasLimit, err = cast.ToUint64E(v); err != nil { + return cfg, err + } + } + return cfg, nil +} diff --git a/x/evm/state/balance.go b/x/evm/state/balance.go index 0ed16f6b1..376826586 100644 --- a/x/evm/state/balance.go +++ b/x/evm/state/balance.go @@ -18,14 +18,25 @@ func (s *DBImpl) SubBalance(evmAddr common.Address, amt *big.Int, reason tracing s.AddBalance(evmAddr, new(big.Int).Neg(amt), reason) return } + if s.HasSelfDestructed(evmAddr) { + // redirect coins to fee collector, since simply burning here would cause coin supply mismatch + evmAddr, _ = s.k.GetFeeCollectorAddress(s.ctx) + } + + ctx := s.ctx + + // this avoids emitting cosmos events for ephemeral bookkeeping transfers like send_native + if s.eventsSuppressed { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + } usei, wei := SplitUseiWeiAmount(amt) addr := s.getSeiAddress(evmAddr) - s.err = s.k.BankKeeper().SubUnlockedCoins(s.ctx, addr, sdk.NewCoins(sdk.NewCoin(s.k.GetBaseDenom(s.ctx), usei)), true) + s.err = s.k.BankKeeper().SubUnlockedCoins(ctx, addr, sdk.NewCoins(sdk.NewCoin(s.k.GetBaseDenom(s.ctx), usei)), true) if s.err != nil { return } - s.err = s.k.BankKeeper().SubWei(s.ctx, addr, wei) + s.err = s.k.BankKeeper().SubWei(ctx, addr, wei) if s.err != nil { return } @@ -51,13 +62,24 @@ func (s *DBImpl) AddBalance(evmAddr common.Address, amt *big.Int, reason tracing return } + if s.HasSelfDestructed(evmAddr) { + // redirect coins to fee collector, since simply burning here would cause coin supply mismatch + evmAddr, _ = s.k.GetFeeCollectorAddress(s.ctx) + } + + ctx := s.ctx + // this avoids emitting cosmos events for ephemeral bookkeeping transfers like send_native + if s.eventsSuppressed { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + } + usei, wei := SplitUseiWeiAmount(amt) addr := s.getSeiAddress(evmAddr) - s.err = s.k.BankKeeper().AddCoins(s.ctx, addr, sdk.NewCoins(sdk.NewCoin(s.k.GetBaseDenom(s.ctx), usei)), true) + s.err = s.k.BankKeeper().AddCoins(ctx, addr, sdk.NewCoins(sdk.NewCoin(s.k.GetBaseDenom(s.ctx), usei)), true) if s.err != nil { return } - s.err = s.k.BankKeeper().AddWei(s.ctx, addr, wei) + s.err = s.k.BankKeeper().AddWei(ctx, addr, wei) if s.err != nil { return } diff --git a/x/evm/state/balance_test.go b/x/evm/state/balance_test.go index 1201d3005..d732b2fb3 100644 --- a/x/evm/state/balance_test.go +++ b/x/evm/state/balance_test.go @@ -31,6 +31,12 @@ func TestAddBalance(t *testing.T) { require.Nil(t, db.Err()) require.Equal(t, db.GetBalance(evmAddr), big.NewInt(10000000000000)) require.Equal(t, db.GetBalance(evmAddr2), big.NewInt(5000000000000)) + + _, evmAddr3 := testkeeper.MockAddressPair() + db.SelfDestruct(evmAddr3) + db.AddBalance(evmAddr2, big.NewInt(5000000000000), tracing.BalanceChangeUnspecified) + require.Nil(t, db.Err()) + require.Equal(t, db.GetBalance(evmAddr3), big.NewInt(0)) } func TestSubBalance(t *testing.T) { @@ -62,6 +68,12 @@ func TestSubBalance(t *testing.T) { // insufficient balance db.SubBalance(evmAddr2, big.NewInt(10000000000000), tracing.BalanceChangeUnspecified) require.NotNil(t, db.Err()) + + _, evmAddr3 := testkeeper.MockAddressPair() + db.SelfDestruct(evmAddr3) + db.SubBalance(evmAddr2, big.NewInt(5000000000000), tracing.BalanceChangeUnspecified) + require.Nil(t, db.Err()) + require.Equal(t, db.GetBalance(evmAddr3), big.NewInt(0)) } func TestSetBalance(t *testing.T) { diff --git a/x/evm/state/check.go b/x/evm/state/check.go index 7053a4b86..3b3a6b606 100644 --- a/x/evm/state/check.go +++ b/x/evm/state/check.go @@ -23,6 +23,11 @@ func (s *DBImpl) Exist(addr common.Address) bool { return true } + // check if account has a balance + if s.GetBalance(addr).Cmp(utils.Big0) > 0 { + return true + } + // go-ethereum impl considers just-deleted accounts as "exist" as well return s.HasSelfDestructed(addr) } diff --git a/x/evm/state/check_test.go b/x/evm/state/check_test.go index 8d3d32133..6c631bd1b 100644 --- a/x/evm/state/check_test.go +++ b/x/evm/state/check_test.go @@ -22,10 +22,15 @@ func TestExist(t *testing.T) { statedb.SetCode(addr2, []byte{3}) require.True(t, statedb.Exist(addr2)) - // destructed + // has balance _, addr3 := testkeeper.MockAddressPair() - statedb.SelfDestruct(addr3) + statedb.AddBalance(addr3, big.NewInt(1000000000000), tracing.BalanceChangeUnspecified) require.True(t, statedb.Exist(addr3)) + + // destructed + _, addr4 := testkeeper.MockAddressPair() + statedb.SelfDestruct(addr4) + require.True(t, statedb.Exist(addr4)) } func TestEmpty(t *testing.T) { diff --git a/x/evm/state/state.go b/x/evm/state/state.go index 5856c8593..7405c5818 100644 --- a/x/evm/state/state.go +++ b/x/evm/state/state.go @@ -70,9 +70,6 @@ func (s *DBImpl) SelfDestruct(acc common.Address) { s.SubBalance(acc, s.GetBalance(acc), tracing.BalanceDecreaseSelfdestruct) - // clear account state - s.clearAccountState(acc) - // mark account as self-destructed s.MarkAccount(acc, AccountDeleted) } @@ -111,6 +108,15 @@ func (s *DBImpl) RevertToSnapshot(rev int) { s.Snapshot() } +func (s *DBImpl) clearAccountStateIfDestructed(st *TemporaryState) { + for acc, status := range st.transientAccounts { + if !bytes.Equal(status, AccountDeleted) { + return + } + s.clearAccountState(common.HexToAddress(acc)) + } +} + func (s *DBImpl) clearAccountState(acc common.Address) { s.k.PrepareReplayedAddr(s.ctx, acc) s.k.PurgePrefix(s.ctx, types.StateKey(acc)) diff --git a/x/evm/state/state_test.go b/x/evm/state/state_test.go index 84f1a9c36..fe4cc57ff 100644 --- a/x/evm/state/state_test.go +++ b/x/evm/state/state_test.go @@ -37,13 +37,16 @@ func TestState(t *testing.T) { tval := common.BytesToHash([]byte("mno")) statedb.SetTransientState(evmAddr, tkey, tval) require.Equal(t, tval, statedb.GetTransientState(evmAddr, tkey)) - // destruct should clear balance and state, but keep transient state. Committed state should also be accessible + // destruct should clear balance, but keep state. Committed state should also be accessible + // state would be cleared after finalize statedb.SelfDestruct(evmAddr) require.Equal(t, tval, statedb.GetTransientState(evmAddr, tkey)) - require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, key)) + require.NotEqual(t, common.Hash{}, statedb.GetState(evmAddr, key)) require.Equal(t, common.Hash{}, statedb.GetCommittedState(evmAddr, key)) require.Equal(t, big.NewInt(0), statedb.GetBalance(evmAddr)) require.True(t, statedb.HasSelfDestructed(evmAddr)) + statedb.Finalize() + require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, key)) // set storage statedb.SetStorage(evmAddr, map[common.Hash]common.Hash{{}: {}}) require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, common.Hash{})) @@ -108,11 +111,13 @@ func TestSelfDestructAssociated(t *testing.T) { // Selfdestruct6780 is equivalent to SelfDestruct if account is created in the same block statedb.Selfdestruct6780(evmAddr) require.Equal(t, tval, statedb.GetTransientState(evmAddr, tkey)) - require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, key)) + require.NotEqual(t, common.Hash{}, statedb.GetState(evmAddr, key)) require.Equal(t, big.NewInt(0), statedb.GetBalance(evmAddr)) require.Equal(t, big.NewInt(0), k.BankKeeper().GetBalance(ctx, seiAddr, k.GetBaseDenom(ctx)).Amount.BigInt()) require.True(t, statedb.HasSelfDestructed(evmAddr)) require.False(t, statedb.Created(evmAddr)) + statedb.Finalize() + require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, key)) // association should also be removed _, ok := k.GetSeiAddress(statedb.Ctx(), evmAddr) require.False(t, ok) diff --git a/x/evm/state/statedb.go b/x/evm/state/statedb.go index dcf818781..6686adb5f 100644 --- a/x/evm/state/statedb.go +++ b/x/evm/state/statedb.go @@ -31,6 +31,9 @@ type DBImpl struct { k EVMKeeper simulation bool + // for cases like bank.send_native, we want to suppress transfer events + eventsSuppressed bool + logger *tracing.Hooks } @@ -47,6 +50,14 @@ func NewDBImpl(ctx sdk.Context, k EVMKeeper, simulation bool) *DBImpl { return s } +func (s *DBImpl) DisableEvents() { + s.eventsSuppressed = true +} + +func (s *DBImpl) EnableEvents() { + s.eventsSuppressed = false +} + func (s *DBImpl) SetLogger(logger *tracing.Hooks) { s.logger = logger } @@ -78,9 +89,13 @@ func (s *DBImpl) Finalize() (surplus sdk.Int, err error) { for i := len(s.snapshottedCtxs) - 1; i > 0; i-- { s.flushCtx(s.snapshottedCtxs[i]) } + + // delete state of self-destructed accoutns + s.clearAccountStateIfDestructed(s.tempStateCurrent) surplus = s.tempStateCurrent.surplus for _, ts := range s.tempStatesHist { surplus = surplus.Add(ts.surplus) + s.clearAccountStateIfDestructed(ts) } if surplus.IsNegative() { err = fmt.Errorf("negative surplus value: %s", surplus.String()) diff --git a/x/evm/state/transfer.go b/x/evm/state/transfer.go new file mode 100644 index 000000000..9a75be9e7 --- /dev/null +++ b/x/evm/state/transfer.go @@ -0,0 +1,21 @@ +package state + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/vm" +) + +func TransferWithoutEvents(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { + sdb, ok := db.(*DBImpl) + if !ok { + panic("EventlessTransfer only works with DBImpl") + } + sdb.DisableEvents() + defer sdb.EnableEvents() + + sdb.SubBalance(sender, amount, tracing.BalanceChangeTransfer) + sdb.AddBalance(recipient, amount, tracing.BalanceChangeTransfer) +} diff --git a/x/evm/state/transfer_test.go b/x/evm/state/transfer_test.go new file mode 100644 index 000000000..f633dc879 --- /dev/null +++ b/x/evm/state/transfer_test.go @@ -0,0 +1,24 @@ +package state_test + +import ( + "math/big" + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" +) + +func TestEventlessTransfer(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + db := state.NewDBImpl(ctx, k, false) + _, fromAddr := testkeeper.MockAddressPair() + _, toAddr := testkeeper.MockAddressPair() + + beforeLen := len(ctx.EventManager().ABCIEvents()) + + state.TransferWithoutEvents(db, fromAddr, toAddr, big.NewInt(100)) + + // should be unchanged + require.Len(t, ctx.EventManager().ABCIEvents(), beforeLen) +} diff --git a/x/evm/types/codec.go b/x/evm/types/codec.go index e4adec0a2..a092de6e0 100644 --- a/x/evm/types/codec.go +++ b/x/evm/types/codec.go @@ -35,6 +35,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { (*sdk.Msg)(nil), &MsgEVMTransaction{}, &MsgSend{}, + &MsgRegisterPointer{}, ) registry.RegisterInterface( "seiprotocol.seichain.evm.TxData", diff --git a/x/evm/types/enums.pb.go b/x/evm/types/enums.pb.go new file mode 100644 index 000000000..d5f2e5642 --- /dev/null +++ b/x/evm/types/enums.pb.go @@ -0,0 +1,78 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/enums.proto + +package types + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + math "math" +) + +// 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 + +type PointerType int32 + +const ( + PointerType_ERC20 PointerType = 0 + PointerType_ERC721 PointerType = 1 + PointerType_NATIVE PointerType = 2 + PointerType_CW20 PointerType = 3 + PointerType_CW721 PointerType = 4 +) + +var PointerType_name = map[int32]string{ + 0: "ERC20", + 1: "ERC721", + 2: "NATIVE", + 3: "CW20", + 4: "CW721", +} + +var PointerType_value = map[string]int32{ + "ERC20": 0, + "ERC721": 1, + "NATIVE": 2, + "CW20": 3, + "CW721": 4, +} + +func (x PointerType) String() string { + return proto.EnumName(PointerType_name, int32(x)) +} + +func (PointerType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_9ba0923a26222f98, []int{0} +} + +func init() { + proto.RegisterEnum("seiprotocol.seichain.evm.PointerType", PointerType_name, PointerType_value) +} + +func init() { proto.RegisterFile("evm/enums.proto", fileDescriptor_9ba0923a26222f98) } + +var fileDescriptor_9ba0923a26222f98 = []byte{ + // 194 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4f, 0x2d, 0xcb, 0xd5, + 0x4f, 0xcd, 0x2b, 0xcd, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x28, 0x4e, 0xcd, + 0x04, 0xb3, 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, 0x33, 0xf3, 0xf4, 0x52, + 0xcb, 0x72, 0xb5, 0x5c, 0xb9, 0xb8, 0x03, 0xf2, 0x33, 0xf3, 0x4a, 0x52, 0x8b, 0x42, 0x2a, 0x0b, + 0x52, 0x85, 0x38, 0xb9, 0x58, 0x5d, 0x83, 0x9c, 0x8d, 0x0c, 0x04, 0x18, 0x84, 0xb8, 0xb8, 0xd8, + 0x5c, 0x83, 0x9c, 0xcd, 0x8d, 0x0c, 0x05, 0x18, 0x41, 0x6c, 0x3f, 0xc7, 0x10, 0xcf, 0x30, 0x57, + 0x01, 0x26, 0x21, 0x0e, 0x2e, 0x16, 0xe7, 0x70, 0x23, 0x03, 0x01, 0x66, 0x90, 0x62, 0xe7, 0x70, + 0x90, 0x02, 0x16, 0x27, 0xf7, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, + 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, + 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x2f, 0x4e, 0xcd, 0xd4, 0x85, + 0x39, 0x03, 0xcc, 0x01, 0xbb, 0x43, 0xbf, 0x42, 0x1f, 0xe4, 0xde, 0x92, 0xca, 0x82, 0xd4, 0xe2, + 0x24, 0x36, 0xb0, 0xbc, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x3c, 0xe6, 0x84, 0x48, 0xc3, 0x00, + 0x00, 0x00, +} diff --git a/x/evm/types/events.go b/x/evm/types/events.go new file mode 100644 index 000000000..45ec378d9 --- /dev/null +++ b/x/evm/types/events.go @@ -0,0 +1,13 @@ +package types + +const ( + EventTypeAddressAssociated = "address_associated" + EventTypePointerRegistered = "pointer_registered" + + AttributeKeySeiAddress = "sei_addr" + AttributeKeyEvmAddress = "evm_addr" + AttributeKeyPointerType = "pointer_type" + AttributeKeyPointee = "pointee" + AttributeKeyPointerAddress = "pointer_address" + AttributeKeyPointerVersion = "pointer_version" +) diff --git a/x/evm/types/gov.go b/x/evm/types/gov.go new file mode 100644 index 000000000..1ef47dddd --- /dev/null +++ b/x/evm/types/gov.go @@ -0,0 +1,139 @@ +package types + +import ( + "errors" + "fmt" + "math" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/ethereum/go-ethereum/common" +) + +const ( + ProposalTypeAddERCNativePointer = "AddERCNativePointer" + ProposalTypeAddERCCW20Pointer = "AddERCCW20Pointer" + ProposalTypeAddERCCW721Pointer = "AddERCCW721Pointer" +) + +func init() { + // for routing + govtypes.RegisterProposalType(ProposalTypeAddERCNativePointer) + govtypes.RegisterProposalType(ProposalTypeAddERCCW20Pointer) + govtypes.RegisterProposalType(ProposalTypeAddERCCW721Pointer) + // for marshal and unmarshal + govtypes.RegisterProposalTypeCodec(&AddERCNativePointerProposal{}, "evm/AddERCNativePointerProposal") + govtypes.RegisterProposalTypeCodec(&AddERCCW20PointerProposal{}, "evm/AddERCCW20PointerProposal") + govtypes.RegisterProposalTypeCodec(&AddERCCW721PointerProposal{}, "evm/AddERCCW721PointerProposal") +} + +func (p *AddERCNativePointerProposal) GetTitle() string { return p.Title } + +func (p *AddERCNativePointerProposal) GetDescription() string { return p.Description } + +func (p *AddERCNativePointerProposal) ProposalRoute() string { return RouterKey } + +func (p *AddERCNativePointerProposal) ProposalType() string { + return ProposalTypeAddERCNativePointer +} + +func (p *AddERCNativePointerProposal) ValidateBasic() error { + if p.Pointer != "" && !common.IsHexAddress(p.Pointer) { + return errors.New("pointer address must be either empty or a valid hex-encoded string") + } + + if p.Version > math.MaxUint16 { + return errors.New("pointer version must be <= 65535") + } + + return govtypes.ValidateAbstract(p) +} + +func (p AddERCNativePointerProposal) String() string { + var b strings.Builder + b.WriteString(fmt.Sprintf(`Add ERC native pointer Proposal: + Title: %s + Description: %s + Token: %s + Pointer: %s + Version: %d +`, p.Title, p.Description, p.Token, p.Pointer, p.Version)) + return b.String() +} + +func (p *AddERCCW20PointerProposal) GetTitle() string { return p.Title } + +func (p *AddERCCW20PointerProposal) GetDescription() string { return p.Description } + +func (p *AddERCCW20PointerProposal) ProposalRoute() string { return RouterKey } + +func (p *AddERCCW20PointerProposal) ProposalType() string { + return ProposalTypeAddERCCW20Pointer +} + +func (p *AddERCCW20PointerProposal) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(p.Pointee); err != nil { + return err + } + + if p.Pointer != "" && !common.IsHexAddress(p.Pointer) { + return errors.New("pointer address must be either empty or a valid hex-encoded string") + } + + if p.Version > math.MaxUint16 { + return errors.New("pointer version must be <= 65535") + } + + return govtypes.ValidateAbstract(p) +} + +func (p AddERCCW20PointerProposal) String() string { + var b strings.Builder + b.WriteString(fmt.Sprintf(`Add ERC CW20 pointer Proposal: + Title: %s + Description: %s + Pointee: %s + Pointer: %s + Version: %d +`, p.Title, p.Description, p.Pointee, p.Pointer, p.Version)) + return b.String() +} + +func (p *AddERCCW721PointerProposal) GetTitle() string { return p.Title } + +func (p *AddERCCW721PointerProposal) GetDescription() string { return p.Description } + +func (p *AddERCCW721PointerProposal) ProposalRoute() string { return RouterKey } + +func (p *AddERCCW721PointerProposal) ProposalType() string { + return ProposalTypeAddERCCW721Pointer +} + +func (p *AddERCCW721PointerProposal) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(p.Pointee); err != nil { + return err + } + + if p.Pointer != "" && !common.IsHexAddress(p.Pointer) { + return errors.New("pointer address must be either empty or a valid hex-encoded string") + } + + if p.Version > math.MaxUint16 { + return errors.New("pointer version must be <= 65535") + } + + return govtypes.ValidateAbstract(p) +} + +func (p AddERCCW721PointerProposal) String() string { + var b strings.Builder + b.WriteString(fmt.Sprintf(`Add ERC CW721 pointer Proposal: + Title: %s + Description: %s + Pointee: %s + Pointer: %s + Version: %d +`, p.Title, p.Description, p.Pointee, p.Pointer, p.Version)) + return b.String() +} diff --git a/x/evm/types/gov.pb.go b/x/evm/types/gov.pb.go new file mode 100644 index 000000000..6e7ef58d2 --- /dev/null +++ b/x/evm/types/gov.pb.go @@ -0,0 +1,1124 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/gov.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/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 + +type AddERCNativePointerProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty" yaml:"token"` + Pointer string `protobuf:"bytes,4,opt,name=pointer,proto3" json:"pointer,omitempty" yaml:"pointer"` + Version uint32 `protobuf:"varint,5,opt,name=version,proto3" json:"version,omitempty" yaml:"version"` +} + +func (m *AddERCNativePointerProposal) Reset() { *m = AddERCNativePointerProposal{} } +func (*AddERCNativePointerProposal) ProtoMessage() {} +func (*AddERCNativePointerProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_fb66eb1aab5c39af, []int{0} +} +func (m *AddERCNativePointerProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddERCNativePointerProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddERCNativePointerProposal.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 *AddERCNativePointerProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddERCNativePointerProposal.Merge(m, src) +} +func (m *AddERCNativePointerProposal) XXX_Size() int { + return m.Size() +} +func (m *AddERCNativePointerProposal) XXX_DiscardUnknown() { + xxx_messageInfo_AddERCNativePointerProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_AddERCNativePointerProposal proto.InternalMessageInfo + +type AddERCCW20PointerProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + Pointee string `protobuf:"bytes,3,opt,name=pointee,proto3" json:"pointee,omitempty" yaml:"pointee"` + Pointer string `protobuf:"bytes,4,opt,name=pointer,proto3" json:"pointer,omitempty" yaml:"pointer"` + Version uint32 `protobuf:"varint,5,opt,name=version,proto3" json:"version,omitempty" yaml:"version"` +} + +func (m *AddERCCW20PointerProposal) Reset() { *m = AddERCCW20PointerProposal{} } +func (*AddERCCW20PointerProposal) ProtoMessage() {} +func (*AddERCCW20PointerProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_fb66eb1aab5c39af, []int{1} +} +func (m *AddERCCW20PointerProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddERCCW20PointerProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddERCCW20PointerProposal.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 *AddERCCW20PointerProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddERCCW20PointerProposal.Merge(m, src) +} +func (m *AddERCCW20PointerProposal) XXX_Size() int { + return m.Size() +} +func (m *AddERCCW20PointerProposal) XXX_DiscardUnknown() { + xxx_messageInfo_AddERCCW20PointerProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_AddERCCW20PointerProposal proto.InternalMessageInfo + +type AddERCCW721PointerProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + Pointee string `protobuf:"bytes,3,opt,name=pointee,proto3" json:"pointee,omitempty" yaml:"pointee"` + Pointer string `protobuf:"bytes,4,opt,name=pointer,proto3" json:"pointer,omitempty" yaml:"pointer"` + Version uint32 `protobuf:"varint,5,opt,name=version,proto3" json:"version,omitempty" yaml:"version"` +} + +func (m *AddERCCW721PointerProposal) Reset() { *m = AddERCCW721PointerProposal{} } +func (*AddERCCW721PointerProposal) ProtoMessage() {} +func (*AddERCCW721PointerProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_fb66eb1aab5c39af, []int{2} +} +func (m *AddERCCW721PointerProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddERCCW721PointerProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddERCCW721PointerProposal.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 *AddERCCW721PointerProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddERCCW721PointerProposal.Merge(m, src) +} +func (m *AddERCCW721PointerProposal) XXX_Size() int { + return m.Size() +} +func (m *AddERCCW721PointerProposal) XXX_DiscardUnknown() { + xxx_messageInfo_AddERCCW721PointerProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_AddERCCW721PointerProposal proto.InternalMessageInfo + +func init() { + proto.RegisterType((*AddERCNativePointerProposal)(nil), "seiprotocol.seichain.evm.AddERCNativePointerProposal") + proto.RegisterType((*AddERCCW20PointerProposal)(nil), "seiprotocol.seichain.evm.AddERCCW20PointerProposal") + proto.RegisterType((*AddERCCW721PointerProposal)(nil), "seiprotocol.seichain.evm.AddERCCW721PointerProposal") +} + +func init() { proto.RegisterFile("evm/gov.proto", fileDescriptor_fb66eb1aab5c39af) } + +var fileDescriptor_fb66eb1aab5c39af = []byte{ + // 359 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4d, 0x2d, 0xcb, 0xd5, + 0x4f, 0xcf, 0x2f, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x28, 0x4e, 0xcd, 0x04, 0xb3, + 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, 0x33, 0xf3, 0xf4, 0x52, 0xcb, 0x72, + 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x52, 0xfa, 0x20, 0x16, 0x44, 0xbd, 0xd2, 0x44, 0x26, + 0x2e, 0x69, 0xc7, 0x94, 0x14, 0xd7, 0x20, 0x67, 0xbf, 0xc4, 0x92, 0xcc, 0xb2, 0xd4, 0x80, 0xfc, + 0xcc, 0xbc, 0x92, 0xd4, 0xa2, 0x80, 0xa2, 0xfc, 0x82, 0xfc, 0xe2, 0xc4, 0x1c, 0x21, 0x35, 0x2e, + 0xd6, 0x92, 0xcc, 0x92, 0x9c, 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0x81, 0x4f, 0xf7, + 0xe4, 0x79, 0x2a, 0x13, 0x73, 0x73, 0xac, 0x94, 0xc0, 0xc2, 0x4a, 0x41, 0x10, 0x69, 0x21, 0x0b, + 0x2e, 0xee, 0x94, 0xd4, 0xe2, 0xe4, 0xa2, 0xcc, 0x82, 0x92, 0xcc, 0xfc, 0x3c, 0x09, 0x26, 0xb0, + 0x6a, 0xb1, 0x4f, 0xf7, 0xe4, 0x85, 0x20, 0xaa, 0x91, 0x24, 0x95, 0x82, 0x90, 0x95, 0x82, 0x6d, + 0xc8, 0xcf, 0x4e, 0xcd, 0x93, 0x60, 0xc6, 0xb0, 0x01, 0x24, 0x0c, 0xb2, 0x01, 0x44, 0x0b, 0xe9, + 0x70, 0xb1, 0x17, 0x40, 0x1c, 0x27, 0xc1, 0x02, 0x56, 0x29, 0xf4, 0xe9, 0x9e, 0x3c, 0x1f, 0x44, + 0x25, 0x54, 0x42, 0x29, 0x08, 0xa6, 0x04, 0xa4, 0xba, 0x2c, 0xb5, 0xa8, 0x18, 0xe4, 0x16, 0x56, + 0x05, 0x46, 0x0d, 0x5e, 0x64, 0xd5, 0x50, 0x09, 0xa5, 0x20, 0x98, 0x12, 0x2b, 0x9e, 0x8e, 0x05, + 0xf2, 0x0c, 0x33, 0x16, 0xc8, 0x33, 0xbc, 0x58, 0x20, 0xcf, 0xa0, 0x34, 0x95, 0x89, 0x4b, 0x12, + 0x12, 0x26, 0xce, 0xe1, 0x46, 0x06, 0xf4, 0x0f, 0x11, 0xb8, 0x4f, 0x53, 0xa1, 0x61, 0x82, 0xe1, + 0xd3, 0x54, 0xb8, 0x4f, 0x53, 0xe9, 0x18, 0x2e, 0xd3, 0x98, 0xb8, 0xa4, 0x60, 0xe1, 0x62, 0x6e, + 0x64, 0x38, 0x1a, 0x30, 0xd0, 0x80, 0x71, 0x72, 0x3f, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, + 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, + 0x39, 0x86, 0x28, 0xdd, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xe2, + 0xd4, 0x4c, 0x5d, 0x58, 0xd6, 0x04, 0x73, 0xc0, 0x79, 0x53, 0xbf, 0x42, 0x1f, 0x94, 0x83, 0x4b, + 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xf2, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x08, + 0x8c, 0x8b, 0x94, 0xd5, 0x03, 0x00, 0x00, +} + +func (m *AddERCNativePointerProposal) 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 *AddERCNativePointerProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddERCNativePointerProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintGov(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x28 + } + if len(m.Pointer) > 0 { + i -= len(m.Pointer) + copy(dAtA[i:], m.Pointer) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointer))) + i-- + dAtA[i] = 0x22 + } + if len(m.Token) > 0 { + i -= len(m.Token) + copy(dAtA[i:], m.Token) + i = encodeVarintGov(dAtA, i, uint64(len(m.Token))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintGov(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintGov(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddERCCW20PointerProposal) 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 *AddERCCW20PointerProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddERCCW20PointerProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintGov(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x28 + } + if len(m.Pointer) > 0 { + i -= len(m.Pointer) + copy(dAtA[i:], m.Pointer) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointer))) + i-- + dAtA[i] = 0x22 + } + if len(m.Pointee) > 0 { + i -= len(m.Pointee) + copy(dAtA[i:], m.Pointee) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointee))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintGov(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintGov(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddERCCW721PointerProposal) 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 *AddERCCW721PointerProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddERCCW721PointerProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintGov(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x28 + } + if len(m.Pointer) > 0 { + i -= len(m.Pointer) + copy(dAtA[i:], m.Pointer) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointer))) + i-- + dAtA[i] = 0x22 + } + if len(m.Pointee) > 0 { + i -= len(m.Pointee) + copy(dAtA[i:], m.Pointee) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointee))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintGov(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintGov(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGov(dAtA []byte, offset int, v uint64) int { + offset -= sovGov(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *AddERCNativePointerProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Token) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointer) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovGov(uint64(m.Version)) + } + return n +} + +func (m *AddERCCW20PointerProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointee) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointer) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovGov(uint64(m.Version)) + } + return n +} + +func (m *AddERCCW721PointerProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointee) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointer) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovGov(uint64(m.Version)) + } + return n +} + +func sovGov(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGov(x uint64) (n int) { + return sovGov(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *AddERCNativePointerProposal) 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 ErrIntOverflowGov + } + 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: AddERCNativePointerProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddERCNativePointerProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Token = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGov(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGov + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddERCCW20PointerProposal) 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 ErrIntOverflowGov + } + 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: AddERCCW20PointerProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddERCCW20PointerProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGov(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGov + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddERCCW721PointerProposal) 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 ErrIntOverflowGov + } + 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: AddERCCW721PointerProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddERCCW721PointerProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + 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 ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGov(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGov + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGov(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, ErrIntOverflowGov + } + 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, ErrIntOverflowGov + } + 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, ErrIntOverflowGov + } + 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, ErrInvalidLengthGov + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGov + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGov + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGov = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGov = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGov = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/keys.go b/x/evm/types/keys.go index 2d1d94043..b376c2b59 100644 --- a/x/evm/types/keys.go +++ b/x/evm/types/keys.go @@ -45,6 +45,17 @@ var ( ReplaySeenAddrPrefix = []byte{0x12} ReplayedHeight = []byte{0x13} ReplayInitialHeight = []byte{0x14} + + PointerRegistryPrefix = []byte{0x15} + PointerCWCodePrefix = []byte{0x16} +) + +var ( + PointerERC20NativePrefix = []byte{0x0} + PointerERC20CW20Prefix = []byte{0x1} + PointerERC721CW721Prefix = []byte{0x2} + PointerCW20ERC20Prefix = []byte{0x3} + PointerCW721ERC721Prefix = []byte{0x4} ) func EVMAddressToSeiAddressKey(evmAddress common.Address) []byte { @@ -74,3 +85,38 @@ func TxHashesKey(height int64) []byte { binary.BigEndian.PutUint64(bz, uint64(height)) return append(TxHashesPrefix, bz...) } + +func PointerERC20NativeKey(token string) []byte { + return append( + append(PointerRegistryPrefix, PointerERC20NativePrefix...), + []byte(token)..., + ) +} + +func PointerERC20CW20Key(cw20Address string) []byte { + return append( + append(PointerRegistryPrefix, PointerERC20CW20Prefix...), + []byte(cw20Address)..., + ) +} + +func PointerERC721CW721Key(cw721Address string) []byte { + return append( + append(PointerRegistryPrefix, PointerERC721CW721Prefix...), + []byte(cw721Address)..., + ) +} + +func PointerCW20ERC20Key(erc20Addr common.Address) []byte { + return append( + append(PointerRegistryPrefix, PointerCW20ERC20Prefix...), + erc20Addr[:]..., + ) +} + +func PointerCW721ERC721Key(erc721Addr common.Address) []byte { + return append( + append(PointerRegistryPrefix, PointerCW721ERC721Prefix...), + erc721Addr[:]..., + ) +} diff --git a/x/evm/types/message_internal_evm_call.go b/x/evm/types/message_internal_evm_call.go index e82bd99e5..83e33eb7c 100644 --- a/x/evm/types/message_internal_evm_call.go +++ b/x/evm/types/message_internal_evm_call.go @@ -18,7 +18,11 @@ func NewMessageInternalEVMCall(from sdk.AccAddress, to string, value *sdk.Int, d } func (msg *MsgInternalEVMCall) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{sdk.MustAccAddressFromBech32(msg.Sender)} + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return []sdk.AccAddress{} + } + return []sdk.AccAddress{senderAddr} } func (msg *MsgInternalEVMCall) ValidateBasic() error { diff --git a/x/evm/types/message_internal_evm_delegate_call.go b/x/evm/types/message_internal_evm_delegate_call.go index f8c21738e..c38cb6042 100644 --- a/x/evm/types/message_internal_evm_delegate_call.go +++ b/x/evm/types/message_internal_evm_delegate_call.go @@ -19,7 +19,11 @@ func NewMessageInternalEVMDelegateCall(from sdk.AccAddress, to string, codeHash } func (msg *MsgInternalEVMDelegateCall) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{sdk.MustAccAddressFromBech32(msg.FromContract)} + contractAddr, err := sdk.AccAddressFromBech32(msg.FromContract) + if err != nil { + return []sdk.AccAddress{} + } + return []sdk.AccAddress{contractAddr} } func (msg *MsgInternalEVMDelegateCall) ValidateBasic() error { diff --git a/x/evm/types/message_register_pointer.go b/x/evm/types/message_register_pointer.go new file mode 100644 index 000000000..1f2c124c4 --- /dev/null +++ b/x/evm/types/message_register_pointer.go @@ -0,0 +1,54 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/ethereum/go-ethereum/common" +) + +const TypeMsgRegisterPointer = "evm_register_pointer" + +var ( + _ sdk.Msg = &MsgSend{} +) + +func NewMsgRegisterERC20Pointer(sender sdk.AccAddress, ercAddress common.Address) *MsgRegisterPointer { + return &MsgRegisterPointer{Sender: sender.String(), ErcAddress: ercAddress.Hex(), PointerType: PointerType_ERC20} +} + +func NewMsgRegisterERC721Pointer(sender sdk.AccAddress, ercAddress common.Address) *MsgRegisterPointer { + return &MsgRegisterPointer{Sender: sender.String(), ErcAddress: ercAddress.Hex(), PointerType: PointerType_ERC721} +} + +func (msg *MsgRegisterPointer) Route() string { + return RouterKey +} + +func (msg *MsgRegisterPointer) Type() string { + return TypeMsgRegisterPointer +} + +func (msg *MsgRegisterPointer) GetSigners() []sdk.AccAddress { + from, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + panic(err) + } + return []sdk.AccAddress{from} +} + +func (msg *MsgRegisterPointer) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +func (msg *MsgRegisterPointer) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + if !common.IsHexAddress(msg.ErcAddress) { + return sdkerrors.ErrInvalidAddress + } + + return nil +} diff --git a/x/evm/types/query.pb.go b/x/evm/types/query.pb.go index ef8c5b7e6..5c80febcc 100644 --- a/x/evm/types/query.pb.go +++ b/x/evm/types/query.pb.go @@ -316,6 +316,118 @@ func (m *QueryStaticCallResponse) GetData() []byte { return nil } +type QueryPointerRequest struct { + PointerType PointerType `protobuf:"varint,1,opt,name=pointer_type,json=pointerType,proto3,enum=seiprotocol.seichain.evm.PointerType" json:"pointer_type,omitempty"` + Pointee string `protobuf:"bytes,2,opt,name=pointee,proto3" json:"pointee,omitempty"` +} + +func (m *QueryPointerRequest) Reset() { *m = QueryPointerRequest{} } +func (m *QueryPointerRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPointerRequest) ProtoMessage() {} +func (*QueryPointerRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{6} +} +func (m *QueryPointerRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPointerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPointerRequest.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 *QueryPointerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPointerRequest.Merge(m, src) +} +func (m *QueryPointerRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPointerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPointerRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPointerRequest proto.InternalMessageInfo + +func (m *QueryPointerRequest) GetPointerType() PointerType { + if m != nil { + return m.PointerType + } + return PointerType_ERC20 +} + +func (m *QueryPointerRequest) GetPointee() string { + if m != nil { + return m.Pointee + } + return "" +} + +type QueryPointerResponse struct { + Pointer string `protobuf:"bytes,1,opt,name=pointer,proto3" json:"pointer,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + Exists bool `protobuf:"varint,3,opt,name=exists,proto3" json:"exists,omitempty"` +} + +func (m *QueryPointerResponse) Reset() { *m = QueryPointerResponse{} } +func (m *QueryPointerResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPointerResponse) ProtoMessage() {} +func (*QueryPointerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{7} +} +func (m *QueryPointerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPointerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPointerResponse.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 *QueryPointerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPointerResponse.Merge(m, src) +} +func (m *QueryPointerResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPointerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPointerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPointerResponse proto.InternalMessageInfo + +func (m *QueryPointerResponse) GetPointer() string { + if m != nil { + return m.Pointer + } + return "" +} + +func (m *QueryPointerResponse) GetVersion() uint32 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *QueryPointerResponse) GetExists() bool { + if m != nil { + return m.Exists + } + return false +} + func init() { proto.RegisterType((*QuerySeiAddressByEVMAddressRequest)(nil), "seiprotocol.seichain.evm.QuerySeiAddressByEVMAddressRequest") proto.RegisterType((*QuerySeiAddressByEVMAddressResponse)(nil), "seiprotocol.seichain.evm.QuerySeiAddressByEVMAddressResponse") @@ -323,39 +435,49 @@ func init() { proto.RegisterType((*QueryEVMAddressBySeiAddressResponse)(nil), "seiprotocol.seichain.evm.QueryEVMAddressBySeiAddressResponse") proto.RegisterType((*QueryStaticCallRequest)(nil), "seiprotocol.seichain.evm.QueryStaticCallRequest") proto.RegisterType((*QueryStaticCallResponse)(nil), "seiprotocol.seichain.evm.QueryStaticCallResponse") + proto.RegisterType((*QueryPointerRequest)(nil), "seiprotocol.seichain.evm.QueryPointerRequest") + proto.RegisterType((*QueryPointerResponse)(nil), "seiprotocol.seichain.evm.QueryPointerResponse") } func init() { proto.RegisterFile("evm/query.proto", fileDescriptor_11c0d37eed5339f7) } var fileDescriptor_11c0d37eed5339f7 = []byte{ - // 427 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xcb, 0x6a, 0xdb, 0x40, - 0x14, 0x86, 0x3d, 0xc2, 0x2d, 0xf5, 0xb4, 0xb4, 0x30, 0x0b, 0xd7, 0x98, 0xa2, 0x1a, 0x15, 0x8a, - 0x37, 0x92, 0x7a, 0xd9, 0xba, 0x8b, 0xba, 0x98, 0xae, 0xba, 0xa8, 0x02, 0x59, 0x64, 0x63, 0xc6, - 0xd2, 0x89, 0x3d, 0x20, 0x69, 0x64, 0xcf, 0x58, 0xc4, 0xdb, 0x3c, 0x41, 0x20, 0x4f, 0x90, 0xe7, - 0xc8, 0x3a, 0x90, 0xa5, 0x21, 0x9b, 0x2c, 0x83, 0x9d, 0x07, 0x09, 0x1a, 0xf9, 0x22, 0x7c, 0x91, - 0xe2, 0xec, 0x0e, 0x33, 0xf3, 0x7f, 0xf3, 0x9f, 0x73, 0x7e, 0xfc, 0x01, 0xe2, 0xc0, 0x1e, 0x8e, - 0x61, 0x34, 0xb1, 0xa2, 0x11, 0x97, 0x9c, 0xd4, 0x04, 0x30, 0x55, 0xb9, 0xdc, 0xb7, 0x04, 0x30, - 0x77, 0x40, 0x59, 0x68, 0x41, 0x1c, 0xd4, 0x3f, 0xf5, 0x39, 0xef, 0xfb, 0x60, 0xd3, 0x88, 0xd9, - 0x34, 0x0c, 0xb9, 0xa4, 0x92, 0xf1, 0x50, 0xa4, 0x3a, 0xa3, 0x83, 0x8d, 0xff, 0x09, 0xe6, 0x08, - 0xd8, 0x6f, 0xcf, 0x1b, 0x81, 0x10, 0xed, 0x49, 0xe7, 0xf8, 0xdf, 0xa2, 0x76, 0x60, 0x38, 0x06, - 0x21, 0xc9, 0x67, 0xfc, 0x16, 0xe2, 0xa0, 0x4b, 0xd3, 0xd3, 0x1a, 0x6a, 0xa0, 0x66, 0xc5, 0xc1, - 0x10, 0x07, 0x8b, 0x77, 0xc6, 0x29, 0xfe, 0x92, 0x8b, 0x11, 0x11, 0x0f, 0x05, 0x24, 0x1c, 0x01, - 0x6c, 0x93, 0x23, 0x56, 0x22, 0xa2, 0x63, 0x4c, 0x85, 0xe0, 0x2e, 0xa3, 0x12, 0xbc, 0x9a, 0xd6, - 0x40, 0xcd, 0x37, 0x4e, 0xe6, 0x64, 0x65, 0x77, 0xcd, 0x6e, 0x67, 0xfe, 0xcc, 0xd8, 0xcd, 0xfd, - 0x66, 0x65, 0x77, 0x1f, 0x66, 0x6d, 0x37, 0xb7, 0xed, 0x42, 0xbb, 0x2d, 0x5c, 0x4d, 0xc7, 0x92, - 0x0c, 0xdd, 0xfd, 0x43, 0x7d, 0x7f, 0x69, 0x91, 0xe0, 0xb2, 0x47, 0x25, 0x55, 0xcc, 0x77, 0x8e, - 0xaa, 0xc9, 0x7b, 0xac, 0x49, 0xae, 0x28, 0x15, 0x47, 0x93, 0xdc, 0x30, 0xf1, 0xc7, 0x2d, 0xf5, - 0xc2, 0xd9, 0x0e, 0xf9, 0x8f, 0xeb, 0x32, 0x7e, 0xa5, 0xde, 0x93, 0x1b, 0x84, 0xab, 0xbb, 0x37, - 0x41, 0x5a, 0xd6, 0xbe, 0xa0, 0x58, 0xc5, 0x39, 0xa8, 0xff, 0x7a, 0xa1, 0x3a, 0x75, 0x6d, 0x58, - 0xe7, 0x77, 0x8f, 0x97, 0x5a, 0x93, 0x7c, 0xb5, 0x05, 0x30, 0x73, 0xc9, 0xb1, 0x97, 0x1c, 0x3b, - 0x09, 0x75, 0x66, 0x71, 0xaa, 0x8f, 0xdd, 0x2b, 0x2a, 0xec, 0x23, 0x37, 0x20, 0x85, 0x7d, 0xe4, - 0xe7, 0xe2, 0x59, 0x7d, 0x64, 0x82, 0x43, 0xae, 0x10, 0xc6, 0xeb, 0x25, 0x92, 0x6f, 0x45, 0x53, - 0xdc, 0x4c, 0x4b, 0xfd, 0xfb, 0x01, 0x8a, 0x43, 0x66, 0xad, 0x64, 0x5d, 0x97, 0xfa, 0x7e, 0xfb, - 0xef, 0xed, 0x4c, 0x47, 0xd3, 0x99, 0x8e, 0x1e, 0x66, 0x3a, 0xba, 0x98, 0xeb, 0xa5, 0xe9, 0x5c, - 0x2f, 0xdd, 0xcf, 0xf5, 0xd2, 0x89, 0xd9, 0x67, 0x72, 0x30, 0xee, 0x59, 0x2e, 0x0f, 0xb6, 0x58, - 0x66, 0x0a, 0x3b, 0x53, 0x38, 0x39, 0x89, 0x40, 0xf4, 0x5e, 0xab, 0xfb, 0x9f, 0x4f, 0x01, 0x00, - 0x00, 0xff, 0xff, 0xa3, 0xfc, 0x90, 0x59, 0xa3, 0x04, 0x00, 0x00, + // 547 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0xcd, 0x6e, 0xd3, 0x4c, + 0x14, 0x8d, 0xf3, 0x7d, 0x6d, 0xe9, 0x6d, 0x29, 0xd2, 0x80, 0x42, 0x14, 0x21, 0x53, 0x99, 0x1f, + 0x45, 0x48, 0xb6, 0xa1, 0x6c, 0xcb, 0x82, 0xa0, 0x0a, 0x36, 0x48, 0x60, 0x10, 0x0b, 0x36, 0xd1, + 0xc4, 0xb9, 0xa4, 0x23, 0xc5, 0x1e, 0xd7, 0x33, 0xb1, 0xea, 0x2d, 0x4f, 0x80, 0x04, 0x2f, 0xc0, + 0xc3, 0x20, 0xb1, 0xac, 0x60, 0xc3, 0x12, 0x25, 0x3c, 0x08, 0xf2, 0x78, 0x9c, 0xb8, 0x6d, 0x62, + 0xb7, 0xec, 0xe6, 0x8e, 0xe7, 0x9c, 0x7b, 0xce, 0xf5, 0xb9, 0x70, 0x0d, 0x93, 0xc0, 0x3d, 0x9a, + 0x60, 0x9c, 0x3a, 0x51, 0xcc, 0x25, 0x27, 0x6d, 0x81, 0x4c, 0x9d, 0x7c, 0x3e, 0x76, 0x04, 0x32, + 0xff, 0x90, 0xb2, 0xd0, 0xc1, 0x24, 0xe8, 0xdc, 0x1a, 0x71, 0x3e, 0x1a, 0xa3, 0x4b, 0x23, 0xe6, + 0xd2, 0x30, 0xe4, 0x92, 0x4a, 0xc6, 0x43, 0x91, 0xe3, 0x3a, 0x8a, 0x08, 0xc3, 0x49, 0xa0, 0x2f, + 0xac, 0x03, 0xb0, 0x5e, 0x67, 0xbc, 0x6f, 0x90, 0x3d, 0x1d, 0x0e, 0x63, 0x14, 0xa2, 0x97, 0x1e, + 0xbc, 0x7b, 0xa9, 0xcf, 0x1e, 0x1e, 0x4d, 0x50, 0x48, 0x72, 0x1b, 0xb6, 0x30, 0x09, 0xfa, 0x34, + 0xbf, 0x6d, 0x1b, 0xbb, 0x46, 0x77, 0xd3, 0x03, 0x4c, 0x02, 0xfd, 0xce, 0xfa, 0x00, 0x77, 0x2a, + 0x69, 0x44, 0xc4, 0x43, 0x81, 0x19, 0x8f, 0x40, 0x76, 0x96, 0x47, 0xcc, 0x41, 0xc4, 0x04, 0xa0, + 0x42, 0x70, 0x9f, 0x51, 0x89, 0xc3, 0x76, 0x73, 0xd7, 0xe8, 0x5e, 0xf1, 0x4a, 0x37, 0x73, 0xb9, + 0x0b, 0xee, 0x5e, 0xa9, 0x67, 0x49, 0x6e, 0x65, 0x9b, 0xb9, 0xdc, 0x55, 0x34, 0x0b, 0xb9, 0x95, + 0xb6, 0x6b, 0xe5, 0xee, 0x43, 0x2b, 0x1f, 0x4b, 0xf6, 0x17, 0xfc, 0x67, 0x74, 0x3c, 0x2e, 0x24, + 0x12, 0xf8, 0x7f, 0x48, 0x25, 0x55, 0x9c, 0xdb, 0x9e, 0x3a, 0x93, 0x1d, 0x68, 0x4a, 0xae, 0x58, + 0x36, 0xbd, 0xa6, 0xe4, 0x96, 0x0d, 0x37, 0xcf, 0xa1, 0xb5, 0xb2, 0x25, 0x70, 0x2b, 0x85, 0xeb, + 0xea, 0xf9, 0x2b, 0xce, 0x42, 0x89, 0x71, 0xd1, 0xe9, 0x05, 0x6c, 0x47, 0xf9, 0x4d, 0x5f, 0xa6, + 0x11, 0x2a, 0xc8, 0xce, 0xde, 0x3d, 0x67, 0x55, 0x82, 0x1c, 0x8d, 0x7f, 0x9b, 0x46, 0xe8, 0x6d, + 0x45, 0x8b, 0x82, 0xb4, 0x61, 0x23, 0x2f, 0x51, 0x8b, 0x2c, 0x4a, 0x6b, 0x00, 0x37, 0x4e, 0xb7, + 0xd6, 0x32, 0xe7, 0x88, 0x58, 0x0f, 0xaf, 0x28, 0xb3, 0x2f, 0x09, 0xc6, 0x82, 0xf1, 0x50, 0x71, + 0x5d, 0xf5, 0x8a, 0x92, 0xb4, 0x60, 0x1d, 0x8f, 0x99, 0x90, 0xa2, 0xfd, 0x9f, 0x9a, 0xa7, 0xae, + 0xf6, 0x7e, 0xac, 0xc1, 0x9a, 0x6a, 0x42, 0xbe, 0x19, 0xd0, 0x5a, 0x1e, 0x34, 0xb2, 0xbf, 0xda, + 0x56, 0x7d, 0xcc, 0x3b, 0x4f, 0xfe, 0x11, 0x9d, 0xbb, 0xb5, 0x9c, 0x8f, 0x3f, 0xff, 0x7c, 0x6e, + 0x76, 0xc9, 0x7d, 0x57, 0x20, 0xb3, 0x0b, 0x1e, 0xb7, 0xe0, 0x71, 0xb3, 0xdd, 0x2b, 0xe5, 0x52, + 0xf9, 0x58, 0x9e, 0xc0, 0x5a, 0x1f, 0x95, 0xf9, 0xaf, 0xf5, 0x51, 0x1d, 0xfb, 0x0b, 0xf9, 0x28, + 0xed, 0x05, 0xf9, 0x6a, 0x00, 0x2c, 0x32, 0x4a, 0x1e, 0xd6, 0x4d, 0xf1, 0xec, 0x32, 0x74, 0x1e, + 0x5d, 0x02, 0x71, 0x99, 0x59, 0x2b, 0x58, 0xdf, 0xcf, 0x44, 0x7d, 0x31, 0x60, 0x43, 0xa7, 0x93, + 0xd8, 0x35, 0xed, 0x4e, 0x2f, 0x50, 0xc7, 0xb9, 0xe8, 0x73, 0x2d, 0xed, 0x81, 0x92, 0x76, 0x97, + 0x58, 0x15, 0xd2, 0xf4, 0x1a, 0xf4, 0x9e, 0x7f, 0x9f, 0x9a, 0xc6, 0xc9, 0xd4, 0x34, 0x7e, 0x4f, + 0x4d, 0xe3, 0xd3, 0xcc, 0x6c, 0x9c, 0xcc, 0xcc, 0xc6, 0xaf, 0x99, 0xd9, 0x78, 0x6f, 0x8f, 0x98, + 0x3c, 0x9c, 0x0c, 0x1c, 0x9f, 0x07, 0xe7, 0x78, 0xec, 0x9c, 0xe8, 0x58, 0x51, 0x65, 0x4b, 0x2d, + 0x06, 0xeb, 0xea, 0xfb, 0xe3, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x7d, 0xec, 0x65, 0x60, 0x2a, + 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -373,6 +495,7 @@ type QueryClient interface { SeiAddressByEVMAddress(ctx context.Context, in *QuerySeiAddressByEVMAddressRequest, opts ...grpc.CallOption) (*QuerySeiAddressByEVMAddressResponse, error) EVMAddressBySeiAddress(ctx context.Context, in *QueryEVMAddressBySeiAddressRequest, opts ...grpc.CallOption) (*QueryEVMAddressBySeiAddressResponse, error) StaticCall(ctx context.Context, in *QueryStaticCallRequest, opts ...grpc.CallOption) (*QueryStaticCallResponse, error) + Pointer(ctx context.Context, in *QueryPointerRequest, opts ...grpc.CallOption) (*QueryPointerResponse, error) } type queryClient struct { @@ -410,11 +533,21 @@ func (c *queryClient) StaticCall(ctx context.Context, in *QueryStaticCallRequest return out, nil } +func (c *queryClient) Pointer(ctx context.Context, in *QueryPointerRequest, opts ...grpc.CallOption) (*QueryPointerResponse, error) { + out := new(QueryPointerResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Query/Pointer", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { SeiAddressByEVMAddress(context.Context, *QuerySeiAddressByEVMAddressRequest) (*QuerySeiAddressByEVMAddressResponse, error) EVMAddressBySeiAddress(context.Context, *QueryEVMAddressBySeiAddressRequest) (*QueryEVMAddressBySeiAddressResponse, error) StaticCall(context.Context, *QueryStaticCallRequest) (*QueryStaticCallResponse, error) + Pointer(context.Context, *QueryPointerRequest) (*QueryPointerResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -430,6 +563,9 @@ func (*UnimplementedQueryServer) EVMAddressBySeiAddress(ctx context.Context, req func (*UnimplementedQueryServer) StaticCall(ctx context.Context, req *QueryStaticCallRequest) (*QueryStaticCallResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method StaticCall not implemented") } +func (*UnimplementedQueryServer) Pointer(ctx context.Context, req *QueryPointerRequest) (*QueryPointerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Pointer not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -489,6 +625,24 @@ func _Query_StaticCall_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } +func _Query_Pointer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPointerRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Pointer(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Query/Pointer", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Pointer(ctx, req.(*QueryPointerRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "seiprotocol.seichain.evm.Query", HandlerType: (*QueryServer)(nil), @@ -505,6 +659,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "StaticCall", Handler: _Query_StaticCall_Handler, }, + { + MethodName: "Pointer", + Handler: _Query_Pointer_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "evm/query.proto", @@ -717,6 +875,86 @@ func (m *QueryStaticCallResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *QueryPointerRequest) 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 *QueryPointerRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPointerRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Pointee) > 0 { + i -= len(m.Pointee) + copy(dAtA[i:], m.Pointee) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Pointee))) + i-- + dAtA[i] = 0x12 + } + if m.PointerType != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PointerType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPointerResponse) 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 *QueryPointerResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPointerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Exists { + i-- + if m.Exists { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.Version != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x10 + } + if len(m.Pointer) > 0 { + i -= len(m.Pointer) + copy(dAtA[i:], m.Pointer) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Pointer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -816,6 +1054,41 @@ func (m *QueryStaticCallResponse) Size() (n int) { return n } +func (m *QueryPointerRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PointerType != 0 { + n += 1 + sovQuery(uint64(m.PointerType)) + } + l = len(m.Pointee) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPointerResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Pointer) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovQuery(uint64(m.Version)) + } + if m.Exists { + n += 2 + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1390,6 +1663,228 @@ func (m *QueryStaticCallResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryPointerRequest) 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: QueryPointerRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPointerRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PointerType", wireType) + } + m.PointerType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PointerType |= PointerType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointee", 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.Pointee = 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 *QueryPointerResponse) 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: QueryPointerResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPointerResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointer", 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.Pointer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Exists", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Exists = bool(v != 0) + 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/evm/types/query.pb.gw.go b/x/evm/types/query.pb.gw.go index 27555d43d..8d4d10c21 100644 --- a/x/evm/types/query.pb.gw.go +++ b/x/evm/types/query.pb.gw.go @@ -141,6 +141,42 @@ func local_request_Query_StaticCall_0(ctx context.Context, marshaler runtime.Mar } +var ( + filter_Query_Pointer_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_Pointer_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPointerRequest + 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_Query_Pointer_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Pointer(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Pointer_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPointerRequest + 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_Query_Pointer_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Pointer(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 +252,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_Pointer_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_Pointer_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_Pointer_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -317,6 +376,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_Pointer_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_Pointer_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_Pointer_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -326,6 +405,8 @@ var ( pattern_Query_EVMAddressBySeiAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "evm_address"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_StaticCall_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "static_call"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_Pointer_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "pointer"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -334,4 +415,6 @@ var ( forward_Query_EVMAddressBySeiAddress_0 = runtime.ForwardResponseMessage forward_Query_StaticCall_0 = runtime.ForwardResponseMessage + + forward_Query_Pointer_0 = runtime.ForwardResponseMessage ) diff --git a/x/evm/types/tx.pb.go b/x/evm/types/tx.pb.go index 531e6c244..d9989aee0 100644 --- a/x/evm/types/tx.pb.go +++ b/x/evm/types/tx.pb.go @@ -450,6 +450,110 @@ func (m *MsgSendResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgSendResponse proto.InternalMessageInfo +type MsgRegisterPointer struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + PointerType PointerType `protobuf:"varint,2,opt,name=pointer_type,json=pointerType,proto3,enum=seiprotocol.seichain.evm.PointerType" json:"pointer_type,omitempty"` + ErcAddress string `protobuf:"bytes,3,opt,name=erc_address,json=ercAddress,proto3" json:"erc_address,omitempty"` +} + +func (m *MsgRegisterPointer) Reset() { *m = MsgRegisterPointer{} } +func (m *MsgRegisterPointer) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterPointer) ProtoMessage() {} +func (*MsgRegisterPointer) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{8} +} +func (m *MsgRegisterPointer) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterPointer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterPointer.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 *MsgRegisterPointer) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterPointer.Merge(m, src) +} +func (m *MsgRegisterPointer) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterPointer) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterPointer.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterPointer proto.InternalMessageInfo + +func (m *MsgRegisterPointer) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgRegisterPointer) GetPointerType() PointerType { + if m != nil { + return m.PointerType + } + return PointerType_ERC20 +} + +func (m *MsgRegisterPointer) GetErcAddress() string { + if m != nil { + return m.ErcAddress + } + return "" +} + +type MsgRegisterPointerResponse struct { + PointerAddress string `protobuf:"bytes,1,opt,name=pointer_address,json=pointerAddress,proto3" json:"pointer_address,omitempty"` +} + +func (m *MsgRegisterPointerResponse) Reset() { *m = MsgRegisterPointerResponse{} } +func (m *MsgRegisterPointerResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterPointerResponse) ProtoMessage() {} +func (*MsgRegisterPointerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{9} +} +func (m *MsgRegisterPointerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterPointerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterPointerResponse.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 *MsgRegisterPointerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterPointerResponse.Merge(m, src) +} +func (m *MsgRegisterPointerResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterPointerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterPointerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterPointerResponse proto.InternalMessageInfo + +func (m *MsgRegisterPointerResponse) GetPointerAddress() string { + if m != nil { + return m.PointerAddress + } + return "" +} + func init() { proto.RegisterType((*MsgEVMTransaction)(nil), "seiprotocol.seichain.evm.MsgEVMTransaction") proto.RegisterType((*MsgEVMTransactionResponse)(nil), "seiprotocol.seichain.evm.MsgEVMTransactionResponse") @@ -459,52 +563,61 @@ func init() { proto.RegisterType((*MsgInternalEVMDelegateCallResponse)(nil), "seiprotocol.seichain.evm.MsgInternalEVMDelegateCallResponse") proto.RegisterType((*MsgSend)(nil), "seiprotocol.seichain.evm.MsgSend") proto.RegisterType((*MsgSendResponse)(nil), "seiprotocol.seichain.evm.MsgSendResponse") + proto.RegisterType((*MsgRegisterPointer)(nil), "seiprotocol.seichain.evm.MsgRegisterPointer") + proto.RegisterType((*MsgRegisterPointerResponse)(nil), "seiprotocol.seichain.evm.MsgRegisterPointerResponse") } func init() { proto.RegisterFile("evm/tx.proto", fileDescriptor_d72e73a3d1d93781) } var fileDescriptor_d72e73a3d1d93781 = []byte{ - // 640 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0xcf, 0x4e, 0xdb, 0x4c, - 0x10, 0xc0, 0x63, 0x12, 0x08, 0xd9, 0x20, 0x3e, 0xb1, 0x42, 0x9f, 0x92, 0xa8, 0x75, 0xa8, 0x55, - 0x55, 0x69, 0x2b, 0xd6, 0x05, 0x0e, 0x3d, 0xf4, 0x52, 0x02, 0xa8, 0xe5, 0x90, 0x8b, 0x0b, 0x1c, - 0x7a, 0x89, 0x36, 0xf6, 0xe0, 0x58, 0xb5, 0x77, 0xd1, 0xee, 0xda, 0x82, 0x17, 0xe8, 0xb9, 0xaa, - 0x7a, 0xe8, 0x33, 0xf4, 0xd4, 0xc7, 0xe0, 0x56, 0x8e, 0x15, 0x07, 0x5a, 0xc1, 0x8b, 0x54, 0xde, - 0xb5, 0xa3, 0x16, 0x04, 0x4d, 0x4f, 0x9e, 0x9d, 0xbf, 0xbf, 0x99, 0xf1, 0xa0, 0x05, 0xc8, 0x12, - 0x57, 0x1d, 0x93, 0x23, 0xc1, 0x15, 0xc7, 0x2d, 0x09, 0x91, 0x96, 0x7c, 0x1e, 0x13, 0x09, 0x91, - 0x3f, 0xa6, 0x11, 0x23, 0x90, 0x25, 0x9d, 0x76, 0xc8, 0x79, 0x18, 0x83, 0xab, 0xad, 0xa3, 0xf4, - 0xd0, 0xa5, 0xec, 0xc4, 0x04, 0x75, 0x96, 0x43, 0x1e, 0x72, 0x2d, 0xba, 0xb9, 0x54, 0x68, 0x6d, - 0x9f, 0xcb, 0x84, 0x4b, 0x77, 0x44, 0x25, 0xb8, 0xd9, 0xda, 0x08, 0x14, 0x5d, 0x73, 0x7d, 0x1e, - 0x31, 0x63, 0x77, 0x3e, 0x59, 0x68, 0x69, 0x20, 0xc3, 0x9d, 0x83, 0xc1, 0x9e, 0xa0, 0x4c, 0x52, - 0x5f, 0x45, 0x9c, 0xe1, 0x1e, 0xaa, 0x05, 0x54, 0xd1, 0x96, 0xb5, 0x62, 0xf5, 0x9a, 0xeb, 0xcb, - 0xc4, 0x54, 0x25, 0x65, 0x55, 0xb2, 0xc9, 0x4e, 0x3c, 0xed, 0x81, 0xf7, 0x51, 0x3d, 0x00, 0x11, - 0x65, 0x10, 0xb4, 0x66, 0x56, 0xac, 0xde, 0x42, 0xff, 0xc5, 0xf9, 0x45, 0xf7, 0x79, 0x18, 0xa9, - 0x71, 0x3a, 0x22, 0x3e, 0x4f, 0x5c, 0x09, 0xd1, 0x6a, 0xd9, 0x8b, 0x7e, 0xe8, 0x66, 0xdc, 0x63, - 0x37, 0xef, 0xb8, 0x08, 0x25, 0xdb, 0xe6, 0xeb, 0x95, 0xb9, 0x9c, 0xf7, 0x16, 0x6a, 0xdf, 0xc0, - 0xf2, 0x40, 0x1e, 0x71, 0x26, 0x01, 0xb7, 0xd1, 0x7c, 0x48, 0xe5, 0x30, 0x95, 0x10, 0x68, 0xc4, - 0x9a, 0x57, 0x0f, 0xa9, 0xdc, 0x97, 0x10, 0xe4, 0xa6, 0x2c, 0x19, 0x82, 0x10, 0x5c, 0x68, 0xa0, - 0x86, 0x57, 0xcf, 0x92, 0x9d, 0xfc, 0x89, 0xbb, 0xa8, 0x29, 0x40, 0xa5, 0x82, 0x0d, 0x75, 0x6f, - 0xd5, 0x1c, 0xd7, 0x43, 0x46, 0xb5, 0x9d, 0xf7, 0x82, 0x51, 0x6d, 0x4c, 0xe5, 0xb8, 0x55, 0xd3, - 0x71, 0x5a, 0x76, 0x3e, 0x5a, 0x08, 0x0f, 0x64, 0xb8, 0xcb, 0x14, 0x08, 0x46, 0xe3, 0x9d, 0x83, - 0xc1, 0x16, 0x8d, 0x63, 0xfc, 0x3f, 0x9a, 0x93, 0xc0, 0x02, 0x10, 0xba, 0x7e, 0xc3, 0x2b, 0x5e, - 0xf8, 0x25, 0x9a, 0xcd, 0x68, 0x9c, 0x82, 0xa9, 0xdd, 0x7f, 0x72, 0x7e, 0xd1, 0x7d, 0xf4, 0xdb, - 0x30, 0x8a, 0x65, 0x98, 0xcf, 0xaa, 0x0c, 0xde, 0xb9, 0xea, 0xe4, 0x08, 0x24, 0xd9, 0x65, 0xca, - 0x33, 0x81, 0x78, 0x11, 0xcd, 0x28, 0xae, 0xe1, 0x1a, 0xde, 0x8c, 0xe2, 0x39, 0x94, 0xc6, 0xad, - 0x69, 0x5c, 0x2d, 0x3b, 0xf7, 0x50, 0xe7, 0x26, 0x53, 0x39, 0x1d, 0xe7, 0xb3, 0x75, 0xdd, 0xbc, - 0x0d, 0x31, 0x84, 0x54, 0xc1, 0x9d, 0xe8, 0x1d, 0x34, 0xef, 0xf3, 0x00, 0x5e, 0xe7, 0x13, 0xd0, - 0xab, 0xf4, 0x26, 0xef, 0x69, 0xa0, 0xb0, 0x83, 0x16, 0x0e, 0x05, 0x4f, 0xb6, 0x38, 0x53, 0x82, - 0xfa, 0xaa, 0x35, 0xab, 0xbd, 0xff, 0xd0, 0x39, 0x0f, 0x91, 0x73, 0x3b, 0xd9, 0xa4, 0x81, 0xaf, - 0x16, 0xaa, 0x0f, 0x64, 0xf8, 0x06, 0x58, 0x80, 0x1f, 0x98, 0xac, 0x43, 0x1a, 0x04, 0x02, 0xa4, - 0x2c, 0x98, 0x9b, 0xb9, 0x6e, 0xd3, 0xa8, 0xf0, 0x7d, 0x84, 0x14, 0x9f, 0x38, 0x98, 0xa5, 0x37, - 0x14, 0x2f, 0xcd, 0x3e, 0x9a, 0xa3, 0x09, 0x4f, 0x99, 0x6a, 0x55, 0x57, 0xaa, 0xbd, 0xe6, 0x7a, - 0x9b, 0x98, 0xf1, 0x93, 0xfc, 0x24, 0x48, 0x71, 0x12, 0x64, 0x8b, 0x47, 0xac, 0xff, 0xec, 0xf4, - 0xa2, 0x5b, 0xf9, 0xf2, 0xa3, 0xdb, 0x9b, 0x62, 0x65, 0x79, 0x80, 0xf4, 0x8a, 0xd4, 0xce, 0x12, - 0xfa, 0xaf, 0x20, 0x2e, 0xbb, 0x58, 0xff, 0x66, 0xa1, 0xea, 0x40, 0x86, 0x58, 0xa0, 0xc5, 0x6b, - 0xd7, 0xf5, 0x94, 0xdc, 0x76, 0xdf, 0xe4, 0xc6, 0x3f, 0xdf, 0xd9, 0xf8, 0x07, 0xe7, 0xc9, 0x81, - 0xec, 0xa1, 0x9a, 0x99, 0xde, 0x9d, 0xc1, 0xb9, 0x4b, 0xe7, 0xf1, 0x5f, 0x5d, 0xca, 0xac, 0xfd, - 0x57, 0xa7, 0x97, 0xb6, 0x75, 0x76, 0x69, 0x5b, 0x3f, 0x2f, 0x6d, 0xeb, 0xc3, 0x95, 0x5d, 0x39, - 0xbb, 0xb2, 0x2b, 0xdf, 0xaf, 0xec, 0xca, 0xdb, 0xd5, 0x69, 0x0f, 0x5e, 0xcf, 0x6e, 0x34, 0xa7, - 0xed, 0x1b, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xec, 0x21, 0x3d, 0x00, 0xf6, 0x04, 0x00, 0x00, + // 744 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcd, 0x4e, 0xdb, 0x48, + 0x1c, 0xc0, 0xe3, 0x24, 0x10, 0x32, 0x89, 0x12, 0x61, 0xa1, 0x55, 0x12, 0xed, 0x26, 0xac, 0xb5, + 0x1f, 0xd9, 0x0f, 0xec, 0x25, 0xac, 0xb4, 0x87, 0xbd, 0x2c, 0x81, 0x68, 0xe1, 0x10, 0x69, 0xe5, + 0x05, 0x0e, 0xbd, 0x44, 0x13, 0xfb, 0x8f, 0x63, 0x35, 0x9e, 0x89, 0x66, 0xc6, 0x11, 0x79, 0x81, + 0x9e, 0xab, 0xaa, 0x52, 0xfb, 0x0c, 0x3d, 0xf5, 0x29, 0x2a, 0x8e, 0x1c, 0x2b, 0x0e, 0xb4, 0x82, + 0x17, 0xa9, 0x66, 0xc6, 0x71, 0x4b, 0x50, 0x28, 0x9c, 0x3c, 0xf3, 0xff, 0xfc, 0xfd, 0x3f, 0xc6, + 0xa8, 0x0c, 0xd3, 0xc8, 0x11, 0x67, 0xf6, 0x84, 0x51, 0x41, 0xcd, 0x1a, 0x87, 0x50, 0x9d, 0x3c, + 0x3a, 0xb6, 0x39, 0x84, 0xde, 0x08, 0x87, 0xc4, 0x86, 0x69, 0xd4, 0xa8, 0x07, 0x94, 0x06, 0x63, + 0x70, 0x94, 0x76, 0x18, 0x9f, 0x3a, 0x98, 0xcc, 0xb4, 0x53, 0x63, 0x23, 0xa0, 0x01, 0x55, 0x47, + 0x47, 0x9e, 0x12, 0x69, 0xd3, 0xa3, 0x3c, 0xa2, 0xdc, 0x19, 0x62, 0x0e, 0xce, 0x74, 0x7b, 0x08, + 0x02, 0x6f, 0x3b, 0x1e, 0x0d, 0x49, 0xa2, 0xaf, 0xca, 0xc4, 0x40, 0xe2, 0x88, 0x6b, 0x81, 0xf5, + 0xd2, 0x40, 0xeb, 0x7d, 0x1e, 0xf4, 0x4e, 0xfa, 0x47, 0x0c, 0x13, 0x8e, 0x3d, 0x11, 0x52, 0x62, + 0xb6, 0x51, 0xde, 0xc7, 0x02, 0xd7, 0x8c, 0x4d, 0xa3, 0x5d, 0xea, 0x6c, 0xd8, 0x1a, 0xc3, 0x9e, + 0x63, 0xd8, 0xbb, 0x64, 0xe6, 0x2a, 0x0b, 0xf3, 0x18, 0x15, 0x7c, 0x60, 0xe1, 0x14, 0xfc, 0x5a, + 0x76, 0xd3, 0x68, 0x97, 0xbb, 0x7f, 0x5f, 0x5e, 0xb5, 0xfe, 0x0a, 0x42, 0x31, 0x8a, 0x87, 0xb6, + 0x47, 0x23, 0x87, 0x43, 0xb8, 0x35, 0x2f, 0x4e, 0x5d, 0x54, 0x75, 0xce, 0x99, 0x23, 0x49, 0x12, + 0x57, 0x7b, 0x5f, 0x7f, 0xdd, 0x79, 0x2c, 0xeb, 0x99, 0x81, 0xea, 0x77, 0xb0, 0x5c, 0xe0, 0x13, + 0x4a, 0x38, 0x98, 0x75, 0xb4, 0x16, 0x60, 0x3e, 0x88, 0x39, 0xf8, 0x0a, 0x31, 0xef, 0x16, 0x02, + 0xcc, 0x8f, 0x39, 0xf8, 0x52, 0x35, 0x8d, 0x06, 0xc0, 0x18, 0x65, 0x0a, 0xa8, 0xe8, 0x16, 0xa6, + 0x51, 0x4f, 0x5e, 0xcd, 0x16, 0x2a, 0x31, 0x10, 0x31, 0x23, 0x03, 0x55, 0x5b, 0x4e, 0xe2, 0xba, + 0x48, 0x8b, 0xf6, 0x65, 0x2d, 0x26, 0xca, 0x8f, 0x30, 0x1f, 0xd5, 0xf2, 0xca, 0x4f, 0x9d, 0xad, + 0x17, 0x06, 0x32, 0xfb, 0x3c, 0x38, 0x24, 0x02, 0x18, 0xc1, 0xe3, 0xde, 0x49, 0x7f, 0x0f, 0x8f, + 0xc7, 0xe6, 0x37, 0x68, 0x95, 0x03, 0xf1, 0x81, 0xa9, 0xfc, 0x45, 0x37, 0xb9, 0x99, 0xff, 0xa0, + 0x95, 0x29, 0x1e, 0xc7, 0xa0, 0x73, 0x77, 0x7f, 0xbd, 0xbc, 0x6a, 0xfd, 0xf4, 0x45, 0x33, 0x92, + 0xe9, 0xe8, 0xcf, 0x16, 0xf7, 0x9f, 0x3a, 0x62, 0x36, 0x01, 0x6e, 0x1f, 0x12, 0xe1, 0x6a, 0x47, + 0xb3, 0x82, 0xb2, 0x82, 0x2a, 0xb8, 0xa2, 0x9b, 0x15, 0x54, 0x42, 0x29, 0xdc, 0xbc, 0xc2, 0x55, + 0x67, 0xeb, 0x5b, 0xd4, 0xb8, 0xcb, 0x34, 0xef, 0x8e, 0xf5, 0xda, 0x58, 0x54, 0xef, 0xc3, 0x18, + 0x02, 0x2c, 0xe0, 0x5e, 0xf4, 0x06, 0x5a, 0xf3, 0xa8, 0x0f, 0x07, 0xb2, 0x03, 0x6a, 0x94, 0x6e, + 0x7a, 0x7f, 0x08, 0x94, 0x69, 0xa1, 0xf2, 0x29, 0xa3, 0xd1, 0x1e, 0x25, 0x82, 0x61, 0x4f, 0xd4, + 0x56, 0x94, 0xf5, 0x2d, 0x99, 0xf5, 0x03, 0xb2, 0x96, 0x93, 0xa5, 0x05, 0xbc, 0x35, 0x50, 0xa1, + 0xcf, 0x83, 0xff, 0x81, 0xf8, 0xe6, 0xf7, 0x3a, 0xea, 0x00, 0xfb, 0x3e, 0x03, 0xce, 0x13, 0xe6, + 0x92, 0x94, 0xed, 0x6a, 0x91, 0xf9, 0x1d, 0x42, 0x82, 0xa6, 0x06, 0x7a, 0xe8, 0x45, 0x41, 0xe7, + 0x6a, 0x0f, 0xad, 0xe2, 0x88, 0xc6, 0x44, 0xd4, 0x72, 0x9b, 0xb9, 0x76, 0xa9, 0x53, 0xb7, 0x75, + 0xfb, 0x6d, 0xf9, 0x46, 0xec, 0xe4, 0x8d, 0xd8, 0x7b, 0x34, 0x24, 0xdd, 0x3f, 0xce, 0xaf, 0x5a, + 0x99, 0x37, 0x1f, 0x5a, 0xed, 0x07, 0x8c, 0x4c, 0x3a, 0x70, 0x37, 0x09, 0x6d, 0xad, 0xa3, 0x6a, + 0x42, 0x9c, 0x56, 0xf1, 0x4a, 0x6f, 0x8e, 0x0b, 0x41, 0xc8, 0x05, 0xb0, 0xff, 0x68, 0x28, 0xcb, + 0x5e, 0xda, 0xfe, 0x03, 0x54, 0x9e, 0x68, 0x93, 0x81, 0x4c, 0xa0, 0xea, 0xa8, 0x74, 0x7e, 0xb4, + 0x97, 0xfd, 0x1b, 0xec, 0x24, 0xe0, 0xd1, 0x6c, 0x02, 0x6e, 0x69, 0xf2, 0xf9, 0x22, 0xf7, 0x1c, + 0x98, 0x97, 0x36, 0x44, 0x4f, 0x0d, 0x01, 0xf3, 0x92, 0x8e, 0x58, 0x3d, 0xb5, 0x1f, 0x0b, 0x60, + 0xe9, 0xe3, 0xfa, 0x19, 0x55, 0xe7, 0x20, 0xb7, 0x9b, 0x5e, 0x49, 0xc4, 0x49, 0x98, 0xce, 0xbb, + 0x2c, 0xca, 0xf5, 0x79, 0x60, 0x32, 0x54, 0x59, 0xf8, 0x7d, 0xfc, 0xb6, 0x9c, 0xfa, 0xce, 0xa3, + 0x6e, 0xec, 0x3c, 0xc2, 0x38, 0x85, 0x3c, 0x42, 0x79, 0xbd, 0x1e, 0xf7, 0x3a, 0x4b, 0x93, 0xc6, + 0x2f, 0x5f, 0x35, 0x49, 0xa3, 0xc6, 0xa8, 0xba, 0x38, 0xae, 0xdf, 0xef, 0xf5, 0x5e, 0xb0, 0x6e, + 0xfc, 0xf9, 0x18, 0xeb, 0x79, 0xda, 0xee, 0xbf, 0xe7, 0xd7, 0x4d, 0xe3, 0xe2, 0xba, 0x69, 0x7c, + 0xbc, 0x6e, 0x1a, 0xcf, 0x6f, 0x9a, 0x99, 0x8b, 0x9b, 0x66, 0xe6, 0xfd, 0x4d, 0x33, 0xf3, 0x64, + 0xeb, 0xa1, 0x3f, 0x52, 0xb5, 0x93, 0xc3, 0x55, 0xa5, 0xdf, 0xf9, 0x14, 0x00, 0x00, 0xff, 0xff, + 0x51, 0x5e, 0xb8, 0x08, 0x5f, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -521,6 +634,7 @@ const _ = grpc.SupportPackageIsVersion4 type MsgClient interface { EVMTransaction(ctx context.Context, in *MsgEVMTransaction, opts ...grpc.CallOption) (*MsgEVMTransactionResponse, error) Send(ctx context.Context, in *MsgSend, opts ...grpc.CallOption) (*MsgSendResponse, error) + RegisterPointer(ctx context.Context, in *MsgRegisterPointer, opts ...grpc.CallOption) (*MsgRegisterPointerResponse, error) } type msgClient struct { @@ -549,10 +663,20 @@ func (c *msgClient) Send(ctx context.Context, in *MsgSend, opts ...grpc.CallOpti return out, nil } +func (c *msgClient) RegisterPointer(ctx context.Context, in *MsgRegisterPointer, opts ...grpc.CallOption) (*MsgRegisterPointerResponse, error) { + out := new(MsgRegisterPointerResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Msg/RegisterPointer", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { EVMTransaction(context.Context, *MsgEVMTransaction) (*MsgEVMTransactionResponse, error) Send(context.Context, *MsgSend) (*MsgSendResponse, error) + RegisterPointer(context.Context, *MsgRegisterPointer) (*MsgRegisterPointerResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -565,6 +689,9 @@ func (*UnimplementedMsgServer) EVMTransaction(ctx context.Context, req *MsgEVMTr func (*UnimplementedMsgServer) Send(ctx context.Context, req *MsgSend) (*MsgSendResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Send not implemented") } +func (*UnimplementedMsgServer) RegisterPointer(ctx context.Context, req *MsgRegisterPointer) (*MsgRegisterPointerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterPointer not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -606,6 +733,24 @@ func _Msg_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{ return interceptor(ctx, in, info, handler) } +func _Msg_RegisterPointer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRegisterPointer) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RegisterPointer(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Msg/RegisterPointer", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RegisterPointer(ctx, req.(*MsgRegisterPointer)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "seiprotocol.seichain.evm.Msg", HandlerType: (*MsgServer)(nil), @@ -618,6 +763,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "Send", Handler: _Msg_Send_Handler, }, + { + MethodName: "RegisterPointer", + Handler: _Msg_RegisterPointer_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "evm/tx.proto", @@ -953,6 +1102,78 @@ func (m *MsgSendResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *MsgRegisterPointer) 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 *MsgRegisterPointer) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterPointer) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ErcAddress) > 0 { + i -= len(m.ErcAddress) + copy(dAtA[i:], m.ErcAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ErcAddress))) + i-- + dAtA[i] = 0x1a + } + if m.PointerType != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PointerType)) + i-- + dAtA[i] = 0x10 + } + 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] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRegisterPointerResponse) 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 *MsgRegisterPointerResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterPointerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PointerAddress) > 0 { + i -= len(m.PointerAddress) + copy(dAtA[i:], m.PointerAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.PointerAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -1109,6 +1330,39 @@ func (m *MsgSendResponse) Size() (n int) { return n } +func (m *MsgRegisterPointer) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PointerType != 0 { + n += 1 + sovTx(uint64(m.PointerType)) + } + l = len(m.ErcAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRegisterPointerResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PointerAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2099,6 +2353,221 @@ func (m *MsgSendResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgRegisterPointer) 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: MsgRegisterPointer: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterPointer: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + 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 + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PointerType", wireType) + } + m.PointerType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PointerType |= PointerType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErcAddress", 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.ErcAddress = 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 *MsgRegisterPointerResponse) 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: MsgRegisterPointerResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterPointerResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PointerAddress", 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.PointerAddress = 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 skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/tokenfactory/types/query.pb.go b/x/tokenfactory/types/query.pb.go index 9970bd075..b1c6dade3 100644 --- a/x/tokenfactory/types/query.pb.go +++ b/x/tokenfactory/types/query.pb.go @@ -344,7 +344,7 @@ func (m *QueryDenomMetadataRequest) GetDenom() string { return "" } -// QueryDenomMetadataResponse is the response type for the Query/DenomMetadata RPC +// QueryDenomMetadataResponse is the response type for the Query/DenomMetadata gRPC // method. type QueryDenomMetadataResponse struct { // metadata describes and provides all the client information for the requested token.