diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 398b390e8..a878de556 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -115,14 +115,12 @@ jobs: { name: "EVM Module", scripts: [ - "python3 integration_test/scripts/runner.py integration_test/evm_module/hardhat_test.yaml", "./integration_test/evm_module/scripts/evm_tests.sh", ] }, { name: "EVM Interoperability", scripts: [ - "python3 integration_test/scripts/runner.py integration_test/evm_module/hardhat_test.yaml", "./integration_test/evm_module/scripts/evm_interoperability_tests.sh" ] }, diff --git a/.golangci.yml b/.golangci.yml index 6490cac8c..511f556fc 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -9,7 +9,6 @@ linters: disable-all: true enable: - bodyclose - - deadcode # - depguard ## see https://github.com/golangci/golangci-lint/issues/3906 - dogsled - exportloopref diff --git a/CHANGELOG.md b/CHANGELOG.md index 928df9d37..133e04a12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,25 @@ Ref: https://keepachangelog.com/en/1.0.0/ --> # Changelog +## v5.5.2 +sei-chain +* [#1685](https://github.com/sei-protocol/sei-chain/pull/1685) Add EVM support to v5.5.2 +## v5.4.0 +sei-chain +* [#1671](https://github.com/sei-protocol/sei-chain/pull/1671) Update and fixes to ERC721 contract +* [#1672](https://github.com/sei-protocol/sei-chain/pull/1672) Add sei_getCosmosTx endpoint +* [#1669](https://github.com/sei-protocol/sei-chain/pull/1669) Add ERC/CW 2981 in pointe +* [#1668](https://github.com/sei-protocol/sei-chain/pull/1673) Bring CW721 pointer contract up to spec +* [#1662](https://github.com/sei-protocol/sei-chain/pull/1662) Add memo support to ibc compiles +* [#1661](https://github.com/sei-protocol/sei-chain/pull/1661) Do not modify original value passed in executeBatch call + +sei-cosmos +*[#505](https://github.com/sei-protocol/sei-cosmos/pull/505) Fix export genesis for historical height +*[#506](https://github.com/sei-protocol/sei-cosmos/pull/506) Allow reading pairs in changeset before flush + +sei-wasmd +*[#50](https://github.com/sei-protocol/sei-wasmd/pull/50) Changes to fix runtime gas and add paramsKeeper to wasmKeeper for query gas multiplier + ## v5.2.0 sei-chain * [#1621](https://github.com/sei-protocol/sei-chain/pull/1621) Add websocket metrics diff --git a/app/antedecorators/gasless.go b/app/antedecorators/gasless.go index 72fe941da..628b1194f 100644 --- a/app/antedecorators/gasless.go +++ b/app/antedecorators/gasless.go @@ -137,7 +137,7 @@ func IsTxGasless(tx sdk.Tx, ctx sdk.Context, oracleKeeper oraclekeeper.Keeper) ( } func dexPlaceOrdersIsGasless(_ *dextypes.MsgPlaceOrders) bool { - return true + return false } // WhitelistedGaslessCancellationAddrs TODO: migrate this into params state diff --git a/app/antedecorators/gasless_test.go b/app/antedecorators/gasless_test.go index 5e77d907b..9f50f7242 100644 --- a/app/antedecorators/gasless_test.go +++ b/app/antedecorators/gasless_test.go @@ -4,7 +4,6 @@ import ( "fmt" "testing" - "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/accesscontrol" "github.com/cosmos/cosmos-sdk/x/staking" @@ -14,9 +13,7 @@ import ( oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/secp256k1" - "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmdb "github.com/tendermint/tm-db" ) var output = "" @@ -112,53 +109,6 @@ func CallGaslessDecoratorWithMsg(ctx sdk.Context, msg sdk.Msg, oracleKeeper orac return err } -func TestGaslessDecorator(t *testing.T) { - output = "" - anteDecorators := []sdk.AnteFullDecorator{ - FakeAnteDecoratorOne{}, - antedecorators.NewGaslessDecorator([]sdk.AnteFullDecorator{FakeAnteDecoratorTwo{}}, oraclekeeper.Keeper{}), - FakeAnteDecoratorThree{}, - } - chainedHandler, depGen := sdk.ChainAnteDecorators(anteDecorators...) - - db := tmdb.NewMemDB() - stateStore := store.NewCommitMultiStore(db) - ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) - - // normal tx (not gasless) - _, err := chainedHandler(ctx, FakeTx{}, false) - require.NoError(t, err) - require.Equal(t, "onetwothree", output) - _, err = depGen([]accesscontrol.AccessOperation{}, FakeTx{}, 1) - require.NoError(t, err) - require.Equal(t, "onetwothree", outputDeps) - - // gasless tx (deliverTx) -> wrapped should still be run - output = "" - outputDeps = "" - _, err = chainedHandler(ctx, FakeTx{ - FakeMsgs: []sdk.Msg{&types.MsgPlaceOrders{}}, - Gas: 100, - }, false) - require.NoError(t, err) - require.Equal(t, "onetwothree", output) - _, err = depGen([]accesscontrol.AccessOperation{}, FakeTx{}, 1) - require.NoError(t, err) - require.Equal(t, "onetwothree", outputDeps) - - // gasless tx (checkTx) -> wrapped should not be run - output = "" - outputDeps = "" - _, err = chainedHandler(ctx.WithIsCheckTx(true), FakeTx{ - FakeMsgs: []sdk.Msg{&types.MsgPlaceOrders{}}, - }, false) - require.NoError(t, err) - require.Equal(t, "onethree", output) - _, err = depGen([]accesscontrol.AccessOperation{}, FakeTx{}, 1) - require.NoError(t, err) - require.Equal(t, "onetwothree", outputDeps) -} - func TestOracleVoteGasless(t *testing.T) { input := oraclekeeper.CreateTestInput(t) @@ -200,15 +150,6 @@ func TestOracleVoteGasless(t *testing.T) { require.True(t, gasless) } -func TestDexPlaceOrderGasless(t *testing.T) { - // this needs to be updated if its changed from constant true - // reset gasless - gasless = true - err := CallGaslessDecoratorWithMsg(sdk.NewContext(nil, tmproto.Header{}, false, nil).WithIsCheckTx(true), &types.MsgPlaceOrders{}, oraclekeeper.Keeper{}) - require.NoError(t, err) - require.True(t, gasless) -} - func TestDexCancelOrderGasless(t *testing.T) { addr1 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) addr2 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) diff --git a/app/app.go b/app/app.go index 88569dc9b..8506ade62 100644 --- a/app/app.go +++ b/app/app.go @@ -578,6 +578,7 @@ func New( app.WasmKeeper = wasm.NewKeeper( appCodec, keys[wasm.StoreKey], + app.ParamsKeeper, app.GetSubspace(wasm.ModuleName), app.AccountKeeper, app.BankKeeper, @@ -597,7 +598,7 @@ func New( app.EvmKeeper = *evmkeeper.NewKeeper(keys[evmtypes.StoreKey], memKeys[evmtypes.MemStoreKey], app.GetSubspace(evmtypes.ModuleName), app.BankKeeper, &app.AccountKeeper, &app.StakingKeeper, - app.TransferKeeper, wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper)) + app.TransferKeeper, wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper), &app.WasmKeeper) app.evmRPCConfig, err = evmrpc.ReadConfig(appOpts) if err != nil { panic(fmt.Sprintf("error reading EVM config due to %s", err)) @@ -683,6 +684,9 @@ func New( app.DistrKeeper, app.OracleKeeper, app.TransferKeeper, + app.IBCKeeper.ClientKeeper, + app.IBCKeeper.ConnectionKeeper, + app.IBCKeeper.ChannelKeeper, ); err != nil { panic(err) } @@ -1019,7 +1023,7 @@ func (app *App) SetStoreUpgradeHandlers() { app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) } - if upgradeInfo.Name == "v5.1.0" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + if (upgradeInfo.Name == "v5.1.0" || upgradeInfo.Name == "v5.5.2") && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { storeUpgrades := storetypes.StoreUpgrades{ Added: []string{evmtypes.StoreKey}, } @@ -1139,7 +1143,8 @@ func (app *App) FinalizeBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) if app.EvmKeeper.EthReplayConfig.Enabled || app.EvmKeeper.EthBlockTestConfig.Enabled { return &abci.ResponseFinalizeBlock{}, nil } - appHash := app.WriteStateToCommitAndGetWorkingHash() + app.WriteState() + appHash := app.GetWorkingHash() resp := app.getFinalizeBlockResponse(appHash, app.optimisticProcessingInfo.Events, app.optimisticProcessingInfo.TxRes, app.optimisticProcessingInfo.EndBlockResp) return &resp, nil } @@ -1154,7 +1159,8 @@ func (app *App) FinalizeBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) if app.EvmKeeper.EthReplayConfig.Enabled || app.EvmKeeper.EthBlockTestConfig.Enabled { return &abci.ResponseFinalizeBlock{}, nil } - appHash := app.WriteStateToCommitAndGetWorkingHash() + app.WriteState() + appHash := app.GetWorkingHash() resp := app.getFinalizeBlockResponse(appHash, events, txResults, endBlockResp) return &resp, nil } @@ -1784,7 +1790,7 @@ func (app *App) RegisterTendermintService(clientCtx client.Context) { app.Logger().Error(fmt.Sprintf("failed to create query context for EVM; using latest context instead: %v+", err.Error())) return app.GetCheckCtx() } - return ctx + return ctx.WithIsEVM(true) } if app.evmRPCConfig.HTTPEnabled { evmHTTPServer, err := evmrpc.NewEVMHTTPServer(app.Logger(), app.evmRPCConfig, clientCtx.Client, &app.EvmKeeper, ctxProvider, app.encodingConfig.TxConfig, DefaultNodeHome) diff --git a/app/upgrades.go b/app/upgrades.go index f0bf59d4e..2a49f9acd 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -94,6 +94,13 @@ var upgradesList = []string{ "v5.0.1", "v5.1.0", "v5.2.0", + "v5.2.1", + "v5.2.2", + "v5.3.0", + "v5.4.0", + "v5.5.0", + "v5.5.1", + "v5.5.2", } // if there is an override list, use that instead, for integration tests diff --git a/cmd/seid/cmd/debug.go b/cmd/seid/cmd/debug.go index 9bd4bee6a..d0a7e3240 100644 --- a/cmd/seid/cmd/debug.go +++ b/cmd/seid/cmd/debug.go @@ -49,6 +49,7 @@ $ %s debug dump-iavl 12345 return cmd } +//nolint:gosec func dumpIavlCmdHandler(cmd *cobra.Command, args []string) error { var err error home, err := os.UserHomeDir() diff --git a/contracts/src/CW721ERC721Pointer.sol b/contracts/src/CW721ERC721Pointer.sol index 259a13573..3898b69e3 100644 --- a/contracts/src/CW721ERC721Pointer.sol +++ b/contracts/src/CW721ERC721Pointer.sol @@ -1,14 +1,16 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.12; +import "@openzeppelin/contracts/token/common/ERC2981.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {IWasmd} from "./precompiles/IWasmd.sol"; import {IJson} from "./precompiles/IJson.sol"; import {IAddr} from "./precompiles/IAddr.sol"; -contract CW721ERC721Pointer is ERC721 { +contract CW721ERC721Pointer is ERC721,ERC2981 { address constant WASMD_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001002; address constant JSON_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001003; @@ -19,6 +21,9 @@ contract CW721ERC721Pointer is ERC721 { IJson public JsonPrecompile; IAddr public AddrPrecompile; + error NotImplementedOnCosmwasmContract(string method); + error NotImplemented(string method); + constructor(string memory Cw721Address_, string memory name_, string memory symbol_) ERC721(name_, symbol_) { WasmdPrecompile = IWasmd(WASMD_PRECOMPILE_ADDRESS); JsonPrecompile = IJson(JSON_PRECOMPILE_ADDRESS); @@ -26,16 +31,43 @@ contract CW721ERC721Pointer is ERC721 { Cw721Address = Cw721Address_; } + function supportsInterface(bytes4 interfaceId) public pure override(ERC721, ERC2981) returns (bool) { + return + interfaceId == type(IERC2981).interfaceId || + interfaceId == type(IERC165).interfaceId || + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId; + } + // Queries function balanceOf(address owner) public view override returns (uint256) { if (owner == address(0)) { revert ERC721InvalidOwner(address(0)); } - string memory ownerAddr = _formatPayload("owner", _doubleQuotes(AddrPrecompile.getSeiAddr(owner))); - string memory req = _curlyBrace(_formatPayload("tokens", _curlyBrace(ownerAddr))); + uint256 numTokens = 0; + string memory startAfter; + string memory qb = string.concat( + string.concat("\"limit\":1000,\"owner\":\"", AddrPrecompile.getSeiAddr(owner)), + "\"" + ); + bytes32 terminator = keccak256("{\"tokens\":[]}"); + + bytes[] memory tokens; + uint256 tokensLength; + string memory req = string.concat(string.concat("{\"tokens\":{", qb), "}}"); bytes memory response = WasmdPrecompile.query(Cw721Address, bytes(req)); - bytes[] memory tokens = JsonPrecompile.extractAsBytesList(response, "tokens"); - return tokens.length; + while (keccak256(response) != terminator) { + tokens = JsonPrecompile.extractAsBytesList(response, "tokens"); + tokensLength = tokens.length; + numTokens += tokensLength; + startAfter = string.concat(",\"start_after\":", string(tokens[tokensLength-1])); + req = string.concat( + string.concat("{\"tokens\":{", string.concat(qb, startAfter)), + "}}" + ); + response = WasmdPrecompile.query(Cw721Address, bytes(req)); + } + return numTokens; } function ownerOf(uint256 tokenId) public view override returns (address) { @@ -72,6 +104,26 @@ contract CW721ERC721Pointer is ERC721 { return false; } + // 2981 + function royaltyInfo(uint256 tokenId, uint256 salePrice) public view override returns (address, uint256) { + bytes memory checkRoyaltyResponse = WasmdPrecompile.query(Cw721Address, bytes("{\"extension\":{\"msg\":{\"check_royalties\":{}}}}")); + bytes memory isRoyaltyImplemented = JsonPrecompile.extractAsBytes(checkRoyaltyResponse, "royalty_payments"); + if (keccak256(isRoyaltyImplemented) != keccak256("true")) { + revert NotImplementedOnCosmwasmContract("royalty_info"); + } + string memory tId = _formatPayload("token_id", _doubleQuotes(Strings.toString(tokenId))); + string memory sPrice = _formatPayload("sale_price", _doubleQuotes(Strings.toString(salePrice))); + string memory req = _curlyBrace(_formatPayload("royalty_info", _curlyBrace(_join(tId, sPrice, ",")))); + string memory fullReq = _curlyBrace(_formatPayload("extension", _curlyBrace(_formatPayload("msg", req)))); + bytes memory response = WasmdPrecompile.query(Cw721Address, bytes(fullReq)); + bytes memory addr = JsonPrecompile.extractAsBytes(response, "address"); + uint256 amt = JsonPrecompile.extractAsUint256(response, "royalty_amount"); + if (addr.length == 0) { + return (address(0), amt); + } + return (AddrPrecompile.getEvmAddr(string(addr)), amt); + } + function tokenURI(uint256 tokenId) public view override returns (string memory) { // revert if token isn't owned ownerOf(tokenId); @@ -82,6 +134,20 @@ contract CW721ERC721Pointer is ERC721 { return string(uri); } + // 721-Enumerable + function totalSupply() public view virtual returns (uint256) { + bytes memory response = WasmdPrecompile.query(Cw721Address, bytes("{\"num_tokens\":{}}")); + return JsonPrecompile.extractAsUint256(response, "count"); + } + + function tokenOfOwnerByIndex(address, uint256) public view virtual returns (uint256) { + revert NotImplemented("tokenOfOwnerByIndex"); + } + + function tokenByIndex(uint256) public view virtual returns (uint256) { + revert NotImplemented("tokenByIndex"); + } + // Transactions function transferFrom(address from, address to, uint256 tokenId) public override { if (to == address(0)) { @@ -126,6 +192,16 @@ contract CW721ERC721Pointer is ERC721 { return ret; } + function _queryContractInfo() internal view virtual returns (string memory, string memory) { + string memory req = _curlyBrace(_formatPayload("contract_info", "{}")); + bytes memory response = WasmdPrecompile.query(Cw721Address, bytes(req)); + bytes memory respName = JsonPrecompile.extractAsBytes(response, "name"); + bytes memory respSymbol = JsonPrecompile.extractAsBytes(response, "symbol"); + string memory nameStr = string(respName); + string memory symbolStr = string(respSymbol); + return (nameStr, symbolStr); + } + function _formatPayload(string memory key, string memory value) internal pure returns (string memory) { return _join(_doubleQuotes(key), value, ":"); } diff --git a/contracts/src/ERC721.sol b/contracts/src/ERC721.sol index c7e89c265..0ad6278a0 100644 --- a/contracts/src/ERC721.sol +++ b/contracts/src/ERC721.sol @@ -51,6 +51,9 @@ contract ERC721 is IERC721 { bool approved ); + // Keeps track of current token supply + uint256 internal _totalSupply = 0; + // Mapping from token ID to owner address mapping(uint => address) internal _ownerOf; @@ -79,6 +82,10 @@ contract ERC721 is IERC721 { return _balanceOf[owner]; } + function totalSupply() external view returns (uint256) { + return _totalSupply; + } + function setApprovalForAll(address operator, bool approved) external { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); @@ -158,6 +165,7 @@ contract ERC721 is IERC721 { require(_ownerOf[id] == address(0), "already minted"); _balanceOf[to]++; + _totalSupply++; _ownerOf[id] = to; emit Transfer(address(0), to, id); @@ -168,6 +176,7 @@ contract ERC721 is IERC721 { require(owner != address(0), "not minted"); _balanceOf[owner] -= 1; + _totalSupply--; delete _ownerOf[id]; delete _approvals[id]; @@ -222,4 +231,9 @@ contract MyNFT is ERC721 { require(msg.sender == _ownerOf[id], "not owner"); _burn(id); } + + function royaltyInfo(uint, uint256 salePrice) external pure returns (address receiver, uint256 royaltyAmount) { + receiver = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; + royaltyAmount = (salePrice * 500) / 10_000; + } } diff --git a/contracts/src/MultiSender.sol b/contracts/src/MultiSender.sol new file mode 100644 index 000000000..4a6fd0f97 --- /dev/null +++ b/contracts/src/MultiSender.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +contract MultiSender { + event SendSuccessful( + address indexed sender, + address recipient, + uint256 amount + ); + + function batchTransferEqualAmount( + address[] calldata recipients, + uint256 amount + ) external payable { + uint256 totalAmount = amount * recipients.length; + require(msg.value >= totalAmount, "Insufficient amount sent"); + + for (uint256 i = 0; i < recipients.length; i++) { + bool success = payable(recipients[i]).send(amount); + require(success, "Failed to send Ether"); + emit SendSuccessful(msg.sender, recipients[i], amount); + } + } + + function batchTransfer( + address[] calldata recipients, + uint256[] calldata amounts + ) external payable { + require( + recipients.length == amounts.length, + "Recipients and amounts do not match" + ); + uint256 totalAmount = 0; + for (uint256 i = 0; i < amounts.length; i++) { + totalAmount += amounts[i]; + } + + require(msg.value >= totalAmount, "Insufficient amount sent"); + + for (uint256 i = 0; i < recipients.length; i++) { + bool success = payable(recipients[i]).send(amounts[i]); + require(success, "Failed to send Ether"); + emit SendSuccessful(msg.sender, recipients[i], amounts[i]); + } + } +} \ No newline at end of file diff --git a/contracts/test/AssociateTest.js b/contracts/test/AssociateTest.js new file mode 100644 index 000000000..04e35eda1 --- /dev/null +++ b/contracts/test/AssociateTest.js @@ -0,0 +1,87 @@ +const { fundAddress, fundSeiAddress, getSeiBalance, associateKey, importKey, waitForReceipt, bankSend, evmSend, getNativeAccount} = require("./lib"); +const { expect } = require("chai"); + +describe("Associate Balances", function () { + + const keys = { + "test1": { + seiAddress: 'sei1nzdg7e6rvkrmvp5zzmp5tupuj0088nqsa4mze4', + evmAddress: '0x90684e7F229f2d8E2336661f79caB693E4228Ff7' + }, + "test2": { + seiAddress: 'sei1jqgph9jpdtvv64e3rzegxtssvgmh7lxnn8vmdq', + evmAddress: '0x28b2B0621f76A2D08A9e04acb7F445E61ba5b7E7' + }, + "test3": { + seiAddress: 'sei1qkawqt7dw09rkvn53lm2deamtfcpuq9v0h6zur', + evmAddress: '0xCb2FB25A6a34Ca874171Ac0406d05A49BC45a1cF' + } + } + + const addresses = { + seiAddress: 'sei1nzdg7e6rvkrmvp5zzmp5tupuj0088nqsa4mze4', + evmAddress: '0x90684e7F229f2d8E2336661f79caB693E4228Ff7' + } + + function truncate(num, byThisManyDecimals) { + return parseFloat(`${num}`.slice(0, 12)) + } + + async function verifyAssociation(seiAddr, evmAddr, associateFunc) { + const beforeSei = BigInt(await getSeiBalance(seiAddr)) + const beforeEvm = await ethers.provider.getBalance(evmAddr) + const gas = await associateFunc(seiAddr) + const afterSei = BigInt(await getSeiBalance(seiAddr)) + const afterEvm = await ethers.provider.getBalance(evmAddr) + + // console.log(`SEI Balance (before): ${beforeSei}`) + // console.log(`EVM Balance (before): ${beforeEvm}`) + // console.log(`SEI Balance (after): ${afterSei}`) + // console.log(`EVM Balance (after): ${afterEvm}`) + + const multiplier = BigInt(1000000000000) + expect(afterEvm).to.equal((beforeSei * multiplier) + beforeEvm - (gas * multiplier)) + expect(afterSei).to.equal(truncate(beforeSei - gas)) + } + + before(async function(){ + await importKey("test1", "../contracts/test/test1.key") + await importKey("test2", "../contracts/test/test2.key") + await importKey("test3", "../contracts/test/test3.key") + }) + + it("should associate with sei transaction", async function(){ + const addr = keys.test1 + await fundSeiAddress(addr.seiAddress, "10000000000") + await fundAddress(addr.evmAddress, "200"); + + await verifyAssociation(addr.seiAddress, addr.evmAddress, async function(){ + await bankSend(addr.seiAddress, "test1") + return BigInt(20000) + }) + }); + + it("should associate with evm transaction", async function(){ + const addr = keys.test2 + await fundSeiAddress(addr.seiAddress, "10000000000") + await fundAddress(addr.evmAddress, "200"); + + await verifyAssociation(addr.seiAddress, addr.evmAddress, async function(){ + const txHash = await evmSend(addr.evmAddress, "test2", "0") + const receipt = await waitForReceipt(txHash) + return BigInt(receipt.gasUsed * (receipt.gasPrice / BigInt(1000000000000))) + }) + }); + + it("should associate with associate transaction", async function(){ + const addr = keys.test3 + await fundSeiAddress(addr.seiAddress, "10000000000") + await fundAddress(addr.evmAddress, "200"); + + await verifyAssociation(addr.seiAddress, addr.evmAddress, async function(){ + await associateKey("test3") + return BigInt(0) + }) + }); + +}) \ No newline at end of file diff --git a/contracts/test/CW20toERC20PointerTest.js b/contracts/test/CW20toERC20PointerTest.js index 6ea2bed7e..19dac07a2 100644 --- a/contracts/test/CW20toERC20PointerTest.js +++ b/contracts/test/CW20toERC20PointerTest.js @@ -1,10 +1,8 @@ -const {fundAddress, storeWasm, instantiateWasm, getSeiAddress, getAdmin, queryWasm, executeWasm, deployEvmContract, setupSigners, - getEvmAddress +const {getAdmin, queryWasm, executeWasm, associateWasm, deployEvmContract, setupSigners, deployErc20PointerForCw20, deployWasm, WASM, + registerPointerForCw20 } = require("./lib") const { expect } = require("chai"); -const {getAdminAddress} = require("@openzeppelin/upgrades-core"); -const CW20_POINTER_WASM = "../example/cosmwasm/cw20/artifacts/cwerc20.wasm"; describe("CW20 to ERC20 Pointer", function () { let accounts; let testToken; @@ -29,8 +27,7 @@ describe("CW20 to ERC20 Pointer", function () { admin = await getAdmin() await setBalance(admin.evmAddress, 1000000000000) - const codeId = await storeWasm(CW20_POINTER_WASM) - cw20Pointer = await instantiateWasm(codeId, accounts[0].seiAddress, "cw20-erc20", {erc20_address: tokenAddr }) + cw20Pointer = await registerPointerForCw20(tokenAddr) }) async function assertUnsupported(addr, operation, args) { @@ -43,6 +40,17 @@ describe("CW20 to ERC20 Pointer", function () { } } + describe("validation", function(){ + it("should not allow a pointer to the pointer", async function(){ + try { + await deployErc20PointerForCw20(hre.ethers.provider, cw20Pointer, 5) + expect.fail(`Expected to be prevented from creating a pointer`); + } catch(e){ + expect(e.message).to.include("contract deployment failed"); + } + }) + }) + describe("query", function(){ it("should return token_info", async function(){ const result = await queryWasm(cw20Pointer, "token_info", {}) @@ -81,10 +89,32 @@ describe("CW20 to ERC20 Pointer", function () { expect(balanceAfter).to.equal((parseInt(balanceBefore) + 100).toString()) }); - //TODO: other execute methods + it("transfer to unassociated address should fail", async function() { + const unassociatedSeiAddr = "sei1z7qugn2xy4ww0c9nsccftxw592n4xhxccmcf4q"; + const respBefore = await queryWasm(cw20Pointer, "balance", {address: accounts[1].seiAddress}) + const balanceBefore = respBefore.data.balance; + + await executeWasm(cw20Pointer, { transfer: { recipient: unassociatedSeiAddr, amount: "100" } }); + const respAfter = await queryWasm(cw20Pointer, "balance", {address: accounts[1].seiAddress}) + const balanceAfter = respAfter.data.balance; + + expect(balanceAfter).to.equal((parseInt(balanceBefore)).toString()) + }); + + it("transfer to contract address should succeed", async function() { + await associateWasm(cw20Pointer); + const respBefore = await queryWasm(cw20Pointer, "balance", {address: admin.seiAddress}) + const balanceBefore = respBefore.data.balance; + + await executeWasm(cw20Pointer, { transfer: { recipient: cw20Pointer, amount: "100" } }); + const respAfter = await queryWasm(cw20Pointer, "balance", {address: admin.seiAddress}) + const balanceAfter = respAfter.data.balance; + + expect(balanceAfter).to.equal((parseInt(balanceBefore) - 100).toString()) + }) it("should increase and decrease allowance for a spender", async function() { - const spender = accounts[1].seiAddress + const spender = accounts[0].seiAddress await executeWasm(cw20Pointer, { increase_allowance: { spender: spender, amount: "300" } }); let allowance = await queryWasm(cw20Pointer, "allowance", { owner: admin.seiAddress, spender: spender }); @@ -96,7 +126,15 @@ describe("CW20 to ERC20 Pointer", function () { expect(allowance.data.allowance).to.equal("0"); }); + it("should transfer token using transferFrom", async function() { + const resp = await testToken.approve(admin.evmAddress, 100); + await resp.wait(); + const respBefore = await queryWasm(cw20Pointer, "balance", {address: accounts[0].seiAddress}); + const balanceBefore = respBefore.data.balance; + await executeWasm(cw20Pointer, { transfer_from: { owner: accounts[0].seiAddress, recipient: accounts[1].seiAddress, amount: "100" } }); + const respAfter = await queryWasm(cw20Pointer, "balance", {address: accounts[0].seiAddress}); + const balanceAfter = respAfter.data.balance; + expect(balanceAfter).to.equal((parseInt(balanceBefore) - 100).toString()) + }); }) - - -}) \ No newline at end of file +}) diff --git a/contracts/test/CW721ERC721PointerTest.t.sol b/contracts/test/CW721ERC721PointerTest.t.sol index 9c4602e7c..59baad9f8 100644 --- a/contracts/test/CW721ERC721PointerTest.t.sol +++ b/contracts/test/CW721ERC721PointerTest.t.sol @@ -106,18 +106,42 @@ contract CW721ERC721PointerTest is Test { function testBalanceOf() public { vm.mockCall( WASMD_PRECOMPILE_ADDRESS, - abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}}")), + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"limit\":1000,\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}}")), abi.encode("{\"tokens\":[\"a\",\"b\"]}") ); - bytes[] memory response = new bytes[](2); - response[0] = bytes("a"); - response[1] = bytes("b"); + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"limit\":1000,\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\",\"start_after\":\"b\"}}")), + abi.encode("{\"tokens\":[\"c\",\"d\"]}") + ); + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"limit\":1000,\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\",\"start_after\":\"d\"}}")), + abi.encode("{\"tokens\":[]}") + ); + bytes[] memory resp1 = new bytes[](2); + bytes[] memory resp2 = new bytes[](2); + bytes[] memory resp3 = new bytes[](0); + resp1[0] = bytes("\"a\""); + resp1[1] = bytes("\"b\""); + resp2[0] = bytes("\"c\""); + resp2[1] = bytes("\"d\""); vm.mockCall( JSON_PRECOMPILE_ADDRESS, abi.encodeWithSignature("extractAsBytesList(bytes,string)", bytes("{\"tokens\":[\"a\",\"b\"]}"), "tokens"), - abi.encode(response) + abi.encode(resp1) ); - assertEq(pointer.balanceOf(MockCallerEVMAddr), 2); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytesList(bytes,string)", bytes("{\"tokens\":[\"c\",\"d\"]}"), "tokens"), + abi.encode(resp2) + ); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytesList(bytes,string)", bytes("{\"tokens\":[]}"), "tokens"), + abi.encode(resp3) + ); + assertEq(pointer.balanceOf(MockCallerEVMAddr), 4); } function testOwnerOf() public { @@ -134,6 +158,20 @@ contract CW721ERC721PointerTest is Test { assertEq(pointer.ownerOf(1), 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); } + function testTotalSupply() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"num_tokens\":{}}")), + abi.encode("{\"count\":100}") + ); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsUint256(bytes,string)", bytes("{\"count\":100}"), "count"), + abi.encode(100) + ); + assertEq(pointer.totalSupply(), 100); + } + function testGetApproved() public { vm.mockCall( WASMD_PRECOMPILE_ADDRESS, diff --git a/contracts/test/CW721toERC721PointerTest.js b/contracts/test/CW721toERC721PointerTest.js index 492b861d3..98a27e5c3 100644 --- a/contracts/test/CW721toERC721PointerTest.js +++ b/contracts/test/CW721toERC721PointerTest.js @@ -1,8 +1,8 @@ -const {setupSigners, deployEvmContract, getAdmin, deployWasm, executeWasm, queryWasm} = require("./lib"); +const {setupSigners, deployEvmContract, getAdmin, deployWasm, executeWasm, queryWasm, deployErc20PointerForCw20, + deployErc721PointerForCw721, WASM, registerPointerForCw721 +} = require("./lib"); const {expect} = require("chai"); -const CW721_POINTER_WASM = "../example/cosmwasm/cw721/artifacts/cwerc721.wasm"; - describe("CW721 to ERC721 Pointer", function () { let accounts; let erc721; @@ -13,11 +13,8 @@ describe("CW721 to ERC721 Pointer", function () { accounts = await setupSigners(await hre.ethers.getSigners()) erc721 = await deployEvmContract("MyNFT") admin = await getAdmin() - pointer = await deployWasm(CW721_POINTER_WASM, - accounts[0].seiAddress, - "cw721-erc721", - {erc721_address: await erc721.getAddress() } - ) + + pointer = await registerPointerForCw721(await erc721.getAddress()) await (await erc721.mint(accounts[0].evmAddress, 1)).wait() await (await erc721.mint(accounts[1].evmAddress, 2)).wait() @@ -27,8 +24,18 @@ describe("CW721 to ERC721 Pointer", function () { await (await erc721.setApprovalForAll(admin.evmAddress, true)).wait(); }) - describe("query", function(){ + describe("validation", function(){ + it("should not allow a pointer to the pointer", async function(){ + try { + await deployErc721PointerForCw721(hre.ethers.provider, pointer, 5) + expect.fail(`Expected to be prevented from creating a pointer`); + } catch(e){ + expect(e.message).to.include("contract deployment failed"); + } + }) + }) + describe("query", function(){ it("should query the owner of a token", async function () { const result = await queryWasm(pointer, "owner_of", { token_id: "1" }); expect(result).to.deep.equal({data:{ @@ -66,39 +73,48 @@ describe("CW721 to ERC721 Pointer", function () { }); }); + it("should retrieve number of circulating tokens", async function () { + const result = await queryWasm(pointer, "num_tokens", {}); + expect(result).to.deep.equal({data:{count:3}}); + }); + it("should retrieve contract information", async function () { const result = await queryWasm(pointer, "contract_info", {}); expect(result).to.deep.equal({data:{name:"MyNFT",symbol:"MYNFT"}}); }); - it("should fetch NFT info based on token ID", async function () { - const result = await queryWasm(pointer, "nft_info", { token_id: "1" }); - expect(result).to.deep.equal({ data: { token_uri: 'https://sei.io/token/1', extension: '' } }); - }); - it("should fetch all information about an NFT", async function () { const result = await queryWasm(pointer, "all_nft_info", { token_id: "1" }); - expect(result).to.deep.equal({ - data: { - access: { - owner: accounts[0].seiAddress, - approvals: [ - { - spender: accounts[1].seiAddress, - expires: { - never: {} - } - } - ] - }, - info: { - token_uri: "https://sei.io/token/1", - extension: "" + expect(result.data.access).to.deep.equal({ + owner: accounts[0].seiAddress, + approvals: [ + { + spender: accounts[1].seiAddress, + expires: { + never: {} + } } - } + ] }); + expect(result.data.info.token_uri).to.equal('https://sei.io/token/1'); + expect(result.data.info.extension.royalty_percentage).to.equal(5); + expect(result.data.info.extension.royalty_payment_address).to.include("sei1"); }); + it("should retrieve all minted NFT token ids", async function () { + const result = await queryWasm(pointer, "all_tokens", {}); + expect(result).to.deep.equal({data:{tokens:["1","2","3"]}}); + }); + + it("should retrieve list of 1 minted NFT token id after token id 1", async function () { + const result = await queryWasm(pointer, "all_tokens", { start_after: "1", limit: 1 }); + expect(result).to.deep.equal({data:{tokens:["2"]}}); + }); + + it("should retrieve list of NFT token ids owned by admin", async function () { + const result = await queryWasm(pointer, "tokens", { owner: admin.seiAddress }); + expect(result).to.deep.equal({data:{tokens:["3"]}}); + }); }) describe("execute operations", function () { diff --git a/contracts/test/ERC20toCW20PointerTest-backup.js b/contracts/test/ERC20toCW20PointerTest-backup.js new file mode 100644 index 000000000..1617cf148 --- /dev/null +++ b/contracts/test/ERC20toCW20PointerTest-backup.js @@ -0,0 +1,241 @@ +const {setupSigners, deployErc20PointerForCw20, getAdmin, deployWasm, WASM, ABI, registerPointerForCw20, + testAPIEnabled, + incrementPointerVersion +} = require("./lib"); +const {expect} = require("chai"); + +describe("ERC20 to CW20 Pointer", function () { + let accounts; + let pointer; + let cw20Address; + let admin; + + before(async function () { + accounts = await setupSigners(await hre.ethers.getSigners()) + admin = await getAdmin() + + cw20Address = await deployWasm(WASM.CW20, accounts[0].seiAddress, "cw20", { + name: "Test", + symbol: "TEST", + decimals: 6, + initial_balances: [ + { address: admin.seiAddress, amount: "1000000" }, + { address: accounts[0].seiAddress, amount: "2000000"}, + { address: accounts[1].seiAddress, amount: "3000000"} + ], + mint: { + "minter": admin.seiAddress, "cap": "99900000000" + } + }) + + // deploy TestToken + const pointerAddr = await deployErc20PointerForCw20(hre.ethers.provider, cw20Address) + const contract = new hre.ethers.Contract(pointerAddr, ABI.ERC20, hre.ethers.provider); + pointer = contract.connect(accounts[0].signer) + }) + + describe("validation", function(){ + it("should not allow a pointer to the pointer", async function(){ + try { + await registerPointerForCw20(await pointer.getAddress()) + expect.fail(`Expected to be prevented from creating a pointer`); + } catch(e){ + expect(e.message).to.include("contract deployment failed"); + } + }) + }) + + describe("read", function(){ + it("get name", async function () { + const name = await pointer.name(); + expect(name).to.equal("Test"); + }); + + it("get symbol", async function () { + const symbol = await pointer.symbol(); + expect(symbol).to.equal("TEST"); + }); + + it("get decimals", async function () { + const decimals = await pointer.decimals(); + expect(Number(decimals)).to.equal(6); + }); + + it("get balanceOf", async function () { + expect(await pointer.balanceOf(admin.evmAddress)).to.equal(1000000) + expect(await pointer.balanceOf(accounts[0].evmAddress)).to.equal(2000000); + expect(await pointer.balanceOf(accounts[1].evmAddress)).to.equal(3000000); + }); + + it("get totalSupply", async function () { + expect(await pointer.totalSupply()).to.equal(6000000); + }); + + it("get allowance", async function () { + expect(await pointer.allowance(accounts[0].evmAddress, accounts[1].evmAddress)).to.equal(0); + }); + }) + + describe("transfer()", function () { + it("should transfer", async function () { + let sender = accounts[0]; + let recipient = accounts[1]; + + expect(await pointer.balanceOf(sender.evmAddress)).to.equal(2000000); + expect(await pointer.balanceOf(recipient.evmAddress)).to.equal(3000000); + + const tx = await pointer.transfer(recipient.evmAddress, 1); + await tx.wait(); + + expect(await pointer.balanceOf(sender.evmAddress)).to.equal(1999999); + expect(await pointer.balanceOf(recipient.evmAddress)).to.equal(3000001); + + const cleanupTx = await pointer.connect(recipient.signer).transfer(sender.evmAddress, 1) + await cleanupTx.wait(); + }); + + it("should fail transfer() if sender has insufficient balance", async function () { + const recipient = accounts[1]; + await expect(pointer.transfer(recipient.evmAddress, 20000000)).to.be.revertedWith("CosmWasm execute failed"); + }); + + it("transfer to unassociated address should fail", async function() { + const unassociatedRecipient = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; + await expect(pointer.transfer(unassociatedRecipient, 1)).to.be.revertedWithoutReason; + }); + + it("transfer to contract address should succeed", async function() { + const contract = await pointer.getAddress(); + const tx = await pointer.transfer(contract, 1); + await tx.wait(); + }); + }); + + describe("approve()", function () { + it("should approve", async function () { + const owner = accounts[0].evmAddress; + const spender = accounts[1].evmAddress; + const tx = await pointer.approve(spender, 1000000); + await tx.wait(); + const allowance = await pointer.allowance(owner, spender); + expect(Number(allowance)).to.equal(1000000); + }); + + it("should lower approval", async function () { + const owner = accounts[0].evmAddress; + const spender = accounts[1].evmAddress; + const tx = await pointer.approve(spender, 0); + await tx.wait(); + const allowance = await pointer.allowance(owner, spender); + expect(Number(allowance)).to.equal(0); + }); + }); + + + describe("transferFrom()", function () { + it("should transferFrom", async function () { + const recipient = admin; + const owner = accounts[0]; + const spender = accounts[1]; + const amountToTransfer = 10; + + // capture balances before + const recipientBalanceBefore = await pointer.balanceOf(recipient.evmAddress); + const ownerBalanceBefore = await pointer.balanceOf(owner.evmAddress); + expect(Number(ownerBalanceBefore)).to.be.greaterThanOrEqual(amountToTransfer); + + // approve the amount + const tx = await pointer.approve(spender.evmAddress, amountToTransfer); + await tx.wait(); + const allowanceBefore = await pointer.allowance(owner.evmAddress, spender.evmAddress); + expect(Number(allowanceBefore)).to.be.greaterThanOrEqual(amountToTransfer); + + // transfer + const tfTx = await pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, amountToTransfer); + const receipt = await tfTx.wait(); + + // capture balances after + const recipientBalanceAfter = await pointer.balanceOf(recipient.evmAddress); + const ownerBalanceAfter = await pointer.balanceOf(owner.evmAddress); + + // check balance diff to ensure transfer went through + const diff = recipientBalanceAfter - recipientBalanceBefore; + expect(diff).to.equal(amountToTransfer); + + // check balanceOf sender (deployerAddr) to ensure it went down + const diff2 = ownerBalanceBefore - ownerBalanceAfter; + expect(diff2).to.equal(amountToTransfer); + + // check that allowance has gone down by amountToTransfer + const allowanceAfter = await pointer.allowance(owner.evmAddress, spender.evmAddress); + expect(Number(allowanceBefore) - Number(allowanceAfter)).to.equal(amountToTransfer); + }); + + it("should fail transferFrom() if sender has insufficient balance", async function () { + const recipient = admin; + const owner = accounts[0]; + const spender = accounts[1]; + + const tx = await pointer.approve(spender.evmAddress, 999999999); + await tx.wait(); + + await expect(pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, 999999999)).to.be.revertedWith("CosmWasm execute failed"); + }); + + it("should fail transferFrom() if allowance is too low", async function () { + const recipient = admin; + const owner = accounts[0]; + const spender = accounts[1]; + + const tx = await pointer.approve(spender.evmAddress, 10); + await tx.wait(); + + await expect(pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, 20)).to.be.revertedWith("CosmWasm execute failed"); + + await (await pointer.approve(spender.evmAddress, 0)).wait() + }); + }); + + describe("upgrade behavior", function () { + + before(async function(){ + const enabled = await testAPIEnabled(ethers.provider) + if(!enabled) { + this.skip() + } + }) + + it("upgrade without version update not allowed", async function () { + try { + await deployErc20PointerForCw20(hre.ethers.provider, cw20Address) + expect.fail("Expected to be prevented from creating a pointer"); + } catch (e) { + expect(e.message).to.equal("contract deployment failed"); + } + }) + + describe("with upgrade", function(){ + let newPointer; + + before(async function(){ + await incrementPointerVersion(ethers.provider, "cw20", 1) + + // deploy a new pointer, now that the version has been incremented + const pointerAddr = await deployErc20PointerForCw20(ethers.provider, cw20Address) + const contract = new hre.ethers.Contract(pointerAddr, ABI.ERC20, hre.ethers.provider); + newPointer = contract.connect(accounts[0].signer) + }) + + it ("should have the correct balance", async function(){ + expect(await pointer.balanceOf(admin.evmAddress)).to.equal(1000010) + expect(await pointer.balanceOf(accounts[0].evmAddress)).to.equal(1999989); + expect(await pointer.balanceOf(accounts[1].evmAddress)).to.equal(3000000); + expect(await newPointer.balanceOf(admin.evmAddress)).to.equal(1000010) + expect(await newPointer.balanceOf(accounts[0].evmAddress)).to.equal(1999989); + expect(await newPointer.balanceOf(accounts[1].evmAddress)).to.equal(3000000); + }) + + }) + + }) +}) \ No newline at end of file diff --git a/contracts/test/ERC20toCW20PointerTest.js b/contracts/test/ERC20toCW20PointerTest.js index b750ce998..d54f5507f 100644 --- a/contracts/test/ERC20toCW20PointerTest.js +++ b/contracts/test/ERC20toCW20PointerTest.js @@ -1,187 +1,267 @@ -const {setupSigners, deployErc20PointerForCw20, getAdmin, storeWasm, instantiateWasm} = require("./lib"); -const {expect} = require("chai"); - -const CW20_BASE_WASM_LOCATION = "../contracts/wasm/cw20_base.wasm"; - -const erc20Abi = [ - "function name() view returns (string)", - "function symbol() view returns (string)", - "function decimals() view returns (uint8)", - "function totalSupply() view returns (uint256)", - "function balanceOf(address owner) view returns (uint256 balance)", - "function transfer(address to, uint amount) returns (bool)", - "function allowance(address owner, address spender) view returns (uint256)", - "function approve(address spender, uint256 value) returns (bool)", - "function transferFrom(address from, address to, uint value) returns (bool)" -]; - +const { + setupSigners, deployErc20PointerForCw20, getAdmin, deployWasm, WASM, ABI, registerPointerForCw20, testAPIEnabled, + incrementPointerVersion +} = require("./lib"); +const { expect } = require("chai"); describe("ERC20 to CW20 Pointer", function () { let accounts; - let pointer; - let cw20Address; let admin; + let cw20Address; before(async function () { - accounts = await setupSigners(await hre.ethers.getSigners()) - admin = await getAdmin() + accounts = await setupSigners(await hre.ethers.getSigners()); + admin = await getAdmin(); - const codeId = await storeWasm(CW20_BASE_WASM_LOCATION) - cw20Address = await instantiateWasm(codeId, accounts[0].seiAddress, "cw20", { + cw20Address = await deployWasm(WASM.CW20, accounts[0].seiAddress, "cw20", { name: "Test", symbol: "TEST", decimals: 6, initial_balances: [ { address: admin.seiAddress, amount: "1000000" }, - { address: accounts[0].seiAddress, amount: "2000000"}, - { address: accounts[1].seiAddress, amount: "3000000"} + { address: accounts[0].seiAddress, amount: "2000000" }, + { address: accounts[1].seiAddress, amount: "3000000" } ], mint: { "minter": admin.seiAddress, "cap": "99900000000" } - }) - - // deploy TestToken - const pointerAddr = await deployErc20PointerForCw20(hre.ethers.provider, cw20Address) - const contract = new hre.ethers.Contract(pointerAddr, erc20Abi, hre.ethers.provider); - pointer = contract.connect(accounts[0].signer) - }) - - describe("read", function(){ - it("get name", async function () { - const name = await pointer.name(); - expect(name).to.equal("Test"); }); + }); - it("get symbol", async function () { - const symbol = await pointer.symbol(); - expect(symbol).to.equal("TEST"); + async function setupPointer() { + const pointerAddr = await deployErc20PointerForCw20(hre.ethers.provider, cw20Address); + const contract = new hre.ethers.Contract(pointerAddr, ABI.ERC20, hre.ethers.provider); + return contract.connect(accounts[0].signer); + } + + function testPointer(getPointer, balances) { + describe("pointer functions", function () { + let pointer; + + beforeEach(async function () { + pointer = await getPointer(); + }); + + describe("validation", function () { + it("should not allow a pointer to the pointer", async function () { + try { + await registerPointerForCw20(await pointer.getAddress()); + expect.fail(`Expected to be prevented from creating a pointer`); + } catch (e) { + expect(e.message).to.include("contract deployment failed"); + } + }); + }); + + describe("read", function () { + it("get name", async function () { + const name = await pointer.name(); + expect(name).to.equal("Test"); + }); + + it("get symbol", async function () { + const symbol = await pointer.symbol(); + expect(symbol).to.equal("TEST"); + }); + + it("get decimals", async function () { + const decimals = await pointer.decimals(); + expect(Number(decimals)).to.equal(6); + }); + + it("get balanceOf", async function () { + expect(await pointer.balanceOf(admin.evmAddress)).to.equal(balances.admin); + expect(await pointer.balanceOf(accounts[0].evmAddress)).to.equal(balances.account0); + expect(await pointer.balanceOf(accounts[1].evmAddress)).to.equal(balances.account1); + }); + + it("get totalSupply", async function () { + expect(await pointer.totalSupply()).to.equal(6000000); + }); + + it("get allowance", async function () { + expect(await pointer.allowance(accounts[0].evmAddress, accounts[1].evmAddress)).to.equal(0); + }); + }); + + describe("transfer()", function () { + it("should transfer", async function () { + let sender = accounts[0]; + let recipient = accounts[1]; + + expect(await pointer.balanceOf(sender.evmAddress)).to.equal(balances.account0); + expect(await pointer.balanceOf(recipient.evmAddress)).to.equal(balances.account1); + + const tx = await pointer.transfer(recipient.evmAddress, 1); + await tx.wait(); + + expect(await pointer.balanceOf(sender.evmAddress)).to.equal(balances.account0-1); + expect(await pointer.balanceOf(recipient.evmAddress)).to.equal(balances.account1+1); + + const cleanupTx = await pointer.connect(recipient.signer).transfer(sender.evmAddress, 1); + await cleanupTx.wait(); + }); + + it("should fail transfer() if sender has insufficient balance", async function () { + const recipient = accounts[1]; + await expect(pointer.transfer(recipient.evmAddress, balances.account0*10)).to.be.revertedWith("CosmWasm execute failed"); + }); + + it("transfer to unassociated address should fail", async function () { + const unassociatedRecipient = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; + await expect(pointer.transfer(unassociatedRecipient, 1)).to.be.revertedWithoutReason; + }); + + it("transfer to contract address should succeed", async function () { + const contract = await pointer.getAddress(); + const tx = await pointer.transfer(contract, 1); + await tx.wait(); + }); + }); + + describe("approve()", function () { + it("should approve", async function () { + const owner = accounts[0].evmAddress; + const spender = accounts[1].evmAddress; + const tx = await pointer.approve(spender, 1000000); + await tx.wait(); + const allowance = await pointer.allowance(owner, spender); + expect(Number(allowance)).to.equal(1000000); + }); + + it("should lower approval", async function () { + const owner = accounts[0].evmAddress; + const spender = accounts[1].evmAddress; + const tx = await pointer.approve(spender, 0); + await tx.wait(); + const allowance = await pointer.allowance(owner, spender); + expect(Number(allowance)).to.equal(0); + }); + }); + + describe("transferFrom()", function () { + it("should transferFrom", async function () { + const recipient = admin; + const owner = accounts[0]; + const spender = accounts[1]; + const amountToTransfer = 10; + + // capture balances before + const recipientBalanceBefore = await pointer.balanceOf(recipient.evmAddress); + const ownerBalanceBefore = await pointer.balanceOf(owner.evmAddress); + expect(Number(ownerBalanceBefore)).to.be.greaterThanOrEqual(amountToTransfer); + + // approve the amount + const tx = await pointer.approve(spender.evmAddress, amountToTransfer); + await tx.wait(); + const allowanceBefore = await pointer.allowance(owner.evmAddress, spender.evmAddress); + expect(Number(allowanceBefore)).to.be.greaterThanOrEqual(amountToTransfer); + + // transfer + const tfTx = await pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, amountToTransfer); + const receipt = await tfTx.wait(); + + // capture balances after + const recipientBalanceAfter = await pointer.balanceOf(recipient.evmAddress); + const ownerBalanceAfter = await pointer.balanceOf(owner.evmAddress); + + // check balance diff to ensure transfer went through + const diff = recipientBalanceAfter - recipientBalanceBefore; + expect(diff).to.equal(amountToTransfer); + + // check balanceOf sender (deployerAddr) to ensure it went down + const diff2 = ownerBalanceBefore - ownerBalanceAfter; + expect(diff2).to.equal(amountToTransfer); + + // check that allowance has gone down by amountToTransfer + const allowanceAfter = await pointer.allowance(owner.evmAddress, spender.evmAddress); + expect(Number(allowanceBefore) - Number(allowanceAfter)).to.equal(amountToTransfer); + }); + + it("should fail transferFrom() if sender has insufficient balance", async function () { + const recipient = admin; + const owner = accounts[0]; + const spender = accounts[1]; + + const tx = await pointer.approve(spender.evmAddress, 999999999); + await tx.wait(); + + await expect(pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, 999999999)).to.be.revertedWith("CosmWasm execute failed"); + }); + + it("should fail transferFrom() if allowance is too low", async function () { + const recipient = admin; + const owner = accounts[0]; + const spender = accounts[1]; + + const tx = await pointer.approve(spender.evmAddress, 10); + await tx.wait(); + + await expect(pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, 20)).to.be.revertedWith("CosmWasm execute failed"); + // put it back + await (await pointer.approve(spender.evmAddress, 0)).wait() + }); + }); }); + } - it("get decimals", async function () { - const decimals = await pointer.decimals(); - expect(Number(decimals)).to.equal(6); - }); + describe("Pointer Functionality", function () { + let pointer; - it("get balanceOf", async function () { - expect(await pointer.balanceOf(admin.evmAddress)).to.equal(1000000) - expect(await pointer.balanceOf(accounts[0].evmAddress)).to.equal(2000000); - expect(await pointer.balanceOf(accounts[1].evmAddress)).to.equal(3000000); + before(async function () { + pointer = await setupPointer(); }); - it("get totalSupply", async function () { - expect(await pointer.totalSupply()).to.equal(6000000); + // verify pointer + testPointer(() => pointer, { + admin: 1000000, + account0: 2000000, + account1: 3000000 }); - it("get allowance", async function () { - expect(await pointer.allowance(accounts[0].evmAddress, accounts[1].evmAddress)).to.equal(0); - }); - }) + describe("Pointer Upgrade", function () { + let newPointer; - describe("transfer()", function () { - it("should transfer", async function () { - let sender = accounts[0]; - let recipient = accounts[1]; + before(async function () { + const enabled = await testAPIEnabled(ethers.provider); + if (!enabled) { + this.skip(); + } - expect(await pointer.balanceOf(sender.evmAddress)).to.equal(2000000); - expect(await pointer.balanceOf(recipient.evmAddress)).to.equal(3000000); + await incrementPointerVersion(ethers.provider, "cw20", 1); - const tx = await pointer.transfer(recipient.evmAddress, 1); - await tx.wait(); + const pointerAddr = await deployErc20PointerForCw20(hre.ethers.provider, cw20Address); + const contract = new hre.ethers.Contract(pointerAddr, ABI.ERC20, hre.ethers.provider); + newPointer = contract.connect(accounts[0].signer); + }); - expect(await pointer.balanceOf(sender.evmAddress)).to.equal(1999999); - expect(await pointer.balanceOf(recipient.evmAddress)).to.equal(3000001); + // verify new pointer + testPointer(() => newPointer, { + admin: 1000010, + account0: 1999989, + account1: 3000000 + }); - const cleanupTx = await pointer.connect(recipient.signer).transfer(sender.evmAddress, 1) - await cleanupTx.wait(); }); - it("should fail transfer() if sender has insufficient balance", async function () { - let recipient = accounts[1]; - await expect(pointer.transfer(recipient.evmAddress, 20000000)).to.be.revertedWith("CosmWasm execute failed"); - }); + // this does not yet pass, so skip + describe.skip("Original Pointer after Upgrade", function(){ + + before(async function () { + const enabled = await testAPIEnabled(ethers.provider); + if (!enabled) { + this.skip(); + } + }); + + // original pointer + testPointer(() => pointer, { + admin: 1000020, + account0: 1999978, + account1: 3000000 + }); + }) }); - describe("approve()", function () { - it("should approve", async function () { - const owner = accounts[0].evmAddress; - const spender = accounts[1].evmAddress; - const tx = await pointer.approve(spender, 1000000); - await tx.wait(); - const allowance = await pointer.allowance(owner, spender); - expect(Number(allowance)).to.equal(1000000); - }); - - it("should lower approval", async function () { - const owner = accounts[0].evmAddress; - const spender = accounts[1].evmAddress; - const tx = await pointer.approve(spender, 0); - await tx.wait(); - const allowance = await pointer.allowance(owner, spender); - expect(Number(allowance)).to.equal(0); - }); }); - - describe("transferFrom()", function () { - it("should transferFrom", async function () { - const recipient = admin; - const owner = accounts[0]; - const spender = accounts[1]; - const amountToTransfer = 10; - - // capture balances before - const recipientBalanceBefore = await pointer.balanceOf(recipient.evmAddress); - const ownerBalanceBefore = await pointer.balanceOf(owner.evmAddress); - expect(Number(ownerBalanceBefore)).to.be.greaterThanOrEqual(amountToTransfer); - - // approve the amount - const tx = await pointer.approve(spender.evmAddress, amountToTransfer); - await tx.wait(); - const allowanceBefore = await pointer.allowance(owner.evmAddress, spender.evmAddress); - expect(Number(allowanceBefore)).to.be.greaterThanOrEqual(amountToTransfer); - - // transfer - const tfTx = await pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, amountToTransfer); - const receipt = await tfTx.wait(); - - // capture balances after - const recipientBalanceAfter = await pointer.balanceOf(recipient.evmAddress); - const ownerBalanceAfter = await pointer.balanceOf(owner.evmAddress); - - // check balance diff to ensure transfer went through - const diff = recipientBalanceAfter - recipientBalanceBefore; - expect(diff).to.equal(amountToTransfer); - - // check balanceOf sender (deployerAddr) to ensure it went down - const diff2 = ownerBalanceBefore - ownerBalanceAfter; - expect(diff2).to.equal(amountToTransfer); - - // check that allowance has gone down by amountToTransfer - const allowanceAfter = await pointer.allowance(owner.evmAddress, spender.evmAddress); - expect(Number(allowanceBefore) - Number(allowanceAfter)).to.equal(amountToTransfer); - }); - - it("should fail transferFrom() if sender has insufficient balance", async function () { - const recipient = admin; - const owner = accounts[0]; - const spender = accounts[1]; - - const tx = await pointer.approve(spender.evmAddress, 999999999); - await tx.wait(); - - await expect(pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, 999999999)).to.be.revertedWith("CosmWasm execute failed"); - }); - - it("should fail transferFrom() if allowance is too low", async function () { - const recipient = admin; - const owner = accounts[0]; - const spender = accounts[1]; - - const tx = await pointer.approve(spender.evmAddress, 10); - await tx.wait(); - - await expect(pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, 20)).to.be.revertedWith("CosmWasm execute failed"); - }); - }); -}) \ No newline at end of file diff --git a/contracts/test/ERC20toNativePointerTest.js b/contracts/test/ERC20toNativePointerTest.js new file mode 100644 index 000000000..5fa2fa4bb --- /dev/null +++ b/contracts/test/ERC20toNativePointerTest.js @@ -0,0 +1,163 @@ +const {setupSigners, deployErc20PointerNative, getAdmin, createTokenFactoryTokenAndMint, ABI} = require("./lib"); +const {expect} = require("chai"); + +const { expectRevert } = require('@openzeppelin/test-helpers'); +require("@nomicfoundation/hardhat-chai-matchers"); + +describe("ERC20 to Native Pointer", function () { + let accounts; + let pointer; + let admin; + let denom; + + before(async function () { + accounts = await setupSigners(await hre.ethers.getSigners()) + admin = await getAdmin() + const random_num = Math.floor(Math.random() * 10000) + denom = await createTokenFactoryTokenAndMint(`native-pointer-test-${random_num}`, 1000, accounts[0].seiAddress) + + // deploy TestToken + const pointerAddr = await deployErc20PointerNative(hre.ethers.provider, denom) + const contract = new hre.ethers.Contract(pointerAddr, ABI.ERC20, hre.ethers.provider); + pointer = contract.connect(accounts[0].signer) + }) + + describe("read", function(){ + it("get name", async function () { + const name = await pointer.name(); + expect(name).to.equal(denom); + }); + + it("get symbol", async function () { + const symbol = await pointer.symbol(); + expect(symbol).to.equal(denom); + }); + + it("get decimals", async function () { + const decimals = await pointer.decimals(); + expect(Number(decimals)).to.equal(0); + }); + + it("get balanceOf", async function () { + expect(await pointer.balanceOf(admin.evmAddress)).to.equal(0) + expect(await pointer.balanceOf(accounts[0].evmAddress)).to.equal(1000); + expect(await pointer.balanceOf(accounts[1].evmAddress)).to.equal(0); + }); + + it("get totalSupply", async function () { + expect(await pointer.totalSupply()).to.equal(1000); + }); + + it("get allowance", async function () { + expect(await pointer.allowance(accounts[0].evmAddress, accounts[1].evmAddress)).to.equal(0); + }); + }) + + describe("transfer()", function () { + it("should transfer", async function () { + let sender = accounts[0]; + let recipient = accounts[1]; + + expect(await pointer.balanceOf(sender.evmAddress)).to.equal(1000); + expect(await pointer.balanceOf(recipient.evmAddress)).to.equal(0); + + const tx = await pointer.transfer(recipient.evmAddress, 5); + await tx.wait(); + + expect(await pointer.balanceOf(sender.evmAddress)).to.equal(995); + expect(await pointer.balanceOf(recipient.evmAddress)).to.equal(5); + + const cleanupTx = await pointer.connect(recipient.signer).transfer(sender.evmAddress, 5) + await cleanupTx.wait(); + }); + + it("should fail transfer() if sender has insufficient balance", async function () { + let recipient = accounts[1]; + // TODO: determine why we aren't able to extract the error message + await expectRevert.unspecified(pointer.transfer(recipient.evmAddress, 1001)); + }); + }); + + describe("approve()", function () { + it("should approve", async function () { + const owner = accounts[0].evmAddress; + const spender = accounts[1].evmAddress; + const tx = await pointer.approve(spender, 50); + await tx.wait(); + const allowance = await pointer.allowance(owner, spender); + expect(Number(allowance)).to.equal(50); + }); + + it("should lower approval", async function () { + const owner = accounts[0].evmAddress; + const spender = accounts[1].evmAddress; + const tx = await pointer.approve(spender, 0); + await tx.wait(); + const allowance = await pointer.allowance(owner, spender); + expect(Number(allowance)).to.equal(0); + }); + }); + + + describe("transferFrom()", function () { + it("should transferFrom", async function () { + const recipient = admin; + const owner = accounts[0]; + const spender = accounts[1]; + const amountToTransfer = 10; + + // capture balances before + const recipientBalanceBefore = await pointer.balanceOf(recipient.evmAddress); + const ownerBalanceBefore = await pointer.balanceOf(owner.evmAddress); + expect(Number(ownerBalanceBefore)).to.be.greaterThanOrEqual(amountToTransfer); + + // approve the amount + const tx = await pointer.approve(spender.evmAddress, amountToTransfer); + await tx.wait(); + const allowanceBefore = await pointer.allowance(owner.evmAddress, spender.evmAddress); + expect(Number(allowanceBefore)).to.be.greaterThanOrEqual(amountToTransfer); + + // transfer + const tfTx = await pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, amountToTransfer); + const receipt = await tfTx.wait(); + + // capture balances after + const recipientBalanceAfter = await pointer.balanceOf(recipient.evmAddress); + const ownerBalanceAfter = await pointer.balanceOf(owner.evmAddress); + + // check balance diff to ensure transfer went through + const diff = recipientBalanceAfter - recipientBalanceBefore; + expect(diff).to.equal(amountToTransfer); + + // check balanceOf sender (deployerAddr) to ensure it went down + const diff2 = ownerBalanceBefore - ownerBalanceAfter; + expect(diff2).to.equal(amountToTransfer); + + // check that allowance has gone down by amountToTransfer + const allowanceAfter = await pointer.allowance(owner.evmAddress, spender.evmAddress); + expect(Number(allowanceBefore) - Number(allowanceAfter)).to.equal(amountToTransfer); + }); + + it("should fail transferFrom() if sender has insufficient balance", async function () { + const recipient = admin; + const owner = accounts[0]; + const spender = accounts[1]; + + const tx = await pointer.approve(spender.evmAddress, 999999999); + await tx.wait(); + // TODO: determine why we aren't able to extract the error message + await expectRevert.unspecified(pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, 999999999)); + }); + + it("should fail transferFrom() if allowance is too low", async function () { + const recipient = admin; + const owner = accounts[0]; + const spender = accounts[1]; + + const tx = await pointer.approve(spender.evmAddress, 10); + await tx.wait(); + + await expect(pointer.connect(spender.signer).transferFrom(owner.evmAddress, recipient.evmAddress, 20)).to.be.revertedWithCustomError(pointer, "ERC20InsufficientAllowance"); + }); + }); +}) \ No newline at end of file diff --git a/contracts/test/ERC721toCW721PointerTest.js b/contracts/test/ERC721toCW721PointerTest.js index 89a9f94d4..2b0e151a1 100644 --- a/contracts/test/ERC721toCW721PointerTest.js +++ b/contracts/test/ERC721toCW721PointerTest.js @@ -1,27 +1,10 @@ -const {setupSigners, deployErc721PointerForCw721, getAdmin, deployWasm, executeWasm} = require("./lib"); +const {setupSigners, deployErc721PointerForCw721, getAdmin, deployWasm, executeWasm, ABI, registerPointerForCw20, + registerPointerForCw721 +} = require("./lib"); const {expect} = require("chai"); const CW721_BASE_WASM_LOCATION = "../contracts/wasm/cw721_base.wasm"; -const erc721Abi = [ - "event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId)", - "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)", - "event ApprovalForAll(address indexed owner, address indexed operator, bool approved)", - "function name() view returns (string)", - "function symbol() view returns (string)", - "function totalSupply() view returns (uint256)", - "function tokenURI(uint256 tokenId) view returns (string)", - "function balanceOf(address owner) view returns (uint256 balance)", - "function ownerOf(uint256 tokenId) view returns (address owner)", - "function getApproved(uint256 tokenId) view returns (address operator)", - "function isApprovedForAll(address owner, address operator) view returns (bool)", - "function approve(address to, uint256 tokenId) returns (bool)", - "function setApprovalForAll(address operator, bool _approved) returns (bool)", - "function transferFrom(address from, address to, uint256 tokenId) returns (bool)", - "function safeTransferFrom(address from, address to, uint256 tokenId) returns (bool)", - "function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) returns (bool)" -]; - describe("ERC721 to CW721 Pointer", function () { let accounts; let pointerAcc0; @@ -44,11 +27,22 @@ describe("ERC721 to CW721 Pointer", function () { await executeWasm(cw721Address, { mint : { token_id : "3", owner : accounts[1].seiAddress, token_uri: "token uri 3"}}); const pointerAddr = await deployErc721PointerForCw721(hre.ethers.provider, cw721Address) - const contract = new hre.ethers.Contract(pointerAddr, erc721Abi, hre.ethers.provider); + const contract = new hre.ethers.Contract(pointerAddr, ABI.ERC721, hre.ethers.provider); pointerAcc0 = contract.connect(accounts[0].signer) pointerAcc1 = contract.connect(accounts[1].signer) }) + describe("validation", function(){ + it("should not allow a pointer to the pointer", async function(){ + try { + await registerPointerForCw721(await pointerAcc0.getAddress()) + expect.fail(`Expected to be prevented from creating a pointer`); + } catch(e){ + expect(e.message).to.include("contract deployment failed"); + } + }) + }) + describe("read", function(){ it("get name", async function () { const name = await pointerAcc0.name(); diff --git a/contracts/test/EVMCompatabilityTest.js b/contracts/test/EVMCompatabilityTest.js index f608b3ec9..335d103c5 100644 --- a/contracts/test/EVMCompatabilityTest.js +++ b/contracts/test/EVMCompatabilityTest.js @@ -3,6 +3,8 @@ const {isBigNumber} = require("hardhat/common"); const {uniq, shuffle} = require("lodash"); const { ethers, upgrades } = require('hardhat'); const { getImplementationAddress } = require('@openzeppelin/upgrades-core'); +const { deployEvmContract, setupSigners, fundAddress, getCosmosTx} = require("./lib") +const axios = require("axios"); function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); @@ -47,6 +49,15 @@ function generateWallet() { return wallet.connect(ethers.provider); } +function generateWallets(num) { + const arr = [] + for(let i=0; i 0) { + this.skip() + } else { + expect(await testToken.getAddress()).to.equal(firstContractAddress); + } }); it("Should estimate gas for a contract deployment", async function () { @@ -297,7 +315,10 @@ describe("EVM Test", function () { it("Should set the string correctly and emit an event", async function () { await delay() const txResponse = await evmTester.setStringVar("test"); - await txResponse.wait(); // Wait for the transaction to be mined + const receipt = await txResponse.wait(); // Wait for the transaction to be mined + + const cosmosTx = await getCosmosTx(ethers.provider, receipt.hash) + expect(cosmosTx.length).to.be.equal(64) await expect(txResponse) .to.emit(evmTester, 'StringSet') @@ -445,7 +466,6 @@ describe("EVM Test", function () { const feeData = await ethers.provider.getFeeData(); const gasPrice = Number(feeData.gasPrice); const higherGasPrice = Number(gasPrice + 9) - console.log(`gasPrice = ${gasPrice}`) const zero = ethers.parseUnits('0', 'ether') const txResponse = await owner.sendTransaction({ @@ -494,8 +514,6 @@ describe("EVM Test", function () { describe("Differing maxPriorityFeePerGas and maxFeePerGas", async function() { for (const [name, maxPriorityFeePerGas, maxFeePerGas] of testCases) { it(`EIP-1559 test: ${name}`, async function() { - console.log(`maxPriorityFeePerGas = ${maxPriorityFeePerGas}`) - console.log(`maxFeePerGas = ${maxFeePerGas}`) const balanceBefore = await ethers.provider.getBalance(owner); const zero = ethers.parseUnits('0', 'ether') const txResponse = await owner.sendTransaction({ @@ -509,7 +527,6 @@ describe("EVM Test", function () { expect(receipt).to.not.be.null; expect(receipt.status).to.equal(1); const gasPrice = Number(receipt.gasPrice); - console.log(`gasPrice = ${gasPrice}`) const balanceAfter = await ethers.provider.getBalance(owner); @@ -517,12 +534,9 @@ describe("EVM Test", function () { Number(maxFeePerGas) - gasPrice, Number(maxPriorityFeePerGas) ); - console.log(`tip = ${tip}`) const effectiveGasPrice = tip + gasPrice; - console.log(`effectiveGasPrice = ${effectiveGasPrice}`) const diff = balanceBefore - balanceAfter; - console.log(`diff = ${diff}`) expect(diff).to.equal(21000 * effectiveGasPrice); }); } @@ -650,6 +664,13 @@ describe("EVM Test", function () { expect(isBigNumber(estimatedGas)).to.be.true; }); + it("Should do large estimate gas efficiently", async function () { + batcher = await deployEvmContract("MultiSender"); + wallets = generateWallets(12).map(wallet => wallet.address); + const gas = await batcher.batchTransferEqualAmount.estimateGas(wallets, 1000000000000, {value: 100000000000000}); + expect(gas).to.be.greaterThan(0); + }); + it("Should check the network status", async function () { const network = await ethers.provider.getNetwork(); expect(network).to.have.property('name'); @@ -781,8 +802,8 @@ describe("EVM Test", function () { await txResponse.wait(); } blockEnd = await ethers.provider.getBlockNumber(); - console.log("blockStart = ", blockStart) - console.log("blockEnd = ", blockEnd) + debug("blockStart = ", blockStart) + debug("blockEnd = ", blockEnd) }); it("Block range filter", async function () { @@ -960,21 +981,19 @@ describe("EVM Test", function () { // deploy BoxV1 const Box = await ethers.getContractFactory("Box"); const val = 42; - console.log('Deploying Box...'); const box = await upgrades.deployProxy(Box, [val], { initializer: 'store' }); const boxReceipt = await box.waitForDeployment() - console.log("boxReceipt = ", JSON.stringify(boxReceipt)) const boxAddr = await box.getAddress(); const implementationAddress = await getImplementationAddress(ethers.provider, boxAddr); - console.log('Box Implementation address:', implementationAddress); - console.log('Box deployed to:', boxAddr) + debug('Box Implementation address:', implementationAddress); + debug('Box deployed to:', boxAddr) // make sure you can retrieve the value const retrievedValue = await box.retrieve(); expect(retrievedValue).to.equal(val); // increment value - console.log("Incrementing value...") + debug("Incrementing value...") const resp = await box.boxIncr(); await resp.wait(); @@ -984,23 +1003,23 @@ describe("EVM Test", function () { // upgrade to BoxV2 const BoxV2 = await ethers.getContractFactory('BoxV2'); - console.log('Upgrading Box...'); + debug('Upgrading Box...'); const box2 = await upgrades.upgradeProxy(boxAddr, BoxV2, [val+1], { initializer: 'store' }); await box2.deployTransaction.wait(); - console.log('Box upgraded'); + debug('Box upgraded'); const boxV2Addr = await box2.getAddress(); expect(boxV2Addr).to.equal(boxAddr); // should be same address as it should be the proxy - console.log('BoxV2 deployed to:', boxV2Addr); + debug('BoxV2 deployed to:', boxV2Addr); const boxV2 = await BoxV2.attach(boxV2Addr); // check that value is still the same - console.log("Calling boxV2 retrieve()...") + debug("Calling boxV2 retrieve()...") const retrievedValue2 = await boxV2.retrieve(); - console.log("retrievedValue2 = ", retrievedValue2) + debug("retrievedValue2 = ", retrievedValue2) expect(retrievedValue2).to.equal(val+1); // use new function in boxV2 and increment value - console.log("Calling boxV2 boxV2Incr()...") + debug("Calling boxV2 boxV2Incr()...") const txResponse = await boxV2.boxV2Incr(); await txResponse.wait(); @@ -1055,14 +1074,106 @@ describe("EVM Test", function () { }); }); +describe("EVM Validations ", function() { + + describe("chainId", async function(){ + let signer; + + before(async function(){ + await setupSigners(await hre.ethers.getSigners()) + signer = generateWallet() + await fundAddress(await signer.getAddress()) + }) + + it("should prevent wrong chainId for eip-155 txs", async function() { + const nonce = await ethers.provider.getTransactionCount(signer, "pending") + + const signedTx = await signer.signTransaction({ + to: await signer.getAddress(), + value: 0, + chainId: "0x12345", + type: 2, + nonce: nonce, + maxPriorityFeePerGas: 21000, + gasLimit: 21000, + maxFeePerGas:10000000000}) + + const nodeUrl = 'http://localhost:8545'; + const response = await axios.post(nodeUrl, { + method: 'eth_sendRawTransaction', + params: [signedTx], + id: 1, + jsonrpc: "2.0" + }) + expect(response.data.error.message).to.include("invalid chain-id") + }); + + it("should prevent wrong chainId for legacy txs", async function() { + const nonce = await ethers.provider.getTransactionCount(signer, "pending") + + + // const accounts = await setupSigners(await hre.ethers.getSigners()) + const signedTx = await signer.signTransaction({ + type: 0, + to: await signer.getAddress(), + value: 0, + nonce: nonce, + chainId: "0x12345", + gasPrice: 1000000000000, + gasLimit: 21000}) + + const nodeUrl = 'http://localhost:8545'; + const response = await axios.post(nodeUrl, { + method: 'eth_sendRawTransaction', + params: [signedTx], + id: 1, + jsonrpc: "2.0" + }) + + expect(response.data.error.message).to.include("invalid chain-id") + }); + + it("should allow empty chainId for legacy txs", async function() { + const nonce = await ethers.provider.getTransactionCount(signer, "pending") + + // const accounts = await setupSigners(await hre.ethers.getSigners()) + const signedTx = await signer.signTransaction({ + type: 0, + to: await signer.getAddress(), + value: 0, + nonce: nonce, + gasPrice: 1000000000000, + gasLimit: 21000}) + + const nodeUrl = 'http://localhost:8545'; + const response = await axios.post(nodeUrl, { + method: 'eth_sendRawTransaction', + params: [signedTx], + id: 1, + jsonrpc: "2.0" + }) + + expect(response.data.result).to.match(/0x.*/) + }); + + + + }) + +}) + describe("EVM throughput", function(){ + let accounts; + before(async function(){ + accounts = await setupSigners(await hre.ethers.getSigners()) + await fundAddress(accounts[0].evmAddress) + }); it("send 100 transactions from one account", async function(){ const wallet = generateWallet() const toAddress =await wallet.getAddress() - const accounts = await ethers.getSigners(); - const sender = accounts[0] - const address = await sender.getAddress(); + const sender = accounts[0].signer + const address = accounts[0].evmAddress; const txCount = 100; const nonce = await ethers.provider.getTransactionCount(address); diff --git a/contracts/test/EVMPrecompileTest.js b/contracts/test/EVMPrecompileTest.js index c094334f8..df831e643 100644 --- a/contracts/test/EVMPrecompileTest.js +++ b/contracts/test/EVMPrecompileTest.js @@ -4,369 +4,257 @@ const fs = require('fs'); const path = require('path'); const { expectRevert } = require('@openzeppelin/test-helpers'); +const {deployWasm, storeWasm, setupSigners, getAdmin, execute, isDocker, ABI} = require("./lib"); -describe("EVM Test", function () { - describe("EVM Precompile Tester", function () { - describe("EVM Bank Precompile Tester", function () { - let contractAddress; - let erc20; - let owner; - let owner2; - let signer; - 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 - [signer, signer2] = await ethers.getSigners(); - owner = await signer.getAddress(); - owner2 = await signer2.getAddress(); - - const contractABIPath = path.join(__dirname, '../../precompiles/common/erc20_abi.json'); - const contractABI = require(contractABIPath); - - // Get a contract instance - erc20 = new ethers.Contract(contractAddress, contractABI, signer); - - // force association on owner2 - const tx1 = await signer.sendTransaction({ - to: owner2, - value: 100000000000000 - }); - const receipt1 = await tx1.wait(); - expect(receipt1.status).to.equal(1); - const tx2 = await signer2.sendTransaction({ - to: owner, - value: 1 - }); - const receipt2 = await tx2.wait(); - expect(receipt2.status).to.equal(1); - }); - - it("Transfer function", async function() { - const beforeBalance = await erc20.balanceOf(owner); - const tx = await erc20.transfer(owner2, 1); - const receipt = await tx.wait(); - expect(receipt.status).to.equal(1); - const afterBalance = await erc20.balanceOf(owner); - const diff = beforeBalance - afterBalance; - expect(diff).to.equal(1); - }); - it("Transfer function with insufficient balance fails", async function() { - const receiver = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'; - await expectRevert.unspecified(erc20.transfer(receiver, 10000)); - }); - - it("No Approve and TransferFrom fails", async function() { - const receiver = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'; - const erc20AsOwner2 = erc20.connect(signer2); +describe("EVM Precompile Tester", function () { - await expectRevert.unspecified(erc20AsOwner2.transferFrom(owner, receiver, 100)); - }); + let accounts; + let admin; - it("Approve and TransferFrom functions", async function() { - // lets have owner approve the transfer and have owner2 do the transferring - const approvalAmount = await erc20.allowance(owner, owner2); - expect(approvalAmount).to.equal(0); - const approveTx = await erc20.approve(owner2, 100); - const approveReceipt = await approveTx.wait(); - expect(approveReceipt.status).to.equal(1); - expect(await erc20.allowance(owner, owner2)).to.equal(100); - - const erc20AsOwner2 = erc20.connect(signer2); - - - // transfer from owner to owner2 - const balanceBefore = await erc20.balanceOf(owner2); - const transferFromTx = await erc20AsOwner2.transferFrom(owner, owner2, 100); - - // await sleep(3000); - const transferFromReceipt = await transferFromTx.wait(); - expect(transferFromReceipt.status).to.equal(1); - const balanceAfter = await erc20.balanceOf(owner2); - const diff = balanceAfter - balanceBefore; - expect(diff).to.equal(100); - }); + before(async function () { + accounts = await setupSigners(await hre.ethers.getSigners()); + admin = await getAdmin(); + }) - it("Balance of function", async function() { - const balance = await erc20.balanceOf(owner); - expect(balance).to.be.greaterThan(Number(0)); - }); + describe("EVM Gov Precompile Tester", function () { + const GovPrecompileContract = '0x0000000000000000000000000000000000001006'; + let gov; + let govProposal; - it("Name function", async function () { - const name = await erc20.name() - expect(name).to.equal('UATOM'); - }); + before(async function () { + const govProposalResponse = JSON.parse(await execute(`seid tx gov submit-proposal param-change ../contracts/test/param_change_proposal.json --from admin --fees 20000usei -b block -y -o json`)) + govProposal = govProposalResponse.logs[0].events[3].attributes[1].value; - it("Symbol function", async function () { - const symbol = await erc20.symbol() - // expect symbol to be 'UATOM' - expect(symbol).to.equal('UATOM'); - }); + const signer = accounts[0].signer + const contractABIPath = '../../precompiles/gov/abi.json'; + const contractABI = require(contractABIPath); + // Get a contract instance + gov = new ethers.Contract(GovPrecompileContract, contractABI, signer); }); - // TODO: Update when we add gov query precompiles - describe("EVM Gov Precompile Tester", function () { - let govProposal; - // TODO: Import this - const GovPrecompileContract = '0x0000000000000000000000000000000000001006'; - before(async function() { - govProposal = readDeploymentOutput('gov_proposal_output.txt'); - await sleep(1000); - - // Create a proposal - const [signer, _] = await ethers.getSigners(); - owner = await signer.getAddress(); - - const contractABIPath = path.join(__dirname, '../../precompiles/gov/abi.json'); - const contractABI = require(contractABIPath); - // Get a contract instance - gov = new ethers.Contract(GovPrecompileContract, contractABI, signer); - }); - - it("Gov deposit", async function () { - const depositAmount = ethers.parseEther('0.01'); - const deposit = await gov.deposit(govProposal, { - value: depositAmount, - }) - const receipt = await deposit.wait(); - expect(receipt.status).to.equal(1); - // TODO: Add gov query precompile here - }); + it("Gov deposit", async function () { + const depositAmount = ethers.parseEther('0.01'); + const deposit = await gov.deposit(govProposal, { + value: depositAmount, + }) + const receipt = await deposit.wait(); + expect(receipt.status).to.equal(1); }); + }); - // TODO: Update when we add distribution query precompiles - describe("EVM Distribution Precompile Tester", function () { - // TODO: Import this - const DistributionPrecompileContract = '0x0000000000000000000000000000000000001007'; - before(async function() { - const [signer, signer2] = await ethers.getSigners(); - owner = await signer.getAddress(); - owner2 = await signer2.getAddress(); - - const contractABIPath = path.join(__dirname, '../../precompiles/distribution/abi.json'); - const contractABI = require(contractABIPath); - // Get a contract instance - distribution = new ethers.Contract(DistributionPrecompileContract, contractABI, signer); - }); - - it("Distribution set withdraw address", async function () { - const setWithdraw = await distribution.setWithdrawAddress(owner) - const receipt = await setWithdraw.wait(); - expect(receipt.status).to.equal(1); - // TODO: Add distribution query precompile here - }); + // TODO: Update when we add distribution query precompiles + describe("EVM Distribution Precompile Tester", function () { + const DistributionPrecompileContract = '0x0000000000000000000000000000000000001007'; + let distribution; + before(async function () { + const signer = accounts[0].signer; + const contractABIPath = '../../precompiles/distribution/abi.json'; + const contractABI = require(contractABIPath); + // Get a contract instance + distribution = new ethers.Contract(DistributionPrecompileContract, contractABI, signer); }); - // TODO: Update when we add staking query precompiles - describe("EVM Staking Precompile Tester", function () { - const StakingPrecompileContract = '0x0000000000000000000000000000000000001005'; - before(async function() { - validatorAddr = readDeploymentOutput('validator_address.txt'); - await sleep(1000); - const [signer, _] = await ethers.getSigners(); - owner = await signer.getAddress(); - - const contractABIPath = path.join(__dirname, '../../precompiles/staking/abi.json'); - const contractABI = require(contractABIPath); - // Get a contract instance - staking = new ethers.Contract(StakingPrecompileContract, contractABI, signer); - }); - - it("Staking delegate", async function () { - const delegateAmount = ethers.parseEther('0.01'); - const delegate = await staking.delegate(validatorAddr, { - value: delegateAmount, - }); - const receipt = await delegate.wait(); - expect(receipt.status).to.equal(1); - // TODO: Add staking query precompile here - }); + it("Distribution set withdraw address", async function () { + const setWithdraw = await distribution.setWithdrawAddress(accounts[0].evmAddress) + const receipt = await setWithdraw.wait(); + expect(receipt.status).to.equal(1); }); + }); - describe("EVM Oracle Precompile Tester", function () { - const OraclePrecompileContract = '0x0000000000000000000000000000000000001008'; - before(async function() { - const exchangeRatesContent = readDeploymentOutput('oracle_exchange_rates.json'); - const twapsContent = readDeploymentOutput('oracle_twaps.json'); - - exchangeRatesJSON = JSON.parse(exchangeRatesContent).denom_oracle_exchange_rate_pairs; - twapsJSON = JSON.parse(twapsContent).oracle_twaps; + // TODO: Update when we add staking query precompiles + describe("EVM Staking Precompile Tester", function () { + const StakingPrecompileContract = '0x0000000000000000000000000000000000001005'; + let validatorAddr; + let signer; + let staking; - const [signer, _] = await ethers.getSigners(); - owner = await signer.getAddress(); + before(async function () { + validatorAddr = JSON.parse(await execute("seid q staking validators -o json")).validators[0].operator_address + signer = accounts[0].signer; - const contractABIPath = path.join(__dirname, '../../precompiles/oracle/abi.json'); - const contractABI = require(contractABIPath); - // Get a contract instance - oracle = new ethers.Contract(OraclePrecompileContract, contractABI, signer); - }); + const contractABIPath = '../../precompiles/staking/abi.json'; + const contractABI = require(contractABIPath); - it("Oracle Exchange Rates", async function () { - const exchangeRates = await oracle.getExchangeRates(); - const exchangeRatesLen = exchangeRatesJSON.length; - expect(exchangeRates.length).to.equal(exchangeRatesLen); - - for (let i = 0; i < exchangeRatesLen; i++) { - expect(exchangeRates[i].denom).to.equal(exchangeRatesJSON[i].denom); - expect(exchangeRates[i].oracleExchangeRateVal.exchangeRate).to.be.a('string').and.to.not.be.empty; - expect(exchangeRates[i].oracleExchangeRateVal.exchangeRate).to.be.a('string').and.to.not.be.empty; - expect(exchangeRates[i].oracleExchangeRateVal.lastUpdateTimestamp).to.exist.and.to.be.gt(0); - } - }); - - it("Oracle Twaps", async function () { - const twaps = await oracle.getOracleTwaps(3600); - const twapsLen = twapsJSON.length - expect(twaps.length).to.equal(twapsLen); + staking = new ethers.Contract(StakingPrecompileContract, contractABI, signer); + }); - for (let i = 0; i < twapsLen; i++) { - expect(twaps[i].denom).to.equal(twapsJSON[i].denom); - expect(twaps[i].twap).to.be.a('string').and.to.not.be.empty; - expect(twaps[i].lookbackSeconds).to.exist.and.to.be.gt(0); - } + it("Staking delegate", async function () { + const delegateAmount = ethers.parseEther('0.01'); + const delegate = await staking.delegate(validatorAddr, { + value: delegateAmount, }); + const receipt = await delegate.wait(); + expect(receipt.status).to.equal(1); + // TODO: Add staking query precompile here }); + }); - describe("EVM Wasm Precompile Tester", function () { - const WasmPrecompileContract = '0x0000000000000000000000000000000000001002'; - before(async function() { - wasmContractAddress = readDeploymentOutput('wasm_contract_addr.txt'); - wasmCodeID = parseInt(readDeploymentOutput('wasm_code_id.txt')); + describe("EVM Oracle Precompile Tester", function () { + const OraclePrecompileContract = '0x0000000000000000000000000000000000001008'; + let oracle; + let twapsJSON; + let exchangeRatesJSON; + + before(async function() { + // this requires an oracle to run which does not happen outside of an integration test + if(!await isDocker()) { + this.skip() + return; + } + const exchangeRatesContent = await execute("seid q oracle exchange-rates -o json") + const twapsContent = await execute("seid q oracle twaps 3600 -o json") + + exchangeRatesJSON = JSON.parse(exchangeRatesContent).denom_oracle_exchange_rate_pairs; + twapsJSON = JSON.parse(twapsContent).oracle_twaps; + + const contractABIPath = '../../precompiles/oracle/abi.json'; + const contractABI = require(contractABIPath); + // Get a contract instance + oracle = new ethers.Contract(OraclePrecompileContract, contractABI, accounts[0].signer); + }); - const [signer, _] = await ethers.getSigners(); - owner = await signer.getAddress(); + it("Oracle Exchange Rates", async function () { + const exchangeRates = await oracle.getExchangeRates(); + const exchangeRatesLen = exchangeRatesJSON.length; + expect(exchangeRates.length).to.equal(exchangeRatesLen); + + for (let i = 0; i < exchangeRatesLen; i++) { + expect(exchangeRates[i].denom).to.equal(exchangeRatesJSON[i].denom); + expect(exchangeRates[i].oracleExchangeRateVal.exchangeRate).to.be.a('string').and.to.not.be.empty; + expect(exchangeRates[i].oracleExchangeRateVal.exchangeRate).to.be.a('string').and.to.not.be.empty; + expect(exchangeRates[i].oracleExchangeRateVal.lastUpdateTimestamp).to.exist.and.to.be.gt(0); + } + }); - const contractABIPath = path.join(__dirname, '../../precompiles/wasmd/abi.json'); - const contractABI = require(contractABIPath); - // Get a contract instance - wasmd = new ethers.Contract(WasmPrecompileContract, contractABI, signer); - }); + it("Oracle Twaps", async function () { + const twaps = await oracle.getOracleTwaps(3600); + const twapsLen = twapsJSON.length + expect(twaps.length).to.equal(twapsLen); - it("Wasm Precompile Instantiate", async function () { - encoder = new TextEncoder(); + for (let i = 0; i < twapsLen; i++) { + expect(twaps[i].denom).to.equal(twapsJSON[i].denom); + expect(twaps[i].twap).to.be.a('string').and.to.not.be.empty; + expect(twaps[i].lookbackSeconds).to.exist.and.to.be.gt(0); + } + }); + }); - queryCountMsg = {get_count: {}}; - queryStr = JSON.stringify(queryCountMsg); - queryBz = encoder.encode(queryStr); + describe("EVM Wasm Precompile Tester", function () { + const WasmPrecompileContract = '0x0000000000000000000000000000000000001002'; + let wasmCodeID; + let wasmContractAddress; + let wasmd; + let owner; + + before(async function () { + const counterWasm = '../integration_test/contracts/counter_parallel.wasm'; + wasmCodeID = await storeWasm(counterWasm); + + const counterParallelWasm = '../integration_test/contracts/counter_parallel.wasm' + wasmContractAddress = await deployWasm(counterParallelWasm, accounts[0].seiAddress, "counter", {count: 0}); + owner = accounts[0].signer; + + const contractABIPath = '../../precompiles/wasmd/abi.json'; + const contractABI = require(contractABIPath); + // Get a contract instance + wasmd = new ethers.Contract(WasmPrecompileContract, contractABI, owner); + }); - instantiateMsg = {count: 2}; - instantiateStr = JSON.stringify(instantiateMsg); - instantiateBz = encoder.encode(instantiateStr); + it("Wasm Precompile Instantiate", async function () { + const encoder = new TextEncoder(); - coins = []; - coinsStr = JSON.stringify(coins); - coinsBz = encoder.encode(coinsStr); + const instantiateMsg = {count: 2}; + const instantiateStr = JSON.stringify(instantiateMsg); + const instantiateBz = encoder.encode(instantiateStr); - instantiate = await wasmd.instantiate(wasmCodeID, "", instantiateBz, "counter-contract", coinsBz); - const receipt = await instantiate.wait(); - expect(receipt.status).to.equal(1); - // TODO: is there any way to get the instantiate results for contract address - or in events? - }); + const coins = []; + const coinsStr = JSON.stringify(coins); + const coinsBz = encoder.encode(coinsStr); - it("Wasm Precompile Execute", async function () { - expect(wasmContractAddress).to.not.be.empty; - encoder = new TextEncoder(); + const instantiate = await wasmd.instantiate(wasmCodeID, "", instantiateBz, "counter-contract", coinsBz); + const receipt = await instantiate.wait(); + expect(receipt.status).to.equal(1); + }); - queryCountMsg = {get_count: {}}; - queryStr = JSON.stringify(queryCountMsg); - queryBz = encoder.encode(queryStr); - initialCountBz = await wasmd.query(wasmContractAddress, queryBz); - initialCount = parseHexToJSON(initialCountBz) + it("Wasm Precompile Execute", async function () { + const encoder = new TextEncoder(); - incrementMsg = {increment: {}}; - incrementStr = JSON.stringify(incrementMsg); - incrementBz = encoder.encode(incrementStr); + const queryCountMsg = {get_count: {}}; + const queryStr = JSON.stringify(queryCountMsg); + const queryBz = encoder.encode(queryStr); + const initialCountBz = await wasmd.query(wasmContractAddress, queryBz); + const initialCount = parseHexToJSON(initialCountBz) - coins = []; - coinsStr = JSON.stringify(coins); - coinsBz = encoder.encode(coinsStr); + const incrementMsg = {increment: {}}; + const incrementStr = JSON.stringify(incrementMsg); + const incrementBz = encoder.encode(incrementStr); - execute = await wasmd.execute(wasmContractAddress, incrementBz, coinsBz); - const receipt = await execute.wait(); - expect(receipt.status).to.equal(1); + const coins = []; + const coinsStr = JSON.stringify(coins); + const coinsBz = encoder.encode(coinsStr); - finalCountBz = await wasmd.query(wasmContractAddress, queryBz); - finalCount = parseHexToJSON(finalCountBz) - expect(finalCount.count).to.equal(initialCount.count + 1); - }); + const response = await wasmd.execute(wasmContractAddress, incrementBz, coinsBz); + const receipt = await response.wait(); + expect(receipt.status).to.equal(1); - it("Wasm Precompile Batch Execute", async function () { - expect(wasmContractAddress).to.not.be.empty; - encoder = new TextEncoder(); - - queryCountMsg = {get_count: {}}; - queryStr = JSON.stringify(queryCountMsg); - queryBz = encoder.encode(queryStr); - initialCountBz = await wasmd.query(wasmContractAddress, queryBz); - initialCount = parseHexToJSON(initialCountBz) - - incrementMsg = {increment: {}}; - incrementStr = JSON.stringify(incrementMsg); - incrementBz = encoder.encode(incrementStr); - - coins = []; - coinsStr = JSON.stringify(coins); - coinsBz = encoder.encode(coinsStr); - - executeBatch = [ - { - contractAddress: wasmContractAddress, - msg: incrementBz, - coins: coinsBz, - }, - { - contractAddress: wasmContractAddress, - msg: incrementBz, - coins: coinsBz, - }, - { - contractAddress: wasmContractAddress, - msg: incrementBz, - coins: coinsBz, - }, - { - contractAddress: wasmContractAddress, - msg: incrementBz, - coins: coinsBz, - }, - ]; - - executeBatch = await wasmd.execute_batch(executeBatch); - const receipt = await executeBatch.wait(); - expect(receipt.status).to.equal(1); - - finalCountBz = await wasmd.query(wasmContractAddress, queryBz); - finalCount = parseHexToJSON(finalCountBz) - expect(finalCount.count).to.equal(initialCount.count + 4); - }); + const finalCountBz = await wasmd.query(wasmContractAddress, queryBz); + const finalCount = parseHexToJSON(finalCountBz) + expect(finalCount.count).to.equal(initialCount.count + 1); + }); + it("Wasm Precompile Batch Execute", async function () { + const encoder = new TextEncoder(); + + const queryCountMsg = {get_count: {}}; + const queryStr = JSON.stringify(queryCountMsg); + const queryBz = encoder.encode(queryStr); + const initialCountBz = await wasmd.query(wasmContractAddress, queryBz); + const initialCount = parseHexToJSON(initialCountBz) + + const incrementMsg = {increment: {}}; + const incrementStr = JSON.stringify(incrementMsg); + const incrementBz = encoder.encode(incrementStr); + + const coins = []; + const coinsStr = JSON.stringify(coins); + const coinsBz = encoder.encode(coinsStr); + + const executeBatch = [ + { + contractAddress: wasmContractAddress, + msg: incrementBz, + coins: coinsBz, + }, + { + contractAddress: wasmContractAddress, + msg: incrementBz, + coins: coinsBz, + }, + { + contractAddress: wasmContractAddress, + msg: incrementBz, + coins: coinsBz, + }, + { + contractAddress: wasmContractAddress, + msg: incrementBz, + coins: coinsBz, + }, + ]; + + const response = await wasmd.execute_batch(executeBatch); + const receipt = await response.wait(); + expect(receipt.status).to.equal(1); + + const finalCountBz = await wasmd.query(wasmContractAddress, queryBz); + const finalCount = parseHexToJSON(finalCountBz) + expect(finalCount.count).to.equal(initialCount.count + 4); }); }); -}); -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -function readDeploymentOutput(fileName) { - let fileContent; - try { - if (fs.existsSync(fileName)) { - fileContent = fs.readFileSync(fileName, 'utf8').trim(); - } else { - console.error("File not found:", fileName); - } - } catch (error) { - console.error(`Error reading file: ${error}`); - } - return fileContent; -} +}); function parseHexToJSON(hexStr) { // Remove the 0x prefix diff --git a/contracts/test/deploy_atom_erc20.sh b/contracts/test/deploy_atom_erc20.sh deleted file mode 100644 index f5408f313..000000000 --- a/contracts/test/deploy_atom_erc20.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# This script is used to deploy the UATOM ERC20 contract and associate it with the SEI account. -set -e - -endpoint=${EVM_RPC:-"http://127.0.0.1:8545"} -owner1=0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 -associated_sei_account1=sei1m9qugvk4h66p6hunfajfg96ysc48zeq4m0d82c -owner2=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 - -echo "Funding account $account with UATOM for testing..." -printf "12345678\n" | seid tx bank send $(printf "12345678\n" | seid keys show admin -a) $associated_sei_account1 10000uatom --fees 20000usei -b block -y - -echo "Fund owners with some SEI" -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..." -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 "$pointer_output" | jq .pointer | tr -d '"') -echo $erc20_deploy_addr > contracts/erc20_deploy_addr.txt - -# wait for deployment to finish on live chain -sleep 3 diff --git a/contracts/test/deploy_wasm_contract.sh b/contracts/test/deploy_wasm_contract.sh deleted file mode 100644 index b35df1703..000000000 --- a/contracts/test/deploy_wasm_contract.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -seidbin=$(which ~/go/bin/seid | tr -d '"') -keyname=$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].name" | tr -d '"') -keyaddress=$(printf "12345678\n" | $seidbin keys list --output json | jq ".[0].address" | tr -d '"') -chainid=$($seidbin status | jq ".NodeInfo.network" | tr -d '"') -seihome=$(git rev-parse --show-toplevel | tr -d '"') - -cd $seihome || exit -echo "Deploying wasm counter contract" - -echo "Storing wasm counter contract" -store_result=$(printf "12345678\n" | $seidbin tx wasm store integration_test/contracts/counter_parallel.wasm -y --from="$keyname" --chain-id="$chainid" --gas=5000000 --fees=1000000usei --broadcast-mode=block --output=json) -contract_id=$(echo "$store_result" | jq -r '.logs[].events[].attributes[] | select(.key == "code_id").value') -echo "$contract_id" > contracts/wasm_code_id.txt -echo "Instantiating wasm counter contract" -instantiate_result=$(printf "12345678\n" | $seidbin tx wasm instantiate "$contract_id" '{"count": 0}' -y --no-admin --from="$keyname" --chain-id="$chainid" --gas=5000000 --fees=1000000usei --broadcast-mode=block --label=dex --output=json) -echo $instantiate_result - -contract_addr=$(echo "$instantiate_result" |jq -r 'first(.logs[].events[].attributes[] | select(.key == "_contract_address").value)') - -echo "Deployed counter contract with address:" -echo $contract_addr - -# write the contract address to wasm_contract_addr.txt -echo "$contract_addr" > contracts/wasm_contract_addr.txt \ No newline at end of file diff --git a/contracts/test/get_validator_address.sh b/contracts/test/get_validator_address.sh deleted file mode 100644 index e8c704981..000000000 --- a/contracts/test/get_validator_address.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -# This script is used to find the validator address. -set -e - -endpoint=${EVM_RPC:-"http://127.0.0.1:8545"} -owner1=0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 -associated_sei_account1=sei1m9qugvk4h66p6hunfajfg96ysc48zeq4m0d82c - -validator_address=$(printf "12345678\n" | seid q staking validators -o json | jq -r '.validators[0].operator_address') - -echo $validator_address > contracts/validator_address.txt diff --git a/contracts/test/lib.js b/contracts/test/lib.js index e409e436a..312481180 100644 --- a/contracts/test/lib.js +++ b/contracts/test/lib.js @@ -2,6 +2,47 @@ const { exec } = require("child_process"); // Importing exec from child_process const adminKeyName = "admin" +const ABI = { + ERC20: [ + "function name() view returns (string)", + "function symbol() view returns (string)", + "function decimals() view returns (uint8)", + "function totalSupply() view returns (uint256)", + "function balanceOf(address owner) view returns (uint256 balance)", + "function transfer(address to, uint amount) returns (bool)", + "function allowance(address owner, address spender) view returns (uint256)", + "function approve(address spender, uint256 value) returns (bool)", + "function transferFrom(address from, address to, uint value) returns (bool)", + "error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed)" + ], + ERC721: [ + "event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId)", + "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)", + "event ApprovalForAll(address indexed owner, address indexed operator, bool approved)", + "function name() view returns (string)", + "function symbol() view returns (string)", + "function totalSupply() view returns (uint256)", + "function tokenURI(uint256 tokenId) view returns (string)", + "function royaltyInfo(uint256 tokenId, uint256 salePrice) view returns (address, uint256)", + "function balanceOf(address owner) view returns (uint256 balance)", + "function ownerOf(uint256 tokenId) view returns (address owner)", + "function getApproved(uint256 tokenId) view returns (address operator)", + "function isApprovedForAll(address owner, address operator) view returns (bool)", + "function approve(address to, uint256 tokenId) returns (bool)", + "function setApprovalForAll(address operator, bool _approved) returns (bool)", + "function transferFrom(address from, address to, uint256 tokenId) returns (bool)", + "function safeTransferFrom(address from, address to, uint256 tokenId) returns (bool)", + "function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) returns (bool)" + ], +} + +const WASM = { + CW721: "../contracts/wasm/cw721_base.wasm", + CW20: "../contracts/wasm/cw20_base.wasm", + POINTER_CW20: "../example/cosmwasm/cw20/artifacts/cwerc20.wasm", + POINTER_CW721: "../example/cosmwasm/cw721/artifacts/cwerc721.wasm", +} + function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } @@ -10,13 +51,56 @@ async function delay() { await sleep(1000) } -async function fundAddress(addr) { - return await execute(`seid tx evm send ${addr} 10000000000000000000 --from ${adminKeyName}`); +async function getCosmosTx(provider, evmTxHash) { + return await provider.send("sei_getCosmosTx", [evmTxHash]) } -async function getAdmin() { - await associateAdmin() - const seiAddress = await getAdminSeiAddress() +async function fundAddress(addr, amount="10000000000000000000") { + const result = await evmSend(addr, adminKeyName, amount) + await delay() + return result +} + +async function evmSend(addr, fromKey, amount="100000000000000000000000") { + const output = await execute(`seid tx evm send ${addr} ${amount} --from ${fromKey} -b block -y`); + return output.replace(/.*0x/, "0x").trim() +} + +async function bankSend(toAddr, fromKey, amount="100000000000", denom="usei") { + const result = await execute(`seid tx bank send ${fromKey} ${toAddr} ${amount}${denom} -b block --fees 20000usei -y`); + await delay() + return result +} + +async function fundSeiAddress(seiAddr, amount="100000000000", denom="usei") { + return await execute(`seid tx bank send ${adminKeyName} ${seiAddr} ${amount}${denom} -b block --fees 20000usei -y`); +} + +async function getSeiBalance(seiAddr, denom="usei") { + const result = await execute(`seid query bank balances ${seiAddr} -o json`); + const balances = JSON.parse(result) + for(let b of balances.balances) { + if(b.denom === denom) { + return parseInt(b.amount, 10) + } + } + return 0 +} + +async function importKey(name, keyfile) { + try { + return await execute(`seid keys import ${name} ${keyfile}`, `printf "12345678\\n12345678\\n"`) + } catch(e) { + console.log("not importing key (skipping)") + console.log(e) + } +} + +async function getNativeAccount(keyName) { + await associateKey(adminKeyName) + const seiAddress = await getKeySeiAddress(keyName) + await fundSeiAddress(seiAddress) + await delay() const evmAddress = await getEvmAddress(seiAddress) return { seiAddress, @@ -24,13 +108,19 @@ async function getAdmin() { } } -async function getAdminSeiAddress() { - return (await execute(`seid keys show ${adminKeyName} -a`)).trim() +async function getAdmin() { + await associateKey(adminKeyName) + return await getNativeAccount(adminKeyName) } -async function associateAdmin() { +async function getKeySeiAddress(name) { + return (await execute(`seid keys show ${name} -a`)).trim() +} + +async function associateKey(keyName) { try { - return await execute(`seid tx evm associate-address --from ${adminKeyName}`) + await execute(`seid tx evm associate-address --from ${keyName} -b block`) + await delay() }catch(e){ console.log("skipping associate") } @@ -53,6 +143,51 @@ function getEventAttribute(response, type, attribute) { throw new Error("attribute not found") } +async function testAPIEnabled(provider) { + try { + // noop operation to see if it throws + await incrementPointerVersion(provider, "cw20", 0) + return true; + } catch(e){ + console.log(e) + return false; + } +} + +async function incrementPointerVersion(provider, pointerType, offset) { + if(await isDocker()) { + // must update on all nodes + for(let i=0; i<4; i++) { + const resultStr = await execCommand(`docker exec sei-node-${i} curl -s -X POST http://localhost:8545 -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"test_incrementPointerVersion","params":["${pointerType}", ${offset}],"id":1}'`) + const result = JSON.parse(resultStr) + if(result.error){ + throw new Error(`failed to increment pointer version: ${result.error}`) + } + } + } else { + await provider.send("test_incrementPointerVersion", [pointerType, offset]); + } +} + +async function createTokenFactoryTokenAndMint(name, amount, recipient) { + const command = `seid tx tokenfactory create-denom ${name} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` + const output = await execute(command); + const response = JSON.parse(output) + const token_denom = getEventAttribute(response, "create_denom", "new_token_denom") + const mint_command = `seid tx tokenfactory mint ${amount}${token_denom} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` + await execute(mint_command); + + const send_command = `seid tx bank send ${adminKeyName} ${recipient} ${amount}${token_denom} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` + await execute(send_command); + return token_denom +} + +async function getPointerForNative(name) { + const command = `seid query evm pointer NATIVE ${name} -o json` + const output = await execute(command); + return JSON.parse(output); +} + async function storeWasm(path) { const command = `seid tx wasm store ${path} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json` const output = await execute(command); @@ -71,15 +206,33 @@ async function getPointerForCw721(cw721Address) { return JSON.parse(output); } -async function deployErc20PointerForCw20(provider, cw20Address) { - const command = `seid tx evm call-precompile pointer addCW20Pointer ${cw20Address} --from=admin -b block` +async function deployErc20PointerForCw20(provider, cw20Address, attempts=10) { + const command = `seid tx evm register-evm-pointer CW20 ${cw20Address} --from=admin -b block` + const output = await execute(command); + const txHash = output.replace(/.*0x/, "0x").trim() + let attempt = 0; + while(attempt < attempts) { + const receipt = await provider.getTransactionReceipt(txHash); + if(receipt && receipt.status === 1) { + return (await getPointerForCw20(cw20Address)).pointer + } else if(receipt){ + throw new Error("contract deployment failed") + } + await sleep(500) + attempt++ + } + throw new Error("contract deployment failed") +} + +async function deployErc20PointerNative(provider, name) { + const command = `seid tx evm call-precompile pointer addNativePointer ${name} --from=admin -b block` const output = await execute(command); const txHash = output.replace(/.*0x/, "0x").trim() let attempt = 0; while(attempt < 10) { const receipt = await provider.getTransactionReceipt(txHash); if(receipt) { - return (await getPointerForCw20(cw20Address)).pointer + return (await getPointerForNative(name)).pointer } await sleep(500) attempt++ @@ -88,14 +241,16 @@ async function deployErc20PointerForCw20(provider, cw20Address) { } async function deployErc721PointerForCw721(provider, cw721Address) { - const command = `seid tx evm call-precompile pointer addCW721Pointer ${cw721Address} --from=admin -b block` + const command = `seid tx evm register-evm-pointer CW721 ${cw721Address} --from=admin -b block` const output = await execute(command); const txHash = output.replace(/.*0x/, "0x").trim() let attempt = 0; while(attempt < 10) { const receipt = await provider.getTransactionReceipt(txHash); - if(receipt) { + if(receipt && receipt.status === 1) { return (await getPointerForCw721(cw721Address)).pointer + } else if(receipt){ + throw new Error("contract deployment failed") } await sleep(500) attempt++ @@ -116,6 +271,26 @@ async function instantiateWasm(codeId, adminAddr, label, args = {}) { return getEventAttribute(response, "instantiate", "_contract_address"); } +async function registerPointerForCw20(erc20Address, fees="20000usei", from=adminKeyName) { + const command = `seid tx evm register-cw-pointer ERC20 ${erc20Address} --from ${from} --fees ${fees} --broadcast-mode block -y -o json` + const output = await execute(command); + const response = JSON.parse(output) + if(response.code !== 0) { + throw new Error("contract deployment failed") + } + return getEventAttribute(response, "pointer_registered", "pointer_address") +} + +async function registerPointerForCw721(erc721Address, fees="20000usei", from=adminKeyName) { + const command = `seid tx evm register-cw-pointer ERC721 ${erc721Address} --from ${from} --fees ${fees} --broadcast-mode block -y -o json` + const output = await execute(command); + const response = JSON.parse(output) + if(response.code !== 0) { + throw new Error("contract deployment failed") + } + return getEventAttribute(response, "pointer_registered", "pointer_address") +} + async function getSeiAddress(evmAddress) { const command = `seid q evm sei-addr ${evmAddress} -o json` @@ -174,42 +349,66 @@ async function executeWasm(contractAddress, msg, coins = "0usei") { return JSON.parse(output); } -async function execute(command) { +async function associateWasm(contractAddress) { + const command = `seid tx evm associate-contract-address ${contractAddress} --from ${adminKeyName} --gas=5000000 --fees=1000000usei -y --broadcast-mode block -o json`; + const output = await execute(command); + return JSON.parse(output); +} + +async function isDocker() { return new Promise((resolve, reject) => { - // Check if the Docker container 'sei-node-0' is running exec("docker ps --filter 'name=sei-node-0' --format '{{.Names}}'", (error, stdout, stderr) => { if (stdout.includes('sei-node-0')) { - // The container is running, modify the command to execute inside Docker - command = command.replace(/\.\.\//g, "/sei-protocol/sei-chain/"); - const dockerCommand = `docker exec sei-node-0 /bin/bash -c 'export PATH=$PATH:/root/go/bin:/root/.foundry/bin && printf "12345678\\n" | ${command}'`; - execCommand(dockerCommand, resolve, reject); + resolve(true) } else { - // The container is not running, execute command normally - execCommand(command, resolve, reject); + resolve(false) } }); }); } -function execCommand(command, resolve, reject) { - exec(command, (error, stdout, stderr) => { - if (error) { - reject(error); - return; - } - if (stderr) { - reject(new Error(stderr)); - return; - } - resolve(stdout); - }); +async function execute(command, interaction=`printf "12345678\\n"`){ + if (await isDocker()) { + command = command.replace(/\.\.\//g, "/sei-protocol/sei-chain/"); + command = command.replace("/sei-protocol/sei-chain//sei-protocol/sei-chain/", "/sei-protocol/sei-chain/") + command = `docker exec sei-node-0 /bin/bash -c 'export PATH=$PATH:/root/go/bin:/root/.foundry/bin && ${interaction} | ${command}'`; + } + return await execCommand(command); +} + +function execCommand(command) { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + reject(error); + return; + } + if (stderr) { + reject(new Error(stderr)); + return; + } + resolve(stdout); + }); + }) +} + +async function waitForReceipt(txHash) { + let receipt = await ethers.provider.getTransactionReceipt(txHash) + while(!receipt) { + await delay() + receipt = await ethers.provider.getTransactionReceipt(txHash) + } + return receipt } module.exports = { fundAddress, + fundSeiAddress, + getSeiBalance, storeWasm, deployWasm, instantiateWasm, + createTokenFactoryTokenAndMint, execute, getSeiAddress, getEvmAddress, @@ -219,5 +418,22 @@ module.exports = { setupSigners, deployEvmContract, deployErc20PointerForCw20, + deployErc20PointerNative, deployErc721PointerForCw721, + registerPointerForCw20, + registerPointerForCw721, + importKey, + getNativeAccount, + associateKey, + delay, + bankSend, + evmSend, + waitForReceipt, + getCosmosTx, + isDocker, + testAPIEnabled, + incrementPointerVersion, + associateWasm, + WASM, + ABI, }; diff --git a/contracts/test/query_oracle_data.sh b/contracts/test/query_oracle_data.sh deleted file mode 100644 index 7531f6fe4..000000000 --- a/contracts/test/query_oracle_data.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -# This script is used to query oracle exchange rates and twap -seid q oracle exchange-rates -o json > contracts/oracle_exchange_rates.json -seid q oracle twaps 3600 -o json > contracts/oracle_twaps.json diff --git a/contracts/test/send_gov_proposal.sh b/contracts/test/send_gov_proposal.sh deleted file mode 100644 index 27641fc89..000000000 --- a/contracts/test/send_gov_proposal.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -# This script is used to send a gov deposit. -set -e - -endpoint=${EVM_RPC:-"http://127.0.0.1:8545"} -owner1=0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 -associated_sei_account1=sei1m9qugvk4h66p6hunfajfg96ysc48zeq4m0d82c - -gov_proposal_output=$(printf "12345678\n" | seid tx gov submit-proposal param-change contracts/test/param_change_proposal.json --from admin --fees 20000usei -b block -y -o json | jq -r '.logs[0].events[3].attributes[1].value') - -echo $gov_proposal_output > contracts/gov_proposal_output.txt diff --git a/contracts/test/test1.key b/contracts/test/test1.key new file mode 100644 index 000000000..51255116e --- /dev/null +++ b/contracts/test/test1.key @@ -0,0 +1,9 @@ +-----BEGIN TENDERMINT PRIVATE KEY----- +kdf: bcrypt +salt: 377151BDAA4DCDD8761F9489519D3E90 +type: secp256k1 + +aMtUz1ow5FBmictYj67Wm5qJksJsiF0O86PrjOHnoINVBn0aCzYNxdkvNg0PP0Qb +jHfcKaDPgk3PaeW16YqNJwveVX71A7lwpUmfT44= +=46/d +-----END TENDERMINT PRIVATE KEY----- diff --git a/contracts/test/test2.key b/contracts/test/test2.key new file mode 100644 index 000000000..b57f16480 --- /dev/null +++ b/contracts/test/test2.key @@ -0,0 +1,9 @@ +-----BEGIN TENDERMINT PRIVATE KEY----- +kdf: bcrypt +salt: 72E32FD4A4089E256F1EFCCBBA576592 +type: secp256k1 + +MZ77pmO6izHdpkKVWYhGLGjZUAhf//WGURYVqUqhjJbCGtAXEkFKrjEAEpO3pyn1 +tYe8Hlry3BiqLoLY+j7CwE7W6g3WshJouXCrUiY= +=VWqu +-----END TENDERMINT PRIVATE KEY----- diff --git a/contracts/test/test3.key b/contracts/test/test3.key new file mode 100644 index 000000000..6202cc16e --- /dev/null +++ b/contracts/test/test3.key @@ -0,0 +1,9 @@ +-----BEGIN TENDERMINT PRIVATE KEY----- +kdf: bcrypt +salt: CDAEDE2709FFE1049C3E217BCD179BB2 +type: secp256k1 + +l8hOkMcbc9ugxiUmS3k1wdziq6N+qhas25H0fjWD9tDK/BPn0QkY3pIz39TZJNuf +/l9ImHhYxccWPoyTybKmXEjMaKLpFRZLdu+t844= +=lvXk +-----END TENDERMINT PRIVATE KEY----- diff --git a/contracts/wasm/cw2981_royalties.wasm b/contracts/wasm/cw2981_royalties.wasm new file mode 100644 index 000000000..d139847a1 Binary files /dev/null and b/contracts/wasm/cw2981_royalties.wasm differ diff --git a/contracts/wasm/cwerc721.wasm b/contracts/wasm/cwerc721.wasm index 318ada77b..a1cfac086 100644 Binary files a/contracts/wasm/cwerc721.wasm and b/contracts/wasm/cwerc721.wasm differ diff --git a/docker/localnode/config/app.toml b/docker/localnode/config/app.toml index b9bf48fa3..a11c0c2d8 100644 --- a/docker/localnode/config/app.toml +++ b/docker/localnode/config/app.toml @@ -263,3 +263,8 @@ ss-prune-interval = 60 # ImportNumWorkers defines the concurrency for state sync import # defaults to 1 ss-import-num-workers = 1 + +[evm] + +# EnableTestAPI enables the EVM test API +enable_test_api = true \ No newline at end of file diff --git a/docker/rpcnode/config/app.toml b/docker/rpcnode/config/app.toml index ce4a0569a..c930b798a 100644 --- a/docker/rpcnode/config/app.toml +++ b/docker/rpcnode/config/app.toml @@ -260,4 +260,9 @@ ss-prune-interval = 60 # ImportNumWorkers defines the concurrency for state sync import # defaults to 1 -ss-import-num-workers = 1 \ No newline at end of file +ss-import-num-workers = 1 + +[evm] + +# EnableTestAPI enables the EVM test API +enable_test_api = true \ No newline at end of file diff --git a/evmrpc/association.go b/evmrpc/association.go index fb3fda479..5d8af571e 100644 --- a/evmrpc/association.go +++ b/evmrpc/association.go @@ -11,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rpc" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" @@ -118,3 +119,44 @@ func decodeHexString(hexString string) ([]byte, error) { } return hex.DecodeString(trimmed) } + +func (t *AssociationAPI) GetCosmosTx(ctx context.Context, ethHash common.Hash) (result string, returnErr error) { + startTime := time.Now() + defer recordMetrics("sei_getCosmosTx", t.connectionType, startTime, returnErr == nil) + receipt, err := t.keeper.GetReceipt(t.ctxProvider(LatestCtxHeight), ethHash) + if err != nil { + return "", err + } + height := int64(receipt.BlockNumber) + number := rpc.BlockNumber(height) + numberPtr, err := getBlockNumber(ctx, t.tmClient, number) + if err != nil { + return "", err + } + block, err := blockByNumberWithRetry(ctx, t.tmClient, numberPtr, 1) + if err != nil { + return "", err + } + blockRes, err := blockResultsWithRetry(ctx, t.tmClient, &height) + if err != nil { + return "", err + } + for i := range blockRes.TxsResults { + tmTx := block.Block.Txs[i] + decoded, err := t.txDecoder(block.Block.Txs[i]) + if err != nil { + return "", err + } + for _, msg := range decoded.GetMsgs() { + switch m := msg.(type) { + case *types.MsgEVMTransaction: + ethtx, _ := m.AsTransaction() + hash := ethtx.Hash() + if hash == ethHash { + return fmt.Sprintf("%X", tmTx.Hash()), nil + } + } + } + } + return "", fmt.Errorf("transaction not found") +} diff --git a/evmrpc/association_test.go b/evmrpc/association_test.go index f9f6f03e5..893ac8365 100644 --- a/evmrpc/association_test.go +++ b/evmrpc/association_test.go @@ -43,3 +43,9 @@ func TestGetEvmAddress(t *testing.T) { body := sendRequestGoodWithNamespace(t, "sei", "getEVMAddress", "sei1mf0llhmqane5w2y8uynmghmk2w4mh0xll9seym") require.Equal(t, body["result"], "0x1df809C639027b465B931BD63Ce71c8E5834D9d6") } + +func TestGetCosmosTx(t *testing.T) { + body := sendRequestGoodWithNamespace(t, "sei", "getCosmosTx", "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e") + fmt.Println(body) + require.Equal(t, body["result"], "690D39ADF56D4C811B766DFCD729A415C36C4BFFE80D63E305373B9518EBFB14") +} diff --git a/evmrpc/block.go b/evmrpc/block.go index 81f834594..2b756d91f 100644 --- a/evmrpc/block.go +++ b/evmrpc/block.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/lib/ethapi" "github.com/ethereum/go-ethereum/rpc" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -152,12 +153,15 @@ func EncodeTmBlock( ) (map[string]interface{}, error) { number := big.NewInt(block.Block.Height) blockhash := common.HexToHash(block.BlockID.Hash.String()) + blockTime := block.Block.Time lastHash := common.HexToHash(block.Block.LastBlockID.Hash.String()) appHash := common.HexToHash(block.Block.AppHash.String()) txHash := common.HexToHash(block.Block.DataHash.String()) resultHash := common.HexToHash(block.Block.LastResultsHash.String()) miner := common.HexToAddress(block.Block.ProposerAddress.String()) + baseFeePerGas := k.GetBaseFeePerGas(ctx).TruncateInt().BigInt() gasLimit, gasWanted := int64(0), int64(0) + chainConfig := types.DefaultChainConfig().EthereumConfig(k.ChainID(ctx)) transactions := []interface{}{} for i, txRes := range blockRes.TxsResults { gasLimit += txRes.GasWanted @@ -181,7 +185,8 @@ func EncodeTmBlock( if err != nil { continue } - transactions = append(transactions, hydrateTransaction(ethtx, number, blockhash, receipt)) + newTx := ethapi.NewRPCTransaction(ethtx, blockhash, number.Uint64(), uint64(blockTime.Second()), uint64(receipt.TransactionIndex), baseFeePerGas, chainConfig) + transactions = append(transactions, newTx) } } } @@ -209,7 +214,7 @@ func EncodeTmBlock( "size": hexutil.Uint64(block.Block.Size()), "uncles": []common.Hash{}, // inapplicable to Sei "transactions": transactions, - "baseFeePerGas": (*hexutil.Big)(k.GetBaseFeePerGas(ctx).TruncateInt().BigInt()), + "baseFeePerGas": (*hexutil.Big)(baseFeePerGas), } if fullTx { result["totalDifficulty"] = (*hexutil.Big)(big.NewInt(0)) // inapplicable to Sei diff --git a/evmrpc/block_test.go b/evmrpc/block_test.go index 331158bdb..29aa42912 100644 --- a/evmrpc/block_test.go +++ b/evmrpc/block_test.go @@ -90,9 +90,9 @@ func verifyBlockResult(t *testing.T, resObj map[string]interface{}) { require.Equal(t, "0x65254651", resObj["timestamp"]) tx := resObj["transactions"].([]interface{})[0].(map[string]interface{}) require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", tx["blockHash"]) - require.Equal(t, "0x1234567890123456789012345678901234567890", tx["from"]) + require.Equal(t, "0x5b4eba929f3811980f5ae0c5d04fa200f837df4e", tx["from"]) require.Equal(t, "0x3e8", tx["gas"]) - require.Equal(t, "0xa", tx["gasPrice"]) + require.Equal(t, "0x0", tx["gasPrice"]) require.Equal(t, "0xa", tx["maxFeePerGas"]) require.Equal(t, "0x0", tx["maxPriorityFeePerGas"]) require.Equal(t, "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e", tx["hash"]) diff --git a/evmrpc/config.go b/evmrpc/config.go index f596acbf1..c53bc5965 100644 --- a/evmrpc/config.go +++ b/evmrpc/config.go @@ -83,6 +83,9 @@ type Config struct { // max number of concurrent NewHead subscriptions MaxSubscriptionsNewHead uint64 `mapstructure:"max_subscriptions_new_head"` + // test api enables certain override apis for integration test situations + EnableTestAPI bool `mapstructure:"enable_test_api"` + // The EVM tracer to use when doing node synchronization, applies to // all block produced but traces only EVM transactions. // @@ -111,6 +114,7 @@ var DefaultConfig = Config{ MaxLogNoBlock: 10000, MaxBlocksForLog: 2000, MaxSubscriptionsNewHead: 10000, + EnableTestAPI: false, LiveEVMTracer: "", } @@ -135,6 +139,7 @@ const ( flagMaxLogNoBlock = "evm.max_log_no_block" flagMaxBlocksForLog = "evm.max_blocks_for_log" flagMaxSubscriptionsNewHead = "evm.max_subscriptions_new_head" + flagEnableTestAPI = "evm.enable_test_api" flagLiveEVMTracer = "evm.live_evm_tracer" ) @@ -241,6 +246,11 @@ func ReadConfig(opts servertypes.AppOptions) (Config, error) { return cfg, err } } + if v := opts.Get(flagEnableTestAPI); v != nil { + if cfg.EnableTestAPI, err = cast.ToBoolE(v); err != nil { + return cfg, err + } + } if v := opts.Get(flagLiveEVMTracer); v != nil { if cfg.LiveEVMTracer, err = cast.ToStringE(v); err != nil { return cfg, err diff --git a/evmrpc/config_test.go b/evmrpc/config_test.go index c1fbec70a..14c0d99c7 100644 --- a/evmrpc/config_test.go +++ b/evmrpc/config_test.go @@ -30,6 +30,7 @@ type opts struct { maxLogNoBlock interface{} maxBlocksForLog interface{} maxSubscriptionsNewHead interface{} + enableTestAPI interface{} liveEVMTracer interface{} } @@ -94,6 +95,9 @@ func (o *opts) Get(k string) interface{} { if k == "evm.max_subscriptions_new_head" { return o.maxSubscriptionsNewHead } + if k == "evm.enable_test_api" { + return o.enableTestAPI + } if k == "evm.live_evm_tracer" { return o.liveEVMTracer } @@ -122,6 +126,7 @@ func TestReadConfig(t *testing.T) { 20000, 1000, 10000, + false, "", } _, err := evmrpc.ReadConfig(&goodOpts) diff --git a/evmrpc/info.go b/evmrpc/info.go index 89e391ad7..f1c0313d4 100644 --- a/evmrpc/info.go +++ b/evmrpc/info.go @@ -24,10 +24,11 @@ type InfoAPI struct { txDecoder sdk.TxDecoder homeDir string connectionType ConnectionType + maxBlocks int64 } -func NewInfoAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txDecoder sdk.TxDecoder, homeDir string, connectionType ConnectionType) *InfoAPI { - return &InfoAPI{tmClient: tmClient, keeper: k, ctxProvider: ctxProvider, txDecoder: txDecoder, homeDir: homeDir, connectionType: connectionType} +func NewInfoAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txDecoder sdk.TxDecoder, homeDir string, maxBlocks int64, connectionType ConnectionType) *InfoAPI { + return &InfoAPI{tmClient: tmClient, keeper: k, ctxProvider: ctxProvider, txDecoder: txDecoder, homeDir: homeDir, connectionType: connectionType, maxBlocks: maxBlocks} } type FeeHistoryResult struct { @@ -93,9 +94,25 @@ func (i *InfoAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64 defer recordMetrics("eth_feeHistory", i.connectionType, startTime, returnErr == nil) result = &FeeHistoryResult{} + // logic consistent with go-ethereum's validation (block < 1 means no block) + if blockCount < 1 { + return result, nil + } + + // default go-ethereum max block history is 1024 + // https://github.com/ethereum/go-ethereum/blob/master/eth/gasprice/feehistory.go#L235 + if blockCount > math.HexOrDecimal64(i.maxBlocks) { + blockCount = math.HexOrDecimal64(i.maxBlocks) + } + + // if someone needs more than 100 reward percentiles, we can discuss, but it's not likely + if len(rewardPercentiles) > 100 { + return nil, errors.New("rewardPercentiles length must be less than or equal to 100") + } + // validate reward percentiles for i, p := range rewardPercentiles { - if p < 0 || p > 100 || (i > 0 && p < rewardPercentiles[i-1]) { + if p < 0 || p > 100 || (i > 0 && p <= rewardPercentiles[i-1]) { return nil, errors.New("invalid reward percentiles: must be ascending and between 0 and 100") } } diff --git a/evmrpc/info_test.go b/evmrpc/info_test.go index 4abe20680..e55538007 100644 --- a/evmrpc/info_test.go +++ b/evmrpc/info_test.go @@ -1,6 +1,7 @@ package evmrpc_test import ( + "errors" "math/big" "testing" @@ -28,7 +29,7 @@ func TestChainID(t *testing.T) { func TestAccounts(t *testing.T) { homeDir := t.TempDir() - api := evmrpc.NewInfoAPI(nil, nil, nil, nil, homeDir, evmrpc.ConnectionTypeHTTP) + api := evmrpc.NewInfoAPI(nil, nil, nil, nil, homeDir, 1024, evmrpc.ConnectionTypeHTTP) clientCtx := client.Context{}.WithViper("").WithHomeDir(homeDir) clientCtx, err := config.ReadFromClientConfig(clientCtx) require.Nil(t, err) @@ -64,42 +65,60 @@ func TestGasPrice(t *testing.T) { } func TestFeeHistory(t *testing.T) { - bodyByNumber := []interface{}{"0x1", "0x8", []interface{}{0.5}} - bodyByLatest := []interface{}{"0x1", "latest", []interface{}{0.5}} - bodyByEarliest := []interface{}{"0x1", "earliest", []interface{}{0.5}} - bodyOld := []interface{}{"0x1", "0x1", []interface{}{0.5}} - bodyFuture := []interface{}{"0x1", "0x9", []interface{}{0.5}} - expectedOldest := []string{"0x1", "0x1", "0x1", "0x1", "0x1"} - Ctx = Ctx.WithBlockHeight(1) - for i, body := range [][]interface{}{ - bodyByNumber, bodyByLatest, bodyByEarliest, bodyOld, bodyFuture, - } { - resObj := sendRequestGood(t, "feeHistory", body...) - resObj = resObj["result"].(map[string]interface{}) - require.Equal(t, expectedOldest[i], resObj["oldestBlock"].(string)) - rewards := resObj["reward"].([]interface{}) - require.Equal(t, 1, len(rewards)) - reward := rewards[0].([]interface{}) - require.Equal(t, 1, len(reward)) - require.Equal(t, "0xa", reward[0].(string)) - baseFeePerGas := resObj["baseFeePerGas"].([]interface{}) - require.Equal(t, 1, len(baseFeePerGas)) - require.Equal(t, "0x0", baseFeePerGas[0].(string)) - gasUsedRatio := resObj["gasUsedRatio"].([]interface{}) - require.Equal(t, 1, len(gasUsedRatio)) - require.Equal(t, 0.5, gasUsedRatio[0].(float64)) + type feeHistoryTestCase struct { + name string + blockCount interface{} + lastBlock interface{} // Changed to interface{} to handle different types + rewardPercentiles interface{} + expectedOldest string + expectedReward string + expectedBaseFee string + expectedGasUsed float64 + expectedError error } - // bad percentile - outOfRangeBody1 := []interface{}{"0x1", "0x8", []interface{}{-1}} - outOfRangeBody2 := []interface{}{"0x1", "0x8", []interface{}{101}} - outOfOrderBody := []interface{}{"0x1", "0x8", []interface{}{99, 1}} - for _, body := range [][]interface{}{outOfRangeBody1, outOfRangeBody2, outOfOrderBody} { - resObj := sendRequestGood(t, "feeHistory", body...) - errMap := resObj["error"].(map[string]interface{}) - require.Equal(t, "invalid reward percentiles: must be ascending and between 0 and 100", errMap["message"].(string)) + Ctx = Ctx.WithBlockHeight(1) // Simulate context with a specific block height + + testCases := []feeHistoryTestCase{ + {name: "Valid request by number", blockCount: 1, lastBlock: "0x8", rewardPercentiles: []interface{}{0.5}, expectedOldest: "0x1", expectedReward: "0xa", expectedBaseFee: "0x0", expectedGasUsed: 0.5}, + {name: "Valid request by latest", blockCount: 1, lastBlock: "latest", rewardPercentiles: []interface{}{0.5}, expectedOldest: "0x1", expectedReward: "0xa", expectedBaseFee: "0x0", expectedGasUsed: 0.5}, + {name: "Valid request by earliest", blockCount: 1, lastBlock: "earliest", rewardPercentiles: []interface{}{0.5}, expectedOldest: "0x1", expectedReward: "0xa", expectedBaseFee: "0x0", expectedGasUsed: 0.5}, + {name: "Request on the same block", blockCount: 1, lastBlock: "0x1", rewardPercentiles: []interface{}{0.5}, expectedOldest: "0x1", expectedReward: "0xa", expectedBaseFee: "0x0", expectedGasUsed: 0.5}, + {name: "Request on future block", blockCount: 1, lastBlock: "0x9", rewardPercentiles: []interface{}{0.5}, expectedOldest: "0x1", expectedReward: "0xa", expectedBaseFee: "0x0", expectedGasUsed: 0.5}, + {name: "Block count truncates", blockCount: 1025, lastBlock: "latest", rewardPercentiles: []interface{}{25}, expectedOldest: "0x1", expectedReward: "0xa", expectedBaseFee: "0x0", expectedGasUsed: 0.5}, + {name: "Too many percentiles", blockCount: 10, lastBlock: "latest", rewardPercentiles: make([]interface{}, 101), expectedError: errors.New("rewardPercentiles length must be less than or equal to 100")}, + {name: "Invalid percentiles order", blockCount: 10, lastBlock: "latest", rewardPercentiles: []interface{}{99, 1}, expectedError: errors.New("invalid reward percentiles: must be ascending and between 0 and 100")}, } - Ctx = Ctx.WithBlockHeight(8) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Mimic request sending and handle the response + resObj := sendRequestGood(t, "feeHistory", tc.blockCount, tc.lastBlock, tc.rewardPercentiles) + if tc.expectedError != nil { + errMap := resObj["error"].(map[string]interface{}) + require.Equal(t, tc.expectedError.Error(), errMap["message"].(string)) + } else { + _, errorExists := resObj["error"] + require.False(t, errorExists) + + resObj = resObj["result"].(map[string]interface{}) + require.Equal(t, tc.expectedOldest, resObj["oldestBlock"].(string)) + rewards, ok := resObj["reward"].([]interface{}) + + require.True(t, ok, "Expected rewards to be a slice of interfaces") + require.Equal(t, 1, len(rewards), "Expected exactly one reward entry") + reward, ok := rewards[0].([]interface{}) + require.True(t, ok, "Expected reward to be a slice of interfaces") + require.Equal(t, 1, len(reward), "Expected exactly one sub-item in reward") + require.Equal(t, tc.expectedReward, reward[0].(string), "Reward does not match expected value") + + require.Equal(t, tc.expectedBaseFee, resObj["baseFeePerGas"].([]interface{})[0].(string)) + require.Equal(t, tc.expectedGasUsed, resObj["gasUsedRatio"].([]interface{})[0].(float64)) + } + }) + } + + Ctx = Ctx.WithBlockHeight(8) // Reset context to a new block height } func TestCalculatePercentiles(t *testing.T) { diff --git a/evmrpc/server.go b/evmrpc/server.go index dfa7156eb..11c1ba672 100644 --- a/evmrpc/server.go +++ b/evmrpc/server.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/rpc" + evmCfg "github.com/sei-protocol/sei-chain/x/evm/config" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/tendermint/tendermint/libs/log" rpcclient "github.com/tendermint/tendermint/rpc/client" @@ -42,6 +43,8 @@ func NewEVMHTTPServer( } simulateConfig := &SimulateConfig{GasCap: config.SimulationGasLimit, EVMTimeout: config.SimulationEVMTimeout} sendAPI := NewSendAPI(tmClient, txConfig, &SendConfig{slow: config.Slow}, k, ctxProvider, homeDir, simulateConfig, ConnectionTypeHTTP) + ctx := ctxProvider(LatestCtxHeight) + apis := []rpc.API{ { Namespace: "echo", @@ -61,7 +64,7 @@ func NewEVMHTTPServer( }, { Namespace: "eth", - Service: NewInfoAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), homeDir, ConnectionTypeHTTP), + Service: NewInfoAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), homeDir, config.MaxBlocksForLog, ConnectionTypeHTTP), }, { Namespace: "eth", @@ -96,6 +99,17 @@ func NewEVMHTTPServer( Service: NewDebugAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), simulateConfig, ConnectionTypeHTTP), }, } + // Test API can only exist on non-live chain IDs. These APIs instrument certain overrides. + if config.EnableTestAPI && !evmCfg.IsLiveChainID(ctx) { + logger.Info("Enabling Test EVM APIs") + apis = append(apis, rpc.API{ + Namespace: "test", + Service: NewTestAPI(), + }) + } else { + logger.Info("Disabling Test EVM APIs", "liveChainID", evmCfg.IsLiveChainID(ctx), "enableTestAPI", config.EnableTestAPI) + } + if err := httpServer.EnableRPC(apis, HTTPConfig{ CorsAllowedOrigins: strings.Split(config.CORSOrigins, ","), Vhosts: []string{"*"}, @@ -143,7 +157,7 @@ func NewEVMWebSocketServer( }, { Namespace: "eth", - Service: NewInfoAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), homeDir, ConnectionTypeWS), + Service: NewInfoAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), homeDir, config.MaxBlocksForLog, ConnectionTypeWS), }, { Namespace: "eth", diff --git a/evmrpc/simulate.go b/evmrpc/simulate.go index f5067ccf8..a6d3d3e98 100644 --- a/evmrpc/simulate.go +++ b/evmrpc/simulate.go @@ -283,7 +283,10 @@ func (b *Backend) StateAtTransaction(ctx context.Context, block *ethtypes.Block, // Recompute transactions up to the target index. (only doing EVM at the moment, but should do both EVM + Cosmos) signer := ethtypes.MakeSigner(b.ChainConfig(), block.Number(), block.Time()) for idx, tx := range block.Transactions() { - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) + msg, err := core.TransactionToMessage(tx, signer, block.BaseFee()) + if err != nil { + return nil, vm.BlockContext{}, nil, nil, err + } txContext := core.NewEVMTxContext(msg) blockContext, err := b.keeper.GetVMBlockContext(b.ctxProvider(prevBlockHeight), core.GasPool(b.RPCGasCap())) if err != nil { @@ -351,11 +354,7 @@ func (b *Backend) GetEVM(_ context.Context, msg *core.Message, stateDB vm.StateD if blockCtx == nil { blockCtx, _ = b.keeper.GetVMBlockContext(b.ctxProvider(LatestCtxHeight), core.GasPool(b.RPCGasCap())) } - evm := vm.NewEVM(*blockCtx, txContext, stateDB, b.ChainConfig(), *vmConfig) - if dbImpl, ok := stateDB.(*state.DBImpl); ok { - dbImpl.SetEVM(evm) - } - return evm + return vm.NewEVM(*blockCtx, txContext, stateDB, b.ChainConfig(), *vmConfig) } func (b *Backend) CurrentHeader() *ethtypes.Header { diff --git a/evmrpc/simulate_test.go b/evmrpc/simulate_test.go index 28b5a06f0..b626ba637 100644 --- a/evmrpc/simulate_test.go +++ b/evmrpc/simulate_test.go @@ -62,7 +62,7 @@ func TestEstimateGas(t *testing.T) { } resObj = sendRequestGood(t, "estimateGas", txArgs, nil, map[string]interface{}{}) result = resObj["result"].(string) - require.Equal(t, "0x53f3", result) // 21491 + require.Equal(t, "0x53f9", result) // 21497 Ctx = Ctx.WithBlockHeight(8) } @@ -127,7 +127,7 @@ func TestCall(t *testing.T) { } resObj := sendRequestGood(t, "call", txArgs, nil, map[string]interface{}{}, map[string]interface{}{}) result := resObj["result"].(string) - require.Equal(t, "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c806360fe47b1146100385780636d4ce63c14610054575b5f80fd5b610052600480360381019061004d91906100f1565b610072565b005b61005c6100b2565b604051610069919061012b565b60405180910390f35b805f819055507f0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1816040516100a7919061012b565b60405180910390a150565b5f8054905090565b5f80fd5b5f819050919050565b6100d0816100be565b81146100da575f80fd5b50565b5f813590506100eb816100c7565b92915050565b5f60208284031215610106576101056100ba565b5b5f610113848285016100dd565b91505092915050565b610125816100be565b82525050565b5f60208201905061013e5f83018461011c565b9291505056fea26469706673582212205b2eaa3bd967fbbfe4490610612964348d1d0b2a793d2b0d117fe05ccb02d1e364736f6c63430008150033", result) // 21325 + require.Equal(t, "0x608060405234801561000f575f80fd5b506004361061003f575f3560e01c806360fe47b1146100435780636d4ce63c1461005f5780639c3674fc1461007d575b5f80fd5b61005d6004803603810190610058919061010a565b610087565b005b6100676100c7565b6040516100749190610144565b60405180910390f35b6100856100cf565b005b805f819055507f0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1816040516100bc9190610144565b60405180910390a150565b5f8054905090565b5f80fd5b5f80fd5b5f819050919050565b6100e9816100d7565b81146100f3575f80fd5b50565b5f81359050610104816100e0565b92915050565b5f6020828403121561011f5761011e6100d3565b5b5f61012c848285016100f6565b91505092915050565b61013e816100d7565b82525050565b5f6020820190506101575f830184610135565b9291505056fea2646970667358221220bb55137839ea2afda11ab2d30ad07fee30bb9438caaa46e30ccd1053ed72439064736f6c63430008150033", result) Ctx = Ctx.WithBlockHeight(8) } diff --git a/evmrpc/subscribe.go b/evmrpc/subscribe.go index b2abb4303..f7b2bbe0b 100644 --- a/evmrpc/subscribe.go +++ b/evmrpc/subscribe.go @@ -20,6 +20,7 @@ import ( ) const SleepInterval = 5 * time.Second +const NewHeadsListenerBuffer = 10 type SubscriptionAPI struct { tmClient rpcclient.Client @@ -64,17 +65,14 @@ func NewSubscriptionAPI(tmClient rpcclient.Client, logFetcher *LogFetcher, subsc continue } api.newHeadListenersMtx.Lock() - for _, c := range api.newHeadListeners { - c := c - go func() { - defer func() { - // if the channel is already closed, sending to it will panic - if err := recover(); err != nil { - return - } - }() - c <- ethHeader - }() + toDelete := []rpc.ID{} + for id, c := range api.newHeadListeners { + if !handleListener(c, ethHeader) { + toDelete = append(toDelete, id) + } + } + for _, id := range toDelete { + delete(api.newHeadListeners, id) } api.newHeadListenersMtx.Unlock() } @@ -82,6 +80,20 @@ func NewSubscriptionAPI(tmClient rpcclient.Client, logFetcher *LogFetcher, subsc return api } +func handleListener(c chan map[string]interface{}, ethHeader map[string]interface{}) bool { + // if the channel is already closed, sending to it/closing it will panic + defer func() { _ = recover() }() + select { + case c <- ethHeader: + return true + default: + // this path is hit when the buffer is full, meaning that the subscriber is not consuming + // fast enough + close(c) + return false + } +} + func (a *SubscriptionAPI) NewHeads(ctx context.Context) (s *rpc.Subscription, err error) { defer recordMetrics("eth_newHeads", a.connectionType, time.Now(), err == nil) notifier, supported := rpc.NotifierFromContext(ctx) @@ -90,7 +102,7 @@ func (a *SubscriptionAPI) NewHeads(ctx context.Context) (s *rpc.Subscription, er } rpcSub := notifier.CreateSubscription() - listener := make(chan map[string]interface{}) + listener := make(chan map[string]interface{}, NewHeadsListenerBuffer) a.newHeadListenersMtx.Lock() defer a.newHeadListenersMtx.Unlock() if uint64(len(a.newHeadListeners)) >= a.subscriptonConfig.newHeadLimit { @@ -102,11 +114,14 @@ func (a *SubscriptionAPI) NewHeads(ctx context.Context) (s *rpc.Subscription, er OUTER: for { select { - case res := <-listener: + case res, ok := <-listener: err = notifier.Notify(rpcSub.ID, res) if err != nil { break OUTER } + if !ok { + break OUTER + } case <-rpcSub.Err(): break OUTER case <-notifier.Closed(): @@ -116,6 +131,7 @@ func (a *SubscriptionAPI) NewHeads(ctx context.Context) (s *rpc.Subscription, er a.newHeadListenersMtx.Lock() defer a.newHeadListenersMtx.Unlock() delete(a.newHeadListeners, rpcSub.ID) + defer func() { _ = recover() }() // might have already been closed close(listener) }() diff --git a/evmrpc/test.go b/evmrpc/test.go new file mode 100644 index 000000000..db9607539 --- /dev/null +++ b/evmrpc/test.go @@ -0,0 +1,23 @@ +package evmrpc + +import ( + "errors" + + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" +) + +type TestAPI struct{} + +func NewTestAPI() *TestAPI { + return &TestAPI{} +} + +func (a *TestAPI) IncrementPointerVersion(pointerType string, offset int16) error { + switch pointerType { + case "cw20": + cw20.SetVersionWithOffset(offset) + default: + return errors.New("invalid pointer type") + } + return nil +} diff --git a/evmrpc/tx.go b/evmrpc/tx.go index 16164cfa7..805d670fb 100644 --- a/evmrpc/tx.go +++ b/evmrpc/tx.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/lib/ethapi" "github.com/ethereum/go-ethereum/rpc" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -68,7 +69,7 @@ func (t *TransactionAPI) GetVMError(hash common.Hash) (result string, returnErr return receipt.VmError, nil } -func (t *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (result *RPCTransaction, returnErr error) { +func (t *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (result *ethapi.RPCTransaction, returnErr error) { startTime := time.Now() defer recordMetrics("eth_getTransactionByBlockNumberAndIndex", t.connectionType, startTime, returnErr == nil) blockNumber, err := getBlockNumber(ctx, t.tmClient, blockNr) @@ -82,7 +83,7 @@ func (t *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context return t.getTransactionWithBlock(block, index) } -func (t *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (result *RPCTransaction, returnErr error) { +func (t *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (result *ethapi.RPCTransaction, returnErr error) { startTime := time.Now() defer recordMetrics("eth_getTransactionByBlockHashAndIndex", t.connectionType, startTime, returnErr == nil) block, err := blockByHash(ctx, t.tmClient, blockHash[:]) @@ -92,7 +93,7 @@ func (t *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, return t.getTransactionWithBlock(block, index) } -func (t *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (result *RPCTransaction, returnErr error) { +func (t *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (result *ethapi.RPCTransaction, returnErr error) { startTime := time.Now() defer recordMetrics("eth_getTransactionByHash", t.connectionType, startTime, returnErr == nil) sdkCtx := t.ctxProvider(LatestCtxHeight) @@ -112,7 +113,7 @@ func (t *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.H ) from, _ := ethtypes.Sender(signer, etx) v, r, s := etx.RawSignatureValues() - res := RPCTransaction{ + res := ethapi.RPCTransaction{ Type: hexutil.Uint64(etx.Type()), From: from, Gas: hexutil.Uint64(etx.Gas()), @@ -181,7 +182,7 @@ func (t *TransactionAPI) GetTransactionCount(ctx context.Context, address common return (*hexutil.Uint64)(&nonce), nil } -func (t *TransactionAPI) getTransactionWithBlock(block *coretypes.ResultBlock, index hexutil.Uint) (*RPCTransaction, error) { +func (t *TransactionAPI) getTransactionWithBlock(block *coretypes.ResultBlock, index hexutil.Uint) (*ethapi.RPCTransaction, error) { if int(index) >= len(block.Block.Txs) { return nil, nil } @@ -193,8 +194,14 @@ func (t *TransactionAPI) getTransactionWithBlock(block *coretypes.ResultBlock, i if err != nil { return nil, err } - res := hydrateTransaction(ethtx, big.NewInt(block.Block.Height), common.HexToHash(block.BlockID.Hash.String()), receipt) - return &res, nil + height := int64(receipt.BlockNumber) + baseFeePerGas := t.keeper.GetBaseFee(t.ctxProvider(height)) + chainConfig := types.DefaultChainConfig().EthereumConfig(t.keeper.ChainID(t.ctxProvider(height))) + blockHash := common.HexToHash(block.BlockID.Hash.String()) + blockNumber := uint64(block.Block.Height) + blockTime := block.Block.Time + res := ethapi.NewRPCTransaction(ethtx, blockHash, blockNumber, uint64(blockTime.Second()), uint64(receipt.TransactionIndex), baseFeePerGas, chainConfig) + return res, nil } func (t *TransactionAPI) Sign(addr common.Address, data hexutil.Bytes) (result hexutil.Bytes, returnErr error) { diff --git a/evmrpc/tx_test.go b/evmrpc/tx_test.go index cb88886c0..002c31f87 100644 --- a/evmrpc/tx_test.go +++ b/evmrpc/tx_test.go @@ -117,7 +117,7 @@ func TestGetTransaction(t *testing.T) { resObj = resObj["result"].(map[string]interface{}) require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", resObj["blockHash"].(string)) require.Equal(t, "0x8", resObj["blockNumber"].(string)) - require.Equal(t, "0x1234567890123456789012345678901234567890", resObj["from"].(string)) + require.Equal(t, "0x5b4eba929f3811980f5ae0c5d04fa200f837df4e", resObj["from"].(string)) require.Equal(t, "0x3e8", resObj["gas"].(string)) require.Equal(t, "0xa", resObj["gasPrice"].(string)) require.Equal(t, "0xa", resObj["maxFeePerGas"].(string)) @@ -226,7 +226,7 @@ func TestGetTransactionError(t *testing.T) { func TestSign(t *testing.T) { homeDir := t.TempDir() txApi := evmrpc.NewTransactionAPI(nil, nil, nil, nil, homeDir, evmrpc.ConnectionTypeHTTP) - infoApi := evmrpc.NewInfoAPI(nil, nil, nil, nil, homeDir, evmrpc.ConnectionTypeHTTP) + infoApi := evmrpc.NewInfoAPI(nil, nil, nil, nil, homeDir, 1024, evmrpc.ConnectionTypeHTTP) clientCtx := client.Context{}.WithViper("").WithHomeDir(homeDir) clientCtx, err := config.ReadFromClientConfig(clientCtx) require.Nil(t, err) diff --git a/evmrpc/txpool.go b/evmrpc/txpool.go index 8f77d996a..95d90bd1e 100644 --- a/evmrpc/txpool.go +++ b/evmrpc/txpool.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/lib/ethapi" "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/evm/types" rpcclient "github.com/tendermint/tendermint/rpc/client" @@ -31,12 +32,12 @@ func NewTxPoolAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func( } // For now, we put all unconfirmed txs in pending and none in queued -func (t *TxPoolAPI) Content(ctx context.Context) (result map[string]map[string]map[string]*RPCTransaction, returnErr error) { +func (t *TxPoolAPI) Content(ctx context.Context) (result map[string]map[string]map[string]*ethapi.RPCTransaction, returnErr error) { startTime := time.Now() defer recordMetrics("sei_content", t.connectionType, startTime, returnErr == nil) - content := map[string]map[string]map[string]*RPCTransaction{ - "pending": make(map[string]map[string]*RPCTransaction), - "queued": make(map[string]map[string]*RPCTransaction), + content := map[string]map[string]map[string]*ethapi.RPCTransaction{ + "pending": make(map[string]map[string]*ethapi.RPCTransaction), + "queued": make(map[string]map[string]*ethapi.RPCTransaction), } total := t.txPoolConfig.maxNumTxs @@ -63,14 +64,15 @@ func (t *TxPoolAPI) Content(ctx context.Context) (result map[string]map[string]m } nonce := ethTx.Nonce() - res := hydratePendingTransaction(ethTx) + chainConfig := types.DefaultChainConfig().EthereumConfig(t.keeper.ChainID(sdkCtx)) + res := ethapi.NewRPCPendingTransaction(ethTx, nil, chainConfig) nonceStr := strconv.FormatUint(nonce, 10) if content["pending"][fromAddr.String()] == nil { - content["pending"][fromAddr.String()] = map[string]*RPCTransaction{ - nonceStr: &res, + content["pending"][fromAddr.String()] = map[string]*ethapi.RPCTransaction{ + nonceStr: res, } } else { - content["pending"][fromAddr.String()][nonceStr] = &res + content["pending"][fromAddr.String()][nonceStr] = res } } return content, nil diff --git a/evmrpc/utils.go b/evmrpc/utils.go index 7b4c84aae..4e8a8e311 100644 --- a/evmrpc/utils.go +++ b/evmrpc/utils.go @@ -15,15 +15,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rpc" "github.com/sei-protocol/sei-chain/utils/metrics" - "github.com/sei-protocol/sei-chain/x/evm/ante" "github.com/sei-protocol/sei-chain/x/evm/keeper" - "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/tendermint/tendermint/libs/bytes" rpcclient "github.com/tendermint/tendermint/rpc/client" "github.com/tendermint/tendermint/rpc/coretypes" @@ -36,110 +31,6 @@ const LatestCtxHeight int64 = -1 // the block is exactly half-utilized. const GasUsedRatio float64 = 0.5 -type RPCTransaction struct { - BlockHash *common.Hash `json:"blockHash"` - BlockNumber *hexutil.Big `json:"blockNumber"` - From common.Address `json:"from"` - Gas hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` - GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` - MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` - Hash common.Hash `json:"hash"` - Input hexutil.Bytes `json:"input"` - Nonce hexutil.Uint64 `json:"nonce"` - To *common.Address `json:"to"` - TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` - Value *hexutil.Big `json:"value"` - Type hexutil.Uint64 `json:"type"` - Accesses *ethtypes.AccessList `json:"accessList,omitempty"` - ChainID *hexutil.Big `json:"chainId,omitempty"` - BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` - V *hexutil.Big `json:"v"` - R *hexutil.Big `json:"r"` - S *hexutil.Big `json:"s"` - YParity *hexutil.Uint64 `json:"yParity,omitempty"` -} - -func hydrateTransaction( - tx *ethtypes.Transaction, - blocknumber *big.Int, - blockhash common.Hash, - receipt *types.Receipt, -) RPCTransaction { - idx := hexutil.Uint64(receipt.TransactionIndex) - al := tx.AccessList() - v, r, s := tx.RawSignatureValues() - var yparity *hexutil.Uint64 - if tx.Type() != ethtypes.LegacyTxType { - yp := hexutil.Uint64(v.Sign()) - yparity = &yp - } - return RPCTransaction{ - BlockHash: &blockhash, - BlockNumber: (*hexutil.Big)(blocknumber), - From: common.HexToAddress(receipt.From), - Gas: hexutil.Uint64(tx.Gas()), - GasPrice: (*hexutil.Big)(tx.GasPrice()), - GasFeeCap: (*hexutil.Big)(tx.GasFeeCap()), - GasTipCap: (*hexutil.Big)(tx.GasTipCap()), - MaxFeePerBlobGas: (*hexutil.Big)(tx.BlobGasFeeCap()), - Hash: tx.Hash(), - Input: tx.Data(), - Nonce: hexutil.Uint64(tx.Nonce()), - To: tx.To(), - Type: hexutil.Uint64(tx.Type()), - TransactionIndex: &idx, - Value: (*hexutil.Big)(tx.Value()), - Accesses: &al, - ChainID: (*hexutil.Big)(tx.ChainId()), - BlobVersionedHashes: tx.BlobHashes(), - V: (*hexutil.Big)(v), - S: (*hexutil.Big)(s), - R: (*hexutil.Big)(r), - YParity: yparity, - } -} - -func hydratePendingTransaction( - tx *ethtypes.Transaction, -) RPCTransaction { - v, r, s := tx.RawSignatureValues() - v = ante.AdjustV(v, tx.Type(), tx.ChainId()) - var yparity *hexutil.Uint64 - if tx.Type() != ethtypes.LegacyTxType { - yp := hexutil.Uint64(v.Sign()) - yparity = &yp - } - al := tx.AccessList() - signer := ethtypes.NewCancunSigner(tx.ChainId()) - fromAddr, err := signer.Sender(tx) - if err != nil { - return RPCTransaction{} - } - return RPCTransaction{ - From: fromAddr, - Gas: hexutil.Uint64(tx.Gas()), - GasPrice: (*hexutil.Big)(tx.GasPrice()), - GasFeeCap: (*hexutil.Big)(tx.GasFeeCap()), - GasTipCap: (*hexutil.Big)(tx.GasTipCap()), - MaxFeePerBlobGas: (*hexutil.Big)(tx.BlobGasFeeCap()), - Hash: tx.Hash(), - Input: tx.Data(), - Nonce: hexutil.Uint64(tx.Nonce()), - To: tx.To(), - Value: (*hexutil.Big)(tx.Value()), - Type: hexutil.Uint64(tx.Type()), - Accesses: &al, - ChainID: (*hexutil.Big)(tx.ChainId()), - BlobVersionedHashes: tx.BlobHashes(), - V: (*hexutil.Big)(v), - S: (*hexutil.Big)(s), - R: (*hexutil.Big)(r), - YParity: yparity, - } -} - func GetBlockNumberByNrOrHash(ctx context.Context, tmClient rpcclient.Client, blockNrOrHash rpc.BlockNumberOrHash) (*int64, error) { if blockNrOrHash.BlockHash != nil { res, err := blockByHash(ctx, tmClient, blockNrOrHash.BlockHash[:]) diff --git a/example/contracts/README b/example/contracts/README index 520262542..fac3bbdb4 100644 --- a/example/contracts/README +++ b/example/contracts/README @@ -10,9 +10,9 @@ make make devtools # Compile sol -solc --bin -o example/contracts/sendall example/contracts/sendall/SendAll.sol -solc @openzeppelin=contracts/lib/openzeppelin-contracts --bin -o x/evm/artifacts contracts/src/CW721ERC721Wrapper.sol +solc --bin -o example/contracts/simplestorage example/contracts/simplestorage/SimpleStorage.sol +solc @openzeppelin=contracts/lib/openzeppelin-contracts --bin -o x/evm/artifacts/cw721 contracts/src/CW721ERC721Pointer.sol # Generate ABI in Go -solc --abi -o example/contracts/sendall example/contracts/sendall/SendAll.sol -abigen --abi=example/contracts/sendall/SendAll.abi --pkg=sendall --out=example/contracts/sendall/SendAll.go +solc --abi -o example/contracts/simplestorage example/contracts/simplestorage/SimpleStorage.sol +abigen --abi=example/contracts/simplestorage/SimpleStorage.abi --pkg=simplestorage --out=example/contracts/simplestorage/SimpleStorage.go diff --git a/example/contracts/erc2981/ERC2981Example.abi b/example/contracts/erc2981/ERC2981Example.abi new file mode 100644 index 000000000..156485d94 --- /dev/null +++ b/example/contracts/erc2981/ERC2981Example.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidDefaultRoyalty","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidDefaultRoyaltyReceiver","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidTokenRoyalty","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidTokenRoyaltyReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"setDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/example/contracts/erc2981/ERC2981Example.bin b/example/contracts/erc2981/ERC2981Example.bin new file mode 100644 index 000000000..add124eee --- /dev/null +++ b/example/contracts/erc2981/ERC2981Example.bin @@ -0,0 +1 @@ +608060405234801562000010575f80fd5b5060405162002798380380620027988339818101604052810190620000369190620001ea565b8181815f9081620000489190620004a4565b5080600190816200005a9190620004a4565b505050505062000588565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f80604083850312156200020357620002026200006e565b5b5f83015167ffffffffffffffff81111562000223576200022262000072565b5b6200023185828601620001b8565b925050602083015167ffffffffffffffff81111562000255576200025462000072565b5b6200026385828601620001b8565b9150509250929050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002bc57607f821691505b602082108103620002d257620002d162000277565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002f9565b620003428683620002f9565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200038c6200038662000380846200035a565b62000363565b6200035a565b9050919050565b5f819050919050565b620003a7836200036c565b620003bf620003b68262000393565b84845462000305565b825550505050565b5f90565b620003d5620003c7565b620003e28184846200039c565b505050565b5b818110156200040957620003fd5f82620003cb565b600181019050620003e8565b5050565b601f82111562000458576200042281620002d8565b6200042d84620002ea565b810160208510156200043d578190505b620004556200044c85620002ea565b830182620003e7565b50505b505050565b5f82821c905092915050565b5f6200047a5f19846008026200045d565b1980831691505092915050565b5f62000494838362000469565b9150826002028217905092915050565b620004af826200026d565b67ffffffffffffffff811115620004cb57620004ca6200008e565b5b620004d78254620002a4565b620004e48282856200040d565b5f60209050601f8311600181146200051a575f841562000505578287015190505b62000511858262000487565b86555062000580565b601f1984166200052a86620002d8565b5f5b8281101562000553578489015182556001820191506020850194506020810190506200052c565b868310156200057357848901516200056f601f89168262000469565b8355505b6001600288020188555050505b505050505050565b61220280620005965f395ff3fe608060405234801561000f575f80fd5b50600436106100fe575f3560e01c806370a0823111610095578063b88d4fde11610064578063b88d4fde146102bb578063ba19322d146102d7578063c87b56dd146102f5578063e985e9c514610325576100fe565b806370a082311461023557806395d89b4114610265578063a22cb46514610283578063b03b74aa1461029f576100fe565b806323b872dd116100d157806323b872dd1461019c5780632a55205a146101b857806342842e0e146101e95780636352211e14610205576100fe565b806301ffc9a71461010257806306fdde0314610132578063081812fc14610150578063095ea7b314610180575b5f80fd5b61011c60048036038101906101179190611918565b610355565b604051610129919061195d565b60405180910390f35b61013a6104f6565b6040516101479190611a00565b60405180910390f35b61016a60048036038101906101659190611a53565b610585565b6040516101779190611abd565b60405180910390f35b61019a60048036038101906101959190611b00565b6105a0565b005b6101b660048036038101906101b19190611b3e565b6105b6565b005b6101d260048036038101906101cd9190611b8e565b6106b5565b6040516101e0929190611bdb565b60405180910390f35b61020360048036038101906101fe9190611b3e565b610891565b005b61021f600480360381019061021a9190611a53565b6108b0565b60405161022c9190611abd565b60405180910390f35b61024f600480360381019061024a9190611c02565b6108c1565b60405161025c9190611c2d565b60405180910390f35b61026d610977565b60405161027a9190611a00565b60405180910390f35b61029d60048036038101906102989190611c70565b610a07565b005b6102b960048036038101906102b49190611c02565b610a1d565b005b6102d560048036038101906102d09190611dda565b610a2c565b005b6102df610a49565b6040516102ec9190611e69565b60405180910390f35b61030f600480360381019061030a9190611a53565b610a70565b60405161031c9190611a00565b60405180910390f35b61033f600480360381019061033a9190611e82565b610ad6565b60405161034c919061195d565b60405180910390f35b5f7f2a55205a000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061041f57507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061048757507f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806104ef57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b60605f805461050490611eed565b80601f016020809104026020016040519081016040528092919081815260200182805461053090611eed565b801561057b5780601f106105525761010080835404028352916020019161057b565b820191905f5260205f20905b81548152906001019060200180831161055e57829003601f168201915b5050505050905090565b5f61058f82610b64565b5061059982610bea565b9050919050565b6105b282826105ad610c23565b610c2a565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610626575f6040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161061d9190611abd565b60405180910390fd5b5f6106398383610634610c23565b610c3c565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146106af578382826040517f64283d7b0000000000000000000000000000000000000000000000000000000081526004016106a693929190611f1d565b60405180910390fd5b50505050565b5f805f60075f8681526020019081526020015f206040518060400160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff168152505090505f73ffffffffffffffffffffffffffffffffffffffff16815f015173ffffffffffffffffffffffffffffffffffffffff160361083e5760066040518060400160405290815f82015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020015f820160149054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff168152505090505b5f610847610e47565b6bffffffffffffffffffffffff1682602001516bffffffffffffffffffffffff16866108739190611f7f565b61087d9190611fed565b9050815f0151819350935050509250929050565b6108ab83838360405180602001604052805f815250610a2c565b505050565b5f6108ba82610b64565b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610932575f6040517f89c62b640000000000000000000000000000000000000000000000000000000081526004016109299190611abd565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b60606001805461098690611eed565b80601f01602080910402602001604051908101604052809291908181526020018280546109b290611eed565b80156109fd5780601f106109d4576101008083540402835291602001916109fd565b820191905f5260205f20905b8154815290600101906020018083116109e057829003601f168201915b5050505050905090565b610a19610a12610c23565b8383610e50565b5050565b610a2981612710610fb9565b50565b610a378484846105b6565b610a4384848484611154565b50505050565b5f7f2a55205a00000000000000000000000000000000000000000000000000000000905090565b6060610a7b82610b64565b505f610a85611306565b90505f815111610aa35760405180602001604052805f815250610ace565b80610aad8461131c565b604051602001610abe929190612057565b6040516020818303038152906040525b915050919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f80610b6f836113e6565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610be157826040517f7e273289000000000000000000000000000000000000000000000000000000008152600401610bd89190611c2d565b60405180910390fd5b80915050919050565b5f60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f33905090565b610c37838383600161141f565b505050565b5f80610c47846113e6565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610c8857610c878184866115de565b5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610d1357610cc75f855f8061141f565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825403925050819055505b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614610d9257600160035f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8460025f8681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4809150509392505050565b5f612710905090565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ec057816040517f5b08ba18000000000000000000000000000000000000000000000000000000008152600401610eb79190611abd565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610fac919061195d565b60405180910390a3505050565b5f610fc2610e47565b6bffffffffffffffffffffffff16905080826bffffffffffffffffffffffff1611156110275781816040517f6f483d0900000000000000000000000000000000000000000000000000000000815260040161101e9291906120ca565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611097575f6040517fb6d9900a00000000000000000000000000000000000000000000000000000000815260040161108e9190611abd565b60405180910390fd5b60405180604001604052808473ffffffffffffffffffffffffffffffffffffffff168152602001836bffffffffffffffffffffffff1681525060065f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506020820151815f0160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550905050505050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b1115611300578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02611197610c23565b8685856040518563ffffffff1660e01b81526004016111b99493929190612143565b6020604051808303815f875af19250505080156111f457506040513d601f19601f820116820180604052508101906111f191906121a1565b60015b611275573d805f8114611222576040519150601f19603f3d011682016040523d82523d5f602084013e611227565b606091505b505f81510361126d57836040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016112649190611abd565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146112fe57836040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016112f59190611abd565b60405180910390fd5b505b50505050565b606060405180602001604052805f815250905090565b60605f600161132a846116a1565b0190505f8167ffffffffffffffff81111561134857611347611cb6565b5b6040519080825280601f01601f19166020018201604052801561137a5781602001600182028036833780820191505090505b5090505f82602001820190505b6001156113db578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85816113d0576113cf611fc0565b5b0494505f8503611387575b819350505050919050565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b808061145757505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15611589575f61146684610b64565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156114d057508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b80156114e357506114e18184610ad6565b155b1561152557826040517fa9fbf51f00000000000000000000000000000000000000000000000000000000815260040161151c9190611abd565b60405180910390fd5b811561158757838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b8360045f8581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b6115e98383836117f2565b61169c575f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361165d57806040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016116549190611c2d565b60405180910390fd5b81816040517f177e802f000000000000000000000000000000000000000000000000000000008152600401611693929190611bdb565b60405180910390fd5b505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106116fd577a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083816116f3576116f2611fc0565b5b0492506040810190505b6d04ee2d6d415b85acef8100000000831061173a576d04ee2d6d415b85acef810000000083816117305761172f611fc0565b5b0492506020810190505b662386f26fc10000831061176957662386f26fc10000838161175f5761175e611fc0565b5b0492506010810190505b6305f5e1008310611792576305f5e100838161178857611787611fc0565b5b0492506008810190505b61271083106117b75761271083816117ad576117ac611fc0565b5b0492506004810190505b606483106117da57606483816117d0576117cf611fc0565b5b0492506002810190505b600a83106117e9576001810190505b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156118a957508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148061186a57506118698484610ad6565b5b806118a857508273ffffffffffffffffffffffffffffffffffffffff1661189083610bea565b73ffffffffffffffffffffffffffffffffffffffff16145b5b90509392505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6118f7816118c3565b8114611901575f80fd5b50565b5f81359050611912816118ee565b92915050565b5f6020828403121561192d5761192c6118bb565b5b5f61193a84828501611904565b91505092915050565b5f8115159050919050565b61195781611943565b82525050565b5f6020820190506119705f83018461194e565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156119ad578082015181840152602081019050611992565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6119d282611976565b6119dc8185611980565b93506119ec818560208601611990565b6119f5816119b8565b840191505092915050565b5f6020820190508181035f830152611a1881846119c8565b905092915050565b5f819050919050565b611a3281611a20565b8114611a3c575f80fd5b50565b5f81359050611a4d81611a29565b92915050565b5f60208284031215611a6857611a676118bb565b5b5f611a7584828501611a3f565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611aa782611a7e565b9050919050565b611ab781611a9d565b82525050565b5f602082019050611ad05f830184611aae565b92915050565b611adf81611a9d565b8114611ae9575f80fd5b50565b5f81359050611afa81611ad6565b92915050565b5f8060408385031215611b1657611b156118bb565b5b5f611b2385828601611aec565b9250506020611b3485828601611a3f565b9150509250929050565b5f805f60608486031215611b5557611b546118bb565b5b5f611b6286828701611aec565b9350506020611b7386828701611aec565b9250506040611b8486828701611a3f565b9150509250925092565b5f8060408385031215611ba457611ba36118bb565b5b5f611bb185828601611a3f565b9250506020611bc285828601611a3f565b9150509250929050565b611bd581611a20565b82525050565b5f604082019050611bee5f830185611aae565b611bfb6020830184611bcc565b9392505050565b5f60208284031215611c1757611c166118bb565b5b5f611c2484828501611aec565b91505092915050565b5f602082019050611c405f830184611bcc565b92915050565b611c4f81611943565b8114611c59575f80fd5b50565b5f81359050611c6a81611c46565b92915050565b5f8060408385031215611c8657611c856118bb565b5b5f611c9385828601611aec565b9250506020611ca485828601611c5c565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b611cec826119b8565b810181811067ffffffffffffffff82111715611d0b57611d0a611cb6565b5b80604052505050565b5f611d1d6118b2565b9050611d298282611ce3565b919050565b5f67ffffffffffffffff821115611d4857611d47611cb6565b5b611d51826119b8565b9050602081019050919050565b828183375f83830152505050565b5f611d7e611d7984611d2e565b611d14565b905082815260208101848484011115611d9a57611d99611cb2565b5b611da5848285611d5e565b509392505050565b5f82601f830112611dc157611dc0611cae565b5b8135611dd1848260208601611d6c565b91505092915050565b5f805f8060808587031215611df257611df16118bb565b5b5f611dff87828801611aec565b9450506020611e1087828801611aec565b9350506040611e2187828801611a3f565b925050606085013567ffffffffffffffff811115611e4257611e416118bf565b5b611e4e87828801611dad565b91505092959194509250565b611e63816118c3565b82525050565b5f602082019050611e7c5f830184611e5a565b92915050565b5f8060408385031215611e9857611e976118bb565b5b5f611ea585828601611aec565b9250506020611eb685828601611aec565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611f0457607f821691505b602082108103611f1757611f16611ec0565b5b50919050565b5f606082019050611f305f830186611aae565b611f3d6020830185611bcc565b611f4a6040830184611aae565b949350505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611f8982611a20565b9150611f9483611a20565b9250828202611fa281611a20565b91508282048414831517611fb957611fb8611f52565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f611ff782611a20565b915061200283611a20565b92508261201257612011611fc0565b5b828204905092915050565b5f81905092915050565b5f61203182611976565b61203b818561201d565b935061204b818560208601611990565b80840191505092915050565b5f6120628285612027565b915061206e8284612027565b91508190509392505050565b5f6bffffffffffffffffffffffff82169050919050565b5f819050919050565b5f6120b46120af6120aa8461207a565b612091565b611a20565b9050919050565b6120c48161209a565b82525050565b5f6040820190506120dd5f8301856120bb565b6120ea6020830184611bcc565b9392505050565b5f81519050919050565b5f82825260208201905092915050565b5f612115826120f1565b61211f81856120fb565b935061212f818560208601611990565b612138816119b8565b840191505092915050565b5f6080820190506121565f830187611aae565b6121636020830186611aae565b6121706040830185611bcc565b8181036060830152612182818461210b565b905095945050505050565b5f8151905061219b816118ee565b92915050565b5f602082840312156121b6576121b56118bb565b5b5f6121c38482850161218d565b9150509291505056fea2646970667358221220f9ccb6daec216bbcf0ba3fe622231e31e3dff6cbec8a8d59adb3627394b23d9e64736f6c63430008150033 \ No newline at end of file diff --git a/example/contracts/erc2981/ERC2981Example.sol b/example/contracts/erc2981/ERC2981Example.sol new file mode 100644 index 000000000..d8c57b876 --- /dev/null +++ b/example/contracts/erc2981/ERC2981Example.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/common/ERC2981.sol"; +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +contract ERC2981Example is ERC721,ERC2981 { + constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) { + } + + function supportsInterface(bytes4 interfaceId) public pure override(ERC721, ERC2981) returns (bool) { + return + interfaceId == type(IERC2981).interfaceId || + interfaceId == type(IERC165).interfaceId || + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId; + } + + function setDefaultRoyalty(address receiver) public { + _setDefaultRoyalty(receiver, 10000); + } +} \ No newline at end of file diff --git a/example/contracts/erc2981/erc2981.go b/example/contracts/erc2981/erc2981.go new file mode 100644 index 000000000..c30e1cc6e --- /dev/null +++ b/example/contracts/erc2981/erc2981.go @@ -0,0 +1,1065 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package erc2981 + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// Erc2981MetaData contains all meta data concerning the Erc2981 contract. +var Erc2981MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numerator\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"ERC2981InvalidDefaultRoyalty\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC2981InvalidDefaultRoyaltyReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numerator\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"ERC2981InvalidTokenRoyalty\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC2981InvalidTokenRoyaltyReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC721IncorrectOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ERC721InsufficientApproval\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC721InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"ERC721InvalidOperator\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC721InvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC721InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC721InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ERC721NonexistentToken\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"salePrice\",\"type\":\"uint256\"}],\"name\":\"royaltyInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"setDefaultRoyalty\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// Erc2981ABI is the input ABI used to generate the binding from. +// Deprecated: Use Erc2981MetaData.ABI instead. +var Erc2981ABI = Erc2981MetaData.ABI + +// Erc2981 is an auto generated Go binding around an Ethereum contract. +type Erc2981 struct { + Erc2981Caller // Read-only binding to the contract + Erc2981Transactor // Write-only binding to the contract + Erc2981Filterer // Log filterer for contract events +} + +// Erc2981Caller is an auto generated read-only Go binding around an Ethereum contract. +type Erc2981Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Erc2981Transactor is an auto generated write-only Go binding around an Ethereum contract. +type Erc2981Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Erc2981Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type Erc2981Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Erc2981Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type Erc2981Session struct { + Contract *Erc2981 // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Erc2981CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type Erc2981CallerSession struct { + Contract *Erc2981Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// Erc2981TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type Erc2981TransactorSession struct { + Contract *Erc2981Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Erc2981Raw is an auto generated low-level Go binding around an Ethereum contract. +type Erc2981Raw struct { + Contract *Erc2981 // Generic contract binding to access the raw methods on +} + +// Erc2981CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type Erc2981CallerRaw struct { + Contract *Erc2981Caller // Generic read-only contract binding to access the raw methods on +} + +// Erc2981TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type Erc2981TransactorRaw struct { + Contract *Erc2981Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewErc2981 creates a new instance of Erc2981, bound to a specific deployed contract. +func NewErc2981(address common.Address, backend bind.ContractBackend) (*Erc2981, error) { + contract, err := bindErc2981(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Erc2981{Erc2981Caller: Erc2981Caller{contract: contract}, Erc2981Transactor: Erc2981Transactor{contract: contract}, Erc2981Filterer: Erc2981Filterer{contract: contract}}, nil +} + +// NewErc2981Caller creates a new read-only instance of Erc2981, bound to a specific deployed contract. +func NewErc2981Caller(address common.Address, caller bind.ContractCaller) (*Erc2981Caller, error) { + contract, err := bindErc2981(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &Erc2981Caller{contract: contract}, nil +} + +// NewErc2981Transactor creates a new write-only instance of Erc2981, bound to a specific deployed contract. +func NewErc2981Transactor(address common.Address, transactor bind.ContractTransactor) (*Erc2981Transactor, error) { + contract, err := bindErc2981(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &Erc2981Transactor{contract: contract}, nil +} + +// NewErc2981Filterer creates a new log filterer instance of Erc2981, bound to a specific deployed contract. +func NewErc2981Filterer(address common.Address, filterer bind.ContractFilterer) (*Erc2981Filterer, error) { + contract, err := bindErc2981(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &Erc2981Filterer{contract: contract}, nil +} + +// bindErc2981 binds a generic wrapper to an already deployed contract. +func bindErc2981(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := Erc2981MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Erc2981 *Erc2981Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Erc2981.Contract.Erc2981Caller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Erc2981 *Erc2981Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Erc2981.Contract.Erc2981Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Erc2981 *Erc2981Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Erc2981.Contract.Erc2981Transactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_Erc2981 *Erc2981CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Erc2981.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_Erc2981 *Erc2981TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Erc2981.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Erc2981 *Erc2981TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Erc2981.Contract.contract.Transact(opts, method, params...) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address owner) view returns(uint256) +func (_Erc2981 *Erc2981Caller) BalanceOf(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { + var out []interface{} + err := _Erc2981.contract.Call(opts, &out, "balanceOf", owner) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address owner) view returns(uint256) +func (_Erc2981 *Erc2981Session) BalanceOf(owner common.Address) (*big.Int, error) { + return _Erc2981.Contract.BalanceOf(&_Erc2981.CallOpts, owner) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address owner) view returns(uint256) +func (_Erc2981 *Erc2981CallerSession) BalanceOf(owner common.Address) (*big.Int, error) { + return _Erc2981.Contract.BalanceOf(&_Erc2981.CallOpts, owner) +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 tokenId) view returns(address) +func (_Erc2981 *Erc2981Caller) GetApproved(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { + var out []interface{} + err := _Erc2981.contract.Call(opts, &out, "getApproved", tokenId) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 tokenId) view returns(address) +func (_Erc2981 *Erc2981Session) GetApproved(tokenId *big.Int) (common.Address, error) { + return _Erc2981.Contract.GetApproved(&_Erc2981.CallOpts, tokenId) +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 tokenId) view returns(address) +func (_Erc2981 *Erc2981CallerSession) GetApproved(tokenId *big.Int) (common.Address, error) { + return _Erc2981.Contract.GetApproved(&_Erc2981.CallOpts, tokenId) +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address owner, address operator) view returns(bool) +func (_Erc2981 *Erc2981Caller) IsApprovedForAll(opts *bind.CallOpts, owner common.Address, operator common.Address) (bool, error) { + var out []interface{} + err := _Erc2981.contract.Call(opts, &out, "isApprovedForAll", owner, operator) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address owner, address operator) view returns(bool) +func (_Erc2981 *Erc2981Session) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { + return _Erc2981.Contract.IsApprovedForAll(&_Erc2981.CallOpts, owner, operator) +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address owner, address operator) view returns(bool) +func (_Erc2981 *Erc2981CallerSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { + return _Erc2981.Contract.IsApprovedForAll(&_Erc2981.CallOpts, owner, operator) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Erc2981 *Erc2981Caller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Erc2981.contract.Call(opts, &out, "name") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Erc2981 *Erc2981Session) Name() (string, error) { + return _Erc2981.Contract.Name(&_Erc2981.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Erc2981 *Erc2981CallerSession) Name() (string, error) { + return _Erc2981.Contract.Name(&_Erc2981.CallOpts) +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 tokenId) view returns(address) +func (_Erc2981 *Erc2981Caller) OwnerOf(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { + var out []interface{} + err := _Erc2981.contract.Call(opts, &out, "ownerOf", tokenId) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 tokenId) view returns(address) +func (_Erc2981 *Erc2981Session) OwnerOf(tokenId *big.Int) (common.Address, error) { + return _Erc2981.Contract.OwnerOf(&_Erc2981.CallOpts, tokenId) +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 tokenId) view returns(address) +func (_Erc2981 *Erc2981CallerSession) OwnerOf(tokenId *big.Int) (common.Address, error) { + return _Erc2981.Contract.OwnerOf(&_Erc2981.CallOpts, tokenId) +} + +// RoyaltyInfo is a free data retrieval call binding the contract method 0x2a55205a. +// +// Solidity: function royaltyInfo(uint256 tokenId, uint256 salePrice) view returns(address, uint256) +func (_Erc2981 *Erc2981Caller) RoyaltyInfo(opts *bind.CallOpts, tokenId *big.Int, salePrice *big.Int) (common.Address, *big.Int, error) { + var out []interface{} + err := _Erc2981.contract.Call(opts, &out, "royaltyInfo", tokenId, salePrice) + + if err != nil { + return *new(common.Address), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// RoyaltyInfo is a free data retrieval call binding the contract method 0x2a55205a. +// +// Solidity: function royaltyInfo(uint256 tokenId, uint256 salePrice) view returns(address, uint256) +func (_Erc2981 *Erc2981Session) RoyaltyInfo(tokenId *big.Int, salePrice *big.Int) (common.Address, *big.Int, error) { + return _Erc2981.Contract.RoyaltyInfo(&_Erc2981.CallOpts, tokenId, salePrice) +} + +// RoyaltyInfo is a free data retrieval call binding the contract method 0x2a55205a. +// +// Solidity: function royaltyInfo(uint256 tokenId, uint256 salePrice) view returns(address, uint256) +func (_Erc2981 *Erc2981CallerSession) RoyaltyInfo(tokenId *big.Int, salePrice *big.Int) (common.Address, *big.Int, error) { + return _Erc2981.Contract.RoyaltyInfo(&_Erc2981.CallOpts, tokenId, salePrice) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) +func (_Erc2981 *Erc2981Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _Erc2981.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) +func (_Erc2981 *Erc2981Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Erc2981.Contract.SupportsInterface(&_Erc2981.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) +func (_Erc2981 *Erc2981CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Erc2981.Contract.SupportsInterface(&_Erc2981.CallOpts, interfaceId) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Erc2981 *Erc2981Caller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Erc2981.contract.Call(opts, &out, "symbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Erc2981 *Erc2981Session) Symbol() (string, error) { + return _Erc2981.Contract.Symbol(&_Erc2981.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Erc2981 *Erc2981CallerSession) Symbol() (string, error) { + return _Erc2981.Contract.Symbol(&_Erc2981.CallOpts) +} + +// TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. +// +// Solidity: function tokenURI(uint256 tokenId) view returns(string) +func (_Erc2981 *Erc2981Caller) TokenURI(opts *bind.CallOpts, tokenId *big.Int) (string, error) { + var out []interface{} + err := _Erc2981.contract.Call(opts, &out, "tokenURI", tokenId) + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. +// +// Solidity: function tokenURI(uint256 tokenId) view returns(string) +func (_Erc2981 *Erc2981Session) TokenURI(tokenId *big.Int) (string, error) { + return _Erc2981.Contract.TokenURI(&_Erc2981.CallOpts, tokenId) +} + +// TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. +// +// Solidity: function tokenURI(uint256 tokenId) view returns(string) +func (_Erc2981 *Erc2981CallerSession) TokenURI(tokenId *big.Int) (string, error) { + return _Erc2981.Contract.TokenURI(&_Erc2981.CallOpts, tokenId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address to, uint256 tokenId) returns() +func (_Erc2981 *Erc2981Transactor) Approve(opts *bind.TransactOpts, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Erc2981.contract.Transact(opts, "approve", to, tokenId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address to, uint256 tokenId) returns() +func (_Erc2981 *Erc2981Session) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Erc2981.Contract.Approve(&_Erc2981.TransactOpts, to, tokenId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address to, uint256 tokenId) returns() +func (_Erc2981 *Erc2981TransactorSession) Approve(to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Erc2981.Contract.Approve(&_Erc2981.TransactOpts, to, tokenId) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId) returns() +func (_Erc2981 *Erc2981Transactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Erc2981.contract.Transact(opts, "safeTransferFrom", from, to, tokenId) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId) returns() +func (_Erc2981 *Erc2981Session) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Erc2981.Contract.SafeTransferFrom(&_Erc2981.TransactOpts, from, to, tokenId) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId) returns() +func (_Erc2981 *Erc2981TransactorSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Erc2981.Contract.SafeTransferFrom(&_Erc2981.TransactOpts, from, to, tokenId) +} + +// SafeTransferFrom0 is a paid mutator transaction binding the contract method 0xb88d4fde. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes data) returns() +func (_Erc2981 *Erc2981Transactor) SafeTransferFrom0(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int, data []byte) (*types.Transaction, error) { + return _Erc2981.contract.Transact(opts, "safeTransferFrom0", from, to, tokenId, data) +} + +// SafeTransferFrom0 is a paid mutator transaction binding the contract method 0xb88d4fde. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes data) returns() +func (_Erc2981 *Erc2981Session) SafeTransferFrom0(from common.Address, to common.Address, tokenId *big.Int, data []byte) (*types.Transaction, error) { + return _Erc2981.Contract.SafeTransferFrom0(&_Erc2981.TransactOpts, from, to, tokenId, data) +} + +// SafeTransferFrom0 is a paid mutator transaction binding the contract method 0xb88d4fde. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId, bytes data) returns() +func (_Erc2981 *Erc2981TransactorSession) SafeTransferFrom0(from common.Address, to common.Address, tokenId *big.Int, data []byte) (*types.Transaction, error) { + return _Erc2981.Contract.SafeTransferFrom0(&_Erc2981.TransactOpts, from, to, tokenId, data) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_Erc2981 *Erc2981Transactor) SetApprovalForAll(opts *bind.TransactOpts, operator common.Address, approved bool) (*types.Transaction, error) { + return _Erc2981.contract.Transact(opts, "setApprovalForAll", operator, approved) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_Erc2981 *Erc2981Session) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _Erc2981.Contract.SetApprovalForAll(&_Erc2981.TransactOpts, operator, approved) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_Erc2981 *Erc2981TransactorSession) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _Erc2981.Contract.SetApprovalForAll(&_Erc2981.TransactOpts, operator, approved) +} + +// SetDefaultRoyalty is a paid mutator transaction binding the contract method 0xb03b74aa. +// +// Solidity: function setDefaultRoyalty(address receiver) returns() +func (_Erc2981 *Erc2981Transactor) SetDefaultRoyalty(opts *bind.TransactOpts, receiver common.Address) (*types.Transaction, error) { + return _Erc2981.contract.Transact(opts, "setDefaultRoyalty", receiver) +} + +// SetDefaultRoyalty is a paid mutator transaction binding the contract method 0xb03b74aa. +// +// Solidity: function setDefaultRoyalty(address receiver) returns() +func (_Erc2981 *Erc2981Session) SetDefaultRoyalty(receiver common.Address) (*types.Transaction, error) { + return _Erc2981.Contract.SetDefaultRoyalty(&_Erc2981.TransactOpts, receiver) +} + +// SetDefaultRoyalty is a paid mutator transaction binding the contract method 0xb03b74aa. +// +// Solidity: function setDefaultRoyalty(address receiver) returns() +func (_Erc2981 *Erc2981TransactorSession) SetDefaultRoyalty(receiver common.Address) (*types.Transaction, error) { + return _Erc2981.Contract.SetDefaultRoyalty(&_Erc2981.TransactOpts, receiver) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() +func (_Erc2981 *Erc2981Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Erc2981.contract.Transact(opts, "transferFrom", from, to, tokenId) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() +func (_Erc2981 *Erc2981Session) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Erc2981.Contract.TransferFrom(&_Erc2981.TransactOpts, from, to, tokenId) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() +func (_Erc2981 *Erc2981TransactorSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Erc2981.Contract.TransferFrom(&_Erc2981.TransactOpts, from, to, tokenId) +} + +// Erc2981ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Erc2981 contract. +type Erc2981ApprovalIterator struct { + Event *Erc2981Approval // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *Erc2981ApprovalIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(Erc2981Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(Erc2981Approval) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *Erc2981ApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Erc2981ApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Erc2981Approval represents a Approval event raised by the Erc2981 contract. +type Erc2981Approval struct { + Owner common.Address + Approved common.Address + TokenId *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) +func (_Erc2981 *Erc2981Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, approved []common.Address, tokenId []*big.Int) (*Erc2981ApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var approvedRule []interface{} + for _, approvedItem := range approved { + approvedRule = append(approvedRule, approvedItem) + } + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _Erc2981.contract.FilterLogs(opts, "Approval", ownerRule, approvedRule, tokenIdRule) + if err != nil { + return nil, err + } + return &Erc2981ApprovalIterator{contract: _Erc2981.contract, event: "Approval", logs: logs, sub: sub}, nil +} + +// WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) +func (_Erc2981 *Erc2981Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *Erc2981Approval, owner []common.Address, approved []common.Address, tokenId []*big.Int) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var approvedRule []interface{} + for _, approvedItem := range approved { + approvedRule = append(approvedRule, approvedItem) + } + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _Erc2981.contract.WatchLogs(opts, "Approval", ownerRule, approvedRule, tokenIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(Erc2981Approval) + if err := _Erc2981.contract.UnpackLog(event, "Approval", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. +// +// Solidity: event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId) +func (_Erc2981 *Erc2981Filterer) ParseApproval(log types.Log) (*Erc2981Approval, error) { + event := new(Erc2981Approval) + if err := _Erc2981.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// Erc2981ApprovalForAllIterator is returned from FilterApprovalForAll and is used to iterate over the raw logs and unpacked data for ApprovalForAll events raised by the Erc2981 contract. +type Erc2981ApprovalForAllIterator struct { + Event *Erc2981ApprovalForAll // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *Erc2981ApprovalForAllIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(Erc2981ApprovalForAll) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(Erc2981ApprovalForAll) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *Erc2981ApprovalForAllIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Erc2981ApprovalForAllIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Erc2981ApprovalForAll represents a ApprovalForAll event raised by the Erc2981 contract. +type Erc2981ApprovalForAll struct { + Owner common.Address + Operator common.Address + Approved bool + Raw types.Log // Blockchain specific contextual infos +} + +// FilterApprovalForAll is a free log retrieval operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. +// +// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) +func (_Erc2981 *Erc2981Filterer) FilterApprovalForAll(opts *bind.FilterOpts, owner []common.Address, operator []common.Address) (*Erc2981ApprovalForAllIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + + logs, sub, err := _Erc2981.contract.FilterLogs(opts, "ApprovalForAll", ownerRule, operatorRule) + if err != nil { + return nil, err + } + return &Erc2981ApprovalForAllIterator{contract: _Erc2981.contract, event: "ApprovalForAll", logs: logs, sub: sub}, nil +} + +// WatchApprovalForAll is a free log subscription operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. +// +// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) +func (_Erc2981 *Erc2981Filterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *Erc2981ApprovalForAll, owner []common.Address, operator []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var operatorRule []interface{} + for _, operatorItem := range operator { + operatorRule = append(operatorRule, operatorItem) + } + + logs, sub, err := _Erc2981.contract.WatchLogs(opts, "ApprovalForAll", ownerRule, operatorRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(Erc2981ApprovalForAll) + if err := _Erc2981.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseApprovalForAll is a log parse operation binding the contract event 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31. +// +// Solidity: event ApprovalForAll(address indexed owner, address indexed operator, bool approved) +func (_Erc2981 *Erc2981Filterer) ParseApprovalForAll(log types.Log) (*Erc2981ApprovalForAll, error) { + event := new(Erc2981ApprovalForAll) + if err := _Erc2981.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// Erc2981TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Erc2981 contract. +type Erc2981TransferIterator struct { + Event *Erc2981Transfer // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *Erc2981TransferIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(Erc2981Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(Erc2981Transfer) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *Erc2981TransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Erc2981TransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Erc2981Transfer represents a Transfer event raised by the Erc2981 contract. +type Erc2981Transfer struct { + From common.Address + To common.Address + TokenId *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) +func (_Erc2981 *Erc2981Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address, tokenId []*big.Int) (*Erc2981TransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _Erc2981.contract.FilterLogs(opts, "Transfer", fromRule, toRule, tokenIdRule) + if err != nil { + return nil, err + } + return &Erc2981TransferIterator{contract: _Erc2981.contract, event: "Transfer", logs: logs, sub: sub}, nil +} + +// WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) +func (_Erc2981 *Erc2981Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *Erc2981Transfer, from []common.Address, to []common.Address, tokenId []*big.Int) (event.Subscription, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + var tokenIdRule []interface{} + for _, tokenIdItem := range tokenId { + tokenIdRule = append(tokenIdRule, tokenIdItem) + } + + logs, sub, err := _Erc2981.contract.WatchLogs(opts, "Transfer", fromRule, toRule, tokenIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(Erc2981Transfer) + if err := _Erc2981.contract.UnpackLog(event, "Transfer", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. +// +// Solidity: event Transfer(address indexed from, address indexed to, uint256 indexed tokenId) +func (_Erc2981 *Erc2981Filterer) ParseTransfer(log types.Log) (*Erc2981Transfer, error) { + event := new(Erc2981Transfer) + if err := _Erc2981.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/example/contracts/erc721/DummyERC721.abi b/example/contracts/erc721/DummyERC721.abi index 9395a3fc5..ce4fea57e 100644 --- a/example/contracts/erc721/DummyERC721.abi +++ b/example/contracts/erc721/DummyERC721.abi @@ -1 +1 @@ -[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"operator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"randomAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"operator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"randomAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"supply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/example/contracts/erc721/DummyERC721.bin b/example/contracts/erc721/DummyERC721.bin index faddd7a16..2eb470db0 100644 --- a/example/contracts/erc721/DummyERC721.bin +++ b/example/contracts/erc721/DummyERC721.bin @@ -1 +1 @@ -608060405273f39fd6e51aad88f6f4ce6ab8827279cfffb9226660045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550348015610063575f80fd5b5061091f806100715f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c806370a082311161008a578063b88d4fde11610064578063b88d4fde14610258578063c87b56dd14610274578063d5bee9f5146102a4578063e985e9c5146102c2576100e8565b806370a08231146101ee57806395d89b411461021e578063a22cb4651461023c576100e8565b8063095ea7b3116100c6578063095ea7b31461016a57806323b872dd1461018657806342842e0e146101a25780636352211e146101be576100e8565b806301ffc9a7146100ec57806306fdde031461011c578063081812fc1461013a575b5f80fd5b61010660048036038101906101019190610495565b6102f2565b60405161011391906104da565b60405180910390f35b6101246102fc565b604051610131919061057d565b60405180910390f35b610154600480360381019061014f91906105d0565b610339565b604051610161919061063a565b60405180910390f35b610184600480360381019061017f919061067d565b61033f565b005b6101a0600480360381019061019b91906106bb565b610343565b005b6101bc60048036038101906101b791906106bb565b610348565b005b6101d860048036038101906101d391906105d0565b61034d565b6040516101e5919061063a565b60405180910390f35b6102086004803603810190610203919061070b565b610377565b6040516102159190610745565b60405180910390f35b610226610381565b604051610233919061057d565b60405180910390f35b61025660048036038101906102519190610788565b6103be565b005b610272600480360381019061026d9190610827565b6103c2565b005b61028e600480360381019061028991906105d0565b6103c9565b60405161029b919061057d565b60405180910390f35b6102ac610408565b6040516102b9919061063a565b60405180910390f35b6102dc60048036038101906102d791906108ab565b61042d565b6040516102e991906104da565b60405180910390f35b5f60019050919050565b60606040518060400160405280600b81526020017f44756d6d79455243373231000000000000000000000000000000000000000000815250905090565b5f919050565b5050565b505050565b505050565b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f60329050919050565b60606040518060400160405280600581526020017f44554d4d59000000000000000000000000000000000000000000000000000000815250905090565b5050565b5050505050565b60606040518060400160405280601381526020017f68747470733a2f2f6578616d706c652e636f6d000000000000000000000000008152509050919050565b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f6001905092915050565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61047481610440565b811461047e575f80fd5b50565b5f8135905061048f8161046b565b92915050565b5f602082840312156104aa576104a9610438565b5b5f6104b784828501610481565b91505092915050565b5f8115159050919050565b6104d4816104c0565b82525050565b5f6020820190506104ed5f8301846104cb565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561052a57808201518184015260208101905061050f565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61054f826104f3565b61055981856104fd565b935061056981856020860161050d565b61057281610535565b840191505092915050565b5f6020820190508181035f8301526105958184610545565b905092915050565b5f819050919050565b6105af8161059d565b81146105b9575f80fd5b50565b5f813590506105ca816105a6565b92915050565b5f602082840312156105e5576105e4610438565b5b5f6105f2848285016105bc565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610624826105fb565b9050919050565b6106348161061a565b82525050565b5f60208201905061064d5f83018461062b565b92915050565b61065c8161061a565b8114610666575f80fd5b50565b5f8135905061067781610653565b92915050565b5f806040838503121561069357610692610438565b5b5f6106a085828601610669565b92505060206106b1858286016105bc565b9150509250929050565b5f805f606084860312156106d2576106d1610438565b5b5f6106df86828701610669565b93505060206106f086828701610669565b9250506040610701868287016105bc565b9150509250925092565b5f602082840312156107205761071f610438565b5b5f61072d84828501610669565b91505092915050565b61073f8161059d565b82525050565b5f6020820190506107585f830184610736565b92915050565b610767816104c0565b8114610771575f80fd5b50565b5f813590506107828161075e565b92915050565b5f806040838503121561079e5761079d610438565b5b5f6107ab85828601610669565b92505060206107bc85828601610774565b9150509250929050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f8401126107e7576107e66107c6565b5b8235905067ffffffffffffffff811115610804576108036107ca565b5b6020830191508360018202830111156108205761081f6107ce565b5b9250929050565b5f805f805f608086880312156108405761083f610438565b5b5f61084d88828901610669565b955050602061085e88828901610669565b945050604061086f888289016105bc565b935050606086013567ffffffffffffffff8111156108905761088f61043c565b5b61089c888289016107d2565b92509250509295509295909350565b5f80604083850312156108c1576108c0610438565b5b5f6108ce85828601610669565b92505060206108df85828601610669565b915050925092905056fea2646970667358221220cac0547d8cdc2d72600e74bf9296eee8caaa1ec4c78594f3b8947dd3ec2baef364736f6c63430008140033 \ No newline at end of file +608060405273f39fd6e51aad88f6f4ce6ab8827279cfffb9226660045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503480156062575f80fd5b50610aec806100705f395ff3fe608060405234801561000f575f80fd5b50600436106100fe575f3560e01c80636352211e11610095578063b88d4fde11610064578063b88d4fde146102bd578063c87b56dd146102d9578063d5bee9f514610309578063e985e9c514610327576100fe565b80636352211e1461022357806370a082311461025357806395d89b4114610283578063a22cb465146102a1576100fe565b806318160ddd116100d157806318160ddd1461019c57806323b872dd146101ba5780632a55205a146101d657806342842e0e14610207576100fe565b806301ffc9a71461010257806306fdde0314610132578063081812fc14610150578063095ea7b314610180575b5f80fd5b61011c6004803603810190610117919061054c565b610357565b6040516101299190610591565b60405180910390f35b61013a610361565b604051610147919061061a565b60405180910390f35b61016a6004803603810190610165919061066d565b61039e565b60405161017791906106d7565b60405180910390f35b61019a6004803603810190610195919061071a565b6103a4565b005b6101a46103a8565b6040516101b19190610767565b60405180910390f35b6101d460048036038101906101cf9190610780565b6103b0565b005b6101f060048036038101906101eb91906107d0565b6103b5565b6040516101fe92919061080e565b60405180910390f35b610221600480360381019061021c9190610780565b6103ff565b005b61023d6004803603810190610238919061066d565b610404565b60405161024a91906106d7565b60405180910390f35b61026d60048036038101906102689190610835565b61042e565b60405161027a9190610767565b60405180910390f35b61028b610438565b604051610298919061061a565b60405180910390f35b6102bb60048036038101906102b6919061088a565b610475565b005b6102d760048036038101906102d29190610929565b610479565b005b6102f360048036038101906102ee919061066d565b610480565b604051610300919061061a565b60405180910390f35b6103116104bf565b60405161031e91906106d7565b60405180910390f35b610341600480360381019061033c91906109ad565b6104e4565b60405161034e9190610591565b60405180910390f35b5f60019050919050565b60606040518060400160405280600b81526020017f44756d6d79455243373231000000000000000000000000000000000000000000815250905090565b5f919050565b5050565b5f6065905090565b505050565b5f8060045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691506127106101f4846103ec9190610a18565b6103f69190610a86565b90509250929050565b505050565b5f60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f60329050919050565b60606040518060400160405280600581526020017f44554d4d59000000000000000000000000000000000000000000000000000000815250905090565b5050565b5050505050565b60606040518060400160405280601381526020017f68747470733a2f2f6578616d706c652e636f6d000000000000000000000000008152509050919050565b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f6001905092915050565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61052b816104f7565b8114610535575f80fd5b50565b5f8135905061054681610522565b92915050565b5f60208284031215610561576105606104ef565b5b5f61056e84828501610538565b91505092915050565b5f8115159050919050565b61058b81610577565b82525050565b5f6020820190506105a45f830184610582565b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6105ec826105aa565b6105f681856105b4565b93506106068185602086016105c4565b61060f816105d2565b840191505092915050565b5f6020820190508181035f83015261063281846105e2565b905092915050565b5f819050919050565b61064c8161063a565b8114610656575f80fd5b50565b5f8135905061066781610643565b92915050565b5f60208284031215610682576106816104ef565b5b5f61068f84828501610659565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6106c182610698565b9050919050565b6106d1816106b7565b82525050565b5f6020820190506106ea5f8301846106c8565b92915050565b6106f9816106b7565b8114610703575f80fd5b50565b5f81359050610714816106f0565b92915050565b5f80604083850312156107305761072f6104ef565b5b5f61073d85828601610706565b925050602061074e85828601610659565b9150509250929050565b6107618161063a565b82525050565b5f60208201905061077a5f830184610758565b92915050565b5f805f60608486031215610797576107966104ef565b5b5f6107a486828701610706565b93505060206107b586828701610706565b92505060406107c686828701610659565b9150509250925092565b5f80604083850312156107e6576107e56104ef565b5b5f6107f385828601610659565b925050602061080485828601610659565b9150509250929050565b5f6040820190506108215f8301856106c8565b61082e6020830184610758565b9392505050565b5f6020828403121561084a576108496104ef565b5b5f61085784828501610706565b91505092915050565b61086981610577565b8114610873575f80fd5b50565b5f8135905061088481610860565b92915050565b5f80604083850312156108a05761089f6104ef565b5b5f6108ad85828601610706565b92505060206108be85828601610876565b9150509250929050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f8401126108e9576108e86108c8565b5b8235905067ffffffffffffffff811115610906576109056108cc565b5b602083019150836001820283011115610922576109216108d0565b5b9250929050565b5f805f805f60808688031215610942576109416104ef565b5b5f61094f88828901610706565b955050602061096088828901610706565b945050604061097188828901610659565b935050606086013567ffffffffffffffff811115610992576109916104f3565b5b61099e888289016108d4565b92509250509295509295909350565b5f80604083850312156109c3576109c26104ef565b5b5f6109d085828601610706565b92505060206109e185828601610706565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610a228261063a565b9150610a2d8361063a565b9250828202610a3b8161063a565b91508282048414831517610a5257610a516109eb565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f610a908261063a565b9150610a9b8361063a565b925082610aab57610aaa610a59565b5b82820490509291505056fea2646970667358221220044a679d63c6ba5d9d54e5c3a3a74e6dcad05fbb5758067ef15fc25af3a3df3e64736f6c63430008190033 \ No newline at end of file diff --git a/example/contracts/erc721/ERC721.sol b/example/contracts/erc721/ERC721.sol index 93044d8ac..b4d844a6f 100644 --- a/example/contracts/erc721/ERC721.sol +++ b/example/contracts/erc721/ERC721.sol @@ -57,6 +57,10 @@ contract DummyERC721 is IERC721 { return 50; } + function totalSupply() public view returns (uint256 supply) { + supply = 101; + } + function ownerOf(uint256 tokenId) public view override returns (address owner) { return randomAddress; } @@ -65,6 +69,11 @@ contract DummyERC721 is IERC721 { return "https://example.com"; } + function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount) { + receiver = randomAddress; + royaltyAmount = (salePrice * 500) / 10_000; + } + function transferFrom(address from, address to, uint256 tokenId) public override {} function safeTransferFrom(address from, address to, uint256 tokenId) public override {} diff --git a/example/contracts/simplestorage/SimpleStorage.abi b/example/contracts/simplestorage/SimpleStorage.abi index 3c5944797..97e20adb5 100644 --- a/example/contracts/simplestorage/SimpleStorage.abi +++ b/example/contracts/simplestorage/SimpleStorage.abi @@ -1 +1 @@ -[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"SetEvent","type":"event"},{"inputs":[],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"SetEvent","type":"event"},{"inputs":[],"name":"bad","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"get","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/example/contracts/simplestorage/SimpleStorage.bin b/example/contracts/simplestorage/SimpleStorage.bin index bb903ae71..08af40cf6 100644 --- a/example/contracts/simplestorage/SimpleStorage.bin +++ b/example/contracts/simplestorage/SimpleStorage.bin @@ -1 +1 @@ -608060405234801561000f575f80fd5b5061017a8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c806360fe47b1146100385780636d4ce63c14610054575b5f80fd5b610052600480360381019061004d91906100f1565b610072565b005b61005c6100b2565b604051610069919061012b565b60405180910390f35b805f819055507f0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1816040516100a7919061012b565b60405180910390a150565b5f8054905090565b5f80fd5b5f819050919050565b6100d0816100be565b81146100da575f80fd5b50565b5f813590506100eb816100c7565b92915050565b5f60208284031215610106576101056100ba565b5b5f610113848285016100dd565b91505092915050565b610125816100be565b82525050565b5f60208201905061013e5f83018461011c565b9291505056fea26469706673582212205b2eaa3bd967fbbfe4490610612964348d1d0b2a793d2b0d117fe05ccb02d1e364736f6c63430008150033 \ No newline at end of file +608060405234801561000f575f80fd5b506101938061001d5f395ff3fe608060405234801561000f575f80fd5b506004361061003f575f3560e01c806360fe47b1146100435780636d4ce63c1461005f5780639c3674fc1461007d575b5f80fd5b61005d6004803603810190610058919061010a565b610087565b005b6100676100c7565b6040516100749190610144565b60405180910390f35b6100856100cf565b005b805f819055507f0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1816040516100bc9190610144565b60405180910390a150565b5f8054905090565b5f80fd5b5f80fd5b5f819050919050565b6100e9816100d7565b81146100f3575f80fd5b50565b5f81359050610104816100e0565b92915050565b5f6020828403121561011f5761011e6100d3565b5b5f61012c848285016100f6565b91505092915050565b61013e816100d7565b82525050565b5f6020820190506101575f830184610135565b9291505056fea2646970667358221220bb55137839ea2afda11ab2d30ad07fee30bb9438caaa46e30ccd1053ed72439064736f6c63430008150033 \ No newline at end of file diff --git a/example/contracts/simplestorage/SimpleStorage.go b/example/contracts/simplestorage/SimpleStorage.go index c3d451e29..deabc03c1 100644 --- a/example/contracts/simplestorage/SimpleStorage.go +++ b/example/contracts/simplestorage/SimpleStorage.go @@ -31,7 +31,7 @@ var ( // SimplestorageMetaData contains all meta data concerning the Simplestorage contract. var SimplestorageMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"SetEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"SetEvent\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"bad\",\"outputs\":[],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // SimplestorageABI is the input ABI used to generate the binding from. @@ -180,6 +180,35 @@ func (_Simplestorage *SimplestorageTransactorRaw) Transact(opts *bind.TransactOp return _Simplestorage.Contract.contract.Transact(opts, method, params...) } +// Bad is a free data retrieval call binding the contract method 0x9c3674fc. +// +// Solidity: function bad() pure returns() +func (_Simplestorage *SimplestorageCaller) Bad(opts *bind.CallOpts) error { + var out []interface{} + err := _Simplestorage.contract.Call(opts, &out, "bad") + + if err != nil { + return err + } + + return err + +} + +// Bad is a free data retrieval call binding the contract method 0x9c3674fc. +// +// Solidity: function bad() pure returns() +func (_Simplestorage *SimplestorageSession) Bad() error { + return _Simplestorage.Contract.Bad(&_Simplestorage.CallOpts) +} + +// Bad is a free data retrieval call binding the contract method 0x9c3674fc. +// +// Solidity: function bad() pure returns() +func (_Simplestorage *SimplestorageCallerSession) Bad() error { + return _Simplestorage.Contract.Bad(&_Simplestorage.CallOpts) +} + // Get is a free data retrieval call binding the contract method 0x6d4ce63c. // // Solidity: function get() view returns(uint256) diff --git a/example/contracts/simplestorage/SimpleStorage.sol b/example/contracts/simplestorage/SimpleStorage.sol index b8688e2b9..67530368d 100644 --- a/example/contracts/simplestorage/SimpleStorage.sol +++ b/example/contracts/simplestorage/SimpleStorage.sol @@ -14,4 +14,8 @@ contract SimpleStorage { function get() public view returns (uint256) { return storedData; } + + function bad() public pure { + revert(); + } } \ No newline at end of file diff --git a/example/cosmwasm/cw721/Cargo.lock b/example/cosmwasm/cw721/Cargo.lock index b9691cd18..83d67866f 100644 --- a/example/cosmwasm/cw721/Cargo.lock +++ b/example/cosmwasm/cw721/Cargo.lock @@ -192,6 +192,52 @@ dependencies = [ "zeroize", ] +[[package]] +name = "cw-address-like" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451a4691083a88a3c0630a8a88799e9d4cd6679b7ce8ff22b8da2873ff31d380" +dependencies = [ + "cosmwasm-std", +] + +[[package]] +name = "cw-ownable" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093dfb4520c48b5848274dd88ea99e280a04bc08729603341c7fb0d758c74321" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-address-like", + "cw-ownable-derive", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "thiserror", +] + +[[package]] +name = "cw-ownable-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d3bf2e0f341bb6cc100d7d441d31cf713fbd3ce0c511f91e79f14b40a889af" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cw-storage-plus" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b6f91c0b94481a3e9ef1ceb183c37d00764f8751e39b45fc09f4d9b970d469" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + [[package]] name = "cw-storage-plus" version = "1.2.0" @@ -203,6 +249,21 @@ dependencies = [ "serde", ] +[[package]] +name = "cw-utils" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a84c6c1c0acc3616398eba50783934bd6c964bad6974241eaee3460c8f5b26" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2 0.16.0", + "schemars", + "semver", + "serde", + "thiserror", +] + [[package]] name = "cw-utils" version = "1.0.3" @@ -211,13 +272,26 @@ checksum = "1c4a657e5caacc3a0d00ee96ca8618745d050b8f757c709babafb81208d4239c" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw2", + "cw2 1.1.2", "schemars", "semver", "serde", "thiserror", ] +[[package]] +name = "cw2" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91398113b806f4d2a8d5f8d05684704a20ffd5968bf87e3473e1973710b884ad" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.16.0", + "schemars", + "serde", +] + [[package]] name = "cw2" version = "1.1.2" @@ -226,13 +300,42 @@ checksum = "c6c120b24fbbf5c3bedebb97f2cc85fbfa1c3287e09223428e7e597b5293c1fa" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus", + "cw-storage-plus 1.2.0", "schemars", "semver", "serde", "thiserror", ] +[[package]] +name = "cw2981-royalties" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985cdd5d304fb37ff16c2538f4d8f12a264af6526b967e066c6bb6972d60ab92" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2 1.1.2", + "cw721 0.18.0", + "cw721-base 0.18.0", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "cw721" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94a1ea6e6277bdd6dfc043a9b1380697fe29d6e24b072597439523658d21d791" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils 0.16.0", + "schemars", + "serde", +] + [[package]] name = "cw721" version = "0.18.0" @@ -241,9 +344,45 @@ checksum = "e3c4d286625ccadc957fe480dd3bdc54ada19e0e6b5b9325379db3130569e914" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-utils", + "cw-utils 1.0.3", + "schemars", + "serde", +] + +[[package]] +name = "cw721-base" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77518e27431d43214cff4cdfbd788a7508f68d9b1f32389e6fce513e7eaccbef" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus 0.16.0", + "cw-utils 0.16.0", + "cw2 0.16.0", + "cw721 0.16.0", "schemars", "serde", + "thiserror", +] + +[[package]] +name = "cw721-base" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da518d9f68bfda7d972cbaca2e8fcf04651d0edc3de72b04ae2bcd9289c81614" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-ownable", + "cw-storage-plus 1.2.0", + "cw-utils 1.0.3", + "cw2 1.1.2", + "cw721 0.18.0", + "cw721-base 0.16.0", + "schemars", + "serde", + "thiserror", ] [[package]] @@ -252,8 +391,10 @@ version = "0.1.0" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-storage-plus", - "cw721", + "cw-storage-plus 1.2.0", + "cw2981-royalties", + "cw721 0.18.0", + "cw721-base 0.18.0", "schemars", "serde", "thiserror", @@ -746,4 +887,4 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" \ No newline at end of file diff --git a/example/cosmwasm/cw721/Cargo.toml b/example/cosmwasm/cw721/Cargo.toml index 5c06474a9..0e33fb244 100644 --- a/example/cosmwasm/cw721/Cargo.toml +++ b/example/cosmwasm/cw721/Cargo.toml @@ -17,7 +17,9 @@ library = [] cosmwasm-schema = "1.5.0" cosmwasm-std = { version = "1.3.1", features = ["staking", "stargate"] } cw-storage-plus = "1.2.0" +cw2981-royalties = "0.18.0" cw721 = "0.18.0" +cw721-base = "0.18.0" schemars = "0.8.16" serde = "1.0.195" -thiserror = "1.0.56" +thiserror = "1.0.56" \ No newline at end of file diff --git a/example/cosmwasm/cw721/artifacts/checksums.txt b/example/cosmwasm/cw721/artifacts/checksums.txt index a31da2c61..c02325416 100644 --- a/example/cosmwasm/cw721/artifacts/checksums.txt +++ b/example/cosmwasm/cw721/artifacts/checksums.txt @@ -1 +1 @@ -94cdd9c3e85c26f7cec43c23bfb4b3b2b2d71a0a8d85c58df12ffec0741febc8 cwerc721.wasm +4355b9f7c6a3337ee6994512155435bdfc80bd151a57e78fd50f9d41e62a8aaa cwerc721.wasm diff --git a/example/cosmwasm/cw721/artifacts/cwerc721.wasm b/example/cosmwasm/cw721/artifacts/cwerc721.wasm index 318ada77b..a1cfac086 100644 Binary files a/example/cosmwasm/cw721/artifacts/cwerc721.wasm and b/example/cosmwasm/cw721/artifacts/cwerc721.wasm differ diff --git a/example/cosmwasm/cw721/src/contract.rs b/example/cosmwasm/cw721/src/contract.rs index 690bb262d..f7515787e 100644 --- a/example/cosmwasm/cw721/src/contract.rs +++ b/example/cosmwasm/cw721/src/contract.rs @@ -1,13 +1,18 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - DepsMut, Deps, Env, MessageInfo, Response, Binary, StdResult, to_json_binary, + DepsMut, Deps, Env, MessageInfo, Response, Binary, StdResult, to_json_binary, Empty, Uint128, Int256, }; -use cw721::{Cw721ReceiveMsg, OwnerOfResponse, Approval, ApprovalResponse, ApprovalsResponse, OperatorResponse, ContractInfoResponse, NftInfoResponse, AllNftInfoResponse}; -use crate::msg::{EvmQueryWrapper, EvmMsg, InstantiateMsg, ExecuteMsg, QueryMsg}; -use crate::querier::EvmQuerier; +use cw721::{Cw721ReceiveMsg, OwnerOfResponse, Approval, ApprovalResponse, ApprovalsResponse, OperatorResponse, ContractInfoResponse, NftInfoResponse, AllNftInfoResponse, TokensResponse, OperatorsResponse, NumTokensResponse}; +use cw2981_royalties::msg::{RoyaltiesInfoResponse, CheckRoyaltiesResponse}; +use cw2981_royalties::{Metadata as Cw2981Metadata, Extension as Cw2981Extension}; +use crate::msg::{EvmQueryWrapper, EvmMsg, InstantiateMsg, ExecuteMsg, QueryMsg, CwErc721QueryMsg}; +use crate::querier::{EvmQuerier, DEFAULT_LIMIT, MAX_LIMIT}; use crate::error::ContractError; use crate::state::ERC721_ADDRESS; +use std::str::FromStr; + +const ERC2981_ID: &str = "0x2a55205a"; #[cfg_attr(not(feature = "library"), entry_point)] pub fn instantiate( @@ -25,7 +30,7 @@ pub fn execute( deps: DepsMut, _env: Env, info: MessageInfo, - msg: ExecuteMsg, + msg: ExecuteMsg, Empty>, ) -> Result, ContractError> { match msg { ExecuteMsg::TransferNft { recipient, token_id } => { @@ -35,18 +40,21 @@ pub fn execute( execute_send_nft(deps, info, contract, token_id, msg) }, ExecuteMsg::Approve { spender, token_id, expires: _ } => { - execute_approve(deps, spender, token_id) + execute_approve(deps, info, spender, token_id, true) }, - ExecuteMsg::Revoke { spender: _, token_id } => { - execute_approve(deps, "".to_string(), token_id) + ExecuteMsg::Revoke { spender, token_id } => { + execute_approve(deps, info, spender, token_id, false) }, ExecuteMsg::ApproveAll { operator, expires: _ } => { - execute_approve_all(deps, operator, true) + execute_approve_all(deps, info, operator, true) }, ExecuteMsg::RevokeAll { operator } => { - execute_approve_all(deps, operator, false) + execute_approve_all(deps, info, operator, false) }, - ExecuteMsg::Burn { token_id: _ } => { execute_burn() } + ExecuteMsg::Burn { token_id: _ } => { execute_burn() }, + ExecuteMsg::Mint { .. } => execute_mint(), + ExecuteMsg::UpdateOwnership(_) => update_ownership(), + ExecuteMsg::Extension { .. } => execute_extension(), } } @@ -56,8 +64,11 @@ pub fn execute_transfer_nft( recipient: String, token_id: String, ) -> Result, ContractError> { - let mut res = transfer_nft(deps, info, recipient, token_id)?; - res = res.add_attribute("action", "transfer_nft"); + let mut res = transfer_nft(deps, &info, &recipient, &token_id)?; + res = res.add_attribute("action", "transfer_nft") + .add_attribute("sender", info.sender) + .add_attribute("recipient", recipient) + .add_attribute("token_id", token_id); Ok(res) } @@ -68,31 +79,44 @@ pub fn execute_send_nft( token_id: String, msg: Binary, ) -> Result, ContractError> { - let mut res = transfer_nft(deps, info.clone(), recipient.clone(), token_id.clone())?; + let mut res = transfer_nft(deps, &info, &recipient, &token_id)?; let send = Cw721ReceiveMsg { sender: info.sender.to_string(), - token_id: token_id.clone(), + token_id: token_id.to_string(), msg, }; res = res .add_message(send.into_cosmos_msg(recipient.clone())?) - .add_attribute("action", "send_nft"); + .add_attribute("action", "send_nft") + .add_attribute("sender", info.sender) + .add_attribute("recipient", recipient) + .add_attribute("token_id", token_id); Ok(res) } pub fn execute_approve( deps: DepsMut, + info: MessageInfo, spender: String, token_id: String, + approved: bool, ) -> Result, ContractError> { let erc_addr = ERC721_ADDRESS.load(deps.storage)?; let querier = EvmQuerier::new(&deps.querier); - let payload = querier.erc721_approve_payload(spender.clone(), token_id.clone())?; + let mut payload_spender = spender.clone(); + let mut action = "approve"; + if !approved { + payload_spender = "".to_string(); + action = "revoke"; + } + let payload = querier.erc721_approve_payload(payload_spender, token_id.clone())?; let msg = EvmMsg::DelegateCallEvm { to: erc_addr, data: payload.encoded_payload }; let res = Response::new() - .add_attribute("action", "approve") + .add_attribute("action", action) .add_attribute("token_id", token_id) + .add_attribute("sender", info.sender) + .add_attribute("spender", spender.clone()) .add_message(msg); Ok(res) @@ -100,6 +124,7 @@ pub fn execute_approve( pub fn execute_approve_all( deps: DepsMut, + info: MessageInfo, to: String, approved: bool, ) -> Result, ContractError> { @@ -108,9 +133,14 @@ pub fn execute_approve_all( let querier = EvmQuerier::new(&deps.querier); let payload = querier.erc721_set_approval_all_payload(to.clone(), approved)?; let msg = EvmMsg::DelegateCallEvm { to: erc_addr, data: payload.encoded_payload }; + let mut action = "approve_all"; + if !approved { + action = "revoke_all"; + } let res = Response::new() - .add_attribute("action", "approve_all") - .add_attribute("to", to) + .add_attribute("action", action) + .add_attribute("operator", to) + .add_attribute("sender", info.sender) .add_attribute("approved", format!("{}", approved)) .add_message(msg); @@ -121,40 +151,89 @@ pub fn execute_burn() -> Result, ContractError> { Err(ContractError::NotSupported {}) } +pub fn execute_mint() -> Result, ContractError> { + Err(ContractError::NotSupported {}) +} + +pub fn update_ownership() -> Result, ContractError> { + Err(ContractError::NotSupported {}) +} + +pub fn execute_extension() -> Result, ContractError> { + Err(ContractError::NotSupported {}) +} + fn transfer_nft( deps: DepsMut, - info: MessageInfo, - recipient: String, - token_id: String, + info: &MessageInfo, + recipient: &str, + token_id: &str, ) -> Result, ContractError> { - deps.api.addr_validate(&recipient)?; + deps.api.addr_validate(recipient)?; let erc_addr = ERC721_ADDRESS.load(deps.storage)?; let querier = EvmQuerier::new(&deps.querier); - let owner = querier.erc721_owner(info.sender.clone().into_string(), erc_addr.clone(), token_id.clone())?.owner; - let payload = querier.erc721_transfer_payload(owner, recipient.clone(), token_id.clone())?; + let owner = querier.erc721_owner(info.sender.to_string(), erc_addr.to_string(), token_id.to_string())?.owner; + let payload = querier.erc721_transfer_payload(owner, recipient.to_string(), token_id.to_string())?; let msg = EvmMsg::DelegateCallEvm { to: erc_addr, data: payload.encoded_payload }; - let res = Response::new() - .add_attribute("from", info.sender) - .add_attribute("to", recipient) - .add_attribute("token_id", token_id) - .add_message(msg); + let res = Response::new().add_message(msg); Ok(res) } #[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result { +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result { match msg { QueryMsg::OwnerOf { token_id, include_expired: _ } => Ok(to_json_binary(&query_owner_of(deps, env, token_id)?)?), QueryMsg::Approval { token_id, spender, include_expired: _ } => Ok(query_approval(deps, env, token_id, spender)?), QueryMsg::Approvals { token_id, include_expired: _ } => Ok(query_approvals(deps, env, token_id)?), QueryMsg::Operator { owner, operator, include_expired: _ } => Ok(query_operator(deps, env, owner, operator)?), + QueryMsg::AllOperators { + owner, + include_expired: _, + start_after, + limit, + } => Ok(to_json_binary(&query_all_operators( + deps, + env, + owner, + start_after, + limit, + )?)?), + QueryMsg::NumTokens {} => Ok(to_json_binary(&query_num_tokens(deps, env)?)?), + QueryMsg::Tokens { + owner, + start_after, + limit, + } => Ok(to_json_binary(&query_tokens( + deps, + env, + owner, + start_after, + limit, + )?)?), + QueryMsg::AllTokens { start_after, limit } => Ok(to_json_binary(&query_all_tokens( + deps, + env, + start_after, + limit, + )?)?), + QueryMsg::Minter {} => Ok(to_json_binary(&query_minter()?)?), + QueryMsg::Ownership {} => Ok(to_json_binary(&query_ownership()?)?), QueryMsg::ContractInfo {} => Ok(query_contract_info(deps, env)?), - QueryMsg::NftInfo { token_id } => Ok(query_nft_info(deps, env, token_id)?), - QueryMsg::AllNftInfo { token_id, include_expired: _ } => Ok(query_all_nft_info(deps, env, token_id)?), - _ => Err(ContractError::NotSupported { }), + QueryMsg::NftInfo { token_id } => Ok(to_json_binary(&query_nft_info(deps, env, token_id)?)?), + QueryMsg::AllNftInfo { token_id, include_expired: _ } => Ok(to_json_binary(&query_all_nft_info(deps, env, token_id)?)?), + QueryMsg::Extension { msg } => match msg { + CwErc721QueryMsg::EvmAddress {} => { + Ok(to_json_binary(&ERC721_ADDRESS.load(deps.storage)?)?) + } + CwErc721QueryMsg::RoyaltyInfo { + token_id, + sale_price, + } => Ok(to_json_binary(&query_royalty_info(deps, env, token_id, sale_price)?)?), + CwErc721QueryMsg::CheckRoyalties {} => Ok(to_json_binary(&query_check_royalties(deps, env)?)?), + }, } } @@ -207,17 +286,157 @@ pub fn query_contract_info(deps: Deps, env: Env) -> StdResult, env: Env, token_id: String) -> StdResult { +pub fn query_nft_info( + deps: Deps, + env: Env, + token_id: String, +) -> StdResult> { + let erc_addr = ERC721_ADDRESS.load(deps.storage)?; + let querier = EvmQuerier::new(&deps.querier); + let res = querier.erc721_uri( + env.clone().contract.address.into_string(), + erc_addr.clone(), + token_id.clone(), + )?; + let royalty_info = query_royalty_info(deps, env, token_id, 100u128.into()); + Ok(NftInfoResponse { + token_uri: Some(res.uri), + extension: Some(Cw2981Metadata { + image: None, + image_data: None, + external_url: None, + description: None, + name: None, + attributes: None, + background_color: None, + animation_url: None, + youtube_url: None, + royalty_percentage: if let Ok(royalty_info) = &royalty_info { + Some(royalty_info.royalty_amount.u128() as u64) + } else { + None + }, + royalty_payment_address: if let Ok(royalty_info) = royalty_info { + Some(royalty_info.address) + } else { + None + }, + }), + }) +} + +pub fn query_all_nft_info( + deps: Deps, + env: Env, + token_id: String, +) -> StdResult> { + let owner_of_res = query_owner_of(deps, env.clone(), token_id.to_string())?; + let nft_info_res = query_nft_info(deps, env, token_id)?; + Ok(AllNftInfoResponse { + access: owner_of_res, + info: nft_info_res, + }) +} + +pub fn query_tokens( + deps: Deps, + env: Env, + owner: String, + start_after: Option, + limit: Option, +) -> StdResult { + let erc_addr = ERC721_ADDRESS.load(deps.storage)?; + let querier = EvmQuerier::new(&deps.querier); + let num_tokens = query_num_tokens(deps, env.clone())?.count; + let start_after_id = Int256::from_str(&start_after.unwrap_or("-1".to_string()))?; + let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; + + let mut cur = Int256::zero(); + let mut counter = 0; + let mut tokens: Vec = vec![]; + while counter < num_tokens && tokens.len() < limit { + let cur_str = cur.to_string(); + let t_owner = match querier.erc721_owner( + env.clone().contract.address.into_string(), + erc_addr.clone(), + cur_str.to_string(), + ) { + Ok(res) => res.owner, + Err(_) => "".to_string(), + }; + if t_owner != "" { + counter += 1; + if (owner.is_empty() || t_owner == owner) && cur > start_after_id { + tokens.push(cur_str); + } + } + cur += Int256::one(); + } + Ok(TokensResponse { tokens }) +} + +pub fn query_all_tokens( + deps: Deps, + env: Env, + start_after: Option, + limit: Option, +) -> StdResult { + query_tokens(deps, env, "".to_string(), start_after, limit) +} + +pub fn query_royalty_info( + deps: Deps, + env: Env, + token_id: String, + sale_price: Uint128, +) -> StdResult { let erc_addr = ERC721_ADDRESS.load(deps.storage)?; let querier = EvmQuerier::new(&deps.querier); - let res = querier.erc721_uri(env.clone().contract.address.into_string(), erc_addr.clone(), token_id.clone())?; - to_json_binary(&NftInfoResponse{token_uri: Some(res.uri), extension: ""}) + let res = querier.erc721_royalty_info( + env.clone().contract.address.into_string(), + erc_addr.clone(), + token_id, + sale_price, + )?; + Ok(RoyaltiesInfoResponse { + address: res.receiver, + royalty_amount: res.royalty_amount, + }) } -pub fn query_all_nft_info(deps: Deps, env: Env, token_id: String) -> StdResult { +pub fn query_check_royalties(deps: Deps, env: Env,) -> StdResult { let erc_addr = ERC721_ADDRESS.load(deps.storage)?; let querier = EvmQuerier::new(&deps.querier); - let res = querier.erc721_uri(env.clone().contract.address.into_string(), erc_addr.clone(), token_id.clone())?; - let owner_of_res = query_owner_of(deps, env, token_id)?; - to_json_binary(&AllNftInfoResponse{access: owner_of_res, info: NftInfoResponse{token_uri: Some(res.uri), extension: ""}}) -} \ No newline at end of file + let res = querier.supports_interface(env.clone().contract.address.into_string(),erc_addr.clone(), ERC2981_ID.to_string())?; + Ok(CheckRoyaltiesResponse { + royalty_payments: res.supported, + }) +} + +pub fn query_minter() -> Result, ContractError> { + Err(ContractError::NotSupported {}) +} + +pub fn query_ownership() -> Result, ContractError> { + Err(ContractError::NotSupported {}) +} + +pub fn query_all_operators( + _deps: Deps, + _env: Env, + _owner: String, + _start_after: Option, + _limit: Option, +) -> Result { + Err(ContractError::NotSupported {}) +} + +pub fn query_num_tokens(deps: Deps, env: Env) -> StdResult { + let erc_addr = ERC721_ADDRESS.load(deps.storage)?; + let querier = EvmQuerier::new(&deps.querier); + let res = querier + .erc721_total_supply(env.clone().contract.address.into_string(), erc_addr.clone())?; + Ok(NumTokensResponse { + count: res.supply.u128() as u64, + }) +} diff --git a/example/cosmwasm/cw721/src/error.rs b/example/cosmwasm/cw721/src/error.rs index 4758f75d2..bcfd0857c 100644 --- a/example/cosmwasm/cw721/src/error.rs +++ b/example/cosmwasm/cw721/src/error.rs @@ -8,4 +8,4 @@ pub enum ContractError { #[error("ERC721 does not have the requested functionality in specification")] NotSupported {}, -} \ No newline at end of file +} diff --git a/example/cosmwasm/cw721/src/msg.rs b/example/cosmwasm/cw721/src/msg.rs index 55ccb153b..d303c35ee 100644 --- a/example/cosmwasm/cw721/src/msg.rs +++ b/example/cosmwasm/cw721/src/msg.rs @@ -1,9 +1,9 @@ -use cosmwasm_std::{CosmosMsg, CustomMsg, CustomQuery}; +use cosmwasm_std::{CosmosMsg, CustomMsg, CustomQuery, Uint128}; use schemars::JsonSchema; -use cosmwasm_schema::cw_serde; +use cosmwasm_schema::{cw_serde, QueryResponses}; use serde::{Deserialize, Serialize}; -pub use cw721::{Cw721ExecuteMsg as ExecuteMsg, Cw721QueryMsg as QueryMsg}; +pub use cw721_base::{ExecuteMsg, QueryMsg}; #[cw_serde] pub struct InstantiateMsg { @@ -70,6 +70,21 @@ pub enum EvmQuery { contract_address: String, token_id: String, }, + Erc721RoyaltyInfo { + caller: String, + contract_address: String, + token_id: String, + sale_price: Uint128, + }, + SupportsInterface { + caller: String, + contract_address: String, + interface_id: String, + }, + Erc721TotalSupply { + caller: String, + contract_address: String, + }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -103,6 +118,22 @@ pub struct Erc721UriResponse { pub uri: String, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Erc721RoyaltyInfoResponse { + pub receiver: String, + pub royalty_amount: Uint128, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct SupportsInterfaceResponse { + pub supported: bool, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Erc721TotalSupplyResponse { + pub supply: Uint128, +} + // implement custom query impl CustomMsg for EvmMsg {} @@ -120,4 +151,41 @@ pub enum EvmMsg { to: String, data: String, // base64 encoded }, -} \ No newline at end of file +} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum CwErc721QueryMsg { + #[returns(String)] + EvmAddress {}, + + // cw2981 + /// Should be called on sale to see if royalties are owed + /// by the marketplace selling the NFT, if CheckRoyalties + /// returns true + /// See https://eips.ethereum.org/EIPS/eip-2981 + #[returns(cw2981_royalties::msg::RoyaltiesInfoResponse)] + RoyaltyInfo { + token_id: String, + // the denom of this sale must also be the denom returned by RoyaltiesInfoResponse + // this was originally implemented as a Coin + // however that would mean you couldn't buy using CW20s + // as CW20 is just mapping of addr -> balance + sale_price: Uint128, + }, + /// Called against contract to determine if this NFT + /// implements royalties. Should return a boolean as part of + /// CheckRoyaltiesResponse - default can simply be true + /// if royalties are implemented at token level + /// (i.e. always check on sale) + #[returns(cw2981_royalties::msg::CheckRoyaltiesResponse)] + CheckRoyalties {}, +} + +impl Default for CwErc721QueryMsg { + fn default() -> Self { + CwErc721QueryMsg::EvmAddress {} + } +} + +impl CustomMsg for CwErc721QueryMsg {} \ No newline at end of file diff --git a/example/cosmwasm/cw721/src/querier.rs b/example/cosmwasm/cw721/src/querier.rs index 542c63f8a..f4b349f1f 100644 --- a/example/cosmwasm/cw721/src/querier.rs +++ b/example/cosmwasm/cw721/src/querier.rs @@ -1,6 +1,9 @@ -use cosmwasm_std::{QuerierWrapper, StdResult}; +use cosmwasm_std::{QuerierWrapper, StdResult, Uint128}; -use crate::msg::{Route, EvmQuery, EvmQueryWrapper, ErcPayloadResponse, Erc721OwnerResponse, Erc721ApprovedResponse, Erc721IsApprovedForAllResponse, Erc721NameSymbolResponse, Erc721UriResponse}; +use crate::msg::{Route, EvmQuery, EvmQueryWrapper, ErcPayloadResponse, Erc721OwnerResponse, Erc721ApprovedResponse, Erc721IsApprovedForAllResponse, Erc721NameSymbolResponse, Erc721UriResponse, Erc721RoyaltyInfoResponse, SupportsInterfaceResponse, Erc721TotalSupplyResponse}; + +pub const DEFAULT_LIMIT: u32 = 10; +pub const MAX_LIMIT: u32 = 30; pub struct EvmQuerier<'a> { querier: &'a QuerierWrapper<'a, EvmQueryWrapper>, @@ -97,4 +100,57 @@ impl<'a> EvmQuerier<'a> { self.querier.query(&request) } + + pub fn erc721_royalty_info( + &self, + caller: String, + contract_address: String, + token_id: String, + sale_price: Uint128, + ) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721RoyaltyInfo { + caller, + contract_address, + token_id, + sale_price, + }, + } + .into(); + + self.querier.query(&request) + } + + pub fn supports_interface( + &self, + caller: String, + contract_address: String, + interface_id: String, + ) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::SupportsInterface { caller, interface_id, contract_address, }, + } + .into(); + + self.querier.query(&request) + } + + pub fn erc721_total_supply( + &self, + caller: String, + contract_address: String, + ) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721TotalSupply { + caller, + contract_address, + }, + } + .into(); + + self.querier.query(&request) + } } \ No newline at end of file diff --git a/go.mod b/go.mod index 778cb9657..34a45f600 100644 --- a/go.mod +++ b/go.mod @@ -40,8 +40,8 @@ require ( go.opentelemetry.io/otel v1.9.0 go.opentelemetry.io/otel/trace v1.9.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa - golang.org/x/sync v0.5.0 - golang.org/x/text v0.14.0 + golang.org/x/sync v0.7.0 + golang.org/x/text v0.15.0 golang.org/x/time v0.3.0 google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe google.golang.org/grpc v1.61.0 @@ -313,13 +313,13 @@ require ( go.opencensus.io v0.23.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.9.0 // indirect go.opentelemetry.io/otel/sdk v1.9.0 // indirect - golang.org/x/crypto v0.18.0 // indirect + golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.16.0 // indirect - golang.org/x/tools v0.15.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/term v0.20.0 // indirect + golang.org/x/tools v0.21.0 // indirect google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe // indirect gopkg.in/ini.v1 v1.67.0 // indirect @@ -344,17 +344,17 @@ require ( ) replace ( - github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.1.2 + github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.1.5 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.3.5 + github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.3.13 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-16 + github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-17 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.36 // Latest goleveldb is broken, we have to stick to this version github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.1 + github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.3.3 github.com/tendermint/tm-db => github.com/sei-protocol/tm-db v0.0.4 google.golang.org/grpc => google.golang.org/grpc v1.33.2 ) diff --git a/go.sum b/go.sum index 12fb9495e..0fdbcea72 100644 --- a/go.sum +++ b/go.sum @@ -1343,24 +1343,24 @@ 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-16 h1:bPQw44//5XHDZWfwO98g2Hie5HguxYZY+AiRsYMBdVg= -github.com/sei-protocol/go-ethereum v1.13.5-sei-16/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= +github.com/sei-protocol/go-ethereum v1.13.5-sei-17 h1:NQcNuL/nmLCzVJFj6Za4ZrNj1ODTmNKDH6ELrJIEpkY= +github.com/sei-protocol/go-ethereum v1.13.5-sei-17/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.3.5 h1:ibWj4uM3YeKLaGKfl1oWj36nkJo/2aZSyS7xo8Ixh6E= -github.com/sei-protocol/sei-cosmos v0.3.5/go.mod h1:imKzUdlLFKj8H39Ej9dICT+HZkx0rgEPsVm0PPb59kc= +github.com/sei-protocol/sei-cosmos v0.3.13 h1:YNlvDYMJZUJjI9nyIeHqxw9TULGulvbClhMJH/gh2oU= +github.com/sei-protocol/sei-cosmos v0.3.13/go.mod h1:WWwx6XlJc9SrjdRwLW69o511hFpfUiHapYb+V9OqOG4= github.com/sei-protocol/sei-db v0.0.36 h1:Qg8MlO/4btECyAB/XrbEexhpaS7OmYsrs9IUYULf+bY= github.com/sei-protocol/sei-db v0.0.36/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= github.com/sei-protocol/sei-iavl v0.1.9/go.mod h1:7PfkEVT5dcoQE+s/9KWdoXJ8VVVP1QpYYPLdxlkSXFk= github.com/sei-protocol/sei-ibc-go/v3 v3.3.0 h1:/mjpTuCSEVDJ51nUDSHU92N0bRSwt49r1rmdC/lqgp8= github.com/sei-protocol/sei-ibc-go/v3 v3.3.0/go.mod h1:VwB/vWu4ysT5DN2aF78d17LYmx3omSAdq6gpKvM7XRA= -github.com/sei-protocol/sei-tendermint v0.3.1 h1:CzlJqFCFBoh0qlzUNc4n3HVNGD9FX+bGTKOyHkgMd4U= -github.com/sei-protocol/sei-tendermint v0.3.1/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= +github.com/sei-protocol/sei-tendermint v0.3.3 h1:zH6xxrSRwHERaj/AcCR76U9daVY3Ub8kcy8+a/z1Dag= +github.com/sei-protocol/sei-tendermint v0.3.3/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= github.com/sei-protocol/sei-tm-db v0.0.5 h1:3WONKdSXEqdZZeLuWYfK5hP37TJpfaUa13vAyAlvaQY= github.com/sei-protocol/sei-tm-db v0.0.5/go.mod h1:Cpa6rGyczgthq7/0pI31jys2Fw0Nfrc+/jKdP1prVqY= -github.com/sei-protocol/sei-wasmd v0.1.2 h1:CHAQGWq0htMsJVo+4CWqz1uCCAMg6bTm1OUlD1mRZ5o= -github.com/sei-protocol/sei-wasmd v0.1.2/go.mod h1:CNF8PPkDFU0I/Lzw2+DbaNQhyxQj309ljOq7Waxj3fk= +github.com/sei-protocol/sei-wasmd v0.1.5 h1:+yO7mihwVTG34DGr/bF1bRwszUfDeN1EnMBZEY67l3k= +github.com/sei-protocol/sei-wasmd v0.1.5/go.mod h1:vd2qO4GOslLnmlsoAk+zE4D8/OQC1AkTqDY8QBOV09U= github.com/sei-protocol/tm-db v0.0.4 h1:7Y4EU62Xzzg6wKAHEotm7SXQR0aPLcGhKHkh3qd0tnk= github.com/sei-protocol/tm-db v0.0.4/go.mod h1:PWsIWOTwdwC7Ow/GUvx8HgUJTO691pBuorIQD8JvwAs= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= @@ -1649,8 +1649,8 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1713,8 +1713,9 @@ golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1789,8 +1790,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.0.0-20170207211851-4464e7848382/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1828,8 +1829,9 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1956,8 +1958,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1970,8 +1972,8 @@ golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1989,8 +1991,9 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2107,8 +2110,9 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/integration_test/dex_module/cancel_order_test.yaml b/integration_test/dex_module/cancel_order_test.yaml index 5086da32d..31496bd87 100644 --- a/integration_test/dex_module/cancel_order_test.yaml +++ b/integration_test/dex_module/cancel_order_test.yaml @@ -7,7 +7,7 @@ - cmd: echo "LONG?1.01?5?SEI?ATOM?LIMIT?{\"leverage\":\"1\",\"position_effect\":\"Open\"}" env: PARAMS # Place an order and set ORDER_ID - - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=5000000 --broadcast-mode=block --output json|jq -M -r ".logs[].events[].attributes[] | select(.key == \"order_id\").value" + - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=500000 --broadcast-mode=block --output json|jq -M -r ".logs[].events[].attributes[] | select(.key == \"order_id\").value" env: ORDER_ID # Prepare parameter to cancel the placed order - cmd: echo $ORDER_ID"?LONG?1.01?SEI?ATOM" @@ -22,4 +22,4 @@ env: NUMORDER verifiers: - type: eval - expr: NUMORDER == 5 # placed from the place_order test + expr: NUMORDER == 4 # placed from the place_order test diff --git a/integration_test/dex_module/place_order_test.yaml b/integration_test/dex_module/place_order_test.yaml index 62fa13ac1..168d4080c 100644 --- a/integration_test/dex_module/place_order_test.yaml +++ b/integration_test/dex_module/place_order_test.yaml @@ -6,19 +6,14 @@ # Prepare parameter - cmd: echo "LONG?1.01?5?SEI?ATOM?LIMIT?{\"leverage\":\"1\",\"position_effect\":\"Open\"}" env: PARAMS - # Verify that placing a dex order with gas > max block gas is okay since gas will be ignored - - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=500000000 --broadcast-mode=block --output json|jq -M -r ".logs[].events[].attributes[] | select(.key == \"order_id\").value" - env: MAX_GAS_ORDER_ID # Place an order and set ORDER_ID - - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=5000000 --broadcast-mode=block --output json|jq -M -r ".logs[].events[].attributes[] | select(.key == \"order_id\").value" + - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=500000 --broadcast-mode=block --output json|jq -M -r ".logs[].events[].attributes[] | select(.key == \"order_id\").value" env: ORDER_ID # Query the order by id - cmd: seid q dex get-orders-by-id $CONTRACT_ADDR SEI ATOM $ORDER_ID --output json |jq .order.status env: RESULT verifiers: # Order ids should be greater or equal to 0 - - type: eval - expr: MAX_GAS_ORDER_ID >= 0 - type: eval expr: ORDER_ID >= 0 # Order status should be something like PLACED @@ -40,7 +35,7 @@ - cmd: echo "LONG?1.0?10?usei?uatom?LIMIT? LONG?3.0?3000?usei?uatomatomatom?LIMIT? LONG?3.0?1000?usei?uatomatom?LIMIT?" env: PARAMS # Place 3 orders - - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=5000000 --broadcast-mode=block --output json| jq .code + - cmd: printf "12345678\n" | seid tx dex place-orders $CONTRACT_ADDR $PARAMS --amount=1000000000usei -y --from=admin --chain-id=sei --fees=1000000usei --gas=500000 --broadcast-mode=block --output json| jq .code # Query all the orders - cmd: seid q dex get-orders $CONTRACT_ADDR $ADMIN_ADDR --output json |jq ".[] | length" diff --git a/integration_test/evm_module/hardhat_test.yaml b/integration_test/evm_module/hardhat_test.yaml deleted file mode 100644 index 14e7c153e..000000000 --- a/integration_test/evm_module/hardhat_test.yaml +++ /dev/null @@ -1,17 +0,0 @@ -- name: Hardhat Test - inputs: - # Fund owner account in hardhat tests - - cmd: printf "12345678\n" | seid tx evm send 0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 10000000000000000000 --from admin | cut -d':' -f2- - env: TX_HASH - - cmd: sleep 3 - - cmd: cast receipt "$TX_HASH" -j |jq -r ."status" - env: RESULT - # Setup for Hardhat Integration Test - - cmd: bash contracts/test/deploy_atom_erc20.sh - - cmd: bash contracts/test/get_validator_address.sh - - cmd: bash contracts/test/send_gov_proposal.sh - - cmd: bash contracts/test/query_oracle_data.sh - - cmd: bash contracts/test/deploy_wasm_contract.sh - verifiers: - - type: eval - expr: RESULT == "0x1" diff --git a/integration_test/evm_module/scripts/evm_interoperability_tests.sh b/integration_test/evm_module/scripts/evm_interoperability_tests.sh index 707991d57..2dc58ab62 100755 --- a/integration_test/evm_module/scripts/evm_interoperability_tests.sh +++ b/integration_test/evm_module/scripts/evm_interoperability_tests.sh @@ -1,6 +1,11 @@ +#!/bin/bash + +set -e + cd contracts npm ci npx hardhat test --network seilocal test/CW20toERC20PointerTest.js npx hardhat test --network seilocal test/ERC20toCW20PointerTest.js +npx hardhat test --network seilocal test/ERC20toNativePointerTest.js npx hardhat test --network seilocal test/CW721toERC721PointerTest.js npx hardhat test --network seilocal test/ERC721toCW721PointerTest.js diff --git a/integration_test/evm_module/scripts/evm_tests.sh b/integration_test/evm_module/scripts/evm_tests.sh index dedc6f2f8..32b647d49 100755 --- a/integration_test/evm_module/scripts/evm_tests.sh +++ b/integration_test/evm_module/scripts/evm_tests.sh @@ -1,4 +1,9 @@ +#!/bin/bash + +set -e + cd contracts npm ci npx hardhat test --network seilocal test/EVMCompatabilityTest.js npx hardhat test --network seilocal test/EVMPrecompileTest.js +npx hardhat test --network seilocal test/AssociateTest.js \ No newline at end of file diff --git a/occ_tests/messages/test_msgs.go b/occ_tests/messages/test_msgs.go index a9f3c2d2a..6ea0d5c65 100644 --- a/occ_tests/messages/test_msgs.go +++ b/occ_tests/messages/test_msgs.go @@ -11,6 +11,7 @@ import ( 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/config" "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" ) @@ -84,7 +85,7 @@ func evmTransfer(testAcct utils.TestAcct, to common.Address, scenario string) *u GasFeeCap: new(big.Int).SetUint64(1000000000000), GasTipCap: new(big.Int).SetUint64(1000000000000), Gas: 21000, - ChainID: big.NewInt(1), + ChainID: big.NewInt(config.DefaultChainID), To: &to, Value: big.NewInt(1), Nonce: 0, diff --git a/occ_tests/occ_test.go b/occ_tests/occ_test.go index ff5cb3c0c..e78e6f4a4 100644 --- a/occ_tests/occ_test.go +++ b/occ_tests/occ_test.go @@ -170,38 +170,40 @@ func TestParallelTransactions(t *testing.T) { } for _, tt := range tests { - blockTime := time.Now() - accts := utils.NewTestAccounts(5) - - // execute sequentially, then in parallel - // the responses and state should match for both - sCtx := utils.NewTestContext(t, accts, blockTime, 1, false) - txs := tt.txs(sCtx) - if tt.shuffle { - txs = utils.Shuffle(txs) - } - - if tt.before != nil { - tt.before(sCtx) - } - - sEvts, sResults, _, sErr := utils.RunWithoutOCC(sCtx, txs) - require.NoError(t, sErr, tt.name) - require.Len(t, sResults, len(txs)) + t.Run(tt.name, func(t *testing.T) { + blockTime := time.Now() + accts := utils.NewTestAccounts(5) + + // execute sequentially, then in parallel + // the responses and state should match for both + sCtx := utils.NewTestContext(t, accts, blockTime, 1, false) + txs := tt.txs(sCtx) + if tt.shuffle { + txs = utils.Shuffle(txs) + } - for i := 0; i < tt.runs; i++ { - pCtx := utils.NewTestContext(t, accts, blockTime, config.DefaultConcurrencyWorkers, true) if tt.before != nil { - tt.before(pCtx) + tt.before(sCtx) } - pEvts, pResults, _, pErr := utils.RunWithOCC(pCtx, txs) - require.NoError(t, pErr, tt.name) - require.Len(t, pResults, len(txs)) - - 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) - } + + sEvts, sResults, _, sErr := utils.RunWithoutOCC(sCtx, txs) + require.NoError(t, sErr, tt.name) + require.Len(t, sResults, len(txs)) + + for i := 0; i < tt.runs; i++ { + pCtx := utils.NewTestContext(t, accts, blockTime, config.DefaultConcurrencyWorkers, true) + if tt.before != nil { + tt.before(pCtx) + } + pEvts, pResults, _, pErr := utils.RunWithOCC(pCtx, txs) + require.NoError(t, pErr, tt.name) + require.Len(t, pResults, len(txs)) + + 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 4b20702ef..e64772664 100644 --- a/occ_tests/utils/utils.go +++ b/occ_tests/utils/utils.go @@ -35,6 +35,7 @@ import ( 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" + "github.com/sei-protocol/sei-chain/x/evm/config" types2 "github.com/sei-protocol/sei-chain/x/evm/types" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" ) @@ -86,7 +87,7 @@ func NewSigner() TestAcct { pvKeyHex := hex.EncodeToString(priv1.Bytes()) key, _ := crypto.HexToECDSA(pvKeyHex) - ethCfg := types2.DefaultChainConfig().EthereumConfig(big.NewInt(1)) + ethCfg := types2.DefaultChainConfig().EthereumConfig(big.NewInt(config.DefaultChainID)) signer := ethtypes.MakeSigner(ethCfg, utils2.Big1, 1) address := crypto.PubkeyToAddress(key.PublicKey) diff --git a/oracle/price-feeder/oracle/provider/mexc_test.go b/oracle/price-feeder/oracle/provider/mexc_test.go index 9353a6429..9acf8672f 100644 --- a/oracle/price-feeder/oracle/provider/mexc_test.go +++ b/oracle/price-feeder/oracle/provider/mexc_test.go @@ -13,6 +13,7 @@ import ( ) func TestMexcProvider_GetTickerPrices(t *testing.T) { + t.Skip("skipping until mexc websocket endpoint is restored") p, err := NewMexcProvider( context.TODO(), zerolog.Nop(), @@ -80,6 +81,7 @@ func TestMexcProvider_GetTickerPrices(t *testing.T) { } func TestMexcProvider_SubscribeCurrencyPairs(t *testing.T) { + t.Skip("skipping until mexc websocket endpoint is restored") p, err := NewMexcProvider( context.TODO(), zerolog.Nop(), diff --git a/precompiles/addr/addr.go b/precompiles/addr/addr.go index f787a4708..35d70952a 100644 --- a/precompiles/addr/addr.go +++ b/precompiles/addr/addr.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/x/evm/state" ) const ( @@ -93,6 +94,11 @@ func (p Precompile) GetName() string { } func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index b461903f2..7a40527c9 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -13,6 +13,7 @@ import ( "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/state" "github.com/sei-protocol/sei-chain/x/evm/tracers" "github.com/tendermint/tendermint/libs/log" ) @@ -132,6 +133,11 @@ func (p Precompile) GetName() string { } func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err diff --git a/precompiles/common/expected_keepers.go b/precompiles/common/expected_keepers.go index 3b8596431..6239cc827 100644 --- a/precompiles/common/expected_keepers.go +++ b/precompiles/common/expected_keepers.go @@ -3,11 +3,15 @@ package common import ( "context" + connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" + "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v3/modules/core/exported" + 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" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + ibctypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" "github.com/ethereum/go-ethereum/common" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" ) @@ -68,14 +72,18 @@ type DistributionKeeper interface { } type TransferKeeper interface { - SendTransfer( - ctx sdk.Context, - sourcePort, - sourceChannel string, - token sdk.Coin, - sender sdk.AccAddress, - receiver string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - ) error + Transfer(goCtx context.Context, msg *ibctypes.MsgTransfer) (*ibctypes.MsgTransferResponse, error) +} + +type ClientKeeper interface { + GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) + GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) +} + +type ConnectionKeeper interface { + GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) +} + +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, portID, channelID string) (types.Channel, bool) } diff --git a/precompiles/distribution/distribution.go b/precompiles/distribution/distribution.go index 08ff3ee5b..5fe383b5d 100644 --- a/precompiles/distribution/distribution.go +++ b/precompiles/distribution/distribution.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/x/evm/state" ) const ( @@ -101,6 +102,11 @@ func (p Precompile) GetName() string { } func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() if readOnly { return nil, errors.New("cannot call distr precompile from staticcall") } diff --git a/precompiles/gov/gov.go b/precompiles/gov/gov.go index 096165fcb..48890f0ea 100644 --- a/precompiles/gov/gov.go +++ b/precompiles/gov/gov.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/x/evm/state" ) const ( @@ -104,6 +105,11 @@ func (p Precompile) GetName() string { } func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() if readOnly { return nil, errors.New("cannot call gov precompile from staticcall") } diff --git a/precompiles/ibc/IBC.sol b/precompiles/ibc/IBC.sol index 649d3a3b6..236d5d789 100644 --- a/precompiles/ibc/IBC.sol +++ b/precompiles/ibc/IBC.sol @@ -17,6 +17,16 @@ interface IBC { uint256 amount, uint64 revisionNumber, uint64 revisionHeight, - uint64 timeoutTimestamp + uint64 timeoutTimestamp, + string memo + ) external returns (bool success); + + function transferWithDefaultTimeout( + string toAddress, + string memory port, + string memory channel, + string memory denom, + uint256 amount, + string memo ) external returns (bool success); } diff --git a/precompiles/ibc/abi.json b/precompiles/ibc/abi.json index a1ff1e9fc..f4e871a3b 100644 --- a/precompiles/ibc/abi.json +++ b/precompiles/ibc/abi.json @@ -1,56 +1 @@ -[ - { - "inputs": [ - { - "internalType": "string", - "name": "toAddress", - "type": "string" - }, - { - "internalType": "string", - "name": "port", - "type": "string" - }, - { - "internalType": "string", - "name": "channel", - "type": "string" - }, - { - "internalType": "string", - "name": "denom", - "type": "string" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint64", - "name": "revisionNumber", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "revisionHeight", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "timeoutTimestamp", - "type": "uint64" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "success", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - } -] +[{"inputs":[{"internalType":"string","name":"toAddress","type":"string"},{"internalType":"string","name":"port","type":"string"},{"internalType":"string","name":"channel","type":"string"},{"internalType":"string","name":"denom","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint64","name":"revisionNumber","type":"uint64"},{"internalType":"uint64","name":"revisionHeight","type":"uint64"},{"internalType":"uint64","name":"timeoutTimestamp","type":"uint64"},{"internalType":"string","name":"memo","type":"string"}],"name":"transfer","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"toAddress","type":"string"},{"internalType":"string","name":"port","type":"string"},{"internalType":"string","name":"channel","type":"string"},{"internalType":"string","name":"denom","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"memo","type":"string"}],"name":"transferWithDefaultTimeout","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"}] diff --git a/precompiles/ibc/ibc.go b/precompiles/ibc/ibc.go index c6f1921d4..d612ca171 100644 --- a/precompiles/ibc/ibc.go +++ b/precompiles/ibc/ibc.go @@ -7,12 +7,16 @@ import ( "fmt" "math/big" + "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + "github.com/cosmos/cosmos-sdk/types/bech32" "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/state" sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v3/modules/core/03-connection/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" @@ -21,7 +25,8 @@ import ( ) const ( - TransferMethod = "transfer" + TransferMethod = "transfer" + TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" ) const ( @@ -51,27 +56,41 @@ func GetABI() abi.ABI { type Precompile struct { pcommon.Precompile - address common.Address - transferKeeper pcommon.TransferKeeper - evmKeeper pcommon.EVMKeeper - - TransferID []byte + address common.Address + transferKeeper pcommon.TransferKeeper + evmKeeper pcommon.EVMKeeper + clientKeeper pcommon.ClientKeeper + connectionKeeper pcommon.ConnectionKeeper + channelKeeper pcommon.ChannelKeeper + + TransferID []byte + TransferWithDefaultTimeoutID []byte } -func NewPrecompile(transferKeeper pcommon.TransferKeeper, evmKeeper pcommon.EVMKeeper) (*Precompile, error) { +func NewPrecompile( + transferKeeper pcommon.TransferKeeper, + evmKeeper pcommon.EVMKeeper, + clientKeeper pcommon.ClientKeeper, + connectionKeeper pcommon.ConnectionKeeper, + channelKeeper pcommon.ChannelKeeper) (*Precompile, error) { newAbi := GetABI() p := &Precompile{ - Precompile: pcommon.Precompile{ABI: newAbi}, - address: common.HexToAddress(IBCAddress), - transferKeeper: transferKeeper, - evmKeeper: evmKeeper, + Precompile: pcommon.Precompile{ABI: newAbi}, + address: common.HexToAddress(IBCAddress), + transferKeeper: transferKeeper, + evmKeeper: evmKeeper, + clientKeeper: clientKeeper, + connectionKeeper: connectionKeeper, + channelKeeper: channelKeeper, } for name, m := range newAbi.Methods { switch name { case TransferMethod: p.TransferID = m.ID + case TransferWithDefaultTimeoutMethod: + p.TransferWithDefaultTimeoutID = m.ID } } @@ -94,7 +113,12 @@ func (p Precompile) RequiredGas(input []byte) uint64 { 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, _ *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { +func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, _ *big.Int, _ *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() if readOnly { return nil, 0, errors.New("cannot call IBC precompile from staticcall") } @@ -116,6 +140,8 @@ func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, calli switch method.Name { case TransferMethod: return p.transfer(ctx, method, args, caller) + case TransferWithDefaultTimeoutMethod: + return p.transferWithDefaultTimeout(ctx, method, args, caller) } return } @@ -134,65 +160,101 @@ func (p Precompile) transfer(ctx sdk.Context, method *abi.Method, args []interfa } }() - if err := pcommon.ValidateArgsLength(args, 8); err != nil { + if err := pcommon.ValidateArgsLength(args, 9); err != nil { rerr = err return } - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - rerr = errors.New("caller is not a valid SEI address") + validatedArgs, err := p.validateCommonArgs(ctx, args, caller) + if err != nil { + rerr = err return } - receiverAddressString, ok := args[0].(string) - if !ok { - rerr = errors.New("receiverAddress is not a string") + if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { + // short circuit + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) + ret, rerr = method.Outputs.Pack(true) return } - _, bz, err := bech32.DecodeAndConvert(receiverAddressString) - if err != nil { - rerr = err - return + + coin := sdk.Coin{ + Denom: validatedArgs.denom, + Amount: sdk.NewIntFromBigInt(validatedArgs.amount), } - err = sdk.VerifyAddressFormat(bz) - if err != nil { - rerr = err + + revisionNumber, ok := args[5].(uint64) + if !ok { + rerr = errors.New("revisionNumber is not a uint64") return } - port, ok := args[1].(string) + revisionHeight, ok := args[6].(uint64) if !ok { - rerr = errors.New("port is not a string") + rerr = errors.New("revisionHeight is not a uint64") return } - if port == "" { - rerr = errors.New("port cannot be empty") - return + + height := clienttypes.Height{ + RevisionNumber: revisionNumber, + RevisionHeight: revisionHeight, } - channelID, ok := args[2].(string) + timeoutTimestamp, ok := args[7].(uint64) if !ok { - rerr = errors.New("channelID is not a string") + rerr = errors.New("timeoutTimestamp is not a uint64") return } - if channelID == "" { - rerr = errors.New("channelID cannot be empty") + + msg := types.MsgTransfer{ + SourcePort: validatedArgs.port, + SourceChannel: validatedArgs.channelID, + Token: coin, + Sender: validatedArgs.senderSeiAddr.String(), + Receiver: validatedArgs.receiverAddressString, + TimeoutHeight: height, + TimeoutTimestamp: timeoutTimestamp, + } + + msg = addMemo(args[8], msg) + + err = msg.ValidateBasic() + if err != nil { + rerr = err return } - denom := args[3].(string) - if denom == "" { - rerr = errors.New("invalid denom") + _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) + + if err != nil { + rerr = err return } + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) + ret, rerr = method.Outputs.Pack(true) + return +} - amount, ok := args[4].(*big.Int) - if !ok { - rerr = errors.New("amount is not a big.Int") +func (p Precompile) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { + defer func() { + if err := recover(); err != nil { + ret = nil + remainingGas = 0 + rerr = fmt.Errorf("%s", err) + return + } + }() + + if err := pcommon.ValidateArgsLength(args, 6); err != nil { + rerr = err + return + } + validatedArgs, err := p.validateCommonArgs(ctx, args, caller) + if err != nil { + rerr = err return } - if amount.Cmp(big.NewInt(0)) == 0 { + if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { // short circuit remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) ret, rerr = method.Outputs.Pack(true) @@ -200,34 +262,54 @@ func (p Precompile) transfer(ctx sdk.Context, method *abi.Method, args []interfa } coin := sdk.Coin{ - Denom: denom, - Amount: sdk.NewIntFromBigInt(amount), + Denom: validatedArgs.denom, + Amount: sdk.NewIntFromBigInt(validatedArgs.amount), } - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") + connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) + + if err != nil { + rerr = err return } - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") + latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) + if err != nil { + rerr = err return } - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, + height, err := GetAdjustedHeight(*latestConsensusHeight) + if err != nil { + rerr = err + return } - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") + timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) + if err != nil { + rerr = err return } - err = p.transferKeeper.SendTransfer(ctx, port, channelID, coin, senderSeiAddr, receiverAddressString, height, timeoutTimestamp) + msg := types.MsgTransfer{ + SourcePort: validatedArgs.port, + SourceChannel: validatedArgs.channelID, + Token: coin, + Sender: validatedArgs.senderSeiAddr.String(), + Receiver: validatedArgs.receiverAddressString, + TimeoutHeight: height, + TimeoutTimestamp: timeoutTimestamp, + } + + msg = addMemo(args[5], msg) + + err = msg.ValidateBasic() + if err != nil { + rerr = err + return + } + + _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) if err != nil { rerr = err @@ -242,6 +324,8 @@ func (Precompile) IsTransaction(method string) bool { switch method { case TransferMethod: return true + case TransferWithDefaultTimeoutMethod: + return true default: return false } @@ -266,3 +350,136 @@ func (p Precompile) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.Acc } return seiAddr, nil } + +func (p Precompile) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { + channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) + if !found { + return nil, errors.New("channel not found") + } + + connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) + + if !found { + return nil, errors.New("connection not found") + } + return &connection, nil +} + +func (p Precompile) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { + clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) + + if !found { + return nil, errors.New("could not get the client state") + } + + latestHeight := clientState.GetLatestHeight() + return &clienttypes.Height{ + RevisionNumber: latestHeight.GetRevisionNumber(), + RevisionHeight: latestHeight.GetRevisionHeight(), + }, nil +} + +func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { + defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) + if err != nil { + return clienttypes.Height{}, err + } + + absoluteHeight := latestConsensusHeight + absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber + absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight + return absoluteHeight, nil +} + +func (p Precompile) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { + consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) + var consensusStateTimestamp uint64 + if found { + consensusStateTimestamp = consensusState.GetTimestamp() + } + + defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp + blockTime := ctx.BlockTime().UnixNano() + if blockTime > 0 { + now := uint64(blockTime) + if now > consensusStateTimestamp { + return now + defaultRelativePacketTimeoutTimestamp, nil + } else { + return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil + } + } else { + return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") + } +} + +type ValidatedArgs struct { + senderSeiAddr sdk.AccAddress + receiverAddressString string + port string + channelID string + denom string + amount *big.Int +} + +func (p Precompile) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { + senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) + if !ok { + return nil, errors.New("caller is not a valid SEI address") + } + + receiverAddressString, ok := args[0].(string) + if !ok { + return nil, errors.New("receiverAddress is not a string") + } + _, bz, err := bech32.DecodeAndConvert(receiverAddressString) + if err != nil { + return nil, err + } + err = sdk.VerifyAddressFormat(bz) + if err != nil { + return nil, err + } + + port, ok := args[1].(string) + if !ok { + return nil, errors.New("port is not a string") + } + if port == "" { + return nil, errors.New("port cannot be empty") + } + + channelID, ok := args[2].(string) + if !ok { + return nil, errors.New("channelID is not a string") + } + if channelID == "" { + return nil, errors.New("channelID cannot be empty") + } + + denom := args[3].(string) + if denom == "" { + return nil, errors.New("invalid denom") + } + + amount, ok := args[4].(*big.Int) + if !ok { + return nil, errors.New("amount is not a big.Int") + } + return &ValidatedArgs{ + senderSeiAddr: senderSeiAddr, + receiverAddressString: receiverAddressString, + port: port, + channelID: channelID, + denom: denom, + amount: amount, + }, nil +} + +func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { + memo := "" + if memoArg != nil { + memo = memoArg.(string) + } + transferMsg.Memo = memo + return transferMsg +} diff --git a/precompiles/ibc/ibc_test.go b/precompiles/ibc/ibc_test.go index fc07b9cb8..396755b4b 100644 --- a/precompiles/ibc/ibc_test.go +++ b/precompiles/ibc/ibc_test.go @@ -1,13 +1,17 @@ package ibc_test import ( + "context" "errors" "math/big" "reflect" "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v3/modules/core/exported" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" @@ -20,23 +24,31 @@ import ( type MockTransferKeeper struct{} -func (tk *MockTransferKeeper) SendTransfer(ctx sdk.Context, sourcePort, sourceChannel string, token sdk.Coin, - sender sdk.AccAddress, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64) error { - return nil +func (tk *MockTransferKeeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { + return nil, nil +} + +type MockMemoTransferKeeper struct { + t require.TestingT + wantMemo string +} + +func (tk *MockMemoTransferKeeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { + require.Equal(tk.t, tk.wantMemo, msg.Memo) + return nil, nil } type MockFailedTransferTransferKeeper struct{} -func (tk *MockFailedTransferTransferKeeper) SendTransfer(ctx sdk.Context, sourcePort, sourceChannel string, token sdk.Coin, - sender sdk.AccAddress, receiver string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64) error { - return errors.New("failed to send transfer") +func (tk *MockFailedTransferTransferKeeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { + return nil, errors.New("failed to send transfer") } func TestPrecompile_Run(t *testing.T) { senderSeiAddress, senderEvmAddress := testkeeper.MockAddressPair() receiverAddress := "cosmos1yykwxjzr2tv4mhx5tsf8090sdg96f2ax8fydk2" - pre, _ := ibc.NewPrecompile(nil, nil) + pre, _ := ibc.NewPrecompile(nil, nil, nil, nil, nil) testTransfer, _ := pre.ABI.MethodById(pre.TransferID) packedTrue, _ := testTransfer.Outputs.Pack(true) @@ -53,6 +65,7 @@ func TestPrecompile_Run(t *testing.T) { revisionNumber uint64 revisionHeight uint64 timeoutTimestamp uint64 + memo string } type args struct { caller common.Address @@ -93,7 +106,7 @@ func TestPrecompile_Run(t *testing.T) { fields: fields{transferKeeper: &MockTransferKeeper{}}, args: commonArgs, wantBz: packedTrue, - wantRemainingGas: 994040, + wantRemainingGas: 994319, wantErr: false, }, { @@ -204,6 +217,47 @@ func TestPrecompile_Run(t *testing.T) { wantErr: true, wantErrMsg: "decoding bech32 failed: invalid bech32 string length 7", }, + { + name: "memo is added to the transfer if passed", + fields: fields{transferKeeper: &MockMemoTransferKeeper{t: t, wantMemo: "test memo"}}, + args: args{ + caller: senderEvmAddress, + callingContract: senderEvmAddress, + input: &input{ + receiverAddr: receiverAddress, + sourcePort: "transfer", + sourceChannel: "channel-0", + denom: "usei", + amount: big.NewInt(100), + memo: "test memo", + }, + suppliedGas: uint64(1000000), + value: nil, + }, + wantBz: packedTrue, + wantRemainingGas: 994319, + wantErr: false, + }, + { + name: "memo is not added to the transfer if not passed", + fields: fields{transferKeeper: &MockMemoTransferKeeper{t: t, wantMemo: ""}}, + args: args{ + caller: senderEvmAddress, + callingContract: senderEvmAddress, + input: &input{ + receiverAddr: receiverAddress, + sourcePort: "transfer", + sourceChannel: "channel-0", + denom: "usei", + amount: big.NewInt(100), + }, + suppliedGas: uint64(1000000), + value: nil, + }, + wantBz: packedTrue, + wantRemainingGas: 994319, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -216,12 +270,13 @@ func TestPrecompile_Run(t *testing.T) { StateDB: stateDb, TxContext: vm.TxContext{Origin: senderEvmAddress}, } - p, _ := ibc.NewPrecompile(tt.fields.transferKeeper, k) + p, _ := ibc.NewPrecompile(tt.fields.transferKeeper, k, nil, nil, nil) transfer, err := p.ABI.MethodById(p.TransferID) require.Nil(t, err) inputs, err := transfer.Inputs.Pack(tt.args.input.receiverAddr, 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) + tt.args.input.revisionNumber, tt.args.input.revisionHeight, tt.args.input.timeoutTimestamp, + tt.args.input.memo) 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, nil, false) if (err != nil) != tt.wantErr { @@ -241,3 +296,366 @@ func TestPrecompile_Run(t *testing.T) { }) } } + +func TestTransferWithDefaultTimeoutPrecompile_Run(t *testing.T) { + senderSeiAddress, senderEvmAddress := testkeeper.MockAddressPair() + receiverAddress := "cosmos1yykwxjzr2tv4mhx5tsf8090sdg96f2ax8fydk2" + + type fields struct { + transferKeeper pcommon.TransferKeeper + clientKeeper pcommon.ClientKeeper + connectionKeeper pcommon.ConnectionKeeper + channelKeeper pcommon.ChannelKeeper + } + + type input struct { + receiverAddr string + sourcePort string + sourceChannel string + denom string + amount *big.Int + memo string + } + type args struct { + caller common.Address + callingContract common.Address + input *input + suppliedGas uint64 + value *big.Int + } + + commonArgs := args{ + caller: senderEvmAddress, + callingContract: senderEvmAddress, + input: &input{ + receiverAddr: receiverAddress, + sourcePort: "transfer", + sourceChannel: "channel-0", + denom: "denom", + amount: big.NewInt(100), + }, + suppliedGas: uint64(1000000), + value: nil, + } + + tests := []struct { + name string + fields fields + args args + wantBz []byte + wantRemainingGas uint64 + wantErr bool + wantErrMsg string + }{ + { + name: "failed transfer: caller not whitelisted", + fields: fields{transferKeeper: &MockTransferKeeper{}}, + args: args{caller: senderEvmAddress, callingContract: common.Address{}, input: commonArgs.input, suppliedGas: 1000000, value: nil}, + wantBz: nil, + wantErr: true, + wantErrMsg: "cannot delegatecall IBC", + }, + { + name: "failed transfer: empty sourcePort", + fields: fields{transferKeeper: &MockTransferKeeper{}}, + args: args{ + caller: senderEvmAddress, + callingContract: senderEvmAddress, + input: &input{ + receiverAddr: receiverAddress, + sourcePort: "", // empty sourcePort + sourceChannel: "channel-0", + denom: "denom", + amount: big.NewInt(100), + }, + suppliedGas: uint64(1000000), + value: nil, + }, + wantBz: nil, + wantErr: true, + wantErrMsg: "port cannot be empty", + }, + { + name: "failed transfer: empty sourceChannel", + fields: fields{transferKeeper: &MockTransferKeeper{}}, + args: args{ + caller: senderEvmAddress, + callingContract: senderEvmAddress, + input: &input{ + receiverAddr: receiverAddress, + sourcePort: "transfer", + sourceChannel: "", + denom: "denom", + amount: big.NewInt(100), + }, + suppliedGas: uint64(1000000), + value: nil, + }, + wantBz: nil, + wantErr: true, + wantErrMsg: "channelID cannot be empty", + }, + { + name: "failed transfer: invalid denom", + fields: fields{transferKeeper: &MockTransferKeeper{}}, + args: args{ + caller: senderEvmAddress, + callingContract: senderEvmAddress, + input: &input{ + receiverAddr: receiverAddress, + sourcePort: "transfer", + sourceChannel: "channel-0", + denom: "", + amount: big.NewInt(100), + }, + suppliedGas: uint64(1000000), + value: nil, + }, + wantBz: nil, + wantErr: true, + wantErrMsg: "invalid denom", + }, + { + name: "failed transfer: invalid receiver address", + fields: fields{transferKeeper: &MockTransferKeeper{}}, + args: args{ + caller: senderEvmAddress, + callingContract: senderEvmAddress, + input: &input{ + receiverAddr: "invalid", + sourcePort: "transfer", + sourceChannel: "channel-0", + denom: "", + amount: big.NewInt(100), + }, + suppliedGas: uint64(1000000), + value: nil, + }, + wantBz: nil, + wantErr: true, + wantErrMsg: "decoding bech32 failed: invalid bech32 string length 7", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testApp := testkeeper.EVMTestApp + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + k := &testApp.EvmKeeper + k.SetAddressMapping(ctx, senderSeiAddress, senderEvmAddress) + stateDb := state.NewDBImpl(ctx, k, true) + evm := vm.EVM{ + StateDB: stateDb, + TxContext: vm.TxContext{Origin: senderEvmAddress}, + } + + p, _ := ibc.NewPrecompile(tt.fields.transferKeeper, + k, tt.fields.clientKeeper, + tt.fields.connectionKeeper, + tt.fields.channelKeeper) + transfer, err := p.ABI.MethodById(p.TransferWithDefaultTimeoutID) + require.Nil(t, err) + inputs, err := transfer.Inputs.Pack(tt.args.input.receiverAddr, + tt.args.input.sourcePort, tt.args.input.sourceChannel, tt.args.input.denom, tt.args.input.amount, + tt.args.input.memo) + require.Nil(t, err) + gotBz, gotRemainingGas, err := p.RunAndCalculateGas(&evm, + tt.args.caller, + tt.args.callingContract, + append(p.TransferWithDefaultTimeoutID, 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 + } + if err != nil { + require.Equal(t, tt.wantErrMsg, err.Error()) + } + + if !reflect.DeepEqual(gotBz, tt.wantBz) { + t.Errorf("Run() gotBz = %v, want %v", gotBz, tt.wantBz) + } + if !reflect.DeepEqual(gotRemainingGas, tt.wantRemainingGas) { + t.Errorf("Run() gotRemainingGas = %v, want %v", gotRemainingGas, tt.wantRemainingGas) + } + }) + } +} + +func TestPrecompile_GetAdjustedHeight(t *testing.T) { + type args struct { + latestConsensusHeight clienttypes.Height + } + tests := []struct { + name string + args args + want clienttypes.Height + wantErr bool + }{ + { + name: "height is adjusted with defaults", + args: args{ + latestConsensusHeight: clienttypes.NewHeight(2, 3), + }, + want: clienttypes.Height{ + RevisionNumber: 2, + RevisionHeight: 1003, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ibc.GetAdjustedHeight(tt.args.latestConsensusHeight) + if (err != nil) != tt.wantErr { + t.Errorf("GetAdjustedHeight() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetAdjustedHeight() got = %v, want %v", got, tt.want) + } + }) + } +} + +type MockClientKeeper struct { + consensusState *MockConsensusState + returnConsensusState bool +} + +func (ck *MockClientKeeper) GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) { + return nil, false +} + +func (ck *MockClientKeeper) GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) { + return ck.consensusState, ck.returnConsensusState +} + +type MockConsensusState struct { + timestamp uint64 +} + +func (m *MockConsensusState) Reset() { + panic("implement me") +} + +func (m *MockConsensusState) String() string { + panic("implement me") +} + +func (m *MockConsensusState) ProtoMessage() { + panic("implement me") +} + +func (m *MockConsensusState) ClientType() string { + return "mock" +} + +func (m *MockConsensusState) GetRoot() exported.Root { + return nil +} + +func (m *MockConsensusState) GetTimestamp() uint64 { + return m.timestamp +} + +func (m *MockConsensusState) ValidateBasic() error { + return nil +} + +func TestPrecompile_GetAdjustedTimestamp(t *testing.T) { + type fields struct { + transferKeeper pcommon.TransferKeeper + evmKeeper pcommon.EVMKeeper + clientKeeper pcommon.ClientKeeper + connectionKeeper pcommon.ConnectionKeeper + channelKeeper pcommon.ChannelKeeper + } + type args struct { + ctx sdk.Context + clientId string + height clienttypes.Height + } + timestampSeconds := 1714680155 + ctx := sdk.Context{} + tests := []struct { + name string + fields fields + args args + want uint64 + wantErr bool + }{ + { + name: "if consensus timestamp is less than the given time, return the given time adjusted with default", + fields: fields{ + clientKeeper: &MockClientKeeper{ + consensusState: &MockConsensusState{ + timestamp: uint64(timestampSeconds - 1), + }, + returnConsensusState: true, + }, + }, + args: args{ + ctx: ctx.WithBlockTime(time.Unix(int64(timestampSeconds), 0)), + }, + want: uint64(timestampSeconds)*1_000_000_000 + uint64((time.Duration(10) * time.Minute).Nanoseconds()), + wantErr: false, + }, + { + name: "if consensus state is not found, return the given time adjusted with default", + fields: fields{ + clientKeeper: &MockClientKeeper{ + returnConsensusState: false, + }, + }, + args: args{ + ctx: ctx.WithBlockTime(time.Unix(int64(timestampSeconds), 0)), + }, + want: uint64(timestampSeconds)*1_000_000_000 + uint64((time.Duration(10) * time.Minute).Nanoseconds()), + wantErr: false, + }, + { + name: "if time from local clock can not be retrieved, return error", + fields: fields{ + clientKeeper: &MockClientKeeper{ + returnConsensusState: false, + }, + }, + args: args{ + ctx: ctx.WithBlockTime(time.Unix(int64(0), 0)), + }, + wantErr: true, + }, + { + name: "if consensus timestamp is > than the given time, return the consensus time adjusted with default", + fields: fields{ + clientKeeper: &MockClientKeeper{ + consensusState: &MockConsensusState{ + timestamp: uint64(timestampSeconds+1) * 1_000_000_000, + }, + returnConsensusState: true, + }, + }, + args: args{ + ctx: ctx.WithBlockTime(time.Unix(int64(timestampSeconds), 0)), + }, + want: uint64(timestampSeconds+1)*1_000_000_000 + uint64((time.Duration(10) * time.Minute).Nanoseconds()), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p, _ := ibc.NewPrecompile(tt.fields.transferKeeper, tt.fields.evmKeeper, tt.fields.clientKeeper, tt.fields.connectionKeeper, tt.fields.channelKeeper) + got, err := p.GetAdjustedTimestamp(tt.args.ctx, tt.args.clientId, tt.args.height) + if (err != nil) != tt.wantErr { + t.Errorf("GetAdjustedTimestamp() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("GetAdjustedTimestamp() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/precompiles/json/json.go b/precompiles/json/json.go index 0a0344f51..8f8a35805 100644 --- a/precompiles/json/json.go +++ b/precompiles/json/json.go @@ -15,6 +15,7 @@ import ( "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/state" ) const ( @@ -42,19 +43,27 @@ type Precompile struct { ExtractAsUint256ID []byte } -func NewPrecompile() (*Precompile, error) { +func ABI() (*abi.ABI, error) { abiBz, err := f.ReadFile("abi.json") if err != nil { - return nil, fmt.Errorf("error loading the staking ABI %s", err) + return nil, fmt.Errorf("error loading the json ABI %s", err) } newAbi, err := abi.JSON(bytes.NewReader(abiBz)) if err != nil { return nil, err } + return &newAbi, nil +} + +func NewPrecompile() (*Precompile, error) { + newAbi, err := ABI() + if err != nil { + return nil, err + } p := &Precompile{ - Precompile: pcommon.Precompile{ABI: newAbi}, + Precompile: pcommon.Precompile{ABI: *newAbi}, address: common.HexToAddress(JSONAddress), } @@ -93,6 +102,11 @@ func (p Precompile) GetName() string { } func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err diff --git a/precompiles/oracle/oracle.go b/precompiles/oracle/oracle.go index 44c954a59..161c6ea8b 100644 --- a/precompiles/oracle/oracle.go +++ b/precompiles/oracle/oracle.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/x/evm/state" "github.com/sei-protocol/sei-chain/x/oracle/types" ) @@ -118,6 +119,11 @@ func (p Precompile) GetName() string { } func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err diff --git a/precompiles/pointer/Pointer.sol b/precompiles/pointer/Pointer.sol index d85893949..a9575b5d5 100644 --- a/precompiles/pointer/Pointer.sol +++ b/precompiles/pointer/Pointer.sol @@ -8,13 +8,13 @@ IPointer constant POINTER_CONTRACT = IPointer(POINTER_PRECOMPILE_ADDRESS); interface IPointer { function addNativePointer( string memory token - ) payable external returns (address ret); + ) external returns (address ret); function addCW20Pointer( string memory cwAddr - ) payable external returns (address ret); + ) external returns (address ret); function addCW721Pointer( string memory cwAddr - ) payable external returns (address ret); + ) external returns (address ret); } diff --git a/precompiles/pointer/pointer.go b/precompiles/pointer/pointer.go index 88b933c7f..2e274ddca 100644 --- a/precompiles/pointer/pointer.go +++ b/precompiles/pointer/pointer.go @@ -19,10 +19,12 @@ 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/state" "github.com/sei-protocol/sei-chain/x/evm/types" ) const ( + PrecompileName = "pointer" AddNativePointer = "addNativePointer" AddCW20Pointer = "addCW20Pointer" AddCW721Pointer = "addCW721Pointer" @@ -50,7 +52,7 @@ type Precompile struct { AddCW721PointerID []byte } -func NewPrecompile(evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper, wasmdKeeper pcommon.WasmdViewKeeper) (*Precompile, error) { +func ABI() (*ethabi.ABI, error) { abiBz, err := f.ReadFile("abi.json") if err != nil { return nil, fmt.Errorf("error loading the pointer ABI %s", err) @@ -60,9 +62,17 @@ func NewPrecompile(evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper, w if err != nil { return nil, err } + return &newAbi, nil +} + +func NewPrecompile(evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper, wasmdKeeper pcommon.WasmdViewKeeper) (*Precompile, error) { + newAbi, err := ABI() + if err != nil { + return nil, err + } p := &Precompile{ - Precompile: pcommon.Precompile{ABI: newAbi}, + Precompile: pcommon.Precompile{ABI: *newAbi}, evmKeeper: evmKeeper, bankKeeper: bankKeeper, wasmdKeeper: wasmdKeeper, @@ -94,10 +104,15 @@ func (p Precompile) Address() common.Address { } func (p Precompile) GetName() string { - return "pointer" + return PrecompileName } 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) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() if readOnly { return nil, 0, errors.New("cannot call pointer precompile from staticcall") } @@ -127,6 +142,9 @@ func (p Precompile) Run(*vm.EVM, common.Address, common.Address, []byte, *big.In } 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.ValidateNonPayable(value); err != nil { + return nil, 0, err + } if err := pcommon.ValidateArgsLength(args, 1); err != nil { return nil, 0, err } @@ -181,13 +199,16 @@ func (p Precompile) AddNative(ctx sdk.Context, method *ethabi.Method, caller com } 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.ValidateNonPayable(value); err != nil { + return nil, 0, err + } 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) + if exists && existingVersion >= cw20.CurrentVersion(ctx) { + 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(ctx)) } cwAddress, err := sdk.AccAddressFromBech32(cwAddr) if err != nil { @@ -226,12 +247,15 @@ func (p Precompile) AddCW20(ctx sdk.Context, method *ethabi.Method, caller commo 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)))) + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", cw20.CurrentVersion(ctx))))) 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.ValidateNonPayable(value); err != nil { + return nil, 0, err + } if err := pcommon.ValidateArgsLength(args, 1); err != nil { return nil, 0, err } diff --git a/precompiles/pointer/pointer_test.go b/precompiles/pointer/pointer_test.go index f621a66c3..3d5f25f6a 100644 --- a/precompiles/pointer/pointer_test.go +++ b/precompiles/pointer/pointer_test.go @@ -36,6 +36,7 @@ func TestAddNative(t *testing.T) { 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.NotNil(t, statedb.GetPrecompileError()) require.Equal(t, uint64(0), g) _, _, exists := testApp.EvmKeeper.GetERC20NativePointer(statedb.Ctx(), "test") require.False(t, exists) @@ -79,5 +80,6 @@ func TestAddNative(t *testing.T) { 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.NotNil(t, statedb.GetPrecompileError()) require.Equal(t, uint64(0), g) } diff --git a/precompiles/pointerview/pointerview.go b/precompiles/pointerview/pointerview.go index 6019dd7dd..f56e8ce05 100644 --- a/precompiles/pointerview/pointerview.go +++ b/precompiles/pointerview/pointerview.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/x/evm/state" ) const ( @@ -83,6 +84,11 @@ func (p Precompile) GetName() string { } func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, _ *big.Int, _ bool) (ret []byte, err error) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, err diff --git a/precompiles/pointerview/pointerview_test.go b/precompiles/pointerview/pointerview_test.go index ad6d28bff..a520878c4 100644 --- a/precompiles/pointerview/pointerview_test.go +++ b/precompiles/pointerview/pointerview_test.go @@ -42,7 +42,7 @@ func TestPointerView(t *testing.T) { 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.Equal(t, cw20.CurrentVersion(ctx), outputs[1].(uint16)) require.True(t, outputs[2].(bool)) ret, err = p.GetCW20(ctx, m, []interface{}{"test2"}) require.Nil(t, err) diff --git a/precompiles/setup.go b/precompiles/setup.go index 3cadd9792..052c05e9d 100644 --- a/precompiles/setup.go +++ b/precompiles/setup.go @@ -49,6 +49,9 @@ func InitializePrecompiles( distrKeeper common.DistributionKeeper, oracleKeeper common.OracleKeeper, transferKeeper common.TransferKeeper, + clientKeeper common.ClientKeeper, + connectionKeeper common.ConnectionKeeper, + channelKeeper common.ChannelKeeper, ) error { SetupMtx.Lock() defer SetupMtx.Unlock() @@ -87,7 +90,7 @@ func InitializePrecompiles( if err != nil { return err } - ibcp, err := ibc.NewPrecompile(transferKeeper, evmKeeper) + ibcp, err := ibc.NewPrecompile(transferKeeper, evmKeeper, clientKeeper, connectionKeeper, channelKeeper) if err != nil { return err } @@ -130,7 +133,7 @@ func InitializePrecompiles( func GetPrecompileInfo(name string) PrecompileInfo { if !Initialized { // Precompile Info does not require any keeper state - _ = InitializePrecompiles(true, nil, nil, nil, nil, nil, nil, nil, nil, nil) + _ = InitializePrecompiles(true, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) } i, ok := PrecompileNamesToInfo[name] if !ok { diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index e828a02ff..c6854613a 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/x/evm/state" ) const ( @@ -110,6 +111,11 @@ func (p Precompile) GetName() string { } func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() if readOnly { return nil, errors.New("cannot call staking precompile from staticcall") } diff --git a/precompiles/wasmd/wasmd.go b/precompiles/wasmd/wasmd.go index b8e61cbe9..f6187c832 100644 --- a/precompiles/wasmd/wasmd.go +++ b/precompiles/wasmd/wasmd.go @@ -130,10 +130,18 @@ func (p Precompile) GetName() string { } 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) { + defer func() { + if err != nil { + evm.StateDB.(*state.DBImpl).SetPrecompileError(err) + } + }() ctx, method, args, err := p.Prepare(evm, input) if err != nil { return nil, 0, err } + if method.Name != QueryMethod && !ctx.IsEVM() { + return nil, 0, errors.New("sei does not support CW->EVM->CW call pattern") + } gasMultipler := p.evmKeeper.GetPriorityNormalizer(ctx) gasLimitBigInt := sdk.NewDecFromInt(sdk.NewIntFromUint64(suppliedGas)).Mul(gasMultipler).TruncateInt().BigInt() if gasLimitBigInt.Cmp(utils.BigMaxU64) > 0 { @@ -151,7 +159,7 @@ func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, calli case ExecuteMethod: return p.execute(ctx, method, caller, callingContract, args, value, readOnly) case ExecuteBatchMethod: - return p.execute_batch(ctx, method, caller, callingContract, args, value, readOnly) + return p.executeBatch(ctx, method, caller, callingContract, args, value, readOnly) case QueryMethod: return p.query(ctx, method, args, value) } @@ -255,7 +263,7 @@ func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller comm return } -func (p Precompile) execute_batch(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) { +func (p Precompile) executeBatch(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 @@ -300,6 +308,13 @@ func (p Precompile) execute_batch(ctx sdk.Context, method *abi.Method, caller co rerr = errors.New("sum of coin amounts must equal value specified") return } + // Copy to avoid modifying the original value + var valueCopy *big.Int + if value != nil { + valueCopy = new(big.Int).Set(value) + } else { + valueCopy = value + } for i := 0; i < len(executeMsgs); i++ { executeMsg := ExecuteMsg(executeMsgs[i]) @@ -318,7 +333,11 @@ func (p Precompile) execute_batch(ctx sdk.Context, method *abi.Method, caller co rerr = err return } - senderAddr := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + senderAddr, senderAssociated := p.evmKeeper.GetSeiAddress(ctx, caller) + if !senderAssociated { + rerr = fmt.Errorf("sender %s is not associated", caller.Hex()) + return + } msg := executeMsg.Msg coinsBz := executeMsg.Coins coins := sdk.NewCoins() @@ -327,7 +346,7 @@ func (p Precompile) execute_batch(ctx sdk.Context, method *abi.Method, caller co return } useiAmt := coins.AmountOf(sdk.MustGetBaseDenom()) - if value != nil && !useiAmt.IsZero() { + if valueCopy != nil && !useiAmt.IsZero() { // process coin amount from the value provided useiAmtAsWei := useiAmt.Mul(state.SdkUseiToSweiMultiplier).BigInt() coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), senderAddr, useiAmtAsWei, p.bankKeeper) @@ -335,8 +354,8 @@ func (p Precompile) execute_batch(ctx sdk.Context, method *abi.Method, caller co rerr = err return } - value.Sub(value, useiAmtAsWei) - if value.Sign() == -1 { + valueCopy.Sub(valueCopy, useiAmtAsWei) + if valueCopy.Sign() == -1 { rerr = errors.New("insufficient value provided for payment") return } @@ -365,7 +384,7 @@ func (p Precompile) execute_batch(ctx sdk.Context, method *abi.Method, caller co } responses = append(responses, res) } - if value != nil && value.Sign() != 0 { + if valueCopy != nil && valueCopy.Sign() != 0 { rerr = errors.New("value remaining after execution, must match provided amounts exactly") return } diff --git a/precompiles/wasmd/wasmd_test.go b/precompiles/wasmd/wasmd_test.go index 0950d14c5..dde3e5114 100644 --- a/precompiles/wasmd/wasmd_test.go +++ b/precompiles/wasmd/wasmd_test.go @@ -40,6 +40,7 @@ func TestInstantiate(t *testing.T) { testApp := app.Setup(false, false) mockAddr, mockEVMAddr := testkeeper.MockAddressPair() ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithIsEVM(true) testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) @@ -78,7 +79,7 @@ func TestInstantiate(t *testing.T) { require.Equal(t, 2, len(outputs)) require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) require.Empty(t, outputs[1].([]byte)) - require.Equal(t, uint64(880848), g) + require.Equal(t, uint64(881127), g) amtsbz, err = sdk.NewCoins().MarshalJSON() require.Nil(t, err) @@ -101,7 +102,7 @@ func TestInstantiate(t *testing.T) { require.Equal(t, 2, len(outputs)) require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) require.Empty(t, outputs[1].([]byte)) - require.Equal(t, uint64(903904), g) + require.Equal(t, uint64(904183), g) // non-existent code ID args, _ = instantiateMethod.Inputs.Pack( @@ -113,21 +114,27 @@ func TestInstantiate(t *testing.T) { ) _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) + require.NotNil(t, statedb.GetPrecompileError()) require.Equal(t, uint64(0), g) // bad inputs badArgs, _ := instantiateMethod.Inputs.Pack(codeID, "not bech32", []byte("{}"), "test", amtsbz) + statedb.SetPrecompileError(nil) _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, badArgs...), suppliedGas, nil, nil, false) require.NotNil(t, err) + require.NotNil(t, statedb.GetPrecompileError()) badArgs, _ = instantiateMethod.Inputs.Pack(codeID, mockAddr.String(), []byte("{}"), "test", []byte("bad coins")) + statedb.SetPrecompileError(nil) _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, badArgs...), suppliedGas, nil, nil, false) require.NotNil(t, err) + require.NotNil(t, statedb.GetPrecompileError()) } func TestExecute(t *testing.T) { testApp := app.Setup(false, false) mockAddr, mockEVMAddr := testkeeper.MockAddressPair() ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithIsEVM(true) testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) @@ -156,13 +163,18 @@ func TestExecute(t *testing.T) { } suppliedGas := uint64(1000000) testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) + // circular interop + statedb.WithCtx(statedb.Ctx().WithIsEVM(false)) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.Equal(t, "sei does not support CW->EVM->CW call pattern", err.Error()) + statedb.WithCtx(statedb.Ctx().WithIsEVM(true)) 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) require.Equal(t, 1, len(outputs)) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(outputs[0].([]byte))) - require.Equal(t, uint64(907107), g) + require.Equal(t, uint64(907386), g) require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) amtsbz, err = sdk.NewCoins().MarshalJSON() @@ -192,30 +204,39 @@ func TestExecute(t *testing.T) { // disallowed delegatecall contractAddrDisallowed := common.BytesToAddress([]byte("contractB")) + statedb.SetPrecompileError(nil) _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrDisallowed, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) require.NotNil(t, err) + require.NotNil(t, statedb.GetPrecompileError()) // bad contract address args, _ = executeMethod.Inputs.Pack(mockAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + statedb.SetPrecompileError(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) + require.NotNil(t, statedb.GetPrecompileError()) // bad inputs args, _ = executeMethod.Inputs.Pack("not bech32", []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + statedb.SetPrecompileError(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) + require.NotNil(t, statedb.GetPrecompileError()) args, _ = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), []byte("bad coins")) + statedb.SetPrecompileError(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) + require.NotNil(t, statedb.GetPrecompileError()) } func TestQuery(t *testing.T) { testApp := app.Setup(false, false) mockAddr, mockEVMAddr := testkeeper.MockAddressPair() ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithIsEVM(true) testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) @@ -242,7 +263,7 @@ func TestQuery(t *testing.T) { require.Nil(t, err) require.Equal(t, 1, len(outputs)) require.Equal(t, "{\"message\":\"query test\"}", string(outputs[0].([]byte))) - require.Equal(t, uint64(931433), g) + require.Equal(t, uint64(931712), g) // bad contract address args, _ = queryMethod.Inputs.Pack(mockAddr.String(), []byte("{\"info\":{}}")) @@ -265,6 +286,7 @@ func TestExecuteBatchOneMessage(t *testing.T) { testApp := app.Setup(false, false) mockAddr, mockEVMAddr := testkeeper.MockAddressPair() ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithIsEVM(true) testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) @@ -304,7 +326,7 @@ func TestExecuteBatchOneMessage(t *testing.T) { require.Nil(t, err) require.Equal(t, 1, len(outputs)) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string((outputs[0].([][]byte))[0])) - require.Equal(t, uint64(907107), g) + require.Equal(t, uint64(907386), g) require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) amtsbz, err = sdk.NewCoins().MarshalJSON() @@ -362,10 +384,56 @@ func TestExecuteBatchOneMessage(t *testing.T) { require.Equal(t, uint64(0), g) } +func TestExecuteBatchValueImmutability(t *testing.T) { + testApp := app.Setup(false, false) + mockAddr, mockEVMAddr := testkeeper.MockAddressPair() + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithIsEVM(true) + testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) + wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) + p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) + require.Nil(t, err) + code, err := os.ReadFile("../../example/cosmwasm/echo/artifacts/echo.wasm") + require.Nil(t, err) + codeID, err := wasmKeeper.Create(ctx, mockAddr, code, nil) + require.Nil(t, err) + contractAddr, _, err := wasmKeeper.Instantiate(ctx, codeID, mockAddr, mockAddr, []byte("{}"), "test", sdk.NewCoins()) + require.Nil(t, err) + + amts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000))) + testApp.BankKeeper.MintCoins(ctx, "evm", amts) + testApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", mockAddr, amts) + testApp.BankKeeper.MintCoins(ctx, "evm", amts) + testApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", mockAddr, amts) + amtsbz, err := amts.MarshalJSON() + require.Nil(t, err) + executeMethod, err := p.ABI.MethodById(p.ExecuteBatchID) + require.Nil(t, err) + executeMsg := wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + args, err := executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsg}) + require.Nil(t, err) + statedb := state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm := vm.EVM{ + StateDB: statedb, + } + suppliedGas := uint64(1000000) + testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) + value := big.NewInt(1000_000_000_000_000) + valueCopy := new(big.Int).Set(value) + p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, value, nil, false) + + require.Equal(t, valueCopy, value) +} + func TestExecuteBatchMultipleMessages(t *testing.T) { testApp := app.Setup(false, false) mockAddr, mockEVMAddr := testkeeper.MockAddressPair() ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + ctx = ctx.WithIsEVM(true) testApp.EvmKeeper.SetAddressMapping(ctx, mockAddr, mockEVMAddr) wasmKeeper := wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper) p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmKeeper, testApp.WasmKeeper, testApp.BankKeeper) @@ -409,7 +477,7 @@ func TestExecuteBatchMultipleMessages(t *testing.T) { require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[0])) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[1])) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[2])) - require.Equal(t, uint64(726445), g) + require.Equal(t, uint64(726724), g) require.Equal(t, int64(3000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) amtsbz2, err := sdk.NewCoins().MarshalJSON() @@ -436,7 +504,7 @@ func TestExecuteBatchMultipleMessages(t *testing.T) { require.Equal(t, fmt.Sprintf("received test msg from %s with", mockAddr.String()), string(parsedOutputs[0])) require.Equal(t, fmt.Sprintf("received test msg from %s with 1000usei", mockAddr.String()), string(parsedOutputs[1])) require.Equal(t, fmt.Sprintf("received test msg from %s with", mockAddr.String()), string(parsedOutputs[2])) - require.Equal(t, uint64(774966), g) + require.Equal(t, uint64(775245), g) require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) // allowed delegatecall diff --git a/proto/evm/genesis.proto b/proto/evm/genesis.proto index 6862e42f9..4ce0ae02d 100644 --- a/proto/evm/genesis.proto +++ b/proto/evm/genesis.proto @@ -12,8 +12,34 @@ message AddressAssociation { string eth_address = 2; // Ethereum address } +message Code { + string address = 1; + bytes code = 2; +} + +message ContractState { + string address = 1; + bytes key = 2; + bytes value = 3; +} + +message Nonce { + string address = 1; + uint64 nonce = 2; +} + +message Serialized { + bytes prefix = 1; + bytes key = 2; + bytes value = 3; +} + // GenesisState defines the evm module's genesis state. message GenesisState { Params params = 1 [(gogoproto.nullable) = false]; repeated AddressAssociation address_associations = 2; // List of address associations + repeated Code codes = 3; // List of stored code + repeated ContractState states = 4; // List of contract state + repeated Nonce nonces = 5; + repeated Serialized serialized = 6; } diff --git a/proto/evm/query.proto b/proto/evm/query.proto index 6f90daa9b..f92d02df0 100644 --- a/proto/evm/query.proto +++ b/proto/evm/query.proto @@ -23,6 +23,10 @@ service Query { rpc Pointer(QueryPointerRequest) returns (QueryPointerResponse) { option (google.api.http).get = "/sei-protocol/seichain/evm/pointer"; } + + rpc PointerVersion(QueryPointerVersionRequest) returns (QueryPointerVersionResponse) { + option (google.api.http).get = "/sei-protocol/seichain/evm/pointer_version"; + } } message QuerySeiAddressByEVMAddressRequest { @@ -62,3 +66,12 @@ message QueryPointerResponse { uint32 version = 2; bool exists = 3; } + +message QueryPointerVersionRequest { + PointerType pointer_type = 1; +} + +message QueryPointerVersionResponse { + uint32 version = 1; + uint64 cw_code_id = 2; +} diff --git a/proto/evm/tx.proto b/proto/evm/tx.proto index 03eaa8ce9..8b00a6690 100644 --- a/proto/evm/tx.proto +++ b/proto/evm/tx.proto @@ -12,6 +12,7 @@ service Msg { rpc EVMTransaction(MsgEVMTransaction) returns (MsgEVMTransactionResponse); rpc Send(MsgSend) returns (MsgSendResponse); rpc RegisterPointer(MsgRegisterPointer) returns (MsgRegisterPointerResponse); + rpc AssociateContractAddress(MsgAssociateContractAddress) returns (MsgAssociateContractAddressResponse); } message MsgEVMTransaction { @@ -65,3 +66,10 @@ message MsgRegisterPointer { message MsgRegisterPointerResponse { string pointer_address = 1; } + +message MsgAssociateContractAddress { + string sender = 1; + string address = 2; +} + +message MsgAssociateContractAddressResponse {} \ No newline at end of file diff --git a/wasmbinding/queries.go b/wasmbinding/queries.go index 6acbe57d0..6ed1b157c 100644 --- a/wasmbinding/queries.go +++ b/wasmbinding/queries.go @@ -239,18 +239,27 @@ func (qp QueryPlugin) HandleEVMQuery(ctx sdk.Context, queryData json.RawMessage) case parsedQuery.ERC721IsApprovedForAll != nil: c := parsedQuery.ERC721IsApprovedForAll return qp.evmHandler.HandleERC721IsApprovedForAll(ctx, c.Caller, c.ContractAddress, c.Owner, c.Operator) + case parsedQuery.ERC721TotalSupply != nil: + c := parsedQuery.ERC721TotalSupply + return qp.evmHandler.HandleERC721TotalSupply(ctx, c.Caller, c.ContractAddress) case parsedQuery.ERC721NameSymbol != nil: c := parsedQuery.ERC721NameSymbol return qp.evmHandler.HandleERC721NameSymbol(ctx, c.Caller, c.ContractAddress) case parsedQuery.ERC721Uri != nil: c := parsedQuery.ERC721Uri return qp.evmHandler.HandleERC721Uri(ctx, c.Caller, c.ContractAddress, c.TokenID) + case parsedQuery.ERC721RoyaltyInfo != nil: + c := parsedQuery.ERC721RoyaltyInfo + return qp.evmHandler.HandleERC721RoyaltyInfo(ctx, c.Caller, c.ContractAddress, c.TokenID, c.SalePrice) case parsedQuery.GetEvmAddress != nil: c := parsedQuery.GetEvmAddress return qp.evmHandler.HandleGetEvmAddress(ctx, c.SeiAddress) case parsedQuery.GetSeiAddress != nil: c := parsedQuery.GetSeiAddress return qp.evmHandler.HandleGetSeiAddress(ctx, c.EvmAddress) + case parsedQuery.SupportsInterface != nil: + c := parsedQuery.SupportsInterface + return qp.evmHandler.HandleSupportsInterface(ctx, c.Caller, c.InterfaceID, c.ContractAddress) default: return nil, errors.New("unknown EVM query") } diff --git a/x/evm/ante/fee.go b/x/evm/ante/fee.go index 1e64bd920..9cb04160d 100644 --- a/x/evm/ante/fee.go +++ b/x/evm/ante/fee.go @@ -69,7 +69,6 @@ func (fc EVMFeeCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b cfg := evmtypes.DefaultChainConfig().EthereumConfig(fc.evmKeeper.ChainID(ctx)) txCtx := core.NewEVMTxContext(emsg) evmInstance := vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) - stateDB.SetEVM(evmInstance) st := core.NewStateTransition(evmInstance, emsg, &gp, true) // run stateless checks before charging gas (mimicking Geth behavior) if !ctx.IsCheckTx() && !ctx.IsReCheckTx() { @@ -87,7 +86,9 @@ func (fc EVMFeeCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b if err != nil { return ctx, err } - msg.Derived.AnteSurplus = surplus + if err := fc.evmKeeper.AddAnteSurplus(ctx, etx.Hash(), surplus); err != nil { + return ctx, err + } } // calculate the priority by dividing the total fee with the native gas limit (i.e. the effective native gas price) diff --git a/x/evm/ante/preprocess.go b/x/evm/ante/preprocess.go index bb0e1d0a2..0789a15cd 100644 --- a/x/evm/ante/preprocess.go +++ b/x/evm/ante/preprocess.go @@ -15,7 +15,6 @@ import ( accountkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -66,6 +65,9 @@ func (p *EVMPreprocessDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate derived := msg.Derived seiAddr := derived.SenderSeiAddr evmAddr := derived.SenderEVMAddr + ctx.EventManager().EmitEvent(sdk.NewEvent(evmtypes.EventTypeSigner, + sdk.NewAttribute(evmtypes.AttributeKeyEvmAddress, evmAddr.Hex()), + sdk.NewAttribute(evmtypes.AttributeKeySeiAddress, seiAddr.String()))) pubkey := derived.PubKey isAssociateTx := derived.IsAssociate _, isAssociated := p.evmKeeper.GetEVMAddress(ctx, seiAddr) @@ -73,20 +75,8 @@ func (p *EVMPreprocessDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "account already has association set") } else if isAssociateTx { // check if the account has enough balance (without charging) - baseDenom := p.evmKeeper.GetBaseDenom(ctx) - seiBalance := p.evmKeeper.BankKeeper().GetBalance(ctx, seiAddr, baseDenom).Amount - castBalance := p.evmKeeper.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), baseDenom).Amount - totalUsei := new(big.Int).Add(seiBalance.BigInt(), castBalance.BigInt()) - if totalUsei.Cmp(BigBalanceThreshold) < 0 { - if totalUsei.Cmp(BigBalanceThresholdMinus1) < 0 { - // no need to check for wei balances since the sum wouldn't reach 2usei - return ctx, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "account needs to have at least 1Sei to force association") - } - seiWeiBalance := p.evmKeeper.BankKeeper().GetWeiBalance(ctx, seiAddr) - evmWeiBalance := p.evmKeeper.BankKeeper().GetWeiBalance(ctx, sdk.AccAddress(evmAddr[:])) - if seiWeiBalance.Add(evmWeiBalance).LT(bankkeeper.OneUseiInWei) { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "account needs to have at least 1Sei to force association") - } + if !p.IsAccountBalancePositive(ctx, seiAddr, evmAddr) { + return ctx, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "account needs to have at least 1 wei to force association") } if err := p.AssociateAddresses(ctx, seiAddr, evmAddr, pubkey); err != nil { return ctx, err @@ -115,21 +105,21 @@ func (p *EVMPreprocessDecorator) AssociateAddresses(ctx sdk.Context, seiAddr sdk } p.accountKeeper.SetAccount(ctx, acc) } - castAddr := sdk.AccAddress(evmAddr[:]) - castAddrBalances := p.evmKeeper.BankKeeper().GetAllBalances(ctx, castAddr) - if !castAddrBalances.IsZero() { - if err := p.evmKeeper.BankKeeper().SendCoins(ctx, castAddr, seiAddr, castAddrBalances); err != nil { - return err - } + return migrateBalance(ctx, p.evmKeeper, evmAddr, seiAddr) +} + +func (p *EVMPreprocessDecorator) IsAccountBalancePositive(ctx sdk.Context, seiAddr sdk.AccAddress, evmAddr common.Address) bool { + baseDenom := p.evmKeeper.GetBaseDenom(ctx) + if amt := p.evmKeeper.BankKeeper().GetBalance(ctx, seiAddr, baseDenom).Amount; amt.IsPositive() { + return true } - castAddrWei := p.evmKeeper.BankKeeper().GetWeiBalance(ctx, castAddr) - if !castAddrWei.IsZero() { - if err := p.evmKeeper.BankKeeper().SendCoinsAndWei(ctx, castAddr, seiAddr, sdk.ZeroInt(), castAddrWei); err != nil { - return err - } + if amt := p.evmKeeper.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), baseDenom).Amount; amt.IsPositive() { + return true } - p.evmKeeper.AccountKeeper().RemoveAccount(ctx, authtypes.NewBaseAccountWithAddress(castAddr)) - return nil + if amt := p.evmKeeper.BankKeeper().GetWeiBalance(ctx, seiAddr); amt.IsPositive() { + return true + } + return p.evmKeeper.BankKeeper().GetWeiBalance(ctx, sdk.AccAddress(evmAddr[:])).IsPositive() } // stateless @@ -340,6 +330,24 @@ func NewEVMAddressDecorator(evmKeeper *evmkeeper.Keeper, accountKeeper *accountk return &EVMAddressDecorator{evmKeeper: evmKeeper, accountKeeper: accountKeeper} } +func migrateBalance(ctx sdk.Context, evmKeeper *evmkeeper.Keeper, evmAddr common.Address, seiAddr sdk.AccAddress) error { + castAddr := sdk.AccAddress(evmAddr[:]) + castAddrBalances := evmKeeper.BankKeeper().GetAllBalances(ctx, castAddr) + if !castAddrBalances.IsZero() { + if err := evmKeeper.BankKeeper().SendCoins(ctx, castAddr, seiAddr, castAddrBalances); err != nil { + return err + } + } + castAddrWei := evmKeeper.BankKeeper().GetWeiBalance(ctx, castAddr) + if !castAddrWei.IsZero() { + if err := evmKeeper.BankKeeper().SendCoinsAndWei(ctx, castAddr, seiAddr, sdk.ZeroInt(), castAddrWei); err != nil { + return err + } + } + evmKeeper.AccountKeeper().RemoveAccount(ctx, authtypes.NewBaseAccountWithAddress(castAddr)) + return nil +} + //nolint:revive func (p *EVMAddressDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { sigTx, ok := tx.(authsigning.SigVerifiableTx) @@ -348,25 +356,41 @@ func (p *EVMAddressDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo } signers := sigTx.GetSigners() for _, signer := range signers { - if _, associated := p.evmKeeper.GetEVMAddress(ctx, signer); associated { + if evmAddr, associated := p.evmKeeper.GetEVMAddress(ctx, signer); associated { + ctx.EventManager().EmitEvent(sdk.NewEvent(evmtypes.EventTypeSigner, + sdk.NewAttribute(evmtypes.AttributeKeyEvmAddress, evmAddr.Hex()), + sdk.NewAttribute(evmtypes.AttributeKeySeiAddress, signer.String()))) continue } acc := p.accountKeeper.GetAccount(ctx, signer) if acc.GetPubKey() == nil { ctx.Logger().Error(fmt.Sprintf("missing pubkey for %s", signer.String())) + ctx.EventManager().EmitEvent(sdk.NewEvent(evmtypes.EventTypeSigner, + sdk.NewAttribute(evmtypes.AttributeKeySeiAddress, signer.String()))) continue } pk, err := btcec.ParsePubKey(acc.GetPubKey().Bytes(), btcec.S256()) if err != nil { ctx.Logger().Debug(fmt.Sprintf("failed to parse pubkey for %s, likely due to the fact that it isn't on secp256k1 curve", acc.GetPubKey()), "err", err) + ctx.EventManager().EmitEvent(sdk.NewEvent(evmtypes.EventTypeSigner, + sdk.NewAttribute(evmtypes.AttributeKeySeiAddress, signer.String()))) continue } evmAddr, err := pubkeyToEVMAddress(pk.SerializeUncompressed()) if err != nil { ctx.Logger().Error(fmt.Sprintf("failed to get EVM address from pubkey due to %s", err)) + ctx.EventManager().EmitEvent(sdk.NewEvent(evmtypes.EventTypeSigner, + sdk.NewAttribute(evmtypes.AttributeKeySeiAddress, signer.String()))) continue } + ctx.EventManager().EmitEvent(sdk.NewEvent(evmtypes.EventTypeSigner, + sdk.NewAttribute(evmtypes.AttributeKeyEvmAddress, evmAddr.Hex()), + sdk.NewAttribute(evmtypes.AttributeKeySeiAddress, signer.String()))) p.evmKeeper.SetAddressMapping(ctx, signer, evmAddr) + if err := migrateBalance(ctx, p.evmKeeper, evmAddr, signer); err != nil { + ctx.Logger().Error(fmt.Sprintf("failed to migrate EVM address balance (%s) %s", evmAddr.Hex(), err)) + return ctx, err + } } return next(ctx, tx, simulate) } diff --git a/x/evm/ante/preprocess_test.go b/x/evm/ante/preprocess_test.go index bec4ea685..b1a31a74d 100644 --- a/x/evm/ante/preprocess_test.go +++ b/x/evm/ante/preprocess_test.go @@ -11,7 +11,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -130,7 +129,7 @@ func TestPreprocessAssociateTx(t *testing.T) { require.True(t, ok) require.Equal(t, evmAddr, associated) - ctx, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { panic("should not be called") }) // already associated @@ -157,12 +156,9 @@ func TestPreprocessAssociateTxWithWeiBalance(t *testing.T) { require.Nil(t, err) seiAddr := sdk.AccAddress(privKey.PubKey().Address()) evmAddr := crypto.PubkeyToAddress(key.PublicKey) - k.BankKeeper().AddCoins(ctx, seiAddr, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(int64(ante.BalanceThreshold-1)))), true) - k.BankKeeper().AddWei(ctx, sdk.AccAddress(evmAddr[:]), bankkeeper.OneUseiInWei.Sub(sdk.OneInt())) ctx, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { panic("should not be called") }) - // not enough balance (0.9999999999999999 wei only) require.NotNil(t, err) k.BankKeeper().AddWei(ctx, seiAddr, sdk.OneInt()) ctx, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { @@ -220,6 +216,25 @@ func TestEVMAddressDecorator(t *testing.T) { require.Equal(t, evmAddr, associatedEvmAddr) } +func TestIsAccountBalancePositive(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + s1, e1 := testkeeper.MockAddressPair() + s2, e2 := testkeeper.MockAddressPair() + s3, e3 := testkeeper.MockAddressPair() + s4, e4 := testkeeper.MockAddressPair() + s5, e5 := testkeeper.MockAddressPair() + require.Nil(t, k.BankKeeper().AddCoins(ctx, s1, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.OneInt())), true)) + require.Nil(t, k.BankKeeper().AddCoins(ctx, sdk.AccAddress(e2[:]), sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.OneInt())), true)) + require.Nil(t, k.BankKeeper().AddWei(ctx, s3, sdk.OneInt())) + require.Nil(t, k.BankKeeper().AddWei(ctx, sdk.AccAddress(e4[:]), sdk.OneInt())) + handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + require.True(t, handler.IsAccountBalancePositive(ctx, s1, e1)) + require.True(t, handler.IsAccountBalancePositive(ctx, s2, e2)) + require.True(t, handler.IsAccountBalancePositive(ctx, s3, e3)) + require.True(t, handler.IsAccountBalancePositive(ctx, s4, e4)) + require.False(t, handler.IsAccountBalancePositive(ctx, s5, e5)) +} + // MockTxNotSigVerifiable is a simple mock transaction type that implements sdk.Tx but not SigVerifiableTx type MockTxIncompatible struct { msgs []sdk.Msg @@ -266,7 +281,7 @@ func TestEVMAddressDecoratorContinueDespiteErrors(t *testing.T) { // Prepare a SigVerifiableTx with a pubkey that fails to parse brokenPubKey := &secp256k1.PubKey{Key: []byte{1, 2, 3}} // deliberately too short to be valid k.AccountKeeper().SetAccount(ctx, authtypes.NewBaseAccount(sender, brokenPubKey, 1, 1)) - ctx, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}, signers: []sdk.AccAddress{sender}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}, signers: []sdk.AccAddress{sender}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { return ctx, nil }) diff --git a/x/evm/ante/sig.go b/x/evm/ante/sig.go index 55f3f69e7..4d0ed5a8c 100644 --- a/x/evm/ante/sig.go +++ b/x/evm/ante/sig.go @@ -1,8 +1,11 @@ package ante import ( + "math/big" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + ethtypes "github.com/ethereum/go-ethereum/core/types" abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" @@ -36,6 +39,25 @@ func (svd *EVMSigVerifyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat ctx = ctx.WithEVMSenderAddress(evmAddr.Hex()) ctx = ctx.WithEVMTxHash(ethTx.Hash().Hex()) + chainID := svd.evmKeeper.ChainID(ctx) + txChainID := ethTx.ChainId() + + // validate chain ID on the transaction + switch ethTx.Type() { + case ethtypes.LegacyTxType: + // legacy either can have a zero or correct chain ID + if txChainID.Cmp(big.NewInt(0)) != 0 && txChainID.Cmp(chainID) != 0 { + ctx.Logger().Error("chainID mismatch", "txChainID", ethTx.ChainId(), "chainID", chainID) + return ctx, sdkerrors.ErrInvalidChainID + } + default: + // after legacy, all transactions must have the correct chain ID + if txChainID.Cmp(chainID) != 0 { + ctx.Logger().Error("chainID mismatch", "txChainID", ethTx.ChainId(), "chainID", chainID) + return ctx, sdkerrors.ErrInvalidChainID + } + } + if ctx.IsCheckTx() { if txNonce < nextNonce { return ctx, sdkerrors.ErrWrongSequence diff --git a/x/evm/artifacts/cw20/artifacts.go b/x/evm/artifacts/cw20/artifacts.go index 073971723..838c3ceb2 100644 --- a/x/evm/artifacts/cw20/artifacts.go +++ b/x/evm/artifacts/cw20/artifacts.go @@ -7,10 +7,25 @@ import ( "fmt" "strings" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/accounts/abi" + + "github.com/sei-protocol/sei-chain/x/evm/config" ) -const CurrentVersion uint16 = 1 +const currentVersion uint16 = 1 + +var versionOverride uint16 + +// SetVersionWithOffset allows for overriding the version for integration test scenarios +func SetVersionWithOffset(offset int16) { + // this allows for negative offsets to mock lower versions + versionOverride = uint16(int16(currentVersion) + offset) +} + +func CurrentVersion(ctx sdk.Context) uint16 { + return config.GetVersionWthDefault(ctx, versionOverride, currentVersion) +} //go:embed CW20ERC20Pointer.abi //go:embed CW20ERC20Pointer.bin diff --git a/x/evm/artifacts/cw721/CW721ERC721Pointer.abi b/x/evm/artifacts/cw721/CW721ERC721Pointer.abi index fccb8a07a..7dc59839d 100644 --- a/x/evm/artifacts/cw721/CW721ERC721Pointer.abi +++ b/x/evm/artifacts/cw721/CW721ERC721Pointer.abi @@ -1 +1 @@ -[{"inputs":[{"internalType":"string","name":"Cw721Address_","type":"string"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"AddrPrecompile","outputs":[{"internalType":"contract IAddr","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"Cw721Address","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"JsonPrecompile","outputs":[{"internalType":"contract IJson","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WasmdPrecompile","outputs":[{"internalType":"contract IWasmd","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file +[{"inputs":[{"internalType":"string","name":"Cw721Address_","type":"string"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidDefaultRoyalty","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidDefaultRoyaltyReceiver","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidTokenRoyalty","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidTokenRoyaltyReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[{"internalType":"string","name":"method","type":"string"}],"name":"NotImplemented","type":"error"},{"inputs":[{"internalType":"string","name":"method","type":"string"}],"name":"NotImplementedOnCosmwasmContract","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"AddrPrecompile","outputs":[{"internalType":"contract IAddr","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"Cw721Address","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"JsonPrecompile","outputs":[{"internalType":"contract IJson","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WasmdPrecompile","outputs":[{"internalType":"contract IWasmd","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","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":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/x/evm/artifacts/cw721/CW721ERC721Pointer.bin b/x/evm/artifacts/cw721/CW721ERC721Pointer.bin index 700510ae7..8c67fd57d 100644 --- a/x/evm/artifacts/cw721/CW721ERC721Pointer.bin +++ b/x/evm/artifacts/cw721/CW721ERC721Pointer.bin @@ -1 +1 @@ -608060405234801562000010575f80fd5b5060405162003cc638038062003cc68339818101604052810190620000369190620002c3565b8181815f9081620000489190620005b0565b5080600190816200005a9190620005b0565b50505061100260075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100360085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100460095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260069081620001349190620005b0565b5050505062000694565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200019f8262000157565b810181811067ffffffffffffffff82111715620001c157620001c062000167565b5b80604052505050565b5f620001d56200013e565b9050620001e3828262000194565b919050565b5f67ffffffffffffffff82111562000205576200020462000167565b5b620002108262000157565b9050602081019050919050565b5f5b838110156200023c5780820151818401526020810190506200021f565b5f8484015250505050565b5f6200025d6200025784620001e8565b620001ca565b9050828152602081018484840111156200027c576200027b62000153565b5b620002898482856200021d565b509392505050565b5f82601f830112620002a857620002a76200014f565b5b8151620002ba84826020860162000247565b91505092915050565b5f805f60608486031215620002dd57620002dc62000147565b5b5f84015167ffffffffffffffff811115620002fd57620002fc6200014b565b5b6200030b8682870162000291565b935050602084015167ffffffffffffffff8111156200032f576200032e6200014b565b5b6200033d8682870162000291565b925050604084015167ffffffffffffffff8111156200036157620003606200014b565b5b6200036f8682870162000291565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620003c857607f821691505b602082108103620003de57620003dd62000383565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004427fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000405565b6200044e868362000405565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000498620004926200048c8462000466565b6200046f565b62000466565b9050919050565b5f819050919050565b620004b38362000478565b620004cb620004c2826200049f565b84845462000411565b825550505050565b5f90565b620004e1620004d3565b620004ee818484620004a8565b505050565b5b818110156200051557620005095f82620004d7565b600181019050620004f4565b5050565b601f82111562000564576200052e81620003e4565b6200053984620003f6565b8101602085101562000549578190505b620005616200055885620003f6565b830182620004f3565b50505b505050565b5f82821c905092915050565b5f620005865f198460080262000569565b1980831691505092915050565b5f620005a0838362000575565b9150826002028217905092915050565b620005bb8262000379565b67ffffffffffffffff811115620005d757620005d662000167565b5b620005e38254620003b0565b620005f082828562000519565b5f60209050601f83116001811462000626575f841562000611578287015190505b6200061d858262000593565b8655506200068c565b601f1984166200063686620003e4565b5f5b828110156200065f5784890151825560018201915060208501945060208101905062000638565b868310156200067f57848901516200067b601f89168262000575565b8355505b6001600288020188555050505b505050505050565b61362480620006a25f395ff3fe608060405234801561000f575f80fd5b5060043610610109575f3560e01c806370a08231116100a0578063c2aed3021161006f578063c2aed302146102b3578063c87b56dd146102d1578063de4725cc14610301578063e985e9c51461031f578063f00b02551461034f57610109565b806370a082311461022d57806395d89b411461025d578063a22cb4651461027b578063b88d4fde1461029757610109565b806323b872dd116100dc57806323b872dd146101a757806342842e0e146101c35780635c4aead7146101df5780636352211e146101fd57610109565b806301ffc9a71461010d57806306fdde031461013d578063081812fc1461015b578063095ea7b31461018b575b5f80fd5b61012760048036038101906101229190612462565b61036d565b60405161013491906124a7565b60405180910390f35b61014561044e565b604051610152919061254a565b60405180910390f35b6101756004803603810190610170919061259d565b6104dd565b6040516101829190612607565b60405180910390f35b6101a560048036038101906101a0919061264a565b610837565b005b6101c160048036038101906101bc9190612688565b610a73565b005b6101dd60048036038101906101d89190612688565b610d8e565b005b6101e7610dad565b6040516101f4919061254a565b60405180910390f35b6102176004803603810190610212919061259d565b610e39565b6040516102249190612607565b60405180910390f35b610247600480360381019061024291906126d8565b6110c3565b6040516102549190612712565b60405180910390f35b6102656113b9565b604051610272919061254a565b60405180910390f35b61029560048036038101906102909190612755565b611449565b005b6102b160048036038101906102ac91906128bf565b61164c565b005b6102bb611671565b6040516102c8919061299a565b60405180910390f35b6102eb60048036038101906102e6919061259d565b611696565b6040516102f8919061254a565b60405180910390f35b610309611893565b60405161031691906129d3565b60405180910390f35b610339600480360381019061033491906129ec565b6118b8565b60405161034691906124a7565b60405180910390f35b610357611cf2565b6040516103649190612a4a565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061043757507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610447575061044682611d17565b5b9050919050565b60605f805461045c90612a90565b80601f016020809104026020016040519081016040528092919081815260200182805461048890612a90565b80156104d35780601f106104aa576101008083540402835291602001916104d3565b820191905f5260205f20905b8154815290600101906020018083116104b657829003601f168201915b5050505050905090565b5f8061052e6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061052961052486611d80565b611e4a565b611e92565b90505f61058061057b6040518060400160405280600981526020017f617070726f76616c73000000000000000000000000000000000000000000000081525061057685611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016105e0929190612ba5565b5f60405180830381865afa1580156105fa573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106229190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b815260040161067f9190612cd9565b5f60405180830381865afa158015610699573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106c19190612dee565b90505f8151111561082a575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5835f8151811061071d5761071c612e35565b5b60200260200101516040518263ffffffff1660e01b81526004016107419190612eac565b5f60405180830381865afa15801561075b573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906107839190612c48565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b81526004016107df919061254a565b602060405180830381865afa1580156107fa573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061081e9190612ef3565b95505050505050610832565b5f9450505050505b919050565b5f61091a6040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061091560095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b81526004016108ce9190612607565b5f60405180830381865afa1580156108e8573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906109109190612fbc565b611e4a565b611e92565b90505f61096c6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061096761096286611d80565b611e4a565b611e92565b90505f6109fd6109f86040518060400160405280600781526020017f617070726f7665000000000000000000000000000000000000000000000000008152506109f36109ee87876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611f2c565b611ee4565b611e92565b611ee4565b9050610a0881611f7a565b50838573ffffffffffffffffffffffffffffffffffffffff16610a2a86610e39565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ae3575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ada9190612607565b60405180910390fd5b610aec81610e39565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610b59576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b509061304d565b60405180910390fd5b5f610c3c6040518060400160405280600981526020017f726563697069656e740000000000000000000000000000000000000000000000815250610c3760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401610bf09190612607565b5f60405180830381865afa158015610c0a573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610c329190612fbc565b611e4a565b611e92565b90505f610c8e6040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610c89610c8486611d80565b611e4a565b611e92565b90505f610d1f610d1a6040518060400160405280600c81526020017f7472616e736665725f6e66740000000000000000000000000000000000000000815250610d15610d1087876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611f2c565b611ee4565b611e92565b611ee4565b9050610d2a81611f7a565b50838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b610da883838360405180602001604052805f81525061164c565b505050565b60068054610dba90612a90565b80601f0160208091040260200160405190810160405280929190818152602001828054610de690612a90565b8015610e315780601f10610e0857610100808354040283529160200191610e31565b820191905f5260205f20905b815481529060010190602001808311610e1457829003601f168201915b505050505081565b5f80610e8a6040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610e85610e8086611d80565b611e4a565b611e92565b90505f610edc610ed76040518060400160405280600881526020017f6f776e65725f6f66000000000000000000000000000000000000000000000000815250610ed285611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401610f3c929190612ba5565b5f60405180830381865afa158015610f56573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610f7e9190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b8152600401610fdb91906130b5565b5f60405180830381865afa158015610ff5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061101d9190612c48565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b8152600401611079919061254a565b602060405180830381865afa158015611094573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110b89190612ef3565b945050505050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611134575f6040517f89c62b6400000000000000000000000000000000000000000000000000000000815260040161112b9190612607565b60405180910390fd5b5f6112176040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061121260095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b81526004016111cb9190612607565b5f60405180830381865afa1580156111e5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061120d9190612fbc565b611e4a565b611e92565b90505f6112696112646040518060400160405280600681526020017f746f6b656e73000000000000000000000000000000000000000000000000000081525061125f85611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016112c9929190612ba5565b5f60405180830381865afa1580156112e3573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061130b9190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b81526004016113689190613132565b5f60405180830381865afa158015611382573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906113aa9190612dee565b90508051945050505050919050565b6060600180546113c890612a90565b80601f01602080910402602001604051908101604052809291908181526020018280546113f490612a90565b801561143f5780601f106114165761010080835404028352916020019161143f565b820191905f5260205f20905b81548152906001019060200180831161142257829003601f168201915b5050505050905090565b5f61153461152f6040518060400160405280600881526020017f6f70657261746f7200000000000000000000000000000000000000000000000081525061152a60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b81526004016114e39190612607565b5f60405180830381865afa1580156114fd573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906115259190612fbc565b611e4a565b611e92565b611ee4565b905081156115915761158b6115866115816040518060400160405280600b81526020017f617070726f76655f616c6c00000000000000000000000000000000000000000081525084611e92565b611ee4565b611f7a565b506115e2565b6115e06115db6115d66040518060400160405280600a81526020017f7265766f6b655f616c6c0000000000000000000000000000000000000000000081525084611e92565b611ee4565b611f7a565b505b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318460405161163f91906124a7565b60405180910390a3505050565b611657848484610a73565b61166b6116626120f8565b858585856120ff565b50505050565b60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606116a182610e39565b505f6116f26040518060400160405280600881526020017f746f6b656e5f69640000000000000000000000000000000000000000000000008152506116ed6116e886611d80565b611e4a565b611e92565b90505f61174461173f6040518060400160405280600881526020017f6e66745f696e666f00000000000000000000000000000000000000000000000081525061173a85611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016117a4929190612ba5565b5f60405180830381865afa1580156117be573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906117e69190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b815260040161184391906131af565b5f60405180830381865afa15801561185d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906118859190612c48565b905080945050505050919050565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f8061199c6040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061199760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b81526004016119509190612607565b5f60405180830381865afa15801561196a573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906119929190612fbc565b611e4a565b611e92565b90505f6119ee6119e96040518060400160405280600d81526020017f616c6c5f6f70657261746f7273000000000000000000000000000000000000008152506119e485611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401611a4e929190612ba5565b5f60405180830381865afa158015611a68573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611a909190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b8152600401611aed919061322c565b5f60405180830381865afa158015611b07573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611b2f9190612dee565b90505f5b8151811015611ce3575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5848481518110611b8d57611b8c612e35565b5b60200260200101516040518263ffffffff1660e01b8152600401611bb19190612eac565b5f60405180830381865afa158015611bcb573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611bf39190612c48565b90508773ffffffffffffffffffffffffffffffffffffffff1660095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539836040518263ffffffff1660e01b8152600401611c66919061254a565b602060405180830381865afa158015611c81573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ca59190612ef3565b73ffffffffffffffffffffffffffffffffffffffff1603611ccf5760019650505050505050611cec565b508080611cdb9061328c565b915050611b33565b505f9450505050505b92915050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60605f6001611d8e846122ab565b0190505f8167ffffffffffffffff811115611dac57611dab61279b565b5b6040519080825280601f01601f191660200182016040528015611dde5781602001600182028036833780820191505090505b5090505f82602001820190505b600115611e3f578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581611e3457611e336132d3565b5b0494505f8503611deb575b819350505050919050565b606081604051602001611e5d9190613360565b604051602081830303815290604052604051602001611e7c9190613385565b6040516020818303038152906040529050919050565b6060611edc611ea084611e4a565b836040518060400160405280600181526020017f3a00000000000000000000000000000000000000000000000000000000000000815250611f2c565b905092915050565b606081604051602001611ef791906133d0565b604051602081830303815290604052604051602001611f16919061341b565b6040516020818303038152906040529050919050565b6060838284604051602001611f42929190613440565b604051602081830303815290604052604051602001611f62929190613440565b60405160208183030381529060405290509392505050565b60605f8061100273ffffffffffffffffffffffffffffffffffffffff166006856040518060400160405280600281526020017f5b5d000000000000000000000000000000000000000000000000000000000000815250604051602401611fe293929190613463565b6040516020818303038152906040527f44d227ae000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161206c91906134e7565b5f60405180830381855af49150503d805f81146120a4576040519150601f19603f3d011682016040523d82523d5f602084013e6120a9565b606091505b5091509150816120ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120e590613547565b60405180910390fd5b8092505050919050565b5f33905090565b5f8373ffffffffffffffffffffffffffffffffffffffff163b11156122a4578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02868685856040518563ffffffff1660e01b815260040161215d9493929190613565565b6020604051808303815f875af192505050801561219857506040513d601f19601f8201168201806040525081019061219591906135c3565b60015b612219573d805f81146121c6576040519150601f19603f3d011682016040523d82523d5f602084013e6121cb565b606091505b505f81510361221157836040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016122089190612607565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146122a257836040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016122999190612607565b60405180910390fd5b505b5050505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612307577a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083816122fd576122fc6132d3565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612344576d04ee2d6d415b85acef8100000000838161233a576123396132d3565b5b0492506020810190505b662386f26fc10000831061237357662386f26fc100008381612369576123686132d3565b5b0492506010810190505b6305f5e100831061239c576305f5e1008381612392576123916132d3565b5b0492506008810190505b61271083106123c15761271083816123b7576123b66132d3565b5b0492506004810190505b606483106123e457606483816123da576123d96132d3565b5b0492506002810190505b600a83106123f3576001810190505b80915050919050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6124418161240d565b811461244b575f80fd5b50565b5f8135905061245c81612438565b92915050565b5f6020828403121561247757612476612405565b5b5f6124848482850161244e565b91505092915050565b5f8115159050919050565b6124a18161248d565b82525050565b5f6020820190506124ba5f830184612498565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156124f75780820151818401526020810190506124dc565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61251c826124c0565b61252681856124ca565b93506125368185602086016124da565b61253f81612502565b840191505092915050565b5f6020820190508181035f8301526125628184612512565b905092915050565b5f819050919050565b61257c8161256a565b8114612586575f80fd5b50565b5f8135905061259781612573565b92915050565b5f602082840312156125b2576125b1612405565b5b5f6125bf84828501612589565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6125f1826125c8565b9050919050565b612601816125e7565b82525050565b5f60208201905061261a5f8301846125f8565b92915050565b612629816125e7565b8114612633575f80fd5b50565b5f8135905061264481612620565b92915050565b5f80604083850312156126605761265f612405565b5b5f61266d85828601612636565b925050602061267e85828601612589565b9150509250929050565b5f805f6060848603121561269f5761269e612405565b5b5f6126ac86828701612636565b93505060206126bd86828701612636565b92505060406126ce86828701612589565b9150509250925092565b5f602082840312156126ed576126ec612405565b5b5f6126fa84828501612636565b91505092915050565b61270c8161256a565b82525050565b5f6020820190506127255f830184612703565b92915050565b6127348161248d565b811461273e575f80fd5b50565b5f8135905061274f8161272b565b92915050565b5f806040838503121561276b5761276a612405565b5b5f61277885828601612636565b925050602061278985828601612741565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6127d182612502565b810181811067ffffffffffffffff821117156127f0576127ef61279b565b5b80604052505050565b5f6128026123fc565b905061280e82826127c8565b919050565b5f67ffffffffffffffff82111561282d5761282c61279b565b5b61283682612502565b9050602081019050919050565b828183375f83830152505050565b5f61286361285e84612813565b6127f9565b90508281526020810184848401111561287f5761287e612797565b5b61288a848285612843565b509392505050565b5f82601f8301126128a6576128a5612793565b5b81356128b6848260208601612851565b91505092915050565b5f805f80608085870312156128d7576128d6612405565b5b5f6128e487828801612636565b94505060206128f587828801612636565b935050604061290687828801612589565b925050606085013567ffffffffffffffff81111561292757612926612409565b5b61293387828801612892565b91505092959194509250565b5f819050919050565b5f61296261295d612958846125c8565b61293f565b6125c8565b9050919050565b5f61297382612948565b9050919050565b5f61298482612969565b9050919050565b6129948161297a565b82525050565b5f6020820190506129ad5f83018461298b565b92915050565b5f6129bd82612969565b9050919050565b6129cd816129b3565b82525050565b5f6020820190506129e65f8301846129c4565b92915050565b5f8060408385031215612a0257612a01612405565b5b5f612a0f85828601612636565b9250506020612a2085828601612636565b9150509250929050565b5f612a3482612969565b9050919050565b612a4481612a2a565b82525050565b5f602082019050612a5d5f830184612a3b565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680612aa757607f821691505b602082108103612aba57612ab9612a63565b5b50919050565b5f819050815f5260205f209050919050565b5f8154612ade81612a90565b612ae881866124ca565b9450600182165f8114612b025760018114612b1857612b4a565b60ff198316865281151560200286019350612b4a565b612b2185612ac0565b5f5b83811015612b4257815481890152600182019150602081019050612b23565b808801955050505b50505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f612b7782612b53565b612b818185612b5d565b9350612b918185602086016124da565b612b9a81612502565b840191505092915050565b5f6040820190508181035f830152612bbd8185612ad2565b90508181036020830152612bd18184612b6d565b90509392505050565b5f612bec612be784612813565b6127f9565b905082815260208101848484011115612c0857612c07612797565b5b612c138482856124da565b509392505050565b5f82601f830112612c2f57612c2e612793565b5b8151612c3f848260208601612bda565b91505092915050565b5f60208284031215612c5d57612c5c612405565b5b5f82015167ffffffffffffffff811115612c7a57612c79612409565b5b612c8684828501612c1b565b91505092915050565b7f617070726f76616c7300000000000000000000000000000000000000000000005f82015250565b5f612cc36009836124ca565b9150612cce82612c8f565b602082019050919050565b5f6040820190508181035f830152612cf18184612b6d565b90508181036020830152612d0481612cb7565b905092915050565b5f67ffffffffffffffff821115612d2657612d2561279b565b5b602082029050602081019050919050565b5f80fd5b5f612d4d612d4884612d0c565b6127f9565b90508083825260208201905060208402830185811115612d7057612d6f612d37565b5b835b81811015612db757805167ffffffffffffffff811115612d9557612d94612793565b5b808601612da28982612c1b565b85526020850194505050602081019050612d72565b5050509392505050565b5f82601f830112612dd557612dd4612793565b5b8151612de5848260208601612d3b565b91505092915050565b5f60208284031215612e0357612e02612405565b5b5f82015167ffffffffffffffff811115612e2057612e1f612409565b5b612e2c84828501612dc1565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f7370656e646572000000000000000000000000000000000000000000000000005f82015250565b5f612e966007836124ca565b9150612ea182612e62565b602082019050919050565b5f6040820190508181035f830152612ec48184612b6d565b90508181036020830152612ed781612e8a565b905092915050565b5f81519050612eed81612620565b92915050565b5f60208284031215612f0857612f07612405565b5b5f612f1584828501612edf565b91505092915050565b5f67ffffffffffffffff821115612f3857612f3761279b565b5b612f4182612502565b9050602081019050919050565b5f612f60612f5b84612f1e565b6127f9565b905082815260208101848484011115612f7c57612f7b612797565b5b612f878482856124da565b509392505050565b5f82601f830112612fa357612fa2612793565b5b8151612fb3848260208601612f4e565b91505092915050565b5f60208284031215612fd157612fd0612405565b5b5f82015167ffffffffffffffff811115612fee57612fed612409565b5b612ffa84828501612f8f565b91505092915050565b7f6066726f6d60206d75737420626520746865206f776e657200000000000000005f82015250565b5f6130376018836124ca565b915061304282613003565b602082019050919050565b5f6020820190508181035f8301526130648161302b565b9050919050565b7f6f776e65720000000000000000000000000000000000000000000000000000005f82015250565b5f61309f6005836124ca565b91506130aa8261306b565b602082019050919050565b5f6040820190508181035f8301526130cd8184612b6d565b905081810360208301526130e081613093565b905092915050565b7f746f6b656e7300000000000000000000000000000000000000000000000000005f82015250565b5f61311c6006836124ca565b9150613127826130e8565b602082019050919050565b5f6040820190508181035f83015261314a8184612b6d565b9050818103602083015261315d81613110565b905092915050565b7f746f6b656e5f75726900000000000000000000000000000000000000000000005f82015250565b5f6131996009836124ca565b91506131a482613165565b602082019050919050565b5f6040820190508181035f8301526131c78184612b6d565b905081810360208301526131da8161318d565b905092915050565b7f6f70657261746f727300000000000000000000000000000000000000000000005f82015250565b5f6132166009836124ca565b9150613221826131e2565b602082019050919050565b5f6040820190508181035f8301526132448184612b6d565b905081810360208301526132578161320a565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6132968261256a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036132c8576132c761325f565b5b600182019050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f81905092915050565b5f613314826124c0565b61331e8185613300565b935061332e8185602086016124da565b80840191505092915050565b7f2200000000000000000000000000000000000000000000000000000000000000815250565b5f61336b828461330a565b91506133768261333a565b60018201915081905092915050565b5f61338f8261333a565b60018201915061339f828461330a565b915081905092915050565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b5f6133db828461330a565b91506133e6826133aa565b60018201915081905092915050565b7f7b00000000000000000000000000000000000000000000000000000000000000815250565b5f613425826133f5565b600182019150613435828461330a565b915081905092915050565b5f61344b828561330a565b9150613457828461330a565b91508190509392505050565b5f6060820190508181035f83015261347b8186612ad2565b9050818103602083015261348f8185612b6d565b905081810360408301526134a38184612b6d565b9050949350505050565b5f81905092915050565b5f6134c182612b53565b6134cb81856134ad565b93506134db8185602086016124da565b80840191505092915050565b5f6134f282846134b7565b915081905092915050565b7f436f736d5761736d2065786563757465206661696c65640000000000000000005f82015250565b5f6135316017836124ca565b915061353c826134fd565b602082019050919050565b5f6020820190508181035f83015261355e81613525565b9050919050565b5f6080820190506135785f8301876125f8565b61358560208301866125f8565b6135926040830185612703565b81810360608301526135a48184612b6d565b905095945050505050565b5f815190506135bd81612438565b92915050565b5f602082840312156135d8576135d7612405565b5b5f6135e5848285016135af565b9150509291505056fea2646970667358221220a2c419c1e43b74d07c7e3f63d55af936cde414fdc186470d597ab1da5b53412e64736f6c63430008150033 \ No newline at end of file +608060405234801561000f575f80fd5b50604051614c2c380380614c2c8339818101604052810190610031919061027f565b8181815f90816100419190610530565b5080600190816100519190610530565b50505061100260095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611003600a5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611004600b5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600890816101299190610530565b505050506105ff565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6101918261014b565b810181811067ffffffffffffffff821117156101b0576101af61015b565b5b80604052505050565b5f6101c2610132565b90506101ce8282610188565b919050565b5f67ffffffffffffffff8211156101ed576101ec61015b565b5b6101f68261014b565b9050602081019050919050565b8281835e5f83830152505050565b5f61022361021e846101d3565b6101b9565b90508281526020810184848401111561023f5761023e610147565b5b61024a848285610203565b509392505050565b5f82601f83011261026657610265610143565b5b8151610276848260208601610211565b91505092915050565b5f805f606084860312156102965761029561013b565b5b5f84015167ffffffffffffffff8111156102b3576102b261013f565b5b6102bf86828701610252565b935050602084015167ffffffffffffffff8111156102e0576102df61013f565b5b6102ec86828701610252565b925050604084015167ffffffffffffffff81111561030d5761030c61013f565b5b61031986828701610252565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061037157607f821691505b6020821081036103845761038361032d565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026103e67fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826103ab565b6103f086836103ab565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f61043461042f61042a84610408565b610411565b610408565b9050919050565b5f819050919050565b61044d8361041a565b6104616104598261043b565b8484546103b7565b825550505050565b5f90565b610475610469565b610480818484610444565b505050565b5b818110156104a3576104985f8261046d565b600181019050610486565b5050565b601f8211156104e8576104b98161038a565b6104c28461039c565b810160208510156104d1578190505b6104e56104dd8561039c565b830182610485565b50505b505050565b5f82821c905092915050565b5f6105085f19846008026104ed565b1980831691505092915050565b5f61052083836104f9565b9150826002028217905092915050565b61053982610323565b67ffffffffffffffff8111156105525761055161015b565b5b61055c825461035a565b6105678282856104a7565b5f60209050601f831160018114610598575f8415610586578287015190505b6105908582610515565b8655506105f7565b601f1984166105a68661038a565b5f5b828110156105cd578489015182556001820191506020850194506020810190506105a8565b868310156105ea57848901516105e6601f8916826104f9565b8355505b6001600288020188555050505b505050505050565b6146208061060c5f395ff3fe608060405234801561000f575f80fd5b5060043610610135575f3560e01c80635c4aead7116100b6578063b88d4fde1161007a578063b88d4fde14610372578063c2aed3021461038e578063c87b56dd146103ac578063de4725cc146103dc578063e985e9c5146103fa578063f00b02551461042a57610135565b80635c4aead7146102ba5780636352211e146102d857806370a082311461030857806395d89b4114610338578063a22cb4651461035657610135565b806323b872dd116100fd57806323b872dd146101f15780632a55205a1461020d5780632f745c591461023e57806342842e0e1461026e5780634f6ccce71461028a57610135565b806301ffc9a71461013957806306fdde0314610169578063081812fc14610187578063095ea7b3146101b757806318160ddd146101d3575b5f80fd5b610153600480360381019061014e9190612f31565b610448565b6040516101609190612f76565b60405180910390f35b6101716105e9565b60405161017e9190612fff565b60405180910390f35b6101a1600480360381019061019c9190613052565b610678565b6040516101ae91906130bc565b60405180910390f35b6101d160048036038101906101cc91906130ff565b6109d2565b005b6101db610c0e565b6040516101e8919061314c565b60405180910390f35b61020b60048036038101906102069190613165565b610d85565b005b610227600480360381019061022291906131b5565b6110a0565b6040516102359291906131f3565b60405180910390f35b610258600480360381019061025391906130ff565b6116d1565b604051610265919061314c565b60405180910390f35b61028860048036038101906102839190613165565b61170d565b005b6102a4600480360381019061029f9190613052565b61172c565b6040516102b1919061314c565b60405180910390f35b6102c2611768565b6040516102cf9190612fff565b60405180910390f35b6102f260048036038101906102ed9190613052565b6117f4565b6040516102ff91906130bc565b60405180910390f35b610322600480360381019061031d919061321a565b611a7e565b60405161032f919061314c565b60405180910390f35b610340611ef9565b60405161034d9190612fff565b60405180910390f35b610370600480360381019061036b919061326f565b611f89565b005b61038c600480360381019061038791906133d9565b61218c565b005b6103966121a9565b6040516103a391906134b4565b60405180910390f35b6103c660048036038101906103c19190613052565b6121ce565b6040516103d39190612fff565b60405180910390f35b6103e46123cb565b6040516103f191906134ed565b60405180910390f35b610414600480360381019061040f9190613506565b6123f0565b6040516104219190612f76565b60405180910390f35b610432612824565b60405161043f9190613564565b60405180910390f35b5f7f2a55205a000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061051257507f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061057a57507f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806105e257507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b9050919050565b60605f80546105f7906135aa565b80601f0160208091040260200160405190810160405280929190818152602001828054610623906135aa565b801561066e5780601f106106455761010080835404028352916020019161066e565b820191905f5260205f20905b81548152906001019060200180831161065157829003601f168201915b5050505050905090565b5f806106c96040518060400160405280600881526020017f746f6b656e5f69640000000000000000000000000000000000000000000000008152506106c46106bf86612849565b612913565b61295b565b90505f61071b6107166040518060400160405280600981526020017f617070726f76616c730000000000000000000000000000000000000000000000815250610711856129ad565b61295b565b6129ad565b90505f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296008846040518363ffffffff1660e01b815260040161077b9291906136bf565b5f60405180830381865afa158015610795573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906107bd9190613762565b90505f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b815260040161081a91906137f3565b5f60405180830381865afa158015610834573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061085c9190613908565b90505f815111156109c5575f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5835f815181106108b8576108b761394f565b5b60200260200101516040518263ffffffff1660e01b81526004016108dc91906139c6565b5f60405180830381865afa1580156108f6573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061091e9190613762565b9050600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b815260040161097a9190612fff565b602060405180830381865afa158015610995573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109b99190613a0d565b955050505050506109cd565b5f9450505050505b919050565b5f610ab56040518060400160405280600781526020017f7370656e64657200000000000000000000000000000000000000000000000000815250610ab0600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401610a6991906130bc565b5f60405180830381865afa158015610a83573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610aab9190613ad6565b612913565b61295b565b90505f610b076040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610b02610afd86612849565b612913565b61295b565b90505f610b98610b936040518060400160405280600781526020017f617070726f766500000000000000000000000000000000000000000000000000815250610b8e610b8987876040518060400160405280600181526020017f2c000000000000000000000000000000000000000000000000000000000000008152506129f5565b6129ad565b61295b565b6129ad565b9050610ba381612a43565b50838573ffffffffffffffffffffffffffffffffffffffff16610bc5866117f4565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050505050565b5f8060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d2960086040518060400160405280601181526020017f7b226e756d5f746f6b656e73223a7b7d7d0000000000000000000000000000008152506040518363ffffffff1660e01b8152600401610ca29291906136bf565b5f60405180830381865afa158015610cbc573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610ce49190613762565b9050600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982826040518263ffffffff1660e01b8152600401610d409190613b67565b602060405180830381865afa158015610d5b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d7f9190613bae565b91505090565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610df5575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610dec91906130bc565b60405180910390fd5b610dfe816117f4565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610e6b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6290613c23565b60405180910390fd5b5f610f4e6040518060400160405280600981526020017f726563697069656e740000000000000000000000000000000000000000000000815250610f49600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401610f0291906130bc565b5f60405180830381865afa158015610f1c573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610f449190613ad6565b612913565b61295b565b90505f610fa06040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610f9b610f9686612849565b612913565b61295b565b90505f61103161102c6040518060400160405280600c81526020017f7472616e736665725f6e6674000000000000000000000000000000000000000081525061102761102287876040518060400160405280600181526020017f2c000000000000000000000000000000000000000000000000000000000000008152506129f5565b6129ad565b61295b565b6129ad565b905061103c81612a43565b50838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b5f805f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d2960086040518060600160405280602c81526020016145bf602c91396040518363ffffffff1660e01b81526004016111189291906136bf565b5f60405180830381865afa158015611132573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061115a9190613762565b90505f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b81526004016111b79190613c8b565b5f60405180830381865afa1580156111d1573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906111f99190613762565b90507f6273151f959616268004b58dbb21e5c851b7b8d04498b4aabee12291d22fc034818051906020012014611264576040517f438c4bcb00000000000000000000000000000000000000000000000000000000815260040161125b90613d08565b60405180910390fd5b5f6112b46040518060400160405280600881526020017f746f6b656e5f69640000000000000000000000000000000000000000000000008152506112af6112aa8a612849565b612913565b61295b565b90505f6113066040518060400160405280600a81526020017f73616c655f7072696365000000000000000000000000000000000000000000008152506113016112fc8a612849565b612913565b61295b565b90505f6113976113926040518060400160405280600c81526020017f726f79616c74795f696e666f000000000000000000000000000000000000000081525061138d61138887876040518060400160405280600181526020017f2c000000000000000000000000000000000000000000000000000000000000008152506129f5565b6129ad565b61295b565b6129ad565b90505f6114276114226040518060400160405280600981526020017f657874656e73696f6e000000000000000000000000000000000000000000000081525061141d6114186040518060400160405280600381526020017f6d736700000000000000000000000000000000000000000000000000000000008152508761295b565b6129ad565b61295b565b6129ad565b90505f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296008846040518363ffffffff1660e01b81526004016114879291906136bf565b5f60405180830381865afa1580156114a1573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906114c99190613762565b90505f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b81526004016115269190613d70565b5f60405180830381865afa158015611540573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906115689190613762565b90505f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982846040518263ffffffff1660e01b81526004016115c59190613ded565b602060405180830381865afa1580156115e0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116049190613bae565b90505f825103611622575f819a509a505050505050505050506116ca565b600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539836040518263ffffffff1660e01b815260040161167c9190612fff565b602060405180830381865afa158015611697573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116bb9190613a0d565b819a509a505050505050505050505b9250929050565b5f6040517f74115a7400000000000000000000000000000000000000000000000000000000815260040161170490613e6a565b60405180910390fd5b61172783838360405180602001604052805f81525061218c565b505050565b5f6040517f74115a7400000000000000000000000000000000000000000000000000000000815260040161175f90613ed2565b60405180910390fd5b60088054611775906135aa565b80601f01602080910402602001604051908101604052809291908181526020018280546117a1906135aa565b80156117ec5780601f106117c3576101008083540402835291602001916117ec565b820191905f5260205f20905b8154815290600101906020018083116117cf57829003601f168201915b505050505081565b5f806118456040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061184061183b86612849565b612913565b61295b565b90505f6118976118926040518060400160405280600881526020017f6f776e65725f6f6600000000000000000000000000000000000000000000000081525061188d856129ad565b61295b565b6129ad565b90505f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296008846040518363ffffffff1660e01b81526004016118f79291906136bf565b5f60405180830381865afa158015611911573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906119399190613762565b90505f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b81526004016119969190613f3a565b5f60405180830381865afa1580156119b0573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906119d89190613762565b9050600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b8152600401611a349190612fff565b602060405180830381865afa158015611a4f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a739190613a0d565b945050505050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611aef575f6040517f89c62b64000000000000000000000000000000000000000000000000000000008152600401611ae691906130bc565b60405180910390fd5b5f60605f600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed866040518263ffffffff1660e01b8152600401611b4d91906130bc565b5f60405180830381865afa158015611b67573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611b8f9190613ad6565b604051602001611b9f9190613fcd565b604051602081830303815290604052604051602001611bbe9190614018565b60405160208183030381529060405290505f7fcc1a5a473fb6da314e591eaff47c9e633c2fdb385df3a7900f90f8a3ce756bdd905060605f8084604051602001611c089190614063565b604051602081830303815290604052604051602001611c2791906140ae565b60405160208183030381529060405290505f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296008846040518363ffffffff1660e01b8152600401611c969291906136bf565b5f60405180830381865afa158015611cb0573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611cd89190613762565b90505b84818051906020012014611ee957600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621826040518263ffffffff1660e01b8152600401611d43919061411d565b5f60405180830381865afa158015611d5d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611d859190613908565b9350835192508288611d97919061417d565b975083600184611da791906141b0565b81518110611db857611db761394f565b5b6020026020010151604051602001611dd09190614209565b60405160208183030381529060405296508587604051602001611df492919061422e565b604051602081830303815290604052604051602001611e139190614063565b604051602081830303815290604052604051602001611e3291906140ae565b604051602081830303815290604052915060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296008846040518363ffffffff1660e01b8152600401611ea09291906136bf565b5f60405180830381865afa158015611eba573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611ee29190613762565b9050611cdb565b8798505050505050505050919050565b606060018054611f08906135aa565b80601f0160208091040260200160405190810160405280929190818152602001828054611f34906135aa565b8015611f7f5780601f10611f5657610100808354040283529160200191611f7f565b820191905f5260205f20905b815481529060010190602001808311611f6257829003601f168201915b5050505050905090565b5f61207461206f6040518060400160405280600881526020017f6f70657261746f7200000000000000000000000000000000000000000000000081525061206a600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161202391906130bc565b5f60405180830381865afa15801561203d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906120659190613ad6565b612913565b61295b565b6129ad565b905081156120d1576120cb6120c66120c16040518060400160405280600b81526020017f617070726f76655f616c6c0000000000000000000000000000000000000000008152508461295b565b6129ad565b612a43565b50612122565b61212061211b6121166040518060400160405280600a81526020017f7265766f6b655f616c6c000000000000000000000000000000000000000000008152508461295b565b6129ad565b612a43565b505b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318460405161217f9190612f76565b60405180910390a3505050565b612197848484610d85565b6121a384848484612bc1565b50505050565b600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606121d9826117f4565b505f61222a6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061222561222086612849565b612913565b61295b565b90505f61227c6122776040518060400160405280600881526020017f6e66745f696e666f000000000000000000000000000000000000000000000000815250612272856129ad565b61295b565b6129ad565b90505f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296008846040518363ffffffff1660e01b81526004016122dc9291906136bf565b5f60405180830381865afa1580156122f6573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061231e9190613762565b90505f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b815260040161237b919061429b565b5f60405180830381865afa158015612395573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906123bd9190613762565b905080945050505050919050565b600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f806124d46040518060400160405280600581526020017f6f776e65720000000000000000000000000000000000000000000000000000008152506124cf600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161248891906130bc565b5f60405180830381865afa1580156124a2573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906124ca9190613ad6565b612913565b61295b565b90505f6125266125216040518060400160405280600d81526020017f616c6c5f6f70657261746f72730000000000000000000000000000000000000081525061251c856129ad565b61295b565b6129ad565b90505f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296008846040518363ffffffff1660e01b81526004016125869291906136bf565b5f60405180830381865afa1580156125a0573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906125c89190613762565b90505f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b81526004016126259190614318565b5f60405180830381865afa15801561263f573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906126679190613908565b90505f5b8151811015612815575f600a5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e58484815181106126c5576126c461394f565b5b60200260200101516040518263ffffffff1660e01b81526004016126e991906139c6565b5f60405180830381865afa158015612703573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061272b9190613762565b90508773ffffffffffffffffffffffffffffffffffffffff16600b5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539836040518263ffffffff1660e01b815260040161279e9190612fff565b602060405180830381865afa1580156127b9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127dd9190613a0d565b73ffffffffffffffffffffffffffffffffffffffff1603612807576001965050505050505061281e565b50808060010191505061266b565b505f9450505050505b92915050565b60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60605f600161285784612d73565b0190505f8167ffffffffffffffff811115612875576128746132b5565b5b6040519080825280601f01601f1916602001820160405280156128a75781602001600182028036833780820191505090505b5090505f82602001820190505b600115612908578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85816128fd576128fc61434b565b5b0494505f85036128b4575b819350505050919050565b6060816040516020016129269190614018565b6040516020818303038152906040526040516020016129459190614378565b6040516020818303038152906040529050919050565b60606129a561296984612913565b836040518060400160405280600181526020017f3a000000000000000000000000000000000000000000000000000000000000008152506129f5565b905092915050565b6060816040516020016129c091906143c3565b6040516020818303038152906040526040516020016129df919061440e565b6040516020818303038152906040529050919050565b6060838284604051602001612a0b92919061422e565b604051602081830303815290604052604051602001612a2b92919061422e565b60405160208183030381529060405290509392505050565b60605f8061100273ffffffffffffffffffffffffffffffffffffffff166008856040518060400160405280600281526020017f5b5d000000000000000000000000000000000000000000000000000000000000815250604051602401612aab93929190614433565b6040516020818303038152906040527f44d227ae000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051612b3591906144b7565b5f60405180830381855af49150503d805f8114612b6d576040519150601f19603f3d011682016040523d82523d5f602084013e612b72565b606091505b509150915081612bb7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612bae90614517565b60405180910390fd5b8092505050919050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b1115612d6d578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02612c04612ec4565b8685856040518563ffffffff1660e01b8152600401612c269493929190614535565b6020604051808303815f875af1925050508015612c6157506040513d601f19601f82011682018060405250810190612c5e9190614593565b60015b612ce2573d805f8114612c8f576040519150601f19603f3d011682016040523d82523d5f602084013e612c94565b606091505b505f815103612cda57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401612cd191906130bc565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612d6b57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401612d6291906130bc565b60405180910390fd5b505b50505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612dcf577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381612dc557612dc461434b565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612e0c576d04ee2d6d415b85acef81000000008381612e0257612e0161434b565b5b0492506020810190505b662386f26fc100008310612e3b57662386f26fc100008381612e3157612e3061434b565b5b0492506010810190505b6305f5e1008310612e64576305f5e1008381612e5a57612e5961434b565b5b0492506008810190505b6127108310612e89576127108381612e7f57612e7e61434b565b5b0492506004810190505b60648310612eac5760648381612ea257612ea161434b565b5b0492506002810190505b600a8310612ebb576001810190505b80915050919050565b5f33905090565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b612f1081612edc565b8114612f1a575f80fd5b50565b5f81359050612f2b81612f07565b92915050565b5f60208284031215612f4657612f45612ed4565b5b5f612f5384828501612f1d565b91505092915050565b5f8115159050919050565b612f7081612f5c565b82525050565b5f602082019050612f895f830184612f67565b92915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f612fd182612f8f565b612fdb8185612f99565b9350612feb818560208601612fa9565b612ff481612fb7565b840191505092915050565b5f6020820190508181035f8301526130178184612fc7565b905092915050565b5f819050919050565b6130318161301f565b811461303b575f80fd5b50565b5f8135905061304c81613028565b92915050565b5f6020828403121561306757613066612ed4565b5b5f6130748482850161303e565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6130a68261307d565b9050919050565b6130b68161309c565b82525050565b5f6020820190506130cf5f8301846130ad565b92915050565b6130de8161309c565b81146130e8575f80fd5b50565b5f813590506130f9816130d5565b92915050565b5f806040838503121561311557613114612ed4565b5b5f613122858286016130eb565b92505060206131338582860161303e565b9150509250929050565b6131468161301f565b82525050565b5f60208201905061315f5f83018461313d565b92915050565b5f805f6060848603121561317c5761317b612ed4565b5b5f613189868287016130eb565b935050602061319a868287016130eb565b92505060406131ab8682870161303e565b9150509250925092565b5f80604083850312156131cb576131ca612ed4565b5b5f6131d88582860161303e565b92505060206131e98582860161303e565b9150509250929050565b5f6040820190506132065f8301856130ad565b613213602083018461313d565b9392505050565b5f6020828403121561322f5761322e612ed4565b5b5f61323c848285016130eb565b91505092915050565b61324e81612f5c565b8114613258575f80fd5b50565b5f8135905061326981613245565b92915050565b5f806040838503121561328557613284612ed4565b5b5f613292858286016130eb565b92505060206132a38582860161325b565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6132eb82612fb7565b810181811067ffffffffffffffff8211171561330a576133096132b5565b5b80604052505050565b5f61331c612ecb565b905061332882826132e2565b919050565b5f67ffffffffffffffff821115613347576133466132b5565b5b61335082612fb7565b9050602081019050919050565b828183375f83830152505050565b5f61337d6133788461332d565b613313565b905082815260208101848484011115613399576133986132b1565b5b6133a484828561335d565b509392505050565b5f82601f8301126133c0576133bf6132ad565b5b81356133d084826020860161336b565b91505092915050565b5f805f80608085870312156133f1576133f0612ed4565b5b5f6133fe878288016130eb565b945050602061340f878288016130eb565b93505060406134208782880161303e565b925050606085013567ffffffffffffffff81111561344157613440612ed8565b5b61344d878288016133ac565b91505092959194509250565b5f819050919050565b5f61347c6134776134728461307d565b613459565b61307d565b9050919050565b5f61348d82613462565b9050919050565b5f61349e82613483565b9050919050565b6134ae81613494565b82525050565b5f6020820190506134c75f8301846134a5565b92915050565b5f6134d782613483565b9050919050565b6134e7816134cd565b82525050565b5f6020820190506135005f8301846134de565b92915050565b5f806040838503121561351c5761351b612ed4565b5b5f613529858286016130eb565b925050602061353a858286016130eb565b9150509250929050565b5f61354e82613483565b9050919050565b61355e81613544565b82525050565b5f6020820190506135775f830184613555565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806135c157607f821691505b6020821081036135d4576135d361357d565b5b50919050565b5f819050815f5260205f209050919050565b5f81546135f8816135aa565b6136028186612f99565b9450600182165f811461361c576001811461363257613664565b60ff198316865281151560200286019350613664565b61363b856135da565b5f5b8381101561365c5781548189015260018201915060208101905061363d565b808801955050505b50505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f6136918261366d565b61369b8185613677565b93506136ab818560208601612fa9565b6136b481612fb7565b840191505092915050565b5f6040820190508181035f8301526136d781856135ec565b905081810360208301526136eb8184613687565b90509392505050565b5f6137066137018461332d565b613313565b905082815260208101848484011115613722576137216132b1565b5b61372d848285612fa9565b509392505050565b5f82601f830112613749576137486132ad565b5b81516137598482602086016136f4565b91505092915050565b5f6020828403121561377757613776612ed4565b5b5f82015167ffffffffffffffff81111561379457613793612ed8565b5b6137a084828501613735565b91505092915050565b7f617070726f76616c7300000000000000000000000000000000000000000000005f82015250565b5f6137dd600983612f99565b91506137e8826137a9565b602082019050919050565b5f6040820190508181035f83015261380b8184613687565b9050818103602083015261381e816137d1565b905092915050565b5f67ffffffffffffffff8211156138405761383f6132b5565b5b602082029050602081019050919050565b5f80fd5b5f61386761386284613826565b613313565b9050808382526020820190506020840283018581111561388a57613889613851565b5b835b818110156138d157805167ffffffffffffffff8111156138af576138ae6132ad565b5b8086016138bc8982613735565b8552602085019450505060208101905061388c565b5050509392505050565b5f82601f8301126138ef576138ee6132ad565b5b81516138ff848260208601613855565b91505092915050565b5f6020828403121561391d5761391c612ed4565b5b5f82015167ffffffffffffffff81111561393a57613939612ed8565b5b613946848285016138db565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f7370656e646572000000000000000000000000000000000000000000000000005f82015250565b5f6139b0600783612f99565b91506139bb8261397c565b602082019050919050565b5f6040820190508181035f8301526139de8184613687565b905081810360208301526139f1816139a4565b905092915050565b5f81519050613a07816130d5565b92915050565b5f60208284031215613a2257613a21612ed4565b5b5f613a2f848285016139f9565b91505092915050565b5f67ffffffffffffffff821115613a5257613a516132b5565b5b613a5b82612fb7565b9050602081019050919050565b5f613a7a613a7584613a38565b613313565b905082815260208101848484011115613a9657613a956132b1565b5b613aa1848285612fa9565b509392505050565b5f82601f830112613abd57613abc6132ad565b5b8151613acd848260208601613a68565b91505092915050565b5f60208284031215613aeb57613aea612ed4565b5b5f82015167ffffffffffffffff811115613b0857613b07612ed8565b5b613b1484828501613aa9565b91505092915050565b7f636f756e740000000000000000000000000000000000000000000000000000005f82015250565b5f613b51600583612f99565b9150613b5c82613b1d565b602082019050919050565b5f6040820190508181035f830152613b7f8184613687565b90508181036020830152613b9281613b45565b905092915050565b5f81519050613ba881613028565b92915050565b5f60208284031215613bc357613bc2612ed4565b5b5f613bd084828501613b9a565b91505092915050565b7f6066726f6d60206d75737420626520746865206f776e657200000000000000005f82015250565b5f613c0d601883612f99565b9150613c1882613bd9565b602082019050919050565b5f6020820190508181035f830152613c3a81613c01565b9050919050565b7f726f79616c74795f7061796d656e7473000000000000000000000000000000005f82015250565b5f613c75601083612f99565b9150613c8082613c41565b602082019050919050565b5f6040820190508181035f830152613ca38184613687565b90508181036020830152613cb681613c69565b905092915050565b7f726f79616c74795f696e666f00000000000000000000000000000000000000005f82015250565b5f613cf2600c83612f99565b9150613cfd82613cbe565b602082019050919050565b5f6020820190508181035f830152613d1f81613ce6565b9050919050565b7f61646472657373000000000000000000000000000000000000000000000000005f82015250565b5f613d5a600783612f99565b9150613d6582613d26565b602082019050919050565b5f6040820190508181035f830152613d888184613687565b90508181036020830152613d9b81613d4e565b905092915050565b7f726f79616c74795f616d6f756e740000000000000000000000000000000000005f82015250565b5f613dd7600e83612f99565b9150613de282613da3565b602082019050919050565b5f6040820190508181035f830152613e058184613687565b90508181036020830152613e1881613dcb565b905092915050565b7f746f6b656e4f664f776e65724279496e646578000000000000000000000000005f82015250565b5f613e54601383612f99565b9150613e5f82613e20565b602082019050919050565b5f6020820190508181035f830152613e8181613e48565b9050919050565b7f746f6b656e4279496e64657800000000000000000000000000000000000000005f82015250565b5f613ebc600c83612f99565b9150613ec782613e88565b602082019050919050565b5f6020820190508181035f830152613ee981613eb0565b9050919050565b7f6f776e65720000000000000000000000000000000000000000000000000000005f82015250565b5f613f24600583612f99565b9150613f2f82613ef0565b602082019050919050565b5f6040820190508181035f830152613f528184613687565b90508181036020830152613f6581613f18565b905092915050565b7f226c696d6974223a313030302c226f776e6572223a2200000000000000000000815250565b5f81905092915050565b5f613fa782612f8f565b613fb18185613f93565b9350613fc1818560208601612fa9565b80840191505092915050565b5f613fd782613f6d565b601682019150613fe78284613f9d565b915081905092915050565b7f2200000000000000000000000000000000000000000000000000000000000000815250565b5f6140238284613f9d565b915061402e82613ff2565b60018201915081905092915050565b7f7b22746f6b656e73223a7b000000000000000000000000000000000000000000815250565b5f61406d8261403d565b600b8201915061407d8284613f9d565b915081905092915050565b7f7d7d000000000000000000000000000000000000000000000000000000000000815250565b5f6140b98284613f9d565b91506140c482614088565b60028201915081905092915050565b7f746f6b656e7300000000000000000000000000000000000000000000000000005f82015250565b5f614107600683612f99565b9150614112826140d3565b602082019050919050565b5f6040820190508181035f8301526141358184613687565b90508181036020830152614148816140fb565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6141878261301f565b91506141928361301f565b92508282019050808211156141aa576141a9614150565b5b92915050565b5f6141ba8261301f565b91506141c58361301f565b92508282039050818111156141dd576141dc614150565b5b92915050565b7f2c2273746172745f6166746572223a0000000000000000000000000000000000815250565b5f614213826141e3565b600f820191506142238284613f9d565b915081905092915050565b5f6142398285613f9d565b91506142458284613f9d565b91508190509392505050565b7f746f6b656e5f75726900000000000000000000000000000000000000000000005f82015250565b5f614285600983612f99565b915061429082614251565b602082019050919050565b5f6040820190508181035f8301526142b38184613687565b905081810360208301526142c681614279565b905092915050565b7f6f70657261746f727300000000000000000000000000000000000000000000005f82015250565b5f614302600983612f99565b915061430d826142ce565b602082019050919050565b5f6040820190508181035f8301526143308184613687565b90508181036020830152614343816142f6565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f61438282613ff2565b6001820191506143928284613f9d565b915081905092915050565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b5f6143ce8284613f9d565b91506143d98261439d565b60018201915081905092915050565b7f7b00000000000000000000000000000000000000000000000000000000000000815250565b5f614418826143e8565b6001820191506144288284613f9d565b915081905092915050565b5f6060820190508181035f83015261444b81866135ec565b9050818103602083015261445f8185613687565b905081810360408301526144738184613687565b9050949350505050565b5f81905092915050565b5f6144918261366d565b61449b818561447d565b93506144ab818560208601612fa9565b80840191505092915050565b5f6144c28284614487565b915081905092915050565b7f436f736d5761736d2065786563757465206661696c65640000000000000000005f82015250565b5f614501601783612f99565b915061450c826144cd565b602082019050919050565b5f6020820190508181035f83015261452e816144f5565b9050919050565b5f6080820190506145485f8301876130ad565b61455560208301866130ad565b614562604083018561313d565b81810360608301526145748184613687565b905095945050505050565b5f8151905061458d81612f07565b92915050565b5f602082840312156145a8576145a7612ed4565b5b5f6145b58482850161457f565b9150509291505056fe7b22657874656e73696f6e223a7b226d7367223a7b22636865636b5f726f79616c74696573223a7b7d7d7d7da26469706673582212202cfa5745319dd924bc8557dfafdf484a8e400b4f43ea1d4904335aa5e8097f2c64736f6c63430008190033 \ No newline at end of file diff --git a/x/evm/artifacts/cw721/artifacts.go b/x/evm/artifacts/cw721/artifacts.go index 18e5f812a..38cb29b63 100644 --- a/x/evm/artifacts/cw721/artifacts.go +++ b/x/evm/artifacts/cw721/artifacts.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" ) -const CurrentVersion uint16 = 2 +const CurrentVersion uint16 = 4 //go:embed CW721ERC721Pointer.abi //go:embed CW721ERC721Pointer.bin diff --git a/x/evm/artifacts/cw721/cw721.go b/x/evm/artifacts/cw721/cw721.go index d7d3efcbc..570c13a89 100644 --- a/x/evm/artifacts/cw721/cw721.go +++ b/x/evm/artifacts/cw721/cw721.go @@ -31,7 +31,7 @@ var ( // Cw721MetaData contains all meta data concerning the Cw721 contract. var Cw721MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"Cw721Address_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC721IncorrectOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ERC721InsufficientApproval\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC721InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"ERC721InvalidOperator\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC721InvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC721InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC721InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ERC721NonexistentToken\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"AddrPrecompile\",\"outputs\":[{\"internalType\":\"contractIAddr\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Cw721Address\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"JsonPrecompile\",\"outputs\":[{\"internalType\":\"contractIJson\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WasmdPrecompile\",\"outputs\":[{\"internalType\":\"contractIWasmd\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approved\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"Cw721Address_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numerator\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"ERC2981InvalidDefaultRoyalty\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC2981InvalidDefaultRoyaltyReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"numerator\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"denominator\",\"type\":\"uint256\"}],\"name\":\"ERC2981InvalidTokenRoyalty\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC2981InvalidTokenRoyaltyReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC721IncorrectOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ERC721InsufficientApproval\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC721InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"ERC721InvalidOperator\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC721InvalidOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC721InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC721InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ERC721NonexistentToken\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"method\",\"type\":\"string\"}],\"name\":\"NotImplemented\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"method\",\"type\":\"string\"}],\"name\":\"NotImplementedOnCosmwasmContract\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"approved\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"ApprovalForAll\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"AddrPrecompile\",\"outputs\":[{\"internalType\":\"contractIAddr\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Cw721Address\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"JsonPrecompile\",\"outputs\":[{\"internalType\":\"contractIJson\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"WasmdPrecompile\",\"outputs\":[{\"internalType\":\"contractIWasmd\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approved\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"salePrice\",\"type\":\"uint256\"}],\"name\":\"royaltyInfo\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"safeTransferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"approved\",\"type\":\"bool\"}],\"name\":\"setApprovalForAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"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\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // Cw721ABI is the input ABI used to generate the binding from. @@ -459,9 +459,41 @@ func (_Cw721 *Cw721CallerSession) OwnerOf(tokenId *big.Int) (common.Address, err return _Cw721.Contract.OwnerOf(&_Cw721.CallOpts, tokenId) } +// RoyaltyInfo is a free data retrieval call binding the contract method 0x2a55205a. +// +// Solidity: function royaltyInfo(uint256 tokenId, uint256 salePrice) view returns(address, uint256) +func (_Cw721 *Cw721Caller) RoyaltyInfo(opts *bind.CallOpts, tokenId *big.Int, salePrice *big.Int) (common.Address, *big.Int, error) { + var out []interface{} + err := _Cw721.contract.Call(opts, &out, "royaltyInfo", tokenId, salePrice) + + if err != nil { + return *new(common.Address), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +// RoyaltyInfo is a free data retrieval call binding the contract method 0x2a55205a. +// +// Solidity: function royaltyInfo(uint256 tokenId, uint256 salePrice) view returns(address, uint256) +func (_Cw721 *Cw721Session) RoyaltyInfo(tokenId *big.Int, salePrice *big.Int) (common.Address, *big.Int, error) { + return _Cw721.Contract.RoyaltyInfo(&_Cw721.CallOpts, tokenId, salePrice) +} + +// RoyaltyInfo is a free data retrieval call binding the contract method 0x2a55205a. +// +// Solidity: function royaltyInfo(uint256 tokenId, uint256 salePrice) view returns(address, uint256) +func (_Cw721 *Cw721CallerSession) RoyaltyInfo(tokenId *big.Int, salePrice *big.Int) (common.Address, *big.Int, error) { + return _Cw721.Contract.RoyaltyInfo(&_Cw721.CallOpts, tokenId, salePrice) +} + // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) func (_Cw721 *Cw721Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { var out []interface{} err := _Cw721.contract.Call(opts, &out, "supportsInterface", interfaceId) @@ -478,14 +510,14 @@ func (_Cw721 *Cw721Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4 // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) func (_Cw721 *Cw721Session) SupportsInterface(interfaceId [4]byte) (bool, error) { return _Cw721.Contract.SupportsInterface(&_Cw721.CallOpts, interfaceId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) func (_Cw721 *Cw721CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { return _Cw721.Contract.SupportsInterface(&_Cw721.CallOpts, interfaceId) } @@ -521,6 +553,68 @@ func (_Cw721 *Cw721CallerSession) Symbol() (string, error) { return _Cw721.Contract.Symbol(&_Cw721.CallOpts) } +// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. +// +// Solidity: function tokenByIndex(uint256 ) view returns(uint256) +func (_Cw721 *Cw721Caller) TokenByIndex(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { + var out []interface{} + err := _Cw721.contract.Call(opts, &out, "tokenByIndex", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. +// +// Solidity: function tokenByIndex(uint256 ) view returns(uint256) +func (_Cw721 *Cw721Session) TokenByIndex(arg0 *big.Int) (*big.Int, error) { + return _Cw721.Contract.TokenByIndex(&_Cw721.CallOpts, arg0) +} + +// TokenByIndex is a free data retrieval call binding the contract method 0x4f6ccce7. +// +// Solidity: function tokenByIndex(uint256 ) view returns(uint256) +func (_Cw721 *Cw721CallerSession) TokenByIndex(arg0 *big.Int) (*big.Int, error) { + return _Cw721.Contract.TokenByIndex(&_Cw721.CallOpts, arg0) +} + +// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. +// +// Solidity: function tokenOfOwnerByIndex(address , uint256 ) view returns(uint256) +func (_Cw721 *Cw721Caller) TokenOfOwnerByIndex(opts *bind.CallOpts, arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + var out []interface{} + err := _Cw721.contract.Call(opts, &out, "tokenOfOwnerByIndex", arg0, arg1) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. +// +// Solidity: function tokenOfOwnerByIndex(address , uint256 ) view returns(uint256) +func (_Cw721 *Cw721Session) TokenOfOwnerByIndex(arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + return _Cw721.Contract.TokenOfOwnerByIndex(&_Cw721.CallOpts, arg0, arg1) +} + +// TokenOfOwnerByIndex is a free data retrieval call binding the contract method 0x2f745c59. +// +// Solidity: function tokenOfOwnerByIndex(address , uint256 ) view returns(uint256) +func (_Cw721 *Cw721CallerSession) TokenOfOwnerByIndex(arg0 common.Address, arg1 *big.Int) (*big.Int, error) { + return _Cw721.Contract.TokenOfOwnerByIndex(&_Cw721.CallOpts, arg0, arg1) +} + // TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. // // Solidity: function tokenURI(uint256 tokenId) view returns(string) @@ -552,6 +646,37 @@ func (_Cw721 *Cw721CallerSession) TokenURI(tokenId *big.Int) (string, error) { return _Cw721.Contract.TokenURI(&_Cw721.CallOpts, tokenId) } +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Cw721 *Cw721Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Cw721.contract.Call(opts, &out, "totalSupply") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Cw721 *Cw721Session) TotalSupply() (*big.Int, error) { + return _Cw721.Contract.TotalSupply(&_Cw721.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Cw721 *Cw721CallerSession) TotalSupply() (*big.Int, error) { + return _Cw721.Contract.TotalSupply(&_Cw721.CallOpts) +} + // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // // Solidity: function approve(address approved, uint256 tokenId) returns() diff --git a/x/evm/artifacts/erc721/artifacts.go b/x/evm/artifacts/erc721/artifacts.go index b542ee3b4..04b51cf6b 100644 --- a/x/evm/artifacts/erc721/artifacts.go +++ b/x/evm/artifacts/erc721/artifacts.go @@ -2,7 +2,7 @@ package erc721 import "embed" -const CurrentVersion uint16 = 1 +const CurrentVersion uint16 = 5 //go:embed cwerc721.wasm var f embed.FS diff --git a/x/evm/artifacts/erc721/cwerc721.wasm b/x/evm/artifacts/erc721/cwerc721.wasm index 318ada77b..a1cfac086 100644 Binary files a/x/evm/artifacts/erc721/cwerc721.wasm and b/x/evm/artifacts/erc721/cwerc721.wasm differ diff --git a/x/evm/client/cli/native_tx.go b/x/evm/client/cli/native_tx.go index 180035041..b08518455 100644 --- a/x/evm/client/cli/native_tx.go +++ b/x/evm/client/cli/native_tx.go @@ -1,14 +1,24 @@ package cli import ( + "fmt" + "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" + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/sei-protocol/sei-chain/precompiles" + "github.com/sei-protocol/sei-chain/precompiles/pointer" "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/spf13/cobra" ) +const ( + FlagCwAddress = "cw-address" +) + func NativeSendTxCmd() *cobra.Command { cmd := &cobra.Command{ Use: "native-send [from_key_or_address] [to_evm_address] [amount]", @@ -46,10 +56,10 @@ func NativeSendTxCmd() *cobra.Command { return cmd } -func NativeRegisterPointerCmd() *cobra.Command { +func RegisterCwPointerCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "register-pointer [pointer type] [erc address]", - Short: `Register a CosmWasm pointer for an ERC20/721 contract. Pointer type is either ERC20 or ERC721`, + Use: "register-cw-pointer [pointer type] [erc address]", + Short: `Register a CosmWasm pointer for an ERC20/721 contract. Pointer type is either ERC20 or ERC721.`, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientTxContext(cmd) @@ -74,3 +84,96 @@ func NativeRegisterPointerCmd() *cobra.Command { return cmd } + +func RegisterEvmPointerCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "register-evm-pointer [pointer type] [cw-address] --gas-fee-cap= --gas-limit= --evm-rpc=", + Short: `Register an EVM pointer for a CosmWasm contract. Pointer type is either CW20, CW721, or NATIVE.`, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + pInfo := precompiles.GetPrecompileInfo(pointer.PrecompileName) + var payload []byte + var err error + switch args[0] { + case "CW20": + payload, err = getMethodPayload(pInfo.ABI, []string{pointer.AddCW20Pointer, args[1]}) + case "CW721": + payload, err = getMethodPayload(pInfo.ABI, []string{pointer.AddCW721Pointer, args[1]}) + case "NATIVE": + payload, err = getMethodPayload(pInfo.ABI, []string{pointer.AddNativePointer, args[1]}) + default: + return fmt.Errorf("invalid pointer type: %s", args[0]) + } + if err != nil { + return err + } + txData, err := getTxData(cmd) + if err != nil { + return err + } + key, err := getPrivateKey(cmd) + if err != nil { + return err + } + + rpc, err := cmd.Flags().GetString(FlagRPC) + if err != nil { + return err + } + nonce, err := getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + + txData.Nonce = nonce + txData.Data = payload + addr := common.HexToAddress(pointer.PointerAddress) + txData.To = &addr + + resp, err := sendTx(txData, rpc, key) + if err != nil { + return err + } + + fmt.Println("Transaction hash:", resp.Hex()) + return nil + }, + } + + cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") + cmd.Flags().Uint64(FlagGas, 7000000, "Gas limit for the transaction") + cmd.Flags().String(FlagCwAddress, "", "CosmWasm contract address") + cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func AssociateContractAddressCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "associate-contract-address [cw-address]", + Short: `Set address association for a CosmWasm contract.`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + addr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + msg := types.NewMsgAssociateContractAddress(clientCtx.GetFromAddress(), addr) + if err := msg.ValidateBasic(); 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 ff9f10210..ad8806f81 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(CmdQueryERC20()) cmd.AddCommand(CmdQueryPayload()) cmd.AddCommand(CmdQueryPointer()) + cmd.AddCommand(CmdQueryPointerVersion()) return cmd } @@ -53,7 +54,10 @@ func CmdQuerySeiAddress() *cobra.Command { Short: "gets sei address (sei...) by EVM address (0x...) if account has association set", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) @@ -77,8 +81,10 @@ func CmdQueryEVMAddress() *cobra.Command { Short: "gets evm address (0x...) by Sei address (sei...) if account has association set", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) res, err := queryClient.EVMAddressBySeiAddress(context.Background(), &types.QueryEVMAddressBySeiAddressRequest{SeiAddress: args[0]}) @@ -101,7 +107,10 @@ func CmdQueryERC20() *cobra.Command { Short: "get hex payload for the given inputs", Args: cobra.MinimumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) abi, err := native.NativeMetaData.GetAbi() if err != nil { @@ -160,8 +169,10 @@ func CmdQueryPayload() *cobra.Command { Short: "get hex payload for the given inputs", Args: cobra.MinimumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } dat, err := os.ReadFile(args[0]) if err != nil { return err @@ -191,8 +202,10 @@ func CmdQueryERC20Payload() *cobra.Command { Short: "get hex payload for the given inputs", Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } abi, err := cw20.Cw20MetaData.GetAbi() if err != nil { return err @@ -200,14 +213,23 @@ func CmdQueryERC20Payload() *cobra.Command { var bz []byte switch args[0] { case "transfer": + if len(args) != 3 { + return errors.New("expected usage: `seid tx evm erc20-payload transfer [to] [amount]`") + } to := common.HexToAddress(args[1]) amt, _ := sdk.NewIntFromString(args[2]) bz, err = abi.Pack(args[0], to, amt.BigInt()) case "approve": + if len(args) != 3 { + return errors.New("expected usage: `seid tx evm erc20-payload approve [spender] [amount]`") + } spender := common.HexToAddress(args[1]) amt, _ := sdk.NewIntFromString(args[2]) bz, err = abi.Pack(args[0], spender, amt.BigInt()) case "transferFrom": + if len(args) != 4 { + return errors.New("expected usage: `seid tx evm erc20-payload transferFrom [from] [to] [amount]`") + } from := common.HexToAddress(args[1]) to := common.HexToAddress(args[2]) amt, _ := sdk.NewIntFromString(args[3]) @@ -232,8 +254,10 @@ func CmdQueryERC721Payload() *cobra.Command { Short: "get hex payload for the given inputs", Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) - + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } abi, err := cw721.Cw721MetaData.GetAbi() if err != nil { return err @@ -273,11 +297,14 @@ func CmdQueryPointer() *cobra.Command { 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) - + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) + ctx := cmd.Context() - res, err := queryClient.Pointer(context.Background(), &types.QueryPointerRequest{ + res, err := queryClient.Pointer(ctx, &types.QueryPointerRequest{ PointerType: types.PointerType(types.PointerType_value[args[0]]), Pointee: args[1], }) if err != nil { @@ -292,3 +319,32 @@ func CmdQueryPointer() *cobra.Command { return cmd } + +func CmdQueryPointerVersion() *cobra.Command { + cmd := &cobra.Command{ + Use: "pointer-version [type]", + Short: "Query for the current pointer version and stored code ID (if applicable)", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + ctx := cmd.Context() + + req := types.QueryPointerVersionRequest{PointerType: types.PointerType(types.PointerType_value[args[0]])} + res, err := queryClient.PointerVersion(ctx, &req) + 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 6cc9d3ce3..fd48a96f4 100644 --- a/x/evm/client/cli/tx.go +++ b/x/evm/client/cli/tx.go @@ -63,10 +63,12 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(CmdERC20Send()) cmd.AddCommand(CmdCallPrecompile()) cmd.AddCommand(NativeSendTxCmd()) - cmd.AddCommand(NativeRegisterPointerCmd()) + cmd.AddCommand(RegisterCwPointerCmd()) + cmd.AddCommand(RegisterEvmPointerCmd()) cmd.AddCommand(NewAddERCNativePointerProposalTxCmd()) cmd.AddCommand(NewAddERCCW20PointerProposalTxCmd()) cmd.AddCommand(NewAddERCCW721PointerProposalTxCmd()) + cmd.AddCommand(AssociateContractAddressCmd()) return cmd } diff --git a/x/evm/client/wasm/bindings/queries.go b/x/evm/client/wasm/bindings/queries.go index efb74a4f0..420f1a81a 100644 --- a/x/evm/client/wasm/bindings/queries.go +++ b/x/evm/client/wasm/bindings/queries.go @@ -18,10 +18,13 @@ type SeiEVMQuery struct { ERC721SetApprovalAllPayload *ERC721SetApprovalAllPayloadRequest `json:"erc721_set_approval_all_payload,omitempty"` ERC721Approved *ERC721ApprovedRequest `json:"erc721_approved,omitempty"` ERC721IsApprovedForAll *ERC721IsApprovedForAllRequest `json:"erc721_is_approved_for_all,omitempty"` + ERC721TotalSupply *ERC721TotalSupplyRequest `json:"erc721_total_supply,omitempty"` ERC721NameSymbol *ERC721NameSymbolRequest `json:"erc721_name_symbol,omitempty"` ERC721Uri *ERC721UriRequest `json:"erc721_uri,omitempty"` + ERC721RoyaltyInfo *ERC721RoyaltyInfoRequest `json:"erc721_royalty_info,omitempty"` GetEvmAddress *GetEvmAddressRequest `json:"get_evm_address,omitempty"` GetSeiAddress *GetSeiAddressRequest `json:"get_sei_address,omitempty"` + SupportsInterface *SupportsInterfaceRequest `json:"supports_interface,omitempty"` } type StaticCallRequest struct { @@ -97,6 +100,11 @@ type ERC721IsApprovedForAllRequest struct { Operator string `json:"operator"` } +type ERC721TotalSupplyRequest struct { + Caller string `json:"caller"` + ContractAddress string `json:"contract_address"` +} + type ERC721NameSymbolRequest struct { Caller string `json:"caller"` ContractAddress string `json:"contract_address"` @@ -108,6 +116,13 @@ type ERC721UriRequest struct { TokenID string `json:"token_id"` } +type ERC721RoyaltyInfoRequest struct { + Caller string `json:"caller"` + ContractAddress string `json:"contract_address"` + TokenID string `json:"token_id"` + SalePrice *sdk.Int `json:"sale_price"` +} + type GetEvmAddressRequest struct { SeiAddress string `json:"sei_address"` } @@ -116,6 +131,12 @@ type GetSeiAddressRequest struct { EvmAddress string `json:"evm_address"` } +type SupportsInterfaceRequest struct { + Caller string `json:"caller"` + ContractAddress string `json:"contract_address"` + InterfaceID string `json:"interface_id"` +} + type StaticCallResponse struct { EncodedData string `json:"encoded_data"` } @@ -151,6 +172,10 @@ type ERC721IsApprovedForAllResponse struct { IsApproved bool `json:"is_approved"` } +type ERC721TotalSupplyResponse struct { + Supply *sdk.Int `json:"supply"` +} + type ERC721NameSymbolResponse struct { Name string `json:"name"` Symbol string `json:"symbol"` @@ -160,6 +185,11 @@ type ERC721UriResponse struct { Uri string `json:"uri"` } +type ERC721RoyaltyInfoResponse struct { + Receiver string `json:"receiver"` + RoyaltyAmount *sdk.Int `json:"royalty_amount"` +} + type GetEvmAddressResponse struct { EvmAddress string `json:"evm_address"` Associated bool `json:"associated"` @@ -169,3 +199,7 @@ type GetSeiAddressResponse struct { SeiAddress string `json:"sei_address"` Associated bool `json:"associated"` } + +type SupportsInterfaceResponse struct { + Supported bool `json:"supported"` +} diff --git a/x/evm/client/wasm/query.go b/x/evm/client/wasm/query.go index 294fd65ff..f93597d90 100644 --- a/x/evm/client/wasm/query.go +++ b/x/evm/client/wasm/query.go @@ -2,10 +2,12 @@ package wasm import ( "encoding/base64" + "encoding/hex" "encoding/json" "errors" "fmt" "math/big" + "strings" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" @@ -173,7 +175,7 @@ func (h *EVMQueryHandler) HandleERC721Owner(ctx sdk.Context, caller string, cont } t, ok := sdk.NewIntFromString(tokenId) if !ok { - return nil, errors.New("invalid token ID for ERC20, must be a big Int") + return nil, errors.New("invalid token ID for ERC721, must be a big Int") } bz, err := abi.Pack("ownerOf", t.BigInt()) if err != nil { @@ -211,7 +213,7 @@ func (h *EVMQueryHandler) HandleERC721TransferPayload(ctx sdk.Context, from stri } t, ok := sdk.NewIntFromString(tokenId) if !ok { - return nil, errors.New("invalid token ID for ERC20, must be a big Int") + return nil, errors.New("invalid token ID for ERC721, must be a big Int") } bz, err := abi.Pack("transferFrom", fromEvmAddr, toEvmAddr, t.BigInt()) if err != nil { @@ -237,7 +239,7 @@ func (h *EVMQueryHandler) HandleERC721ApprovePayload(ctx sdk.Context, spender st } t, ok := sdk.NewIntFromString(tokenId) if !ok { - return nil, errors.New("invalid token ID for ERC20, must be a big Int") + return nil, errors.New("invalid token ID for ERC721, must be a big Int") } bz, err := abi.Pack("approve", spenderEvmAddr, t.BigInt()) if err != nil { @@ -360,7 +362,7 @@ func (h *EVMQueryHandler) HandleERC721Approved(ctx sdk.Context, caller string, c } t, ok := sdk.NewIntFromString(tokenId) if !ok { - return nil, errors.New("invalid token ID for ERC20, must be a big Int") + return nil, errors.New("invalid token ID for ERC721, must be a big Int") } bz, err := abi.Pack("getApproved", t.BigInt()) if err != nil { @@ -417,6 +419,33 @@ func (h *EVMQueryHandler) HandleERC721IsApprovedForAll(ctx sdk.Context, caller s return json.Marshal(response) } +func (h *EVMQueryHandler) HandleERC721TotalSupply(ctx sdk.Context, caller string, contractAddress string) ([]byte, error) { + callerAddr, err := sdk.AccAddressFromBech32(caller) + if err != nil { + return nil, err + } + contract := common.HexToAddress(contractAddress) + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return nil, err + } + bz, err := abi.Pack("totalSupply") + if err != nil { + return nil, err + } + res, err := h.k.StaticCallEVM(ctx, callerAddr, &contract, bz) + if err != nil { + return nil, err + } + typed, err := abi.Unpack("totalSupply", res) + if err != nil { + return nil, err + } + totalSupply := sdk.NewIntFromBigInt(typed[0].(*big.Int)) + response := bindings.ERC721TotalSupplyResponse{Supply: &totalSupply} + return json.Marshal(response) +} + func (h *EVMQueryHandler) HandleERC721NameSymbol(ctx sdk.Context, caller string, contractAddress string) ([]byte, error) { callerAddr, err := sdk.AccAddressFromBech32(caller) if err != nil { @@ -464,7 +493,7 @@ func (h *EVMQueryHandler) HandleERC721Uri(ctx sdk.Context, caller string, contra } t, ok := sdk.NewIntFromString(tokenId) if !ok { - return nil, errors.New("invalid token ID for ERC20, must be a big Int") + return nil, errors.New("invalid token ID for ERC721, must be a big Int") } contract := common.HexToAddress(contractAddress) abi, err := cw721.Cw721MetaData.GetAbi() @@ -503,3 +532,71 @@ func (h *EVMQueryHandler) HandleGetSeiAddress(ctx sdk.Context, evmAddr string) ( response := bindings.GetSeiAddressResponse{SeiAddress: seiAddr.String(), Associated: associated} return json.Marshal(response) } + +func (h *EVMQueryHandler) HandleERC721RoyaltyInfo(ctx sdk.Context, caller string, contractAddress string, tokenId string, salePrice *sdk.Int) ([]byte, error) { + callerAddr, err := sdk.AccAddressFromBech32(caller) + if err != nil { + return nil, err + } + t, ok := sdk.NewIntFromString(tokenId) + if !ok { + return nil, errors.New("invalid token ID for ERC721, must be a big Int") + } + contract := common.HexToAddress(contractAddress) + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return nil, err + } + bz, err := abi.Pack("royaltyInfo", t.BigInt(), salePrice.BigInt()) + if err != nil { + return nil, err + } + res, err := h.k.StaticCallEVM(ctx, callerAddr, &contract, bz) + if err != nil { + return nil, err + } + typed, err := abi.Unpack("royaltyInfo", res) + if err != nil { + return nil, err + } + + typedReceiver := typed[0].(common.Address) + receiver := "" + if (typedReceiver != common.Address{}) { + receiver = h.k.GetSeiAddressOrDefault(ctx, typedReceiver).String() + } + royaltyAmount := sdk.NewIntFromBigInt(typed[1].(*big.Int)) + response := bindings.ERC721RoyaltyInfoResponse{Receiver: receiver, RoyaltyAmount: &royaltyAmount} + return json.Marshal(response) +} + +func (h *EVMQueryHandler) HandleSupportsInterface(ctx sdk.Context, caller string, id string, contractAddress string) ([]byte, error) { + callerAddr, err := sdk.AccAddressFromBech32(caller) + if err != nil { + return nil, err + } + contract := common.HexToAddress(contractAddress) + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return nil, err + } + aid := [4]byte{} + idbz, err := hex.DecodeString(strings.TrimPrefix(id, "0x")) + if err != nil { + return nil, err + } + copy(aid[:], idbz) + bz, err := abi.Pack("supportsInterface", aid) + if err != nil { + return nil, err + } + res, err := h.k.StaticCallEVM(ctx, callerAddr, &contract, bz) + if err != nil { + return nil, err + } + typed, err := abi.Unpack("supportsInterface", res) + if err != nil { + return nil, err + } + return json.Marshal(bindings.SupportsInterfaceResponse{Supported: typed[0].(bool)}) +} diff --git a/x/evm/client/wasm/query_test.go b/x/evm/client/wasm/query_test.go index 6ef307da9..194aec2cc 100644 --- a/x/evm/client/wasm/query_test.go +++ b/x/evm/client/wasm/query_test.go @@ -6,6 +6,7 @@ import ( "encoding/json" "math/big" "os" + "regexp" "strings" "testing" @@ -194,6 +195,22 @@ func TestHandleERC721IsApprovedForAll(t *testing.T) { require.NotEmpty(t, res2) } +func TestHandleERC721TotalSupply(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + privKey := testkeeper.MockPrivateKey() + res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc721/DummyERC721.bin", privKey) + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + receipt, err := k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + contractAddr := common.HexToAddress(receipt.ContractAddress) + h := wasm.NewEVMQueryHandler(k) + res2, err := h.HandleERC721TotalSupply(ctx, addr1.String(), contractAddr.String()) + require.Nil(t, err) + require.NotEmpty(t, res2) + require.Equal(t, string(res2), "{\"supply\":\"101\"}") +} + func TestHandleERC721NameSymbol(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() privKey := testkeeper.MockPrivateKey() @@ -225,6 +242,24 @@ func TestHandleERC721TokenURI(t *testing.T) { require.NotEmpty(t, res2) } +func TestHandleERC721RoyaltyInfo(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + privKey := testkeeper.MockPrivateKey() + res, _ := deployContract(t, ctx, k, "../../../../example/contracts/erc721/DummyERC721.bin", privKey) + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + receipt, err := k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + contractAddr := common.HexToAddress(receipt.ContractAddress) + h := wasm.NewEVMQueryHandler(k) + value := types.NewInt(100) + res2, err := h.HandleERC721RoyaltyInfo(ctx, addr1.String(), contractAddr.String(), "1", &value) + require.Nil(t, err) + require.NotEmpty(t, res2) + match, _ := regexp.MatchString(`{"receiver":"sei\w{39}","royalty_amount":"5"}`, string(res2)) + require.True(t, match) +} + func TestGetAddress(t *testing.T) { k, ctx := testkeeper.MockEVMKeeper() seiAddr1, evmAddr1 := testkeeper.MockAddressPair() diff --git a/x/evm/config/config.go b/x/evm/config/config.go index c0535da0f..4913571a0 100644 --- a/x/evm/config/config.go +++ b/x/evm/config/config.go @@ -1,6 +1,10 @@ package config -import "math/big" +import ( + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" +) const DefaultChainID = int64(713715) @@ -19,3 +23,17 @@ func GetEVMChainID(cosmosChainID string) *big.Int { } return big.NewInt(DefaultChainID) } + +func GetVersionWthDefault(ctx sdk.Context, override uint16, defaultVersion uint16) uint16 { + // overrides are only available on non-live chain IDs + if override > 0 && !IsLiveChainID(ctx) { + return override + } + return defaultVersion +} + +// IsLiveChainID return true if one of the live chainIDs +func IsLiveChainID(ctx sdk.Context) bool { + _, ok := ChainIDMapping[ctx.ChainID()] + return ok +} diff --git a/x/evm/derived/derived.go b/x/evm/derived/derived.go index a97d64b8a..810df0b27 100644 --- a/x/evm/derived/derived.go +++ b/x/evm/derived/derived.go @@ -19,7 +19,6 @@ type Derived struct { PubKey *secp256k1.PubKey IsAssociate bool Version SignerVersion - AnteSurplus sdk.Int } // Derived should never come from deserialization or be transmitted after serialization, diff --git a/x/evm/genesis.go b/x/evm/genesis.go index 54eacf22d..7e3802b31 100644 --- a/x/evm/genesis.go +++ b/x/evm/genesis.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" 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" ) @@ -12,11 +13,72 @@ import ( func InitGenesis(ctx sdk.Context, k *keeper.Keeper, genState types.GenesisState) { k.InitGenesis(ctx, genState) k.SetParams(ctx, genState.Params) + for _, aa := range genState.AddressAssociations { + k.SetAddressMapping(ctx, sdk.MustAccAddressFromBech32(aa.SeiAddress), common.HexToAddress(aa.EthAddress)) + } + for _, code := range genState.Codes { + k.SetCode(ctx, common.HexToAddress(code.Address), code.Code) + } + for _, state := range genState.States { + k.SetState(ctx, common.HexToAddress(state.Address), common.BytesToHash(state.Key), common.BytesToHash(state.Value)) + } + for _, nonce := range genState.Nonces { + k.SetNonce(ctx, common.HexToAddress(nonce.Address), nonce.Nonce) + } + for _, serialized := range genState.Serialized { + k.PrefixStore(ctx, serialized.Prefix).Set(serialized.Key, serialized.Value) + } } func ExportGenesis(ctx sdk.Context, k *keeper.Keeper) *types.GenesisState { genesis := types.DefaultGenesis() genesis.Params = k.GetParams(ctx) + k.IterateSeiAddressMapping(ctx, func(evmAddr common.Address, seiAddr sdk.AccAddress) bool { + genesis.AddressAssociations = append(genesis.AddressAssociations, &types.AddressAssociation{ + SeiAddress: seiAddr.String(), + EthAddress: evmAddr.Hex(), + }) + return false + }) + k.IterateAllCode(ctx, func(addr common.Address, code []byte) bool { + genesis.Codes = append(genesis.Codes, &types.Code{ + Address: addr.Hex(), + Code: code, + }) + return false + }) + k.IterateState(ctx, func(addr common.Address, key, val common.Hash) bool { + genesis.States = append(genesis.States, &types.ContractState{ + Address: addr.Hex(), + Key: key[:], + Value: val[:], + }) + return false + }) + k.IterateAllNonces(ctx, func(addr common.Address, nonce uint64) bool { + genesis.Nonces = append(genesis.Nonces, &types.Nonce{ + Address: addr.Hex(), + Nonce: nonce, + }) + return false + }) + for _, prefix := range [][]byte{ + types.ReceiptKeyPrefix, + types.BlockBloomPrefix, + types.TxHashesPrefix, + types.PointerRegistryPrefix, + types.PointerCWCodePrefix, + types.PointerReverseRegistryPrefix, + } { + k.IterateAll(ctx, prefix, func(key, val []byte) bool { + genesis.Serialized = append(genesis.Serialized, &types.Serialized{ + Prefix: prefix, + Key: key, + Value: val, + }) + return false + }) + } return genesis } diff --git a/x/evm/genesis_test.go b/x/evm/genesis_test.go index e2b815129..19a0a9f96 100644 --- a/x/evm/genesis_test.go +++ b/x/evm/genesis_test.go @@ -3,14 +3,28 @@ package evm_test import ( "testing" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" 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/assert" + "github.com/stretchr/testify/require" ) -func TestExportGenesis(t *testing.T) { - keeper, ctx := testkeeper.MockEVMKeeper() +func TestExportImportGenesis(t *testing.T) { + keeper, origctx := testkeeper.MockEVMKeeper() + ctx := origctx.WithMultiStore(origctx.MultiStore().CacheMultiStore()) + seiAddr, evmAddr := testkeeper.MockAddressPair() + keeper.SetAddressMapping(ctx, seiAddr, evmAddr) + _, codeAddr := testkeeper.MockAddressPair() + keeper.SetCode(ctx, codeAddr, []byte("abcde")) + keeper.SetState(ctx, codeAddr, common.BytesToHash([]byte("123")), common.BytesToHash([]byte("456"))) + keeper.SetNonce(ctx, evmAddr, 2) + keeper.SetReceipt(ctx, common.BytesToHash([]byte("789")), &types.Receipt{TxType: 2}) + keeper.SetBlockBloom(ctx, 5, []ethtypes.Bloom{{1}}) + keeper.SetTxHashesOnHeight(ctx, 5, []common.Hash{common.BytesToHash([]byte("123"))}) + keeper.SetERC20CW20Pointer(ctx, "cw20addr", codeAddr) genesis := evm.ExportGenesis(ctx, keeper) assert.NoError(t, genesis.Validate()) param := genesis.GetParams() @@ -18,4 +32,17 @@ func TestExportGenesis(t *testing.T) { assert.Equal(t, types.DefaultParams().BaseFeePerGas, param.BaseFeePerGas) assert.Equal(t, types.DefaultParams().MinimumFeePerGas, param.MinimumFeePerGas) assert.Equal(t, types.DefaultParams().WhitelistedCwCodeHashesForDelegateCall, param.WhitelistedCwCodeHashesForDelegateCall) + evm.InitGenesis(origctx, keeper, *genesis) + require.Equal(t, evmAddr, keeper.GetEVMAddressOrDefault(origctx, seiAddr)) + require.Equal(t, keeper.GetCode(ctx, codeAddr), keeper.GetCode(origctx, codeAddr)) + require.Equal(t, keeper.GetCodeHash(ctx, codeAddr), keeper.GetCodeHash(origctx, codeAddr)) + require.Equal(t, keeper.GetCodeSize(ctx, codeAddr), keeper.GetCodeSize(origctx, codeAddr)) + require.Equal(t, keeper.GetState(ctx, codeAddr, common.BytesToHash([]byte("123"))), keeper.GetState(origctx, codeAddr, common.BytesToHash([]byte("123")))) + require.Equal(t, keeper.GetNonce(ctx, evmAddr), keeper.GetNonce(origctx, evmAddr)) + _, err := keeper.GetReceipt(origctx, common.BytesToHash([]byte("789"))) + require.Nil(t, err) + require.Equal(t, keeper.GetBlockBloom(ctx, 5), keeper.GetBlockBloom(origctx, 5)) + require.Equal(t, keeper.GetTxHashesOnHeight(ctx, 5), keeper.GetTxHashesOnHeight(origctx, 5)) + _, _, exists := keeper.GetERC20CW20Pointer(origctx, "cw20addr") + require.True(t, exists) } diff --git a/x/evm/handler.go b/x/evm/handler.go index f610540ec..03e4eaca8 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -24,6 +24,12 @@ func NewHandler(k *keeper.Keeper) sdk.Handler { case *types.MsgSend: res, err := msgServer.Send(sdk.WrapSDKContext(ctx), msg) return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgRegisterPointer: + res, err := msgServer.RegisterPointer(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgAssociateContractAddress: + res, err := msgServer.AssociateContractAddress(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) default: errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) diff --git a/x/evm/integration_test.go b/x/evm/integration_test.go new file mode 100644 index 000000000..f28397768 --- /dev/null +++ b/x/evm/integration_test.go @@ -0,0 +1,242 @@ +package evm_test + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "os" + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethabi "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "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/cw721" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" +) + +func TestERC2981PointerToCW2981(t *testing.T) { + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + adminSeiAddr, adminEvmAddr := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, adminSeiAddr, adminEvmAddr) + // deploy cw2981 + bz, err := os.ReadFile("../../contracts/wasm/cw2981_royalties.wasm") + if err != nil { + panic(err) + } + codeID, err := k.WasmKeeper().Create(ctx, adminSeiAddr, bz, nil) + require.Nil(t, err) + instantiateMsg, err := json.Marshal(map[string]interface{}{"name": "test", "symbol": "TEST", "minter": adminSeiAddr.String()}) + require.Nil(t, err) + cw2981Addr, _, err := k.WasmKeeper().Instantiate(ctx, codeID, adminSeiAddr, adminSeiAddr, instantiateMsg, "cw2981", sdk.NewCoins()) + require.Nil(t, err) + require.NotEmpty(t, cw2981Addr) + // mint a NFT and set royalty info to 1% + executeMsg, err := json.Marshal(map[string]interface{}{ + "mint": map[string]interface{}{ + "token_id": "1", + "owner": adminSeiAddr.String(), + "extension": map[string]interface{}{ + "royalty_percentage": 1, + "royalty_payment_address": adminSeiAddr.String(), + }, + }, + }) + require.Nil(t, err) + _, err = k.WasmKeeper().Execute(ctx, cw2981Addr, adminSeiAddr, executeMsg, sdk.NewCoins()) + require.Nil(t, err) + // deploy pointer to cw2981 + privKey := testkeeper.MockPrivateKey() + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) + require.Nil(t, k.BankKeeper().AddCoins(ctx, seiAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000))), true)) + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + to := common.HexToAddress(pointer.PointerAddress) + abi, err := pointer.ABI() + require.Nil(t, err) + data, err := abi.Pack("addCW721Pointer", cw2981Addr.String()) + require.Nil(t, err) + txData := ethtypes.LegacyTx{ + Nonce: 0, + GasPrice: big.NewInt(1000000000), + Gas: 5000000, + To: &to, + Data: data, + } + chainID := k.ChainID(ctx) + chainCfg := types.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + blockNum := big.NewInt(ctx.BlockHeight()) + signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + typedTx, err := ethtx.NewLegacyTx(tx) + require.Nil(t, err) + msg, err := types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + txBuilder := testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + txBuilder.SetMsgs(msg) + cosmosTx := txBuilder.GetTx() + txbz, err := testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(cosmosTx) + require.Nil(t, err) + res := testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, cosmosTx, sha256.Sum256(txbz)) + require.Equal(t, uint32(0), res.Code) + pointerAddr, _, exists := k.GetERC721CW721Pointer(ctx, cw2981Addr.String()) + require.True(t, exists) + require.NotEmpty(t, pointerAddr) + // call pointer to get royalty info + abi, err = cw721.Cw721MetaData.GetAbi() + require.Nil(t, err) + data, err = abi.Pack("royaltyInfo", big.NewInt(1), big.NewInt(1000)) + require.Nil(t, err) + txData = ethtypes.LegacyTx{ + Nonce: 2, + GasPrice: big.NewInt(1000000000), + Gas: 1000000, + To: &pointerAddr, + Data: data, + } + tx, err = ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + typedTx, err = ethtx.NewLegacyTx(tx) + require.Nil(t, err) + msg, err = types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + txBuilder = testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + txBuilder.SetMsgs(msg) + cosmosTx = txBuilder.GetTx() + txbz, err = testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(cosmosTx) + require.Nil(t, err) + res = testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, cosmosTx, sha256.Sum256(txbz)) + require.Equal(t, uint32(0), res.Code) + typedTxData := sdk.TxMsgData{} + require.Nil(t, typedTxData.Unmarshal(res.Data)) + typedMsgData := types.MsgEVMTransactionResponse{} + require.Nil(t, typedMsgData.Unmarshal(typedTxData.Data[0].Data)) + ret, err := abi.Unpack("royaltyInfo", typedMsgData.ReturnData) + require.Nil(t, err) + require.Equal(t, big.NewInt(10), ret[1].(*big.Int)) + require.Equal(t, adminEvmAddr.Hex(), ret[0].(common.Address).Hex()) +} + +func TestCW2981PointerToERC2981(t *testing.T) { + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + // deploy erc2981 + privKey := testkeeper.MockPrivateKey() + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) + require.Nil(t, k.BankKeeper().AddCoins(ctx, seiAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000))), true)) + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + abiBz, err := os.ReadFile("../../example/contracts/erc2981/ERC2981Example.abi") + require.Nil(t, err) + abi, err := ethabi.JSON(bytes.NewReader(abiBz)) + require.Nil(t, err) + code, err := os.ReadFile("../../example/contracts/erc2981/ERC2981Example.bin") + require.Nil(t, err) + bz, err := hex.DecodeString(string(code)) + require.Nil(t, err) + data, err := abi.Pack("", "test", "TEST") + require.Nil(t, err) + txData := ethtypes.LegacyTx{ + Nonce: 0, + GasPrice: big.NewInt(1000000000), + Gas: 5000000, + To: nil, + Data: append(bz, data...), + } + chainID := k.ChainID(ctx) + chainCfg := types.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + blockNum := big.NewInt(ctx.BlockHeight()) + signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + typedTx, err := ethtx.NewLegacyTx(tx) + require.Nil(t, err) + msg, err := types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + txBuilder := testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + txBuilder.SetMsgs(msg) + cosmosTx := txBuilder.GetTx() + txbz, err := testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(cosmosTx) + require.Nil(t, err) + res := testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, cosmosTx, sha256.Sum256(txbz)) + require.Equal(t, uint32(0), res.Code) + receipt, err := k.GetReceipt(ctx, tx.Hash()) + require.Nil(t, err) + require.NotEmpty(t, receipt.ContractAddress) + require.Empty(t, receipt.VmError) + // set royalty + data, err = abi.Pack("setDefaultRoyalty", evmAddr) + require.Nil(t, err) + to := common.HexToAddress(receipt.ContractAddress) + txData = ethtypes.LegacyTx{ + Nonce: 1, + GasPrice: big.NewInt(1000000000), + Gas: 1000000, + To: &to, + Data: data, + } + tx, err = ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + typedTx, err = ethtx.NewLegacyTx(tx) + require.Nil(t, err) + msg, err = types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + txBuilder = testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + txBuilder.SetMsgs(msg) + cosmosTx = txBuilder.GetTx() + txbz, err = testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(cosmosTx) + require.Nil(t, err) + res = testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, cosmosTx, sha256.Sum256(txbz)) + require.Equal(t, uint32(0), res.Code) + // deploy CW->ERC pointer + res2, err := keeper.NewMsgServerImpl(&k).RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: seiAddr.String(), + PointerType: types.PointerType_ERC721, + ErcAddress: receipt.ContractAddress, + }) + require.Nil(t, err) + require.NotEmpty(t, res2.PointerAddress) + // call pointer to get royalty info + query, err := json.Marshal(map[string]interface{}{ + "extension": map[string]interface{}{ + "msg": map[string]interface{}{ + "check_royalties": map[string]interface{}{}, + }, + }, + }) + require.Nil(t, err) + ret, err := testkeeper.EVMTestApp.WasmKeeper.QuerySmart(ctx, sdk.MustAccAddressFromBech32(res2.PointerAddress), query) + require.Nil(t, err) + require.Equal(t, "{\"royalty_payments\":true}", string(ret)) + query, err = json.Marshal(map[string]interface{}{ + "extension": map[string]interface{}{ + "msg": map[string]interface{}{ + "royalty_info": map[string]interface{}{ + "token_id": "1", + "sale_price": "1000", + }, + }, + }, + }) + require.Nil(t, err) + ret, err = testkeeper.EVMTestApp.WasmKeeper.QuerySmart(ctx, sdk.MustAccAddressFromBech32(res2.PointerAddress), query) + require.Nil(t, err) + require.Equal(t, fmt.Sprintf("{\"address\":\"%s\",\"royalty_amount\":\"1000\"}", seiAddr.String()), string(ret)) +} diff --git a/x/evm/keeper/address.go b/x/evm/keeper/address.go index 99f13cc1c..ac043e33c 100644 --- a/x/evm/keeper/address.go +++ b/x/evm/keeper/address.go @@ -1,6 +1,7 @@ package keeper import ( + "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/types" @@ -61,3 +62,15 @@ func (k *Keeper) GetSeiAddressOrDefault(ctx sdk.Context, evmAddress common.Addre } return sdk.AccAddress(evmAddress[:]) } + +func (k *Keeper) IterateSeiAddressMapping(ctx sdk.Context, cb func(evmAddr common.Address, seiAddr sdk.AccAddress) bool) { + iter := prefix.NewStore(ctx.KVStore(k.storeKey), types.EVMAddressToSeiAddressKeyPrefix).Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + evmAddr := common.BytesToAddress(iter.Key()) + seiAddr := sdk.AccAddress(iter.Value()) + if cb(evmAddr, seiAddr) { + break + } + } +} diff --git a/x/evm/keeper/ante.go b/x/evm/keeper/ante.go new file mode 100644 index 000000000..4499a84ee --- /dev/null +++ b/x/evm/keeper/ante.go @@ -0,0 +1,34 @@ +package keeper + +import ( + "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/types" +) + +func (k *Keeper) AddAnteSurplus(ctx sdk.Context, txHash common.Hash, surplus sdk.Int) error { + store := prefix.NewStore(ctx.KVStore(k.memStoreKey), types.AnteSurplusPrefix) + bz, err := surplus.Marshal() + if err != nil { + return err + } + store.Set(txHash[:], bz) + return nil +} + +func (k *Keeper) GetAnteSurplusSum(ctx sdk.Context) sdk.Int { + iter := prefix.NewStore(ctx.KVStore(k.memStoreKey), types.AnteSurplusPrefix).Iterator(nil, nil) + defer iter.Close() + res := sdk.ZeroInt() + for ; iter.Valid(); iter.Next() { + surplus := sdk.Int{} + _ = surplus.Unmarshal(iter.Value()) + res = res.Add(surplus) + } + return res +} + +func (k *Keeper) DeleteAllAnteSurplus(ctx sdk.Context) { + _ = prefix.NewStore(ctx.KVStore(k.memStoreKey), types.AnteSurplusPrefix).DeleteAll(nil, nil) +} diff --git a/x/evm/keeper/code.go b/x/evm/keeper/code.go index d2412f26d..be7d1fe20 100644 --- a/x/evm/keeper/code.go +++ b/x/evm/keeper/code.go @@ -3,6 +3,7 @@ package keeper import ( "encoding/binary" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -48,3 +49,14 @@ func (k *Keeper) GetCodeSize(ctx sdk.Context, addr common.Address) int { } return int(binary.BigEndian.Uint64(bz)) } + +func (k *Keeper) IterateAllCode(ctx sdk.Context, cb func(addr common.Address, code []byte) bool) { + iter := prefix.NewStore(ctx.KVStore(k.storeKey), types.CodeKeyPrefix).Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + evmAddr := common.BytesToAddress(iter.Key()) + if cb(evmAddr, iter.Value()) { + break + } + } +} diff --git a/x/evm/keeper/evm.go b/x/evm/keeper/evm.go index 15b6b388a..23db1e18e 100644 --- a/x/evm/keeper/evm.go +++ b/x/evm/keeper/evm.go @@ -40,13 +40,16 @@ func (k *Keeper) HandleInternalEVMCall(ctx sdk.Context, req *types.MsgInternalEV } func (k *Keeper) HandleInternalEVMDelegateCall(ctx sdk.Context, req *types.MsgInternalEVMDelegateCall) (*sdk.Result, error) { - if !k.IsCWCodeHashWhitelistedForEVMDelegateCall(ctx, req.CodeHash) { - return nil, errors.New("code hash not authorized to make EVM delegate call") - } var to *common.Address if req.To != "" { addr := common.HexToAddress(req.To) to = &addr + } else { + return nil, errors.New("cannot use a CosmWasm contract to delegate-create an EVM contract") + } + addr, _, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(common.BytesToAddress([]byte(req.FromContract)))) + if !exists || common.BytesToAddress(addr).Cmp(*to) != 0 { + return nil, errors.New("only pointer contract can make delegatecalls") } zeroInt := sdk.ZeroInt() senderAddr, err := sdk.AccAddressFromBech32(req.Sender) @@ -67,6 +70,9 @@ func (k *Keeper) HandleInternalEVMDelegateCall(ctx sdk.Context, req *types.MsgIn } func (k *Keeper) CallEVM(ctx sdk.Context, from common.Address, to *common.Address, val *sdk.Int, data []byte) (retdata []byte, reterr error) { + if ctx.IsEVM() { + return nil, errors.New("sei does not support EVM->CW->EVM call pattern") + } if to == nil && len(data) > params.MaxInitCodeSize { return nil, fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(data), params.MaxInitCodeSize) } @@ -77,57 +83,40 @@ func (k *Keeper) CallEVM(ctx sdk.Context, from common.Address, to *common.Addres } value = val.BigInt() } - evm := types.GetCtxEVM(ctx) - if evm == nil { - // This call was not part of an existing StateTransition, so it should trigger one - executionCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) - stateDB := state.NewDBImpl(executionCtx, k, false) - gp := k.GetGasPool() - evmMsg := &core.Message{ - Nonce: stateDB.GetNonce(from), // replay attack is prevented by the AccountSequence number set on the CW transaction that triggered this call - GasLimit: k.getEvmGasLimitFromCtx(ctx), - GasPrice: utils.Big0, // fees are already paid on the CW transaction - GasFeeCap: utils.Big0, - GasTipCap: utils.Big0, - To: to, - Value: value, - Data: data, - SkipAccountChecks: false, - From: from, - } - res, err := k.applyEVMMessage(ctx, evmMsg, stateDB, gp) - if err != nil { - return nil, err - } - k.consumeEvmGas(ctx, res.UsedGas) - if res.Err != nil { - return nil, res.Err - } - surplus, err := stateDB.Finalize() - if err != nil { - return nil, err - } - k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{}, ethtypes.EmptyTxsHash, surplus) - return res.ReturnData, nil - } - // This call is part of an existing StateTransition, so directly invoking `Call` - 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, _, leftoverGas, err := evm.Create(caller, input, gas, value) - return ret, leftoverGas, err - } - } else { - f = func(caller vm.ContractRef, addr *common.Address, input []byte, gas uint64, value *big.Int) ([]byte, uint64, error) { - return evm.Call(caller, *addr, input, gas, value) - } + // This call was not part of an existing StateTransition, so it should trigger one + executionCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) + stateDB := state.NewDBImpl(executionCtx, k, false) + gp := k.GetGasPool() + evmMsg := &core.Message{ + Nonce: stateDB.GetNonce(from), // replay attack is prevented by the AccountSequence number set on the CW transaction that triggered this call + GasLimit: k.getEvmGasLimitFromCtx(ctx), + GasPrice: utils.Big0, // fees are already paid on the CW transaction + GasFeeCap: utils.Big0, + GasTipCap: utils.Big0, + To: to, + Value: value, + Data: data, + SkipAccountChecks: false, + From: from, + } + res, err := k.applyEVMMessage(ctx, evmMsg, stateDB, gp) + if err != nil { + return nil, err + } + k.consumeEvmGas(ctx, res.UsedGas) + if res.Err != nil { + return nil, res.Err } - return k.callEVM(ctx, from, to, val, data, f) + surplus, err := stateDB.Finalize() + if err != nil { + return nil, err + } + k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{}, ethtypes.EmptyTxsHash, surplus) + return res.ReturnData, nil } func (k *Keeper) StaticCallEVM(ctx sdk.Context, from sdk.AccAddress, to *common.Address, data []byte) ([]byte, error) { - evm, err := k.getOrCreateEVM(ctx, from) + evm, err := k.createReadOnlyEVM(ctx, from) if err != nil { return nil, err } @@ -151,13 +140,9 @@ func (k *Keeper) callEVM(ctx sdk.Context, from common.Address, to *common.Addres } // only used for StaticCalls -func (k *Keeper) getOrCreateEVM(ctx sdk.Context, from sdk.AccAddress) (*vm.EVM, error) { - evm := types.GetCtxEVM(ctx) - if evm != nil { - return evm, nil - } +func (k *Keeper) createReadOnlyEVM(ctx sdk.Context, from sdk.AccAddress) (*vm.EVM, error) { executionCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) - stateDB := state.NewDBImpl(executionCtx, k, false) + stateDB := state.NewDBImpl(executionCtx, k, true) gp := k.GetGasPool() blockCtx, err := k.GetVMBlockContext(executionCtx, gp) if err != nil { @@ -165,9 +150,7 @@ func (k *Keeper) getOrCreateEVM(ctx sdk.Context, from sdk.AccAddress) (*vm.EVM, } cfg := types.DefaultChainConfig().EthereumConfig(k.ChainID(ctx)) txCtx := vm.TxContext{Origin: k.GetEVMAddressOrDefault(ctx, from)} - evm = vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) - stateDB.SetEVM(evm) - return evm, nil + return vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}), nil } func (k *Keeper) getEvmGasLimitFromCtx(ctx sdk.Context) uint64 { diff --git a/x/evm/keeper/evm_test.go b/x/evm/keeper/evm_test.go index a7e7fc024..81938a4d6 100644 --- a/x/evm/keeper/evm_test.go +++ b/x/evm/keeper/evm_test.go @@ -32,6 +32,11 @@ func TestInternalCallCreateContract(t *testing.T) { Sender: testAddr.String(), Data: contractData, } + // circular interop call + ctx = ctx.WithIsEVM(true) + _, err = k.HandleInternalEVMCall(ctx, req) + require.Equal(t, "sei does not support EVM->CW->EVM call pattern", err.Error()) + ctx = ctx.WithIsEVM(false) _, err = k.HandleInternalEVMCall(ctx, req) require.Nil(t, err) } @@ -55,6 +60,10 @@ func TestInternalCall(t *testing.T) { Sender: testAddr.String(), Data: contractData, } + ctx = ctx.WithIsEVM(true) + _, err = k.HandleInternalEVMCall(ctx, req) + require.Equal(t, "sei does not support EVM->CW->EVM call pattern", err.Error()) + ctx = ctx.WithIsEVM(false) ret, err := k.HandleInternalEVMCall(ctx, req) require.Nil(t, err) contractAddr := crypto.CreateAddress(senderEvmAddr, 0) diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 451e2998e..095f2c3c1 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -7,6 +7,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "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" ) @@ -111,3 +116,33 @@ func (q Querier) Pointer(c context.Context, req *types.QueryPointerRequest) (*ty return nil, errors.ErrUnsupported } } + +func (q Querier) PointerVersion(c context.Context, req *types.QueryPointerVersionRequest) (*types.QueryPointerVersionResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + switch req.PointerType { + case types.PointerType_NATIVE: + return &types.QueryPointerVersionResponse{ + Version: uint32(native.CurrentVersion), + }, nil + case types.PointerType_CW20: + return &types.QueryPointerVersionResponse{ + Version: uint32(cw20.CurrentVersion(ctx)), + }, nil + case types.PointerType_CW721: + return &types.QueryPointerVersionResponse{ + Version: uint32(cw721.CurrentVersion), + }, nil + case types.PointerType_ERC20: + return &types.QueryPointerVersionResponse{ + Version: uint32(erc20.CurrentVersion), + CwCodeId: q.GetStoredPointerCodeID(ctx, types.PointerType_ERC20), + }, nil + case types.PointerType_ERC721: + return &types.QueryPointerVersionResponse{ + Version: uint32(erc721.CurrentVersion), + CwCodeId: q.GetStoredPointerCodeID(ctx, types.PointerType_ERC721), + }, nil + default: + return nil, errors.ErrUnsupported + } +} diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go index 5df048043..30c26af00 100644 --- a/x/evm/keeper/grpc_query_test.go +++ b/x/evm/keeper/grpc_query_test.go @@ -34,7 +34,7 @@ func TestQueryPointer(t *testing.T) { 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) + require.Equal(t, types.QueryPointerResponse{Pointer: evmAddr2.Hex(), Version: uint32(cw20.CurrentVersion(ctx)), 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) diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 209732843..6a03b6083 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -52,6 +52,7 @@ type Keeper struct { stakingKeeper *stakingkeeper.Keeper transferKeeper ibctransferkeeper.Keeper wasmKeeper *wasmkeeper.PermissionedKeeper + wasmViewKeeper *wasmkeeper.Keeper cachedFeeCollectorAddressMtx *sync.RWMutex cachedFeeCollectorAddress *common.Address @@ -115,7 +116,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, wasmKeeper *wasmkeeper.PermissionedKeeper) *Keeper { + transferKeeper ibctransferkeeper.Keeper, wasmKeeper *wasmkeeper.PermissionedKeeper, wasmViewKeeper *wasmkeeper.Keeper) *Keeper { if !paramstore.HasKeyTable() { paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) } @@ -128,6 +129,7 @@ func NewKeeper( stakingKeeper: stakingKeeper, transferKeeper: transferKeeper, wasmKeeper: wasmKeeper, + wasmViewKeeper: wasmViewKeeper, pendingTxs: make(map[string][]*PendingTx), nonceMx: &sync.RWMutex{}, cachedFeeCollectorAddressMtx: &sync.RWMutex{}, @@ -153,6 +155,16 @@ func (k *Keeper) GetStoreKey() sdk.StoreKey { return k.storeKey } +func (k *Keeper) IterateAll(ctx sdk.Context, pref []byte, cb func(key, val []byte) bool) { + iter := k.PrefixStore(ctx, pref).Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + if cb(iter.Key(), iter.Value()) { + break + } + } +} + func (k *Keeper) PrefixStore(ctx sdk.Context, pref []byte) sdk.KVStore { store := ctx.KVStore(k.GetStoreKey()) return prefix.NewStore(store, pref) diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 0e4b33263..4275275e1 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -2,15 +2,14 @@ package keeper import ( "context" - "encoding/binary" "encoding/json" + "errors" "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" @@ -24,7 +23,6 @@ import ( "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" @@ -59,7 +57,6 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeterWithMultiplier(ctx)) stateDB := state.NewDBImpl(ctx, &server, false) - stateDB.AddSurplus(msg.Derived.AnteSurplus) tx, _ := msg.AsTransaction() emsg := server.GetEVMMessage(ctx, tx, msg.Derived.SenderEVMAddr) gp := server.GetGasPool() @@ -86,8 +83,9 @@ func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMT ) return } - receipt, err := server.writeReceipt(ctx, msg, tx, emsg, serverRes, stateDB) - if err != nil { + receipt, rerr := server.writeReceipt(ctx, msg, tx, emsg, serverRes, stateDB) + if rerr != nil { + err = rerr ctx.Logger().Error(fmt.Sprintf("failed to write EVM receipt: %s", err)) telemetry.IncrCounterWithLabels( @@ -312,6 +310,15 @@ func (server msgServer) writeReceipt(ctx sdk.Context, origMsg *types.MsgEVMTrans receipt.Status = uint32(ethtypes.ReceiptStatusFailed) } + if perr := stateDB.GetPrecompileError(); perr != nil { + if receipt.Status > 0 { + ctx.Logger().Error(fmt.Sprintf("Transaction %s succeeded in execution but has precompile error %s", receipt.TxHashHex, perr.Error())) + } else { + // append precompile error to VM error + receipt.VmError = fmt.Sprintf("%s|%s", receipt.VmError, perr.Error()) + } + } + receipt.From = origMsg.Derived.SenderEVMAddr.Hex() return receipt, server.SetReceipt(ctx, tx.Hash(), receipt) @@ -350,19 +357,16 @@ func (server msgServer) RegisterPointer(goCtx context.Context, msg *types.MsgReg 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))) + codeID := server.GetStoredPointerCodeID(ctx, msg.PointerType) bz, err := json.Marshal(payload) if err != nil { return nil, err @@ -391,6 +395,25 @@ func (server msgServer) RegisterPointer(goCtx context.Context, msg *types.MsgReg return &types.MsgRegisterPointerResponse{PointerAddress: pointerAddr.String()}, err } +func (server msgServer) AssociateContractAddress(goCtx context.Context, msg *types.MsgAssociateContractAddress) (*types.MsgAssociateContractAddressResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + addr := sdk.MustAccAddressFromBech32(msg.Address) // already validated + // check if address is for a contract + if server.wasmViewKeeper.GetContractInfo(ctx, addr) == nil { + return nil, errors.New("no wasm contract found at the given address") + } + evmAddr := common.BytesToAddress(addr) + existingEvmAddr, ok := server.GetEVMAddress(ctx, addr) + if ok { + if existingEvmAddr.Cmp(evmAddr) != 0 { + ctx.Logger().Error(fmt.Sprintf("unexpected associated EVM address %s exists for contract %s: expecting %s", existingEvmAddr.Hex(), addr.String(), evmAddr.Hex())) + } + return nil, errors.New("contract already has an associated address") + } + server.SetAddressMapping(ctx, addr, evmAddr) + return &types.MsgAssociateContractAddressResponse{}, nil +} + func getEthReceipt(ctx sdk.Context, tx *ethtypes.Transaction, msg *core.Message, res *core.ExecutionResult, 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 5d1fc24ea..3ca811cfb 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "bytes" + "crypto/sha256" "encoding/hex" "math/big" "os" @@ -25,6 +26,7 @@ import ( "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" ) type mockTx struct { @@ -589,3 +591,120 @@ func TestRegisterPointer(t *testing.T) { } require.False(t, hasRegisteredEvent) } + +func TestEvmError(t *testing.T) { + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}) + code, err := os.ReadFile("../../../example/contracts/simplestorage/SimpleStorage.bin") + require.Nil(t, err) + bz, err := hex.DecodeString(string(code)) + require.Nil(t, err) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + txData := ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 200000, + To: nil, + Value: big.NewInt(0), + Data: bz, + Nonce: 0, + } + chainID := k.ChainID(ctx) + chainCfg := types.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + blockNum := big.NewInt(ctx.BlockHeight()) + signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + txwrapper, err := ethtx.NewLegacyTx(tx) + require.Nil(t, err) + req, err := types.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + _, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(1000000))) + k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(1000000)))) + k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, evmAddr[:], amt) + + tb := testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + tb.SetMsgs(req) + sdktx := tb.GetTx() + txbz, err := testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(sdktx) + require.Nil(t, err) + + res := testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, sdktx, sha256.Sum256(txbz)) + require.Equal(t, uint32(0), res.Code) + receipt, err := k.GetReceipt(ctx, common.HexToHash(res.EvmTxInfo.TxHash)) + require.Nil(t, err) + + // send transaction that's gonna be reverted to the contract + contractAddr := common.HexToAddress(receipt.ContractAddress) + abi, err := simplestorage.SimplestorageMetaData.GetAbi() + require.Nil(t, err) + bz, err = abi.Pack("bad") + require.Nil(t, err) + txData = ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 200000, + To: &contractAddr, + Value: big.NewInt(0), + Data: bz, + Nonce: 1, + } + tx, err = ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + txwrapper, err = ethtx.NewLegacyTx(tx) + require.Nil(t, err) + req, err = types.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + tb = testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + tb.SetMsgs(req) + sdktx = tb.GetTx() + txbz, err = testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(sdktx) + require.Nil(t, err) + + res = testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: txbz}, sdktx, sha256.Sum256(txbz)) + require.Equal(t, uint32(0), res.Code) + receipt, err = k.GetReceipt(ctx, common.HexToHash(res.EvmTxInfo.TxHash)) + require.Nil(t, err) + require.Equal(t, receipt.VmError, res.EvmTxInfo.VmError) +} + +func TestAssociateContractAddress(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + msgServer := keeper.NewMsgServerImpl(k) + dummySeiAddr, dummyEvmAddr := testkeeper.MockAddressPair() + res, err := msgServer.RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: dummySeiAddr.String(), + PointerType: types.PointerType_ERC20, + ErcAddress: dummyEvmAddr.Hex(), + }) + require.Nil(t, err) + _, err = msgServer.AssociateContractAddress(sdk.WrapSDKContext(ctx), &types.MsgAssociateContractAddress{ + Sender: dummySeiAddr.String(), + Address: res.PointerAddress, + }) + require.Nil(t, err) + associatedEvmAddr, found := k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(res.PointerAddress)) + require.True(t, found) + require.Equal(t, common.BytesToAddress(sdk.MustAccAddressFromBech32(res.PointerAddress)), associatedEvmAddr) + associatedSeiAddr, found := k.GetSeiAddress(ctx, associatedEvmAddr) + require.True(t, found) + require.Equal(t, res.PointerAddress, associatedSeiAddr.String()) + // setting for an associated address would fail + _, err = msgServer.AssociateContractAddress(sdk.WrapSDKContext(ctx), &types.MsgAssociateContractAddress{ + Sender: dummySeiAddr.String(), + Address: res.PointerAddress, + }) + require.NotNil(t, err) + require.Contains(t, err.Error(), "contract already has an associated address") + // setting for a non-contract would fail + _, err = msgServer.AssociateContractAddress(sdk.WrapSDKContext(ctx), &types.MsgAssociateContractAddress{ + Sender: dummySeiAddr.String(), + Address: dummySeiAddr.String(), + }) + require.NotNil(t, err) + require.Contains(t, err.Error(), "no wasm contract found at the given address") +} diff --git a/x/evm/keeper/nonce.go b/x/evm/keeper/nonce.go index 27e937ee4..253f66548 100644 --- a/x/evm/keeper/nonce.go +++ b/x/evm/keeper/nonce.go @@ -3,6 +3,7 @@ package keeper import ( "encoding/binary" + "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/types" @@ -21,3 +22,14 @@ func (k *Keeper) SetNonce(ctx sdk.Context, addr common.Address, nonce uint64) { binary.BigEndian.PutUint64(length, nonce) k.PrefixStore(ctx, types.NonceKeyPrefix).Set(addr[:], length) } + +func (k *Keeper) IterateAllNonces(ctx sdk.Context, cb func(addr common.Address, nonce uint64) bool) { + iter := prefix.NewStore(ctx.KVStore(k.storeKey), types.NonceKeyPrefix).Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + evmAddr := common.BytesToAddress(iter.Key()) + if cb(evmAddr, binary.BigEndian.Uint64(iter.Value())) { + break + } + } +} diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go index 211e387d4..a70a52d86 100644 --- a/x/evm/keeper/params.go +++ b/x/evm/keeper/params.go @@ -46,7 +46,3 @@ func (k *Keeper) ChainID(ctx sdk.Context) *big.Int { return config.GetEVMChainID(ctx.ChainID()) } - -func (k *Keeper) WhitelistedCwCodeHashesForDelegateCall(ctx sdk.Context) [][]byte { - return k.GetParams(ctx).WhitelistedCwCodeHashesForDelegateCall -} diff --git a/x/evm/keeper/pointer.go b/x/evm/keeper/pointer.go index e87192834..b3cf5372e 100644 --- a/x/evm/keeper/pointer.go +++ b/x/evm/keeper/pointer.go @@ -6,23 +6,38 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "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" + artifactsutils "github.com/sei-protocol/sei-chain/x/evm/artifacts/utils" "github.com/sei-protocol/sei-chain/x/evm/types" ) +var ErrorPointerToPointerNotAllowed = sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "cannot create a pointer to a pointer") + +// ERC20 -> Native Token func (k *Keeper) SetERC20NativePointer(ctx sdk.Context, token string, addr common.Address) error { - return k.SetPointerInfo(ctx, types.PointerERC20NativeKey(token), addr[:], native.CurrentVersion) + return k.SetERC20NativePointerWithVersion(ctx, token, addr, native.CurrentVersion) } +// ERC20 -> Native Token func (k *Keeper) SetERC20NativePointerWithVersion(ctx sdk.Context, token string, addr common.Address, version uint16) error { - return k.SetPointerInfo(ctx, types.PointerERC20NativeKey(token), addr[:], version) + if k.cwAddressIsPointer(ctx, token) { + return ErrorPointerToPointerNotAllowed + } + err := k.setPointerInfo(ctx, types.PointerERC20NativeKey(token), addr[:], version) + if err != nil { + return err + } + return k.setPointerInfo(ctx, types.PointerReverseRegistryKey(addr), []byte(token), version) } +// ERC20 -> Native Token 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 { @@ -31,18 +46,33 @@ func (k *Keeper) GetERC20NativePointer(ctx sdk.Context, token string) (addr comm return } +// ERC20 -> Native Token func (k *Keeper) DeleteERC20NativePointer(ctx sdk.Context, token string, version uint16) { - k.DeletePointerInfo(ctx, types.PointerERC20NativeKey(token), version) + addr, _, exists := k.GetERC20NativePointer(ctx, token) + if exists { + k.deletePointerInfo(ctx, types.PointerERC20NativeKey(token), version) + k.deletePointerInfo(ctx, types.PointerReverseRegistryKey(addr), version) + } } +// ERC20 -> CW20 func (k *Keeper) SetERC20CW20Pointer(ctx sdk.Context, cw20Address string, addr common.Address) error { - return k.SetPointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), addr[:], cw20.CurrentVersion) + return k.SetERC20CW20PointerWithVersion(ctx, cw20Address, addr, cw20.CurrentVersion(ctx)) } +// ERC20 -> CW20 func (k *Keeper) SetERC20CW20PointerWithVersion(ctx sdk.Context, cw20Address string, addr common.Address, version uint16) error { - return k.SetPointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), addr[:], version) + if k.cwAddressIsPointer(ctx, cw20Address) { + return ErrorPointerToPointerNotAllowed + } + err := k.setPointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), addr[:], version) + if err != nil { + return err + } + return k.setPointerInfo(ctx, types.PointerReverseRegistryKey(addr), []byte(cw20Address), version) } +// ERC20 -> CW20 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 { @@ -51,18 +81,33 @@ func (k *Keeper) GetERC20CW20Pointer(ctx sdk.Context, cw20Address string) (addr return } +// ERC20 -> CW20 func (k *Keeper) DeleteERC20CW20Pointer(ctx sdk.Context, cw20Address string, version uint16) { - k.DeletePointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), version) + addr, _, exists := k.GetERC20CW20Pointer(ctx, cw20Address) + if exists { + k.deletePointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), version) + k.deletePointerInfo(ctx, types.PointerReverseRegistryKey(addr), version) + } } +// ERC721 -> CW721 func (k *Keeper) SetERC721CW721Pointer(ctx sdk.Context, cw721Address string, addr common.Address) error { - return k.SetPointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), addr[:], cw721.CurrentVersion) + return k.SetERC721CW721PointerWithVersion(ctx, cw721Address, addr, cw721.CurrentVersion) } +// ERC721 -> CW721 func (k *Keeper) SetERC721CW721PointerWithVersion(ctx sdk.Context, cw721Address string, addr common.Address, version uint16) error { - return k.SetPointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), addr[:], version) + if k.cwAddressIsPointer(ctx, cw721Address) { + return ErrorPointerToPointerNotAllowed + } + err := k.setPointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), addr[:], version) + if err != nil { + return err + } + return k.setPointerInfo(ctx, types.PointerReverseRegistryKey(addr), []byte(cw721Address), version) } +// ERC721 -> CW721 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 { @@ -71,14 +116,28 @@ func (k *Keeper) GetERC721CW721Pointer(ctx sdk.Context, cw721Address string) (ad return } +// ERC721 -> CW721 func (k *Keeper) DeleteERC721CW721Pointer(ctx sdk.Context, cw721Address string, version uint16) { - k.DeletePointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), version) + addr, _, exists := k.GetERC721CW721Pointer(ctx, cw721Address) + if exists { + k.deletePointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), version) + k.deletePointerInfo(ctx, types.PointerReverseRegistryKey(addr), version) + } } +// CW20 -> ERC20 func (k *Keeper) SetCW20ERC20Pointer(ctx sdk.Context, erc20Address common.Address, addr string) error { - return k.SetPointerInfo(ctx, types.PointerCW20ERC20Key(erc20Address), []byte(addr), erc20.CurrentVersion) + if k.evmAddressIsPointer(ctx, erc20Address) { + return ErrorPointerToPointerNotAllowed + } + err := k.setPointerInfo(ctx, types.PointerCW20ERC20Key(erc20Address), []byte(addr), erc20.CurrentVersion) + if err != nil { + return err + } + return k.setPointerInfo(ctx, types.PointerReverseRegistryKey(common.BytesToAddress([]byte(addr))), erc20Address[:], erc20.CurrentVersion) } +// CW20 -> ERC20 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 { @@ -87,8 +146,25 @@ func (k *Keeper) GetCW20ERC20Pointer(ctx sdk.Context, erc20Address common.Addres return } +func (k *Keeper) evmAddressIsPointer(ctx sdk.Context, addr common.Address) bool { + _, _, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(addr)) + return exists +} + +func (k *Keeper) cwAddressIsPointer(ctx sdk.Context, addr string) bool { + _, _, exists := k.GetPointerInfo(ctx, types.PointerReverseRegistryKey(common.BytesToAddress([]byte(addr)))) + return exists +} + func (k *Keeper) SetCW721ERC721Pointer(ctx sdk.Context, erc721Address common.Address, addr string) error { - return k.SetPointerInfo(ctx, types.PointerCW721ERC721Key(erc721Address), []byte(addr), erc721.CurrentVersion) + if k.evmAddressIsPointer(ctx, erc721Address) { + return ErrorPointerToPointerNotAllowed + } + err := k.setPointerInfo(ctx, types.PointerCW721ERC721Key(erc721Address), []byte(addr), erc721.CurrentVersion) + if err != nil { + return err + } + return k.setPointerInfo(ctx, types.PointerReverseRegistryKey(common.BytesToAddress([]byte(addr))), erc721Address[:], erc721.CurrentVersion) } func (k *Keeper) GetCW721ERC721Pointer(ctx sdk.Context, erc721Address common.Address) (addr sdk.AccAddress, version uint16, exists bool) { @@ -112,10 +188,10 @@ func (k *Keeper) GetPointerInfo(ctx sdk.Context, pref []byte) (addr []byte, vers return } -func (k *Keeper) SetPointerInfo(ctx sdk.Context, pref []byte, addr []byte, version uint16) error { +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) + return fmt.Errorf("pointer at %X 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) @@ -124,9 +200,29 @@ func (k *Keeper) SetPointerInfo(ctx sdk.Context, pref []byte, addr []byte, versi return nil } -func (k *Keeper) DeletePointerInfo(ctx sdk.Context, pref []byte, version uint16) { +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) } + +func (k *Keeper) GetStoredPointerCodeID(ctx sdk.Context, pointerType types.PointerType) uint64 { + store := k.PrefixStore(ctx, types.PointerCWCodePrefix) + var versionBz []byte + switch pointerType { + case types.PointerType_ERC20: + store = prefix.NewStore(store, types.PointerCW20ERC20Prefix) + versionBz = artifactsutils.GetVersionBz(erc20.CurrentVersion) + case types.PointerType_ERC721: + store = prefix.NewStore(store, types.PointerCW721ERC721Prefix) + versionBz = artifactsutils.GetVersionBz(erc721.CurrentVersion) + default: + return 0 + } + bz := store.Get(versionBz) + if bz == nil { + return 0 + } + return binary.BigEndian.Uint64(bz) +} diff --git a/x/evm/keeper/pointer_test.go b/x/evm/keeper/pointer_test.go index e4048af69..3563ebeeb 100644 --- a/x/evm/keeper/pointer_test.go +++ b/x/evm/keeper/pointer_test.go @@ -3,19 +3,246 @@ package keeper_test import ( "testing" - testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + + 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" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" ) -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 +// allows us to permutate different pointer combinations +type handlers struct { + evmSetter func(ctx types.Context, token string, addr common.Address) error + evmGetter func(ctx types.Context, token string) (addr common.Address, version uint16, exists bool) + evmDeleter func(ctx types.Context, token string, version uint16) + cwSetter func(ctx types.Context, erc20Address common.Address, addr string) error + cwGetter func(ctx types.Context, erc20Address common.Address) (addr types.AccAddress, version uint16, exists bool) + cwDeleter func(ctx types.Context, erc20Address common.Address, version uint16) +} + +type seiPointerTest struct { + name string + getHandlers func(k *evmkeeper.Keeper) *handlers + version uint16 +} + +func TestEVMtoCWPointers(t *testing.T) { + _, ctx := testkeeper.MockEVMKeeper() + + tests := []seiPointerTest{ + { + name: "ERC20NativePointer prevents pointer to cw20 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + evmSetter: k.SetERC20NativePointer, + evmGetter: k.GetERC20NativePointer, + evmDeleter: k.DeleteERC20NativePointer, + cwSetter: k.SetCW20ERC20Pointer, + cwGetter: k.GetCW20ERC20Pointer, + } + }, + version: native.CurrentVersion, + }, + { + name: "ERC20NativePointer prevents pointer to cw721 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + evmSetter: k.SetERC20NativePointer, + evmGetter: k.GetERC20NativePointer, + evmDeleter: k.DeleteERC20NativePointer, + cwSetter: k.SetCW721ERC721Pointer, + cwGetter: k.GetCW721ERC721Pointer, + } + }, + version: native.CurrentVersion, + }, + { + name: "ERC20CW20Pointer prevents pointer to cw721 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + evmSetter: k.SetERC20CW20Pointer, + evmGetter: k.GetERC20CW20Pointer, + evmDeleter: k.DeleteERC20CW20Pointer, + cwSetter: k.SetCW721ERC721Pointer, + cwGetter: k.GetCW721ERC721Pointer, + } + }, + version: cw20.CurrentVersion(ctx), + }, + { + name: "ERC20CW20Pointer prevents pointer to cw20 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + evmSetter: k.SetERC20CW20Pointer, + evmGetter: k.GetERC20CW20Pointer, + evmDeleter: k.DeleteERC20CW20Pointer, + cwSetter: k.SetCW20ERC20Pointer, + cwGetter: k.GetCW20ERC20Pointer, + } + }, + version: cw20.CurrentVersion(ctx), + }, + { + name: "ERC721CW721Pointer prevents pointer to cw721 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + evmSetter: k.SetERC721CW721Pointer, + evmGetter: k.GetERC721CW721Pointer, + evmDeleter: k.DeleteERC721CW721Pointer, + cwSetter: k.SetCW721ERC721Pointer, + cwGetter: k.GetCW721ERC721Pointer, + } + }, + version: cw721.CurrentVersion, + }, + { + name: "ERC721CW721Pointer prevents pointer to cw20 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + evmSetter: k.SetERC721CW721Pointer, + evmGetter: k.GetERC721CW721Pointer, + evmDeleter: k.DeleteERC721CW721Pointer, + cwSetter: k.SetCW20ERC20Pointer, + cwGetter: k.GetCW20ERC20Pointer, + } + }, + version: cw721.CurrentVersion, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + handlers := test.getHandlers(k) + cwAddress, evmAddress := testkeeper.MockAddressPair() + + // create a pointer + require.Nil(t, handlers.evmSetter(ctx, cwAddress.String(), evmAddress)) + + // should exist + addr, _, exists := handlers.evmGetter(ctx, cwAddress.String()) + require.Equal(t, evmAddress, addr) + require.True(t, exists) + require.NotNil(t, handlers.evmSetter(ctx, cwAddress.String(), evmAddress)) + + // should delete + var version uint16 = 1 + if test.version != 0 { + version = test.version + } + handlers.evmDeleter(ctx, cwAddress.String(), version) + _, _, exists = handlers.evmGetter(ctx, cwAddress.String()) + require.False(t, exists) + + // setup target as pointer + require.Nil(t, handlers.cwSetter(ctx, evmAddress, cwAddress.String())) + _, _, exists = handlers.cwGetter(ctx, evmAddress) + require.True(t, exists) + + // should not allow pointer to pointer + require.Error(t, handlers.evmSetter(ctx, cwAddress.String(), evmAddress), evmkeeper.ErrorPointerToPointerNotAllowed) + + }) + } +} + +func TestCWtoEVMPointers(t *testing.T) { + tests := []seiPointerTest{ + { + name: "CW20ERC20Pointer prevents pointer to native pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + cwSetter: k.SetCW20ERC20Pointer, + cwGetter: k.GetCW20ERC20Pointer, + evmSetter: k.SetERC20NativePointer, + evmGetter: k.GetERC20NativePointer, + } + }, + }, + { + name: "CW20ERC20Pointer prevents pointer to erc20 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + cwSetter: k.SetCW20ERC20Pointer, + cwGetter: k.GetCW20ERC20Pointer, + evmSetter: k.SetERC20CW20Pointer, + evmGetter: k.GetERC20CW20Pointer, + } + }, + }, + { + name: "CW20ERC20Pointer prevents pointer to erc721 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + cwSetter: k.SetCW20ERC20Pointer, + cwGetter: k.GetCW20ERC20Pointer, + evmSetter: k.SetERC721CW721Pointer, + evmGetter: k.GetERC721CW721Pointer, + } + }, + }, + { + name: "CW721ERC721Pointer prevents pointer to native pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + cwSetter: k.SetCW721ERC721Pointer, + cwGetter: k.GetCW721ERC721Pointer, + evmSetter: k.SetERC20NativePointer, + evmGetter: k.GetERC20NativePointer, + } + }, + }, + { + name: "CW721ERC721Pointer prevents pointer to erc721 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + cwSetter: k.SetCW721ERC721Pointer, + cwGetter: k.GetCW721ERC721Pointer, + evmSetter: k.SetERC721CW721Pointer, + evmGetter: k.GetERC721CW721Pointer, + } + }, + }, + { + name: "CW721ERC721Pointer prevents pointer to erc20 pointer", + getHandlers: func(k *evmkeeper.Keeper) *handlers { + return &handlers{ + cwSetter: k.SetCW721ERC721Pointer, + cwGetter: k.GetCW721ERC721Pointer, + evmSetter: k.SetERC20CW20Pointer, + evmGetter: k.GetERC20CW20Pointer, + } + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + handlers := test.getHandlers(k) + cwAddress, evmAddress := testkeeper.MockAddressPair() + + // create a pointer + require.Nil(t, handlers.cwSetter(ctx, evmAddress, cwAddress.String())) + + // should exist + addr, _, exists := handlers.cwGetter(ctx, evmAddress) + require.Equal(t, cwAddress, addr) + require.True(t, exists) + require.NotNil(t, handlers.cwSetter(ctx, evmAddress, cwAddress.String())) + + // create new address to test prevention logic + cwAddress2, evmAddress2 := testkeeper.MockAddressPair() + + // setup target as pointer (has to be evm so that the target exists) + require.Nil(t, handlers.evmSetter(ctx, cwAddress2.String(), evmAddress2)) + _, _, exists = handlers.evmGetter(ctx, cwAddress2.String()) + require.True(t, exists) + + // should not allow pointer to pointer + require.Error(t, handlers.cwSetter(ctx, evmAddress2, cwAddress2.String()), evmkeeper.ErrorPointerToPointerNotAllowed) + }) + } } diff --git a/x/evm/keeper/precompile.go b/x/evm/keeper/precompile.go index c2a8b5119..24a571493 100644 --- a/x/evm/keeper/precompile.go +++ b/x/evm/keeper/precompile.go @@ -5,6 +5,7 @@ import ( "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/precompiles/wasmd" ) // add any payable precompiles here @@ -13,6 +14,7 @@ var payablePrecompiles = map[string]struct{}{ bank.BankAddress: {}, staking.StakingAddress: {}, gov.GovAddress: {}, + wasmd.WasmdAddress: {}, } func IsPayablePrecompile(addr *common.Address) bool { diff --git a/x/evm/keeper/state.go b/x/evm/keeper/state.go index 2cd0ab722..b2279bb41 100644 --- a/x/evm/keeper/state.go +++ b/x/evm/keeper/state.go @@ -1,6 +1,7 @@ package keeper import ( + "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/types" @@ -29,3 +30,15 @@ func (k *Keeper) GetState(ctx sdk.Context, addr common.Address, hash common.Hash func (k *Keeper) SetState(ctx sdk.Context, addr common.Address, key common.Hash, val common.Hash) { k.PrefixStore(ctx, types.StateKey(addr)).Set(key[:], val[:]) } + +func (k *Keeper) IterateState(ctx sdk.Context, cb func(addr common.Address, key common.Hash, val common.Hash) bool) { + iter := prefix.NewStore(ctx.KVStore(k.storeKey), types.StateKeyPrefix).Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + k := iter.Key() + evmAddr := common.BytesToAddress(k[:common.AddressLength]) + if cb(evmAddr, common.BytesToHash(k[common.AddressLength:]), common.BytesToHash(iter.Value())) { + break + } + } +} diff --git a/x/evm/keeper/whitelist.go b/x/evm/keeper/whitelist.go deleted file mode 100644 index 5e85bfbf4..000000000 --- a/x/evm/keeper/whitelist.go +++ /dev/null @@ -1,16 +0,0 @@ -package keeper - -import ( - "bytes" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func (k *Keeper) IsCWCodeHashWhitelistedForEVMDelegateCall(ctx sdk.Context, h []byte) bool { - for _, w := range k.WhitelistedCwCodeHashesForDelegateCall(ctx) { - if bytes.Equal(w, h) { - return true - } - } - return false -} diff --git a/x/evm/keeper/whitelist_test.go b/x/evm/keeper/whitelist_test.go deleted file mode 100644 index f25db274b..000000000 --- a/x/evm/keeper/whitelist_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package keeper_test - -import ( - "testing" - - keepertest "github.com/sei-protocol/sei-chain/testutil/keeper" - "github.com/stretchr/testify/require" -) - -func TestWhitelist(t *testing.T) { - k, ctx := keepertest.MockEVMKeeper() - require.True(t, k.IsCWCodeHashWhitelistedForEVMDelegateCall(ctx, k.WhitelistedCwCodeHashesForDelegateCall(ctx)[0])) - require.False(t, k.IsCWCodeHashWhitelistedForEVMDelegateCall(ctx, []byte("1"))) -} diff --git a/x/evm/migrations/fix_total_supply.go b/x/evm/migrations/fix_total_supply.go new file mode 100644 index 000000000..e75cf046b --- /dev/null +++ b/x/evm/migrations/fix_total_supply.go @@ -0,0 +1,37 @@ +package migrations + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +// This migration is to fix total supply mismatch caused by mishandled +// ante surplus +func FixTotalSupply(ctx sdk.Context, k *keeper.Keeper) error { + balances := k.BankKeeper().GetAccountsBalances(ctx) + correctSupply := sdk.ZeroInt() + for _, balance := range balances { + correctSupply = correctSupply.Add(balance.Coins.AmountOf(sdk.MustGetBaseDenom())) + } + totalWeiBalance := sdk.ZeroInt() + k.BankKeeper().IterateAllWeiBalances(ctx, func(aa sdk.AccAddress, i sdk.Int) bool { + totalWeiBalance = totalWeiBalance.Add(i) + return false + }) + weiInUsei, weiRemainder := bankkeeper.SplitUseiWeiAmount(totalWeiBalance) + if !weiRemainder.IsZero() { + ctx.Logger().Error("wei total supply has been compromised as well; rounding up and adding to reserve") + if err := k.BankKeeper().AddWei(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), bankkeeper.OneUseiInWei.Sub(weiRemainder)); err != nil { + return err + } + weiInUsei = weiInUsei.Add(sdk.OneInt()) + } + correctSupply = correctSupply.Add(weiInUsei) + currentSupply := k.BankKeeper().GetSupply(ctx, sdk.MustGetBaseDenom()).Amount + if !currentSupply.Equal(correctSupply) { + k.BankKeeper().SetSupply(ctx, sdk.NewCoin(sdk.MustGetBaseDenom(), correctSupply)) + } + return nil +} diff --git a/x/evm/migrations/fix_total_supply_test.go b/x/evm/migrations/fix_total_supply_test.go new file mode 100644 index 000000000..a932098af --- /dev/null +++ b/x/evm/migrations/fix_total_supply_test.go @@ -0,0 +1,26 @@ +package migrations_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/migrations" + "github.com/stretchr/testify/require" +) + +func TestFixTotalSupply(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + addr, _ := testkeeper.MockAddressPair() + balance := sdk.NewCoins(sdk.NewCoin(sdk.MustGetBaseDenom(), sdk.OneInt())) + k.BankKeeper().MintCoins(ctx, "evm", balance) + k.BankKeeper().SendCoinsFromModuleToAccount(ctx, "evm", addr, balance) + k.BankKeeper().AddWei(ctx, addr, sdk.OneInt()) + oldSupply := k.BankKeeper().GetSupply(ctx, sdk.MustGetBaseDenom()).Amount + require.Nil(t, migrations.FixTotalSupply(ctx, k)) + require.Equal(t, oldSupply.Add(sdk.OneInt()), k.BankKeeper().GetSupply(ctx, sdk.MustGetBaseDenom()).Amount) + require.Equal(t, sdk.OneInt(), k.BankKeeper().GetBalance(ctx, addr, sdk.MustGetBaseDenom()).Amount) + require.Equal(t, sdk.ZeroInt(), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress("evm"), sdk.MustGetBaseDenom()).Amount) + require.Equal(t, sdk.OneInt(), k.BankKeeper().GetWeiBalance(ctx, addr)) + require.Equal(t, sdk.NewInt(999_999_999_999), k.BankKeeper().GetWeiBalance(ctx, k.AccountKeeper().GetModuleAddress("evm"))) +} diff --git a/x/evm/migrations/store_cw_pointer_code.go b/x/evm/migrations/store_cw_pointer_code.go index 2e188ec24..3dea8ed44 100644 --- a/x/evm/migrations/store_cw_pointer_code.go +++ b/x/evm/migrations/store_cw_pointer_code.go @@ -10,23 +10,27 @@ import ( "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) +func StoreCWPointerCode(ctx sdk.Context, k *keeper.Keeper, store20 bool, store721 bool) error { + if store20 { + 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), + ) } - 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) + if store721 { + 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), + ) } - 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 86fcff80c..121541101 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -142,7 +142,19 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { }) _ = cfg.RegisterMigration(types.ModuleName, 4, func(ctx sdk.Context) error { - return migrations.StoreCWPointerCode(ctx, am.keeper) + return migrations.StoreCWPointerCode(ctx, am.keeper, true, true) + }) + + _ = cfg.RegisterMigration(types.ModuleName, 5, func(ctx sdk.Context) error { + return migrations.FixTotalSupply(ctx, am.keeper) + }) + + _ = cfg.RegisterMigration(types.ModuleName, 6, func(ctx sdk.Context) error { + return migrations.StoreCWPointerCode(ctx, am.keeper, false, true) + }) + + _ = cfg.RegisterMigration(types.ModuleName, 7, func(ctx sdk.Context) error { + return migrations.StoreCWPointerCode(ctx, am.keeper, false, true) }) } @@ -168,7 +180,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw } // ConsensusVersion implements ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 5 } +func (AppModule) ConsensusVersion() uint64 { return 8 } // BeginBlock executes all ABCI BeginBlock logic respective to the capability module. func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { @@ -220,13 +232,14 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val } denom := am.keeper.GetBaseDenom(ctx) - surplus := utils.Sdk0 + surplus := am.keeper.GetAnteSurplusSum(ctx) for _, deferredInfo := range evmTxDeferredInfoList { if deferredInfo.Error != "" && deferredInfo.TxHash.Cmp(ethtypes.EmptyTxsHash) != 0 { _ = am.keeper.SetReceipt(ctx, deferredInfo.TxHash, &types.Receipt{ TxHashHex: deferredInfo.TxHash.Hex(), TransactionIndex: uint32(deferredInfo.TxIndx), VmError: deferredInfo.Error, + BlockNumber: uint64(ctx.BlockHeight()), }) continue } @@ -246,24 +259,27 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val surplus = surplus.Add(deferredInfo.Surplus) } - surplusUsei, surplusWei := state.SplitUseiWeiAmount(surplus.BigInt()) - if surplusUsei.GT(sdk.ZeroInt()) { - if err := am.keeper.BankKeeper().AddCoins(ctx, am.keeper.AccountKeeper().GetModuleAddress(types.ModuleName), sdk.NewCoins(sdk.NewCoin(am.keeper.GetBaseDenom(ctx), surplusUsei)), true); err != nil { - ctx.Logger().Error("failed to send usei surplus of %s to EVM module account", surplusUsei) + if surplus.IsPositive() { + surplusUsei, surplusWei := state.SplitUseiWeiAmount(surplus.BigInt()) + if surplusUsei.GT(sdk.ZeroInt()) { + if err := am.keeper.BankKeeper().AddCoins(ctx, am.keeper.AccountKeeper().GetModuleAddress(types.ModuleName), sdk.NewCoins(sdk.NewCoin(am.keeper.GetBaseDenom(ctx), surplusUsei)), true); err != nil { + ctx.Logger().Error("failed to send usei surplus of %s to EVM module account", surplusUsei) + } } - } - if surplusWei.GT(sdk.ZeroInt()) { - if err := am.keeper.BankKeeper().AddWei(ctx, am.keeper.AccountKeeper().GetModuleAddress(types.ModuleName), surplusWei); err != nil { - ctx.Logger().Error("failed to send wei surplus of %s to EVM module account", surplusWei) + if surplusWei.GT(sdk.ZeroInt()) { + if err := am.keeper.BankKeeper().AddWei(ctx, am.keeper.AccountKeeper().GetModuleAddress(types.ModuleName), surplusWei); err != nil { + ctx.Logger().Error("failed to send wei surplus of %s to EVM module account", surplusWei) + } } - } - if evmHooks != nil && evmHooks.OnBalanceChange != nil && (surplusUsei.GT(sdk.ZeroInt()) || surplusWei.GT(sdk.ZeroInt())) { - evmModuleAddress := am.keeper.AccountKeeper().GetModuleAddress(types.ModuleName) - tracers.TraceBlockReward(ctx, evmHooks, am.keeper.BankKeeper(), evmModuleAddress, am.keeper.GetEVMAddressOrDefault(ctx, evmModuleAddress), surplusUsei, surplusWei) + if evmHooks != nil && evmHooks.OnBalanceChange != nil && (surplusUsei.GT(sdk.ZeroInt()) || surplusWei.GT(sdk.ZeroInt())) { + evmModuleAddress := am.keeper.AccountKeeper().GetModuleAddress(types.ModuleName) + tracers.TraceBlockReward(ctx, evmHooks, am.keeper.BankKeeper(), evmModuleAddress, am.keeper.GetEVMAddressOrDefault(ctx, evmModuleAddress), surplusUsei, surplusWei) + } } am.keeper.SetTxHashesOnHeight(ctx, ctx.BlockHeight(), utils.Filter(utils.Map(evmTxDeferredInfoList, func(i keeper.EvmTxDeferredInfo) common.Hash { return i.TxHash }), func(h common.Hash) bool { return h.Cmp(ethtypes.EmptyTxsHash) != 0 })) am.keeper.SetBlockBloom(ctx, ctx.BlockHeight(), utils.Map(evmTxDeferredInfoList, func(i keeper.EvmTxDeferredInfo) ethtypes.Bloom { return i.TxBloom })) + am.keeper.DeleteAllAnteSurplus(ctx) return []abci.ValidatorUpdate{} } diff --git a/x/evm/module_test.go b/x/evm/module_test.go index 3c702c2c8..24d618a8c 100644 --- a/x/evm/module_test.go +++ b/x/evm/module_test.go @@ -49,13 +49,13 @@ func TestModuleExportGenesis(t *testing.T) { module := evm.NewAppModule(nil, k) jsonMsg := module.ExportGenesis(ctx, types.ModuleCdc) jsonStr := string(jsonMsg) - assert.Equal(t, "{\"params\":{\"priority_normalizer\":\"1.000000000000000000\",\"base_fee_per_gas\":\"0.000000000000000000\",\"minimum_fee_per_gas\":\"1000000000.000000000000000000\",\"whitelisted_cw_code_hashes_for_delegate_call\":[\"ol1416zS7kfMOcIk4WL+ebU+a75u0qVujAqGWT6+YQI=\",\"lM3Zw+hcJvfOxDwjv7SzsrLXGgqNhcWN8S/+wHQf68g=\"]},\"address_associations\":[]}", jsonStr) + assert.Equal(t, "{\"params\":{\"priority_normalizer\":\"1.000000000000000000\",\"base_fee_per_gas\":\"0.000000000000000000\",\"minimum_fee_per_gas\":\"1000000000.000000000000000000\",\"whitelisted_cw_code_hashes_for_delegate_call\":[]},\"address_associations\":[{\"sei_address\":\"sei17xpfvakm2amg962yls6f84z3kell8c5la4jkdu\",\"eth_address\":\"0x27F7B8B8B5A4e71E8E9aA671f4e4031E3773303F\"}],\"codes\":[],\"states\":[],\"nonces\":[],\"serialized\":[{\"prefix\":\"Fg==\",\"key\":\"AwAB\",\"value\":\"AAAAAAAAAAM=\"},{\"prefix\":\"Fg==\",\"key\":\"BAAF\",\"value\":\"AAAAAAAAAAQ=\"}]}", jsonStr) } func TestConsensusVersion(t *testing.T) { k, _ := testkeeper.MockEVMKeeper() module := evm.NewAppModule(nil, k) - assert.Equal(t, uint64(5), module.ConsensusVersion()) + assert.Equal(t, uint64(8), module.ConsensusVersion()) } func TestABCI(t *testing.T) { @@ -78,7 +78,7 @@ func TestABCI(t *testing.T) { surplus, err := s.Finalize() require.Nil(t, err) require.Equal(t, sdk.ZeroInt(), surplus) - k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(1), ethtypes.Bloom{}, common.Hash{}, surplus) + k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(1), ethtypes.Bloom{}, common.Hash{4}, surplus) // 3rd tx s = state.NewDBImpl(ctx.WithTxIndex(3), k, false) s.SubBalance(evmAddr2, big.NewInt(5000000000000), ethtracing.BalanceChangeUnspecified) @@ -86,7 +86,7 @@ func TestABCI(t *testing.T) { surplus, err = s.Finalize() require.Nil(t, err) require.Equal(t, sdk.ZeroInt(), surplus) - k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(3), ethtypes.Bloom{}, common.Hash{}, surplus) + k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(3), ethtypes.Bloom{}, common.Hash{3}, surplus) k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}, {Code: 0}}) m.EndBlock(ctx, abci.RequestEndBlock{}) require.Equal(t, uint64(0), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), "usei").Amount.Uint64()) @@ -104,7 +104,7 @@ func TestABCI(t *testing.T) { surplus, err = s.Finalize() require.Nil(t, err) require.Equal(t, sdk.NewInt(1000000000000), surplus) - k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(2), ethtypes.Bloom{}, common.Hash{}, surplus) + k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(2), ethtypes.Bloom{}, common.Hash{2}, surplus) k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}}) m.EndBlock(ctx, abci.RequestEndBlock{}) require.Equal(t, uint64(1), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), "usei").Amount.Uint64()) @@ -122,9 +122,13 @@ func TestABCI(t *testing.T) { m.EndBlock(ctx, abci.RequestEndBlock{}) receipt, err := k.GetReceipt(ctx, common.Hash{1}) require.Nil(t, err) + require.Equal(t, receipt.BlockNumber, uint64(ctx.BlockHeight())) require.Equal(t, receipt.VmError, "test error") // fourth block with locked tokens in coinbase address + balanceChanges = make([]evmBalanceChange, 0) + ctx = addTestBalanceChangeTracerToCtx(ctx, &balanceChanges) + m.BeginBlock(ctx, abci.RequestBeginBlock{}) coinbase := state.GetCoinbaseAddress(2) vms := vesting.NewMsgServerImpl(*k.AccountKeeper(), k.BankKeeper()) @@ -147,6 +151,24 @@ func TestABCI(t *testing.T) { m.EndBlock(ctx, abci.RequestEndBlock{}) // should not crash require.Equal(t, sdk.OneInt(), k.BankKeeper().GetBalance(ctx, coinbase, "usei").Amount) require.Equal(t, sdk.ZeroInt(), k.BankKeeper().SpendableCoins(ctx, coinbase).AmountOf("usei")) + + require.Equal(t, 1, len(balanceChanges)) + require.Equal(t, []evmBalanceChange{ + {"2000000000000", "3000000000000", ethtracing.BalanceIncreaseRewardTransactionFee}, + }, balanceChanges, "balance changes do not match, actual are:\n\n%s", balanceChangesValues(balanceChanges)) +} + +func TestAnteSurplus(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + m := evm.NewAppModule(nil, k) + // first block + m.BeginBlock(ctx, abci.RequestBeginBlock{}) + k.AddAnteSurplus(ctx, common.BytesToHash([]byte("1234")), sdk.NewInt(1_000_000_000_001)) + 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(1), k.BankKeeper().GetWeiBalance(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName)).Uint64()) + // ante surplus should be cleared + require.Equal(t, uint64(0), k.GetAnteSurplusSum(ctx).Uint64()) } func addTestBalanceChangeTracerToCtx(ctx sdk.Context, balanceChanges *[]evmBalanceChange) sdk.Context { diff --git a/x/evm/state/balance.go b/x/evm/state/balance.go index f0255429c..dc2b9857f 100644 --- a/x/evm/state/balance.go +++ b/x/evm/state/balance.go @@ -91,8 +91,12 @@ func (s *DBImpl) AddBalance(evmAddr common.Address, amt *big.Int, reason tracing func (s *DBImpl) GetBalance(evmAddr common.Address) *big.Int { s.k.PrepareReplayedAddr(s.ctx, evmAddr) - usei := s.k.BankKeeper().SpendableCoins(s.ctx, s.getSeiAddress(evmAddr)).AmountOf(s.k.GetBaseDenom(s.ctx)) - wei := s.k.BankKeeper().GetWeiBalance(s.ctx, s.getSeiAddress(evmAddr)) + seiAddr := s.getSeiAddress(evmAddr) + denom := s.k.GetBaseDenom(s.ctx) + allUsei := s.k.BankKeeper().GetBalance(s.ctx, seiAddr, denom).Amount + lockedUsei := s.k.BankKeeper().LockedCoins(s.ctx, seiAddr).AmountOf(denom) // LockedCoins doesn't use iterators + usei := allUsei.Sub(lockedUsei) + wei := s.k.BankKeeper().GetWeiBalance(s.ctx, seiAddr) return usei.Mul(SdkUseiToSweiMultiplier).Add(wei).BigInt() } diff --git a/x/evm/state/balance_test.go b/x/evm/state/balance_test.go index 33aa29b32..abe7d5b70 100644 --- a/x/evm/state/balance_test.go +++ b/x/evm/state/balance_test.go @@ -98,16 +98,14 @@ func TestSurplus(t *testing.T) { db := state.NewDBImpl(ctx, k, false) db.AddBalance(evmAddr, big.NewInt(1_000_000_000_001), tracing.BalanceChangeUnspecified) _, err := db.Finalize() - require.NotNil(t, err) - require.Contains(t, err.Error(), "negative surplus value") + require.Nil(t, err) // test negative usei surplus positive wei surplus (negative total) db = state.NewDBImpl(ctx, k, false) db.AddBalance(evmAddr, big.NewInt(1_000_000_000_000), tracing.BalanceChangeUnspecified) db.SubBalance(evmAddr, big.NewInt(1), tracing.BalanceChangeUnspecified) _, err = db.Finalize() - require.NotNil(t, err) - require.Contains(t, err.Error(), "negative surplus value") + require.Nil(t, err) // test negative usei surplus positive wei surplus (positive total) db = state.NewDBImpl(ctx, k, false) @@ -124,8 +122,7 @@ func TestSurplus(t *testing.T) { db.AddBalance(evmAddr, big.NewInt(2), tracing.BalanceChangeUnspecified) db.AddBalance(evmAddr, big.NewInt(999_999_999_999), tracing.BalanceChangeUnspecified) _, err = db.Finalize() - require.NotNil(t, err) - require.Contains(t, err.Error(), "negative surplus value") + require.Nil(t, err) // test positive usei surplus negative wei surplus (positive total) db = state.NewDBImpl(ctx, k, false) diff --git a/x/evm/state/statedb.go b/x/evm/state/statedb.go index 29a61363c..7cd888e82 100644 --- a/x/evm/state/statedb.go +++ b/x/evm/state/statedb.go @@ -1,15 +1,12 @@ package state import ( - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/evm/types" ) // Initialized for each transaction individually @@ -22,6 +19,9 @@ type DBImpl struct { // If err is not nil at the end of the execution, the transaction will be rolled // back. err error + // whenever this is set, the same error would also cause EVM to revert, which is + // why we don't put it in `tempState`, since we still want to be able to access it later. + precompileErr error // a temporary address that collects fees for this particular transaction so that there is // no single bottleneck for fee collection. Its account state and balance will be deleted @@ -72,10 +72,8 @@ func (s *DBImpl) SetLogger(logger *tracing.Hooks) { s.logger = logger } -func (s *DBImpl) SetEVM(evm *vm.EVM) { - s.ctx = types.SetCtxEVM(s.ctx, evm) - s.snapshottedCtxs = utils.Map(s.snapshottedCtxs, func(ctx sdk.Context) sdk.Context { return types.SetCtxEVM(ctx, evm) }) -} +// for interface compliance +func (s *DBImpl) SetEVM(evm *vm.EVM) {} // AddPreimage records a SHA3 preimage seen by the VM. // AddPreimage performs a no-op since the EnablePreimageRecording flag is disabled @@ -112,9 +110,6 @@ func (s *DBImpl) Finalize() (surplus sdk.Int, err error) { for _, ts := range s.tempStatesHist { surplus = surplus.Add(ts.surplus) } - if surplus.IsNegative() { - err = fmt.Errorf("negative surplus value: %s", surplus.String()) - } return } @@ -143,6 +138,7 @@ func (s *DBImpl) Copy() vm.StateDB { coinbaseEvmAddress: s.coinbaseEvmAddress, simulation: s.simulation, err: s.err, + precompileErr: s.precompileErr, logger: s.logger, } } @@ -171,6 +167,14 @@ func (s *DBImpl) Preimages() map[common.Hash][]byte { return map[common.Hash][]byte{} } +func (s *DBImpl) SetPrecompileError(err error) { + s.precompileErr = err +} + +func (s *DBImpl) GetPrecompileError() error { + return s.precompileErr +} + // ** TEST ONLY FUNCTIONS **// func (s *DBImpl) Err() error { return s.err diff --git a/x/evm/types/codec.go b/x/evm/types/codec.go index a092de6e0..bba5d881e 100644 --- a/x/evm/types/codec.go +++ b/x/evm/types/codec.go @@ -11,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/gogo/protobuf/proto" "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" ) @@ -31,11 +32,17 @@ func GetAmino() *codec.LegacyAmino { } func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations((*govtypes.Content)(nil), + &AddERCNativePointerProposal{}, + &AddERCCW20PointerProposal{}, + &AddERCCW721PointerProposal{}, + ) registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgEVMTransaction{}, &MsgSend{}, &MsgRegisterPointer{}, + &MsgAssociateContractAddress{}, ) registry.RegisterInterface( "seiprotocol.seichain.evm.TxData", diff --git a/x/evm/types/context.go b/x/evm/types/context.go deleted file mode 100644 index e3a30f7a7..000000000 --- a/x/evm/types/context.go +++ /dev/null @@ -1,28 +0,0 @@ -package types - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/core/vm" -) - -type CtxEVMKeyType string - -const CtxEVMKey = CtxEVMKeyType("evm") - -func SetCtxEVM(ctx sdk.Context, evm *vm.EVM) sdk.Context { - return ctx.WithContext(context.WithValue(ctx.Context(), CtxEVMKey, evm)) -} - -func GetCtxEVM(ctx sdk.Context) *vm.EVM { - rawVal := ctx.Context().Value(CtxEVMKey) - if rawVal == nil { - return nil - } - evm, ok := rawVal.(*vm.EVM) - if !ok { - return nil - } - return evm -} diff --git a/x/evm/types/events.go b/x/evm/types/events.go index 45ec378d9..92a8f171e 100644 --- a/x/evm/types/events.go +++ b/x/evm/types/events.go @@ -3,6 +3,7 @@ package types const ( EventTypeAddressAssociated = "address_associated" EventTypePointerRegistered = "pointer_registered" + EventTypeSigner = "signer" AttributeKeySeiAddress = "sei_addr" AttributeKeyEvmAddress = "evm_addr" diff --git a/x/evm/types/genesis.pb.go b/x/evm/types/genesis.pb.go index 5b00c8a07..00b8fbf54 100644 --- a/x/evm/types/genesis.pb.go +++ b/x/evm/types/genesis.pb.go @@ -76,17 +76,245 @@ func (m *AddressAssociation) GetEthAddress() string { return "" } +type Code struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Code []byte `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` +} + +func (m *Code) Reset() { *m = Code{} } +func (m *Code) String() string { return proto.CompactTextString(m) } +func (*Code) ProtoMessage() {} +func (*Code) Descriptor() ([]byte, []int) { + return fileDescriptor_9f044f30507c97ed, []int{1} +} +func (m *Code) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Code) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Code.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 *Code) XXX_Merge(src proto.Message) { + xxx_messageInfo_Code.Merge(m, src) +} +func (m *Code) XXX_Size() int { + return m.Size() +} +func (m *Code) XXX_DiscardUnknown() { + xxx_messageInfo_Code.DiscardUnknown(m) +} + +var xxx_messageInfo_Code proto.InternalMessageInfo + +func (m *Code) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *Code) GetCode() []byte { + if m != nil { + return m.Code + } + return nil +} + +type ContractState struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *ContractState) Reset() { *m = ContractState{} } +func (m *ContractState) String() string { return proto.CompactTextString(m) } +func (*ContractState) ProtoMessage() {} +func (*ContractState) Descriptor() ([]byte, []int) { + return fileDescriptor_9f044f30507c97ed, []int{2} +} +func (m *ContractState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractState.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 *ContractState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractState.Merge(m, src) +} +func (m *ContractState) XXX_Size() int { + return m.Size() +} +func (m *ContractState) XXX_DiscardUnknown() { + xxx_messageInfo_ContractState.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractState proto.InternalMessageInfo + +func (m *ContractState) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *ContractState) GetKey() []byte { + if m != nil { + return m.Key + } + return nil +} + +func (m *ContractState) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +type Nonce struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` +} + +func (m *Nonce) Reset() { *m = Nonce{} } +func (m *Nonce) String() string { return proto.CompactTextString(m) } +func (*Nonce) ProtoMessage() {} +func (*Nonce) Descriptor() ([]byte, []int) { + return fileDescriptor_9f044f30507c97ed, []int{3} +} +func (m *Nonce) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Nonce) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Nonce.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 *Nonce) XXX_Merge(src proto.Message) { + xxx_messageInfo_Nonce.Merge(m, src) +} +func (m *Nonce) XXX_Size() int { + return m.Size() +} +func (m *Nonce) XXX_DiscardUnknown() { + xxx_messageInfo_Nonce.DiscardUnknown(m) +} + +var xxx_messageInfo_Nonce proto.InternalMessageInfo + +func (m *Nonce) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *Nonce) GetNonce() uint64 { + if m != nil { + return m.Nonce + } + return 0 +} + +type Serialized struct { + Prefix []byte `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` + Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` + Value []byte `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *Serialized) Reset() { *m = Serialized{} } +func (m *Serialized) String() string { return proto.CompactTextString(m) } +func (*Serialized) ProtoMessage() {} +func (*Serialized) Descriptor() ([]byte, []int) { + return fileDescriptor_9f044f30507c97ed, []int{4} +} +func (m *Serialized) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Serialized) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Serialized.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 *Serialized) XXX_Merge(src proto.Message) { + xxx_messageInfo_Serialized.Merge(m, src) +} +func (m *Serialized) XXX_Size() int { + return m.Size() +} +func (m *Serialized) XXX_DiscardUnknown() { + xxx_messageInfo_Serialized.DiscardUnknown(m) +} + +var xxx_messageInfo_Serialized proto.InternalMessageInfo + +func (m *Serialized) GetPrefix() []byte { + if m != nil { + return m.Prefix + } + return nil +} + +func (m *Serialized) GetKey() []byte { + if m != nil { + return m.Key + } + return nil +} + +func (m *Serialized) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + // GenesisState defines the evm module's genesis state. type GenesisState struct { Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` AddressAssociations []*AddressAssociation `protobuf:"bytes,2,rep,name=address_associations,json=addressAssociations,proto3" json:"address_associations,omitempty"` + Codes []*Code `protobuf:"bytes,3,rep,name=codes,proto3" json:"codes,omitempty"` + States []*ContractState `protobuf:"bytes,4,rep,name=states,proto3" json:"states,omitempty"` + Nonces []*Nonce `protobuf:"bytes,5,rep,name=nonces,proto3" json:"nonces,omitempty"` + Serialized []*Serialized `protobuf:"bytes,6,rep,name=serialized,proto3" json:"serialized,omitempty"` } func (m *GenesisState) Reset() { *m = GenesisState{} } func (m *GenesisState) String() string { return proto.CompactTextString(m) } func (*GenesisState) ProtoMessage() {} func (*GenesisState) Descriptor() ([]byte, []int) { - return fileDescriptor_9f044f30507c97ed, []int{1} + return fileDescriptor_9f044f30507c97ed, []int{5} } func (m *GenesisState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -129,33 +357,76 @@ func (m *GenesisState) GetAddressAssociations() []*AddressAssociation { return nil } +func (m *GenesisState) GetCodes() []*Code { + if m != nil { + return m.Codes + } + return nil +} + +func (m *GenesisState) GetStates() []*ContractState { + if m != nil { + return m.States + } + return nil +} + +func (m *GenesisState) GetNonces() []*Nonce { + if m != nil { + return m.Nonces + } + return nil +} + +func (m *GenesisState) GetSerialized() []*Serialized { + if m != nil { + return m.Serialized + } + return nil +} + func init() { proto.RegisterType((*AddressAssociation)(nil), "seiprotocol.seichain.evm.AddressAssociation") + proto.RegisterType((*Code)(nil), "seiprotocol.seichain.evm.Code") + proto.RegisterType((*ContractState)(nil), "seiprotocol.seichain.evm.ContractState") + proto.RegisterType((*Nonce)(nil), "seiprotocol.seichain.evm.Nonce") + proto.RegisterType((*Serialized)(nil), "seiprotocol.seichain.evm.Serialized") proto.RegisterType((*GenesisState)(nil), "seiprotocol.seichain.evm.GenesisState") } func init() { proto.RegisterFile("evm/genesis.proto", fileDescriptor_9f044f30507c97ed) } var fileDescriptor_9f044f30507c97ed = []byte{ - // 284 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0xb1, 0x4e, 0xc3, 0x30, - 0x10, 0x86, 0x63, 0x40, 0x95, 0x70, 0x18, 0x20, 0x74, 0xa8, 0x3a, 0xb8, 0x55, 0xa7, 0x0e, 0xd4, - 0x91, 0xca, 0x8e, 0xd4, 0x2e, 0x5d, 0x51, 0x90, 0x18, 0x58, 0x22, 0x37, 0x3d, 0x25, 0x27, 0x91, - 0x38, 0xca, 0x99, 0x0a, 0xde, 0x82, 0x37, 0xe1, 0x35, 0x3a, 0x76, 0x64, 0x42, 0x28, 0x79, 0x11, - 0x14, 0xc7, 0xc0, 0x50, 0x75, 0x3b, 0xfb, 0xff, 0xfc, 0xff, 0xbf, 0x8f, 0x5f, 0xc1, 0x36, 0x0f, - 0x53, 0x28, 0x80, 0x90, 0x64, 0x59, 0x69, 0xa3, 0x83, 0x01, 0x01, 0xda, 0x29, 0xd1, 0xcf, 0x92, - 0x00, 0x93, 0x4c, 0x61, 0x21, 0x61, 0x9b, 0x0f, 0xfb, 0xa9, 0x4e, 0xb5, 0x95, 0xc2, 0x76, 0xea, - 0xf8, 0xe1, 0x65, 0x6b, 0x51, 0xaa, 0x4a, 0xe5, 0xce, 0x61, 0xf2, 0xc8, 0x83, 0xc5, 0x66, 0x53, - 0x01, 0xd1, 0x82, 0x48, 0x27, 0xa8, 0x0c, 0xea, 0x22, 0x18, 0x71, 0x9f, 0x00, 0x63, 0xd5, 0x29, - 0x03, 0x36, 0x66, 0xd3, 0xf3, 0x88, 0x13, 0xa0, 0x63, 0x5b, 0x00, 0x4c, 0xf6, 0x07, 0x9c, 0x74, - 0x00, 0x98, 0xcc, 0x01, 0x93, 0x0f, 0xc6, 0x2f, 0x56, 0x5d, 0xd7, 0x07, 0xa3, 0x0c, 0x04, 0x77, - 0xbc, 0xd7, 0x05, 0x5b, 0x37, 0x7f, 0x3e, 0x96, 0xc7, 0xba, 0xcb, 0x7b, 0xcb, 0x2d, 0xcf, 0x76, - 0x5f, 0x23, 0x2f, 0x72, 0xaf, 0x82, 0x98, 0xf7, 0x5d, 0x5a, 0xac, 0xfe, 0x9b, 0xb6, 0xd1, 0xa7, - 0x53, 0x7f, 0x7e, 0x73, 0xdc, 0xed, 0xf0, 0x7b, 0xd1, 0xb5, 0x3a, 0xb8, 0xa3, 0xe5, 0x6a, 0x57, - 0x0b, 0xb6, 0xaf, 0x05, 0xfb, 0xae, 0x05, 0x7b, 0x6f, 0x84, 0xb7, 0x6f, 0x84, 0xf7, 0xd9, 0x08, - 0xef, 0x69, 0x96, 0xa2, 0xc9, 0x5e, 0xd6, 0x32, 0xd1, 0x79, 0x48, 0x80, 0xb3, 0xdf, 0x1c, 0x7b, - 0xb0, 0x41, 0xe1, 0x6b, 0xd8, 0x6e, 0xd6, 0xbc, 0x95, 0x40, 0xeb, 0x9e, 0xd5, 0x6f, 0x7f, 0x02, - 0x00, 0x00, 0xff, 0xff, 0x71, 0xa9, 0x4b, 0x46, 0xb0, 0x01, 0x00, 0x00, + // 461 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xcf, 0x6b, 0x13, 0x41, + 0x14, 0xc7, 0x13, 0xf7, 0x87, 0xf8, 0x12, 0xa1, 0x8e, 0x41, 0x96, 0x1e, 0x36, 0x65, 0x11, 0xec, + 0xc1, 0xee, 0x42, 0x2d, 0xf4, 0xa6, 0xb4, 0x15, 0x7a, 0x11, 0xd1, 0x29, 0x78, 0xf0, 0x12, 0xa6, + 0xbb, 0xcf, 0x64, 0x30, 0xd9, 0x09, 0xfb, 0xa6, 0xa1, 0xf5, 0xaf, 0xf0, 0x9f, 0xf0, 0x7f, 0xe9, + 0xb1, 0x47, 0x4f, 0x22, 0xc9, 0x3f, 0x22, 0xf3, 0x76, 0xfb, 0x43, 0xca, 0x86, 0xde, 0xde, 0xdb, + 0xf9, 0x7e, 0x3f, 0xcc, 0xe4, 0x43, 0xe0, 0x19, 0x2e, 0x66, 0xd9, 0x18, 0x4b, 0x24, 0x4d, 0xe9, + 0xbc, 0x32, 0xd6, 0x88, 0x88, 0x50, 0xf3, 0x94, 0x9b, 0x69, 0x4a, 0xa8, 0xf3, 0x89, 0xd2, 0x65, + 0x8a, 0x8b, 0xd9, 0xe6, 0x60, 0x6c, 0xc6, 0x86, 0x8f, 0x32, 0x37, 0xd5, 0xf9, 0xcd, 0x0d, 0x87, + 0x98, 0xab, 0x4a, 0xcd, 0x1a, 0x42, 0xf2, 0x05, 0xc4, 0x41, 0x51, 0x54, 0x48, 0x74, 0x40, 0x64, + 0x72, 0xad, 0xac, 0x36, 0xa5, 0x18, 0x42, 0x8f, 0x50, 0x8f, 0x54, 0x7d, 0x12, 0x75, 0xb7, 0xba, + 0xdb, 0x4f, 0x24, 0x10, 0xea, 0x26, 0xeb, 0x02, 0x68, 0x27, 0x37, 0x81, 0x47, 0x75, 0x00, 0xed, + 0xa4, 0x09, 0x24, 0x7b, 0xe0, 0x1f, 0x99, 0x02, 0x45, 0x04, 0x8f, 0xff, 0xa7, 0x5c, 0xaf, 0x42, + 0x80, 0x9f, 0x9b, 0x02, 0xb9, 0xdb, 0x97, 0x3c, 0x27, 0x9f, 0xe1, 0xe9, 0x91, 0x29, 0x6d, 0xa5, + 0x72, 0x7b, 0x62, 0x95, 0x5d, 0x57, 0xdf, 0x00, 0xef, 0x3b, 0x5e, 0x34, 0x6d, 0x37, 0x8a, 0x01, + 0x04, 0x0b, 0x35, 0x3d, 0xc3, 0xc8, 0xe3, 0x6f, 0xf5, 0x92, 0xec, 0x43, 0xf0, 0xd1, 0x94, 0xf9, + 0x3a, 0xd4, 0x00, 0x82, 0xd2, 0x45, 0x18, 0xe6, 0xcb, 0x7a, 0x49, 0x3e, 0x00, 0x9c, 0x60, 0xa5, + 0xd5, 0x54, 0xff, 0xc0, 0x42, 0xbc, 0x80, 0x70, 0x5e, 0xe1, 0x37, 0x7d, 0xce, 0xe5, 0xbe, 0x6c, + 0xb6, 0x07, 0x5f, 0xe3, 0x97, 0x07, 0xfd, 0xe3, 0xda, 0x5d, 0xfd, 0xb2, 0xb7, 0x10, 0xd6, 0x22, + 0x18, 0xd8, 0xdb, 0xdd, 0x4a, 0xdb, 0x5c, 0xa6, 0x9f, 0x38, 0x77, 0xe8, 0x5f, 0xfe, 0x19, 0x76, + 0x64, 0xd3, 0x12, 0x23, 0x18, 0x34, 0xf7, 0x1f, 0xa9, 0x5b, 0x73, 0x4e, 0x85, 0xb7, 0xdd, 0xdb, + 0x7d, 0xdd, 0x4e, 0xbb, 0xaf, 0x5b, 0x3e, 0x57, 0xf7, 0xbe, 0x91, 0xd8, 0x83, 0xc0, 0x39, 0xa1, + 0xc8, 0x63, 0x62, 0xdc, 0x4e, 0x74, 0xa2, 0x65, 0x1d, 0x16, 0xef, 0x20, 0x24, 0xf7, 0x3e, 0x8a, + 0x7c, 0xae, 0xbd, 0x5a, 0x57, 0xbb, 0x63, 0x5a, 0x36, 0x35, 0xb1, 0x0f, 0x21, 0xff, 0xfe, 0x14, + 0x05, 0x0c, 0x18, 0xb6, 0x03, 0xd8, 0xab, 0x6c, 0xe2, 0xe2, 0x3d, 0x00, 0xdd, 0xf8, 0x8a, 0x42, + 0x2e, 0xbf, 0x6c, 0x2f, 0xdf, 0xba, 0x95, 0x77, 0x7a, 0x87, 0xc7, 0x97, 0xcb, 0xb8, 0x7b, 0xb5, + 0x8c, 0xbb, 0x7f, 0x97, 0x71, 0xf7, 0xe7, 0x2a, 0xee, 0x5c, 0xad, 0xe2, 0xce, 0xef, 0x55, 0xdc, + 0xf9, 0xba, 0x33, 0xd6, 0x76, 0x72, 0x76, 0x9a, 0xe6, 0x66, 0x96, 0x11, 0xea, 0x9d, 0x6b, 0x2c, + 0x2f, 0xcc, 0xcd, 0xce, 0x33, 0xf7, 0xff, 0xb2, 0x17, 0x73, 0xa4, 0xd3, 0x90, 0xcf, 0xdf, 0xfc, + 0x0b, 0x00, 0x00, 0xff, 0xff, 0x58, 0x59, 0xc2, 0xfb, 0xb6, 0x03, 0x00, 0x00, } func (m *AddressAssociation) Marshal() (dAtA []byte, err error) { @@ -195,7 +466,7 @@ func (m *AddressAssociation) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *GenesisState) Marshal() (dAtA []byte, err error) { +func (m *Code) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -205,95 +476,891 @@ func (m *GenesisState) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { +func (m *Code) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Code) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.AddressAssociations) > 0 { - for iNdEx := len(m.AddressAssociations) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.AddressAssociations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if len(m.Code) > 0 { + i -= len(m.Code) + copy(dAtA[i:], m.Code) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Code))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ContractState) 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 *ContractState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x1a + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Nonce) 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 *Nonce) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Nonce) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Nonce != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x10 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Serialized) 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 *Serialized) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Serialized) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x1a + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0x12 + } + if len(m.Prefix) > 0 { + i -= len(m.Prefix) + copy(dAtA[i:], m.Prefix) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Prefix))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Serialized) > 0 { + for iNdEx := len(m.Serialized) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Serialized[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.Nonces) > 0 { + for iNdEx := len(m.Nonces) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Nonces[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.States) > 0 { + for iNdEx := len(m.States) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.States[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.Codes) > 0 { + for iNdEx := len(m.Codes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Codes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.AddressAssociations) > 0 { + for iNdEx := len(m.AddressAssociations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AddressAssociations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *AddressAssociation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SeiAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.EthAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *Code) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Code) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *ContractState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Key) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *Nonce) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.Nonce != 0 { + n += 1 + sovGenesis(uint64(m.Nonce)) + } + return n +} + +func (m *Serialized) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Prefix) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Key) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.AddressAssociations) > 0 { + for _, e := range m.AddressAssociations { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.Codes) > 0 { + for _, e := range m.Codes { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.States) > 0 { + for _, e := range m.States { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.Nonces) > 0 { + for _, e := range m.Nonces { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.Serialized) > 0 { + for _, e := range m.Serialized { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *AddressAssociation) 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 ErrIntOverflowGenesis + } + 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: AddressAssociation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddressAssociation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SeiAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SeiAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EthAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EthAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Code) 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 ErrIntOverflowGenesis + } + 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: Code: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Code: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Code = append(m.Code[:0], dAtA[iNdEx:postIndex]...) + if m.Code == nil { + m.Code = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContractState) 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 ErrIntOverflowGenesis + } + 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: ContractState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Nonce) 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 ErrIntOverflowGenesis + } + 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: Nonce: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Nonce: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + 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 ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x12 - } - } - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - -func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { - offset -= sovGenesis(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *AddressAssociation) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.SeiAddress) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - l = len(m.EthAddress) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - return n -} -func (m *GenesisState) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Params.Size() - n += 1 + l + sovGenesis(uint64(l)) - if len(m.AddressAssociations) > 0 { - for _, e := range m.AddressAssociations { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } + if iNdEx > l { + return io.ErrUnexpectedEOF } - return n -} - -func sovGenesis(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozGenesis(x uint64) (n int) { - return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + return nil } -func (m *AddressAssociation) Unmarshal(dAtA []byte) error { +func (m *Serialized) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -316,17 +1383,17 @@ func (m *AddressAssociation) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: AddressAssociation: wiretype end group for non-group") + return fmt.Errorf("proto: Serialized: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: AddressAssociation: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Serialized: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SeiAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Prefix", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -336,29 +1403,31 @@ func (m *AddressAssociation) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.SeiAddress = string(dAtA[iNdEx:postIndex]) + m.Prefix = append(m.Prefix[:0], dAtA[iNdEx:postIndex]...) + if m.Prefix == nil { + m.Prefix = []byte{} + } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EthAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -368,23 +1437,59 @@ func (m *AddressAssociation) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.EthAddress = string(dAtA[iNdEx:postIndex]) + m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } iNdEx = postIndex default: iNdEx = preIndex @@ -503,6 +1608,142 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Codes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Codes = append(m.Codes, &Code{}) + if err := m.Codes[len(m.Codes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field States", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.States = append(m.States, &ContractState{}) + if err := m.States[len(m.States)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonces", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Nonces = append(m.Nonces, &Nonce{}) + if err := m.Nonces[len(m.Nonces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Serialized", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Serialized = append(m.Serialized, &Serialized{}) + if err := m.Serialized[len(m.Serialized)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/evm/types/keys.go b/x/evm/types/keys.go index b376c2b59..70bd37119 100644 --- a/x/evm/types/keys.go +++ b/x/evm/types/keys.go @@ -46,8 +46,11 @@ var ( ReplayedHeight = []byte{0x13} ReplayInitialHeight = []byte{0x14} - PointerRegistryPrefix = []byte{0x15} - PointerCWCodePrefix = []byte{0x16} + PointerRegistryPrefix = []byte{0x15} + PointerCWCodePrefix = []byte{0x16} + PointerReverseRegistryPrefix = []byte{0x17} + + AnteSurplusPrefix = []byte{0x18} ) var ( @@ -120,3 +123,7 @@ func PointerCW721ERC721Key(erc721Addr common.Address) []byte { erc721Addr[:]..., ) } + +func PointerReverseRegistryKey(addr common.Address) []byte { + return append(PointerReverseRegistryPrefix, addr[:]...) +} diff --git a/x/evm/types/message_associate_contract_address.go b/x/evm/types/message_associate_contract_address.go new file mode 100644 index 000000000..9f560964c --- /dev/null +++ b/x/evm/types/message_associate_contract_address.go @@ -0,0 +1,49 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const TypeMsgAssociateContractAddress = "evm_associate_contract_address" + +var ( + _ sdk.Msg = &MsgAssociateContractAddress{} +) + +func NewMsgAssociateContractAddress(sender sdk.AccAddress, addr sdk.AccAddress) *MsgAssociateContractAddress { + return &MsgAssociateContractAddress{Sender: sender.String(), Address: addr.String()} +} + +func (msg *MsgAssociateContractAddress) Route() string { + return RouterKey +} + +func (msg *MsgAssociateContractAddress) Type() string { + return TypeMsgAssociateContractAddress +} + +func (msg *MsgAssociateContractAddress) GetSigners() []sdk.AccAddress { + from, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + panic(err) + } + return []sdk.AccAddress{from} +} + +func (msg *MsgAssociateContractAddress) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +func (msg *MsgAssociateContractAddress) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + if _, err := sdk.AccAddressFromBech32(msg.Address); err != nil { + return sdkerrors.ErrInvalidAddress + } + + return nil +} diff --git a/x/evm/types/message_evm_transaction.go b/x/evm/types/message_evm_transaction.go index 5ab737579..b68793830 100644 --- a/x/evm/types/message_evm_transaction.go +++ b/x/evm/types/message_evm_transaction.go @@ -13,6 +13,7 @@ const TypeMsgEVMTransaction = "evm_transaction" var ( _ sdk.Msg = &MsgEVMTransaction{} _ codectypes.UnpackInterfacesMessage = &MsgEVMTransaction{} + _ sdk.ResultDecorator = &MsgEVMTransactionResponse{} ) func NewMsgEVMTransaction(txData proto.Message) (*MsgEVMTransaction, error) { @@ -77,3 +78,12 @@ func MustGetEVMTransactionMessage(tx sdk.Tx) *MsgEVMTransaction { } return msg } + +func (res *MsgEVMTransactionResponse) DecorateSdkResult(sdkRes *sdk.Result) { + if res == nil { + return + } + if res.VmError != "" { + sdkRes.EvmError = res.VmError + } +} diff --git a/x/evm/types/message_register_pointer.go b/x/evm/types/message_register_pointer.go index 1f2c124c4..831f1a0ae 100644 --- a/x/evm/types/message_register_pointer.go +++ b/x/evm/types/message_register_pointer.go @@ -9,7 +9,7 @@ import ( const TypeMsgRegisterPointer = "evm_register_pointer" var ( - _ sdk.Msg = &MsgSend{} + _ sdk.Msg = &MsgRegisterPointer{} ) func NewMsgRegisterERC20Pointer(sender sdk.AccAddress, ercAddress common.Address) *MsgRegisterPointer { diff --git a/x/evm/types/params.go b/x/evm/types/params.go index ff99431f5..faff9e9ec 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -1,7 +1,6 @@ package types import ( - "encoding/hex" "errors" fmt "fmt" @@ -11,9 +10,10 @@ import ( ) var ( - KeyPriorityNormalizer = []byte("KeyPriorityNormalizer") - KeyBaseFeePerGas = []byte("KeyBaseFeePerGas") - KeyMinFeePerGas = []byte("KeyMinFeePerGas") + KeyPriorityNormalizer = []byte("KeyPriorityNormalizer") + KeyBaseFeePerGas = []byte("KeyBaseFeePerGas") + KeyMinFeePerGas = []byte("KeyMinFeePerGas") + // deprecated KeyWhitelistedCwCodeHashesForDelegateCall = []byte("KeyWhitelistedCwCodeHashesForDelegateCall") ) @@ -120,7 +120,5 @@ func validateWhitelistedCwHashesForDelegateCall(i interface{}) error { } func generateDefaultWhitelistedCwCodeHashesForDelegateCall() [][]byte { - cw20, _ := hex.DecodeString("A25D78D7ACD2EE47CC39C224E162FE79B53E6BBE6ED2A56E8C0A86593EBE6102") - cw721, _ := hex.DecodeString("94CDD9C3E85C26F7CEC43C23BFB4B3B2B2D71A0A8D85C58DF12FFEC0741FEBC8") - return [][]byte{cw20, cw721} + return [][]byte(nil) } diff --git a/x/evm/types/query.pb.go b/x/evm/types/query.pb.go index 5c80febcc..a13d53789 100644 --- a/x/evm/types/query.pb.go +++ b/x/evm/types/query.pb.go @@ -428,6 +428,102 @@ func (m *QueryPointerResponse) GetExists() bool { return false } +type QueryPointerVersionRequest struct { + PointerType PointerType `protobuf:"varint,1,opt,name=pointer_type,json=pointerType,proto3,enum=seiprotocol.seichain.evm.PointerType" json:"pointer_type,omitempty"` +} + +func (m *QueryPointerVersionRequest) Reset() { *m = QueryPointerVersionRequest{} } +func (m *QueryPointerVersionRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPointerVersionRequest) ProtoMessage() {} +func (*QueryPointerVersionRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{8} +} +func (m *QueryPointerVersionRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPointerVersionRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPointerVersionRequest.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 *QueryPointerVersionRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPointerVersionRequest.Merge(m, src) +} +func (m *QueryPointerVersionRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPointerVersionRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPointerVersionRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPointerVersionRequest proto.InternalMessageInfo + +func (m *QueryPointerVersionRequest) GetPointerType() PointerType { + if m != nil { + return m.PointerType + } + return PointerType_ERC20 +} + +type QueryPointerVersionResponse struct { + Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` + CwCodeId uint64 `protobuf:"varint,2,opt,name=cw_code_id,json=cwCodeId,proto3" json:"cw_code_id,omitempty"` +} + +func (m *QueryPointerVersionResponse) Reset() { *m = QueryPointerVersionResponse{} } +func (m *QueryPointerVersionResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPointerVersionResponse) ProtoMessage() {} +func (*QueryPointerVersionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{9} +} +func (m *QueryPointerVersionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPointerVersionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPointerVersionResponse.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 *QueryPointerVersionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPointerVersionResponse.Merge(m, src) +} +func (m *QueryPointerVersionResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPointerVersionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPointerVersionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPointerVersionResponse proto.InternalMessageInfo + +func (m *QueryPointerVersionResponse) GetVersion() uint32 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *QueryPointerVersionResponse) GetCwCodeId() uint64 { + if m != nil { + return m.CwCodeId + } + return 0 +} + func init() { proto.RegisterType((*QuerySeiAddressByEVMAddressRequest)(nil), "seiprotocol.seichain.evm.QuerySeiAddressByEVMAddressRequest") proto.RegisterType((*QuerySeiAddressByEVMAddressResponse)(nil), "seiprotocol.seichain.evm.QuerySeiAddressByEVMAddressResponse") @@ -437,47 +533,54 @@ func init() { proto.RegisterType((*QueryStaticCallResponse)(nil), "seiprotocol.seichain.evm.QueryStaticCallResponse") proto.RegisterType((*QueryPointerRequest)(nil), "seiprotocol.seichain.evm.QueryPointerRequest") proto.RegisterType((*QueryPointerResponse)(nil), "seiprotocol.seichain.evm.QueryPointerResponse") + proto.RegisterType((*QueryPointerVersionRequest)(nil), "seiprotocol.seichain.evm.QueryPointerVersionRequest") + proto.RegisterType((*QueryPointerVersionResponse)(nil), "seiprotocol.seichain.evm.QueryPointerVersionResponse") } func init() { proto.RegisterFile("evm/query.proto", fileDescriptor_11c0d37eed5339f7) } var fileDescriptor_11c0d37eed5339f7 = []byte{ - // 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, + // 627 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0xcd, 0x6e, 0xd3, 0x4e, + 0x14, 0xc5, 0xeb, 0xfc, 0xfb, 0xef, 0xc7, 0x6d, 0x29, 0xd2, 0x80, 0x4a, 0x64, 0x2a, 0x53, 0x99, + 0x0f, 0x55, 0x15, 0xb1, 0xa1, 0xc0, 0xae, 0x2c, 0x68, 0x55, 0x01, 0x0b, 0x24, 0x30, 0xd0, 0x05, + 0x1b, 0xcb, 0xb5, 0x6f, 0xdb, 0x91, 0x62, 0x8f, 0xeb, 0x99, 0xa4, 0xcd, 0x96, 0x05, 0x6b, 0x24, + 0x78, 0x01, 0x1e, 0x81, 0x87, 0x40, 0x62, 0x59, 0x89, 0x0d, 0x4b, 0xd4, 0xf0, 0x20, 0xc8, 0xe3, + 0x71, 0xe2, 0xb4, 0x89, 0x9d, 0x20, 0x76, 0x73, 0x27, 0x73, 0xce, 0xfd, 0xdd, 0xc9, 0x1c, 0xc3, + 0x65, 0x6c, 0x87, 0xf6, 0x51, 0x0b, 0x93, 0x8e, 0x15, 0x27, 0x4c, 0x30, 0x52, 0xe7, 0x48, 0xe5, + 0xca, 0x67, 0x4d, 0x8b, 0x23, 0xf5, 0x0f, 0x3d, 0x1a, 0x59, 0xd8, 0x0e, 0xf5, 0x95, 0x03, 0xc6, + 0x0e, 0x9a, 0x68, 0x7b, 0x31, 0xb5, 0xbd, 0x28, 0x62, 0xc2, 0x13, 0x94, 0x45, 0x3c, 0xd3, 0xe9, + 0xd2, 0x08, 0xa3, 0x56, 0xa8, 0x36, 0xcc, 0x1d, 0x30, 0x5f, 0xa5, 0xbe, 0xaf, 0x91, 0x3e, 0x09, + 0x82, 0x04, 0x39, 0xdf, 0xea, 0xec, 0xec, 0xbe, 0x50, 0x6b, 0x07, 0x8f, 0x5a, 0xc8, 0x05, 0xb9, + 0x01, 0x0b, 0xd8, 0x0e, 0x5d, 0x2f, 0xdb, 0xad, 0x6b, 0xab, 0xda, 0xda, 0xbc, 0x03, 0xd8, 0x0e, + 0xd5, 0x39, 0x73, 0x1f, 0x6e, 0x96, 0xda, 0xf0, 0x98, 0x45, 0x1c, 0x53, 0x1f, 0x8e, 0xf4, 0xbc, + 0x0f, 0xef, 0x89, 0x88, 0x01, 0xe0, 0x71, 0xce, 0x7c, 0xea, 0x09, 0x0c, 0xea, 0xb5, 0x55, 0x6d, + 0x6d, 0xce, 0x29, 0xec, 0xf4, 0x70, 0xfb, 0xde, 0x5b, 0x85, 0x9e, 0x05, 0xdc, 0xd2, 0x36, 0x3d, + 0xdc, 0x51, 0x36, 0x7d, 0xdc, 0xd2, 0xb1, 0x2b, 0x71, 0x37, 0x61, 0x39, 0xbb, 0x96, 0xf4, 0x5f, + 0xf0, 0xb7, 0xbd, 0x66, 0x33, 0x47, 0x24, 0x30, 0x1d, 0x78, 0xc2, 0x93, 0x9e, 0x8b, 0x8e, 0x5c, + 0x93, 0x25, 0xa8, 0x09, 0x26, 0x5d, 0xe6, 0x9d, 0x9a, 0x60, 0x66, 0x03, 0xae, 0x5d, 0x50, 0x2b, + 0xb2, 0x21, 0x72, 0xb3, 0x03, 0x57, 0xe4, 0xf1, 0x97, 0x8c, 0x46, 0x02, 0x93, 0xbc, 0xd3, 0x33, + 0x58, 0x8c, 0xb3, 0x1d, 0x57, 0x74, 0x62, 0x94, 0x92, 0xa5, 0x8d, 0xdb, 0xd6, 0xa8, 0x17, 0x64, + 0x29, 0xfd, 0x9b, 0x4e, 0x8c, 0xce, 0x42, 0xdc, 0x2f, 0x48, 0x1d, 0x66, 0xb3, 0x12, 0x15, 0x64, + 0x5e, 0x9a, 0x7b, 0x70, 0x75, 0xb0, 0xb5, 0xc2, 0xec, 0x29, 0x12, 0x75, 0x79, 0x79, 0x99, 0xfe, + 0xd2, 0xc6, 0x84, 0x53, 0x16, 0x49, 0xaf, 0x4b, 0x4e, 0x5e, 0x92, 0x65, 0x98, 0xc1, 0x13, 0xca, + 0x05, 0xaf, 0xff, 0x27, 0xef, 0x53, 0x55, 0xe6, 0x3e, 0xe8, 0xc5, 0x1e, 0xbb, 0xd9, 0xf1, 0x7f, + 0x3e, 0xa5, 0xf9, 0x16, 0xae, 0x0f, 0xed, 0xd3, 0x1f, 0x29, 0x07, 0xd7, 0x06, 0xc1, 0x57, 0x00, + 0xfc, 0x63, 0xd7, 0x67, 0x01, 0xba, 0x34, 0x7b, 0x0c, 0xd3, 0xce, 0x9c, 0x7f, 0xbc, 0xcd, 0x02, + 0x7c, 0x1e, 0x6c, 0x7c, 0x98, 0x85, 0xff, 0xa5, 0x2f, 0xf9, 0xa6, 0xc1, 0xf2, 0xf0, 0x9c, 0x90, + 0xcd, 0xd1, 0xbc, 0xd5, 0x29, 0xd5, 0x1f, 0xff, 0xa5, 0x3a, 0x9b, 0xcc, 0xb4, 0xde, 0xff, 0xf8, + 0xfd, 0xa9, 0xb6, 0x46, 0xee, 0xd8, 0x1c, 0x69, 0x23, 0xf7, 0xb1, 0x73, 0x1f, 0x3b, 0xfd, 0x74, + 0x14, 0x62, 0x25, 0xe7, 0x18, 0x1e, 0xa0, 0xca, 0x39, 0x4a, 0xe3, 0x5b, 0x39, 0x47, 0x79, 0x6a, + 0xc7, 0x9a, 0xa3, 0x10, 0x6b, 0xf2, 0x45, 0x03, 0xe8, 0x47, 0x8c, 0xdc, 0xab, 0xba, 0xc5, 0xf3, + 0x59, 0xd6, 0xef, 0x4f, 0xa0, 0x98, 0xe4, 0xae, 0xa5, 0xcc, 0xf5, 0x53, 0xa8, 0xcf, 0x1a, 0xcc, + 0xaa, 0x07, 0x49, 0x1a, 0x15, 0xed, 0x06, 0xf3, 0xaf, 0x5b, 0xe3, 0x1e, 0x57, 0x68, 0xeb, 0x12, + 0xed, 0x16, 0x31, 0x4b, 0xd0, 0xf2, 0x14, 0x7f, 0xd5, 0x60, 0x69, 0x30, 0x27, 0xe4, 0xe1, 0x78, + 0xed, 0x06, 0xe3, 0xab, 0x3f, 0x9a, 0x50, 0xa5, 0x58, 0x37, 0x24, 0xeb, 0x5d, 0xb2, 0x5e, 0xcd, + 0xea, 0xaa, 0x98, 0x6e, 0x3d, 0xfd, 0x7e, 0x66, 0x68, 0xa7, 0x67, 0x86, 0xf6, 0xeb, 0xcc, 0xd0, + 0x3e, 0x76, 0x8d, 0xa9, 0xd3, 0xae, 0x31, 0xf5, 0xb3, 0x6b, 0x4c, 0xbd, 0x6b, 0x1c, 0x50, 0x71, + 0xd8, 0xda, 0xb3, 0x7c, 0x16, 0x5e, 0xf0, 0x6b, 0x64, 0x86, 0x27, 0xd2, 0x32, 0xfd, 0xc2, 0xf0, + 0xbd, 0x19, 0xf9, 0xfb, 0x83, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x5d, 0xbe, 0x8f, 0x9b, 0x9d, + 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -496,6 +599,7 @@ type QueryClient interface { 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) + PointerVersion(ctx context.Context, in *QueryPointerVersionRequest, opts ...grpc.CallOption) (*QueryPointerVersionResponse, error) } type queryClient struct { @@ -542,12 +646,22 @@ func (c *queryClient) Pointer(ctx context.Context, in *QueryPointerRequest, opts return out, nil } +func (c *queryClient) PointerVersion(ctx context.Context, in *QueryPointerVersionRequest, opts ...grpc.CallOption) (*QueryPointerVersionResponse, error) { + out := new(QueryPointerVersionResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Query/PointerVersion", 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) + PointerVersion(context.Context, *QueryPointerVersionRequest) (*QueryPointerVersionResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -566,6 +680,9 @@ func (*UnimplementedQueryServer) StaticCall(ctx context.Context, req *QueryStati func (*UnimplementedQueryServer) Pointer(ctx context.Context, req *QueryPointerRequest) (*QueryPointerResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Pointer not implemented") } +func (*UnimplementedQueryServer) PointerVersion(ctx context.Context, req *QueryPointerVersionRequest) (*QueryPointerVersionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PointerVersion not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -643,6 +760,24 @@ func _Query_Pointer_Handler(srv interface{}, ctx context.Context, dec func(inter return interceptor(ctx, in, info, handler) } +func _Query_PointerVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPointerVersionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).PointerVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Query/PointerVersion", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).PointerVersion(ctx, req.(*QueryPointerVersionRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "seiprotocol.seichain.evm.Query", HandlerType: (*QueryServer)(nil), @@ -663,6 +798,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "Pointer", Handler: _Query_Pointer_Handler, }, + { + MethodName: "PointerVersion", + Handler: _Query_PointerVersion_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "evm/query.proto", @@ -955,6 +1094,67 @@ func (m *QueryPointerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryPointerVersionRequest) 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 *QueryPointerVersionRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPointerVersionRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.PointerType != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PointerType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPointerVersionResponse) 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 *QueryPointerVersionResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPointerVersionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CwCodeId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.CwCodeId)) + i-- + dAtA[i] = 0x10 + } + if m.Version != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -1089,6 +1289,33 @@ func (m *QueryPointerResponse) Size() (n int) { return n } +func (m *QueryPointerVersionRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PointerType != 0 { + n += 1 + sovQuery(uint64(m.PointerType)) + } + return n +} + +func (m *QueryPointerVersionResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Version != 0 { + n += 1 + sovQuery(uint64(m.Version)) + } + if m.CwCodeId != 0 { + n += 1 + sovQuery(uint64(m.CwCodeId)) + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1885,6 +2112,163 @@ func (m *QueryPointerResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryPointerVersionRequest) 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: QueryPointerVersionRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPointerVersionRequest: 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 + } + } + 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 *QueryPointerVersionResponse) 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: QueryPointerVersionResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPointerVersionResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + 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 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CwCodeId", wireType) + } + m.CwCodeId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CwCodeId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 8d4d10c21..72c5e53f0 100644 --- a/x/evm/types/query.pb.gw.go +++ b/x/evm/types/query.pb.gw.go @@ -177,6 +177,42 @@ func local_request_Query_Pointer_0(ctx context.Context, marshaler runtime.Marsha } +var ( + filter_Query_PointerVersion_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_PointerVersion_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPointerVersionRequest + 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_PointerVersion_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.PointerVersion(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_PointerVersion_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPointerVersionRequest + 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_PointerVersion_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.PointerVersion(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. @@ -275,6 +311,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_PointerVersion_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_PointerVersion_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_PointerVersion_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -396,6 +455,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_PointerVersion_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_PointerVersion_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_PointerVersion_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -407,6 +486,8 @@ var ( 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))) + + pattern_Query_PointerVersion_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "pointer_version"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -417,4 +498,6 @@ var ( forward_Query_StaticCall_0 = runtime.ForwardResponseMessage forward_Query_Pointer_0 = runtime.ForwardResponseMessage + + forward_Query_PointerVersion_0 = runtime.ForwardResponseMessage ) diff --git a/x/evm/types/tx.pb.go b/x/evm/types/tx.pb.go index d9989aee0..fedbdcfee 100644 --- a/x/evm/types/tx.pb.go +++ b/x/evm/types/tx.pb.go @@ -554,6 +554,94 @@ func (m *MsgRegisterPointerResponse) GetPointerAddress() string { return "" } +type MsgAssociateContractAddress struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` +} + +func (m *MsgAssociateContractAddress) Reset() { *m = MsgAssociateContractAddress{} } +func (m *MsgAssociateContractAddress) String() string { return proto.CompactTextString(m) } +func (*MsgAssociateContractAddress) ProtoMessage() {} +func (*MsgAssociateContractAddress) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{10} +} +func (m *MsgAssociateContractAddress) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAssociateContractAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAssociateContractAddress.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 *MsgAssociateContractAddress) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAssociateContractAddress.Merge(m, src) +} +func (m *MsgAssociateContractAddress) XXX_Size() int { + return m.Size() +} +func (m *MsgAssociateContractAddress) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAssociateContractAddress.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAssociateContractAddress proto.InternalMessageInfo + +func (m *MsgAssociateContractAddress) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgAssociateContractAddress) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +type MsgAssociateContractAddressResponse struct { +} + +func (m *MsgAssociateContractAddressResponse) Reset() { *m = MsgAssociateContractAddressResponse{} } +func (m *MsgAssociateContractAddressResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAssociateContractAddressResponse) ProtoMessage() {} +func (*MsgAssociateContractAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{11} +} +func (m *MsgAssociateContractAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAssociateContractAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAssociateContractAddressResponse.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 *MsgAssociateContractAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAssociateContractAddressResponse.Merge(m, src) +} +func (m *MsgAssociateContractAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgAssociateContractAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAssociateContractAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAssociateContractAddressResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgEVMTransaction)(nil), "seiprotocol.seichain.evm.MsgEVMTransaction") proto.RegisterType((*MsgEVMTransactionResponse)(nil), "seiprotocol.seichain.evm.MsgEVMTransactionResponse") @@ -565,59 +653,64 @@ func init() { proto.RegisterType((*MsgSendResponse)(nil), "seiprotocol.seichain.evm.MsgSendResponse") proto.RegisterType((*MsgRegisterPointer)(nil), "seiprotocol.seichain.evm.MsgRegisterPointer") proto.RegisterType((*MsgRegisterPointerResponse)(nil), "seiprotocol.seichain.evm.MsgRegisterPointerResponse") + proto.RegisterType((*MsgAssociateContractAddress)(nil), "seiprotocol.seichain.evm.MsgAssociateContractAddress") + proto.RegisterType((*MsgAssociateContractAddressResponse)(nil), "seiprotocol.seichain.evm.MsgAssociateContractAddressResponse") } func init() { proto.RegisterFile("evm/tx.proto", fileDescriptor_d72e73a3d1d93781) } var fileDescriptor_d72e73a3d1d93781 = []byte{ - // 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, + // 798 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x95, 0x4f, 0x6f, 0xe3, 0x44, + 0x14, 0xc0, 0xeb, 0x26, 0xdb, 0x6c, 0x5f, 0xaa, 0x46, 0x6b, 0xad, 0x90, 0x63, 0x20, 0x29, 0x86, + 0x85, 0xf0, 0xa7, 0x36, 0x9b, 0x05, 0x71, 0x40, 0x48, 0x34, 0x6d, 0xc4, 0xee, 0x21, 0x02, 0x99, + 0xee, 0x1e, 0xb8, 0x44, 0x13, 0xfb, 0xad, 0x63, 0x11, 0xcf, 0x44, 0x33, 0xe3, 0x68, 0xf3, 0x05, + 0x38, 0xaf, 0x10, 0x12, 0x7c, 0x06, 0x4e, 0x7c, 0x8c, 0x3d, 0xee, 0x11, 0xf6, 0x50, 0x50, 0xfb, + 0x45, 0xd0, 0xcc, 0xd8, 0x86, 0xa6, 0x4a, 0x68, 0x39, 0x79, 0xde, 0xdf, 0xf9, 0xbd, 0xf7, 0x66, + 0xc6, 0xb0, 0x87, 0x8b, 0x2c, 0x90, 0xcf, 0xfc, 0x39, 0x67, 0x92, 0xd9, 0x8e, 0xc0, 0x54, 0xaf, + 0x22, 0x36, 0xf3, 0x05, 0xa6, 0xd1, 0x94, 0xa4, 0xd4, 0xc7, 0x45, 0xe6, 0xb6, 0x13, 0xc6, 0x92, + 0x19, 0x06, 0xda, 0x3a, 0xc9, 0x9f, 0x06, 0x84, 0x2e, 0x4d, 0x90, 0x7b, 0x37, 0x61, 0x09, 0xd3, + 0xcb, 0x40, 0xad, 0x0a, 0x6d, 0x27, 0x62, 0x22, 0x63, 0x22, 0x98, 0x10, 0x81, 0xc1, 0xe2, 0xfe, + 0x04, 0x25, 0xb9, 0x1f, 0x44, 0x2c, 0xa5, 0x85, 0xbd, 0xa5, 0x36, 0x46, 0x9a, 0x67, 0xc2, 0x28, + 0xbc, 0x9f, 0x2c, 0xb8, 0x33, 0x12, 0xc9, 0xf0, 0xc9, 0xe8, 0x94, 0x13, 0x2a, 0x48, 0x24, 0x53, + 0x46, 0xed, 0x1e, 0xd4, 0x63, 0x22, 0x89, 0x63, 0x1d, 0x58, 0xbd, 0x66, 0xff, 0xae, 0x6f, 0x30, + 0xfc, 0x12, 0xc3, 0x3f, 0xa2, 0xcb, 0x50, 0x7b, 0xd8, 0x8f, 0xa1, 0x11, 0x23, 0x4f, 0x17, 0x18, + 0x3b, 0xdb, 0x07, 0x56, 0x6f, 0x6f, 0xf0, 0xf9, 0xab, 0xb3, 0xee, 0x67, 0x49, 0x2a, 0xa7, 0xf9, + 0xc4, 0x8f, 0x58, 0x16, 0x08, 0x4c, 0x0f, 0xcb, 0xe2, 0xb4, 0xa0, 0xab, 0x0b, 0x9e, 0x05, 0x8a, + 0xa4, 0x08, 0xf5, 0x4f, 0xcc, 0x37, 0x2c, 0x73, 0x79, 0x3f, 0x58, 0xd0, 0xbe, 0x82, 0x15, 0xa2, + 0x98, 0x33, 0x2a, 0xd0, 0x6e, 0xc3, 0xed, 0x84, 0x88, 0x71, 0x2e, 0x30, 0xd6, 0x88, 0xf5, 0xb0, + 0x91, 0x10, 0xf1, 0x58, 0x60, 0xac, 0x4c, 0x8b, 0x6c, 0x8c, 0x9c, 0x33, 0xae, 0x81, 0x76, 0xc3, + 0xc6, 0x22, 0x1b, 0x2a, 0xd1, 0xee, 0x42, 0x93, 0xa3, 0xcc, 0x39, 0x1d, 0xeb, 0xda, 0x6a, 0x0a, + 0x37, 0x04, 0xa3, 0x3a, 0x51, 0xb5, 0xd8, 0x50, 0x9f, 0x12, 0x31, 0x75, 0xea, 0x3a, 0x4e, 0xaf, + 0xbd, 0x1f, 0x2d, 0xb0, 0x47, 0x22, 0x79, 0x44, 0x25, 0x72, 0x4a, 0x66, 0xc3, 0x27, 0xa3, 0x63, + 0x32, 0x9b, 0xd9, 0xaf, 0xc1, 0x8e, 0x40, 0x1a, 0x23, 0xd7, 0xfb, 0xef, 0x86, 0x85, 0x64, 0x7f, + 0x09, 0xb7, 0x16, 0x64, 0x96, 0xa3, 0xd9, 0x7b, 0xf0, 0xc1, 0xab, 0xb3, 0xee, 0xbb, 0xff, 0x6a, + 0x46, 0x31, 0x1d, 0xf3, 0x39, 0x14, 0xf1, 0xf7, 0x81, 0x5c, 0xce, 0x51, 0xf8, 0x8f, 0xa8, 0x0c, + 0x4d, 0xa0, 0xbd, 0x0f, 0xdb, 0x92, 0x69, 0xb8, 0xdd, 0x70, 0x5b, 0x32, 0x05, 0xa5, 0x71, 0xeb, + 0x1a, 0x57, 0xaf, 0xbd, 0x37, 0xc0, 0xbd, 0xca, 0x54, 0x76, 0xc7, 0xfb, 0xc5, 0x5a, 0x35, 0x9f, + 0xe0, 0x0c, 0x13, 0x22, 0x71, 0x23, 0xba, 0x0b, 0xb7, 0x23, 0x16, 0xe3, 0x43, 0xd5, 0x01, 0x3d, + 0xca, 0xb0, 0x92, 0xaf, 0x03, 0x65, 0x7b, 0xb0, 0xf7, 0x94, 0xb3, 0xec, 0x98, 0x51, 0xc9, 0x49, + 0x24, 0x9d, 0x5b, 0xda, 0xfb, 0x92, 0xce, 0x7b, 0x07, 0xbc, 0xf5, 0x64, 0x55, 0x01, 0xbf, 0x59, + 0xd0, 0x18, 0x89, 0xe4, 0x5b, 0xa4, 0xb1, 0xfd, 0x96, 0xc9, 0x3a, 0x26, 0x71, 0xcc, 0x51, 0x88, + 0x82, 0xb9, 0xa9, 0x74, 0x47, 0x46, 0x65, 0xbf, 0x09, 0x20, 0x59, 0xe5, 0x60, 0x86, 0xbe, 0x2b, + 0x59, 0x69, 0x8e, 0x60, 0x87, 0x64, 0x2c, 0xa7, 0xd2, 0xa9, 0x1d, 0xd4, 0x7a, 0xcd, 0x7e, 0xdb, + 0x37, 0xed, 0xf7, 0xd5, 0x1d, 0xf1, 0x8b, 0x3b, 0xe2, 0x1f, 0xb3, 0x94, 0x0e, 0x3e, 0x7e, 0x71, + 0xd6, 0xdd, 0xfa, 0xf5, 0xcf, 0x6e, 0xef, 0x1a, 0x23, 0x53, 0x01, 0x22, 0x2c, 0x52, 0x7b, 0x77, + 0xa0, 0x55, 0x10, 0x57, 0x55, 0xfc, 0x6c, 0x4e, 0x4e, 0x88, 0x49, 0x2a, 0x24, 0xf2, 0x6f, 0x58, + 0xaa, 0xca, 0x5e, 0xdb, 0xfe, 0x87, 0xb0, 0x37, 0x37, 0x2e, 0x63, 0xb5, 0x81, 0xae, 0x63, 0xbf, + 0x7f, 0xcf, 0x5f, 0xf7, 0x36, 0xf8, 0x45, 0xc2, 0xd3, 0xe5, 0x1c, 0xc3, 0xe6, 0xfc, 0x1f, 0x41, + 0x9d, 0x73, 0xe4, 0x51, 0xd5, 0x10, 0x33, 0x35, 0x40, 0x1e, 0x15, 0x1d, 0xf1, 0x86, 0xfa, 0x7c, + 0xac, 0x80, 0x55, 0x97, 0xeb, 0x3d, 0x68, 0x95, 0x20, 0x97, 0x9b, 0xbe, 0x5f, 0xa8, 0xcb, 0x34, + 0x5f, 0xc3, 0xeb, 0x23, 0x91, 0x1c, 0x09, 0xc1, 0xa2, 0x54, 0x8d, 0xb0, 0x18, 0x72, 0xd9, 0xf7, + 0x75, 0x85, 0x3a, 0xd0, 0xb8, 0x3c, 0xab, 0x52, 0xf4, 0xee, 0xc1, 0xdb, 0x1b, 0x12, 0x96, 0x80, + 0xfd, 0x3f, 0x6a, 0x50, 0x1b, 0x89, 0xc4, 0xe6, 0xb0, 0xbf, 0xf2, 0x6c, 0x7d, 0xb8, 0xbe, 0x5b, + 0x57, 0x1e, 0x13, 0xf7, 0xc1, 0x0d, 0x9c, 0xab, 0xe6, 0x9c, 0x42, 0xdd, 0x1c, 0xcb, 0x8d, 0xc1, + 0xca, 0xc5, 0x7d, 0xff, 0x3f, 0x5d, 0xaa, 0xac, 0x39, 0xb4, 0x56, 0x8f, 0xc9, 0x47, 0x1b, 0xa3, + 0x57, 0xbc, 0xdd, 0x4f, 0x6e, 0xe2, 0x5d, 0x6d, 0xfb, 0xdc, 0x02, 0x67, 0xed, 0xf8, 0x3e, 0xdd, + 0x98, 0x72, 0x5d, 0x98, 0xfb, 0xc5, 0xff, 0x0a, 0x2b, 0x91, 0x06, 0x5f, 0xbd, 0x38, 0xef, 0x58, + 0x2f, 0xcf, 0x3b, 0xd6, 0x5f, 0xe7, 0x1d, 0xeb, 0xf9, 0x45, 0x67, 0xeb, 0xe5, 0x45, 0x67, 0xeb, + 0xf7, 0x8b, 0xce, 0xd6, 0x77, 0x87, 0xd7, 0xfd, 0xa7, 0xe8, 0xeb, 0x39, 0xd9, 0xd1, 0xf6, 0x07, + 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x16, 0xf7, 0xdd, 0x7c, 0x6a, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -635,6 +728,7 @@ 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) + AssociateContractAddress(ctx context.Context, in *MsgAssociateContractAddress, opts ...grpc.CallOption) (*MsgAssociateContractAddressResponse, error) } type msgClient struct { @@ -672,11 +766,21 @@ func (c *msgClient) RegisterPointer(ctx context.Context, in *MsgRegisterPointer, return out, nil } +func (c *msgClient) AssociateContractAddress(ctx context.Context, in *MsgAssociateContractAddress, opts ...grpc.CallOption) (*MsgAssociateContractAddressResponse, error) { + out := new(MsgAssociateContractAddressResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Msg/AssociateContractAddress", 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) + AssociateContractAddress(context.Context, *MsgAssociateContractAddress) (*MsgAssociateContractAddressResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -692,6 +796,9 @@ func (*UnimplementedMsgServer) Send(ctx context.Context, req *MsgSend) (*MsgSend func (*UnimplementedMsgServer) RegisterPointer(ctx context.Context, req *MsgRegisterPointer) (*MsgRegisterPointerResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RegisterPointer not implemented") } +func (*UnimplementedMsgServer) AssociateContractAddress(ctx context.Context, req *MsgAssociateContractAddress) (*MsgAssociateContractAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AssociateContractAddress not implemented") +} func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) @@ -751,6 +858,24 @@ func _Msg_RegisterPointer_Handler(srv interface{}, ctx context.Context, dec func return interceptor(ctx, in, info, handler) } +func _Msg_AssociateContractAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAssociateContractAddress) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).AssociateContractAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Msg/AssociateContractAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).AssociateContractAddress(ctx, req.(*MsgAssociateContractAddress)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "seiprotocol.seichain.evm.Msg", HandlerType: (*MsgServer)(nil), @@ -767,6 +892,10 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "RegisterPointer", Handler: _Msg_RegisterPointer_Handler, }, + { + MethodName: "AssociateContractAddress", + Handler: _Msg_AssociateContractAddress_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "evm/tx.proto", @@ -1174,6 +1303,66 @@ func (m *MsgRegisterPointerResponse) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } +func (m *MsgAssociateContractAddress) 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 *MsgAssociateContractAddress) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAssociateContractAddress) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0x12 + } + 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 *MsgAssociateContractAddressResponse) 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 *MsgAssociateContractAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAssociateContractAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func encodeVarintTx(dAtA []byte, offset int, v uint64) int { offset -= sovTx(v) base := offset @@ -1363,6 +1552,32 @@ func (m *MsgRegisterPointerResponse) Size() (n int) { return n } +func (m *MsgAssociateContractAddress) 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)) + } + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgAssociateContractAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func sovTx(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2568,6 +2783,170 @@ func (m *MsgRegisterPointerResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgAssociateContractAddress) 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: MsgAssociateContractAddress: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAssociateContractAddress: 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 != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 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.Address = 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 *MsgAssociateContractAddressResponse) 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: MsgAssociateContractAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAssociateContractAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTx(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0