diff --git a/.dockerignore b/.dockerignore index 0ccc60fd14..62b03e692c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,4 @@ build/ -.git/ \ No newline at end of file +# The .git folder must be transferred to Docker context since the Makefile +# uses git commands to get the current commit hash and tag for versioning. +# .git/ \ No newline at end of file diff --git a/.github/workflows/compatiblity_check.yml b/.github/workflows/compatiblity_check.yml index 094bfe6715..7002282cda 100644 --- a/.github/workflows/compatiblity_check.yml +++ b/.github/workflows/compatiblity_check.yml @@ -19,11 +19,13 @@ jobs: - name: Check Latest Dependencies run: | - git clone https://github.com/sei-protocol/sei-cosmos.git - git clone https://github.com/sei-protocol/sei-tendermint.git + git clone -b seiv2 https://github.com/sei-protocol/sei-cosmos.git + git clone -b seiv2 https://github.com/sei-protocol/sei-tendermint.git git clone https://github.com/sei-protocol/sei-iavl.git + git clone https://github.com/sei-protocol/go-ethereum.git go mod edit -replace github.com/cosmos/iavl=./sei-iavl go mod edit -replace github.com/tendermint/tendermint=./sei-tendermint go mod edit -replace github.com/cosmos/cosmos-sdk=./sei-cosmos + go mod edit -replace github.com/ethereum/go-ethereum=./go-ethereum go mod tidy make install diff --git a/.github/workflows/eth_blocktests.yml b/.github/workflows/eth_blocktests.yml new file mode 100644 index 0000000000..f85962665e --- /dev/null +++ b/.github/workflows/eth_blocktests.yml @@ -0,0 +1,53 @@ +name: ETH Blocktests + +on: + push: + branches: + - seiv2 + pull_request: + branches: + - seiv2 + +defaults: + run: + shell: bash + +env: + TOTAL_RUNNERS: 5 + +jobs: + runner-indexes: + runs-on: ubuntu-latest + name: Generate runner indexes + outputs: + json: ${{ steps.generate-index-list.outputs.json }} + steps: + - id: generate-index-list + run: | + MAX_INDEX=$((${{ env.TOTAL_RUNNERS }}-1)) + INDEX_LIST=$(seq 0 ${MAX_INDEX}) + INDEX_JSON=$(jq --null-input --compact-output '. |= [inputs]' <<< ${INDEX_LIST}) + echo "json=${INDEX_JSON}" >> $GITHUB_OUTPUT + + eth-blocktests: + name: "Run ETH Blocktests ${{ matrix.runner-index }}" + runs-on: ubuntu-latest + needs: runner-indexes + strategy: + fail-fast: false + matrix: + # generate runner index array from 0 to total-runners + runner-index: ${{fromJson(needs.runner-indexes.outputs.json)}} + steps: + - uses: actions/checkout@v2 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.21 + + - name: Clone ETH Blocktests + run: git clone https://github.com/ethereum/tests.git ethtests + + - name: "Run ETH Blocktest" + run: ./run_blocktests.sh ./ethtests/BlockchainTests/ ${{ matrix.runner-index }} ${{ env.TOTAL_RUNNERS }} diff --git a/.github/workflows/forge-test.yml b/.github/workflows/forge-test.yml new file mode 100644 index 0000000000..f104ac3b51 --- /dev/null +++ b/.github/workflows/forge-test.yml @@ -0,0 +1,40 @@ +name: Forge test + +on: + pull_request: + push: + branches: + - main + - evm + - release/** + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + strategy: + fail-fast: true + + name: Foundry project + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Run Forge build + run: | + forge --version + forge build --sizes + id: build + + - name: Run Forge tests + run: | + forge test -vvv + id: test diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index f743e32a1e..c7d5145508 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -12,6 +12,7 @@ on: branches: - main - seiv2 + - evm defaults: run: @@ -73,7 +74,6 @@ jobs: "python3 integration_test/scripts/runner.py integration_test/chain_operation/snapshot_operation.yaml", "python3 integration_test/scripts/runner.py integration_test/chain_operation/statesync_operation.yaml" ] - }, { name: "Distribution Module", @@ -96,6 +96,21 @@ jobs: "python3 integration_test/scripts/runner.py integration_test/upgrade_module/minor_upgrade_test.yaml" ] }, + { + name: "SeiDB State Store", + scripts: [ + "docker exec sei-node-0 integration_test/contracts/deploy_wasm_contracts.sh", + "docker exec sei-node-0 integration_test/contracts/create_tokenfactory_denoms.sh", + "python3 integration_test/scripts/runner.py integration_test/seidb/state_store_test.yaml", + ], + }, + { + name: "Hardhat tests", + scripts: [ + "python3 integration_test/scripts/runner.py integration_test/evm_module/hardhat_test.yaml", + "./scripts/hardhat.sh" + ] + }, { name: "SeiDB State Store", scripts: [ @@ -110,6 +125,9 @@ jobs: - uses: actions/setup-python@v4 with: python-version: '3.10' + - uses: actions/setup-node@v2 + with: + node-version: '16' - name: Pyyaml run: | diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 068da19bb8..bcab13f140 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -7,6 +7,7 @@ on: branches: - main - seiv2 + - evm - release/** jobs: diff --git a/.gitignore b/.gitignore index 5e375ff79c..ada3dc4f6d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,9 @@ release/ .vscode/ .DS_Store build/ +cache/ -Local .terraform directories +# Local .terraform directories **/.terraform # .tfstate files @@ -18,8 +19,6 @@ yarn.lock # node ignores oracle/node_modules/ node_modules/ -package-lock.json -*/package-lock.json # test coverage output c.out @@ -44,4 +43,12 @@ integration_test/**/*.txt # Coverage Files coverage.html -coverage.out \ No newline at end of file +coverage.out + +# example artifacts +example/cosmwasm/echo/target +example/cosmwasm/cw20/target +example/cosmwasm/cw721/target + +# Solidity contracts artifacts +contracts/artifacts diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..21f4949ec2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "contracts/lib/forge-std"] + path = contracts/lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "contracts/lib/openzeppelin-contracts"] + path = contracts/lib/openzeppelin-contracts + url = https://github.com/openzeppelin/openzeppelin-contracts +[submodule "loadtest/contracts/evm/lib/openzeppelin-contracts"] + path = loadtest/contracts/evm/lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts +[submodule "loadtest/contracts/evm/lib/solmate"] + path = loadtest/contracts/evm/lib/solmate + url = https://github.com/transmissions11/solmate diff --git a/.golangci.yml b/.golangci.yml index 22ed892fc0..6490cac8c8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -15,7 +15,7 @@ linters: - exportloopref - errcheck - goconst - - gocritic + # - gocritic - gofmt - goimports - gosec @@ -23,16 +23,16 @@ linters: - govet - ineffassign - misspell - - nakedret + # - nakedret - prealloc - staticcheck # - structcheck ## author abandoned project - stylecheck # - revive - - typecheck + # - typecheck - unconvert - - unused - - unparam + # - unused + # - unparam - misspell # - nolintlint ## does not work with IDEs like VSCode which automatically insert leading spaces diff --git a/Makefile b/Makefile index eb1dd41a4b..9fe5706065 100644 --- a/Makefile +++ b/Makefile @@ -98,6 +98,8 @@ build-price-feeder: clean: rm -rf ./build +build-loadtest: + go build -o build/loadtest ./loadtest/ ############################################################################### diff --git a/aclmapping/dependency_generator.go b/aclmapping/dependency_generator.go index dcea1baf3f..8a8cabe811 100644 --- a/aclmapping/dependency_generator.go +++ b/aclmapping/dependency_generator.go @@ -4,9 +4,11 @@ import ( aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" aclbankmapping "github.com/sei-protocol/sei-chain/aclmapping/bank" acldexmapping "github.com/sei-protocol/sei-chain/aclmapping/dex" + aclevmmapping "github.com/sei-protocol/sei-chain/aclmapping/evm" acloraclemapping "github.com/sei-protocol/sei-chain/aclmapping/oracle" acltokenfactorymapping "github.com/sei-protocol/sei-chain/aclmapping/tokenfactory" aclwasmmapping "github.com/sei-protocol/sei-chain/aclmapping/wasm" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" ) type CustomDependencyGenerator struct{} @@ -15,7 +17,7 @@ func NewCustomDependencyGenerator() CustomDependencyGenerator { return CustomDependencyGenerator{} } -func (customDepGen CustomDependencyGenerator) GetCustomDependencyGenerators() aclkeeper.DependencyGeneratorMap { +func (customDepGen CustomDependencyGenerator) GetCustomDependencyGenerators(evmKeeper evmkeeper.Keeper) aclkeeper.DependencyGeneratorMap { dependencyGeneratorMap := make(aclkeeper.DependencyGeneratorMap) wasmDependencyGenerators := aclwasmmapping.NewWasmDependencyGenerator() @@ -24,6 +26,7 @@ func (customDepGen CustomDependencyGenerator) GetCustomDependencyGenerators() ac dependencyGeneratorMap = dependencyGeneratorMap.Merge(acltokenfactorymapping.GetTokenFactoryDependencyGenerators()) dependencyGeneratorMap = dependencyGeneratorMap.Merge(wasmDependencyGenerators.GetWasmDependencyGenerators()) dependencyGeneratorMap = dependencyGeneratorMap.Merge(acloraclemapping.GetOracleDependencyGenerator()) + dependencyGeneratorMap = dependencyGeneratorMap.Merge(aclevmmapping.GetEVMDependencyGenerators(evmKeeper)) return dependencyGeneratorMap } diff --git a/aclmapping/dex/mappings_test.go b/aclmapping/dex/mappings_test.go index 7504f51ecc..68634a319d 100644 --- a/aclmapping/dex/mappings_test.go +++ b/aclmapping/dex/mappings_test.go @@ -242,7 +242,7 @@ func (suite *KeeperTestSuite) TestMsgCancelOrder() { func TestGeneratorInvalidMessageTypes(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) oracleVote := oracletypes.MsgAggregateExchangeRateVote{ ExchangeRates: "1usei", diff --git a/aclmapping/evm/mappings.go b/aclmapping/evm/mappings.go new file mode 100644 index 0000000000..c1715dda93 --- /dev/null +++ b/aclmapping/evm/mappings.go @@ -0,0 +1,147 @@ +package evm + +import ( + "encoding/hex" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" + aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" + acltypes "github.com/cosmos/cosmos-sdk/x/accesscontrol/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/sei-protocol/sei-chain/x/evm/ante" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" +) + +var ErrInvalidMessageType = fmt.Errorf("invalid message received for EVM Module") + +func GetEVMDependencyGenerators(evmKeeper evmkeeper.Keeper) aclkeeper.DependencyGeneratorMap { + dependencyGeneratorMap := make(aclkeeper.DependencyGeneratorMap) + EVMTransactionMsgKey := acltypes.GenerateMessageKey(&evmtypes.MsgEVMTransaction{}) + dependencyGeneratorMap[EVMTransactionMsgKey] = func(k aclkeeper.Keeper, ctx sdk.Context, msg sdk.Msg) ([]sdkacltypes.AccessOperation, error) { + return TransactionDependencyGenerator(k, evmKeeper, ctx, msg) + } + + return dependencyGeneratorMap +} + +func TransactionDependencyGenerator(_ aclkeeper.Keeper, evmKeeper evmkeeper.Keeper, ctx sdk.Context, msg sdk.Msg) ([]sdkacltypes.AccessOperation, error) { + evmMsg, ok := msg.(*evmtypes.MsgEVMTransaction) + if !ok { + return []sdkacltypes.AccessOperation{}, ErrInvalidMessageType + } + if evmMsg.IsAssociateTx() { + // msg server will be noop for AssociateTx; all work are done in ante + return []sdkacltypes.AccessOperation{*acltypes.CommitAccessOp()}, nil + } + + if err := ante.Preprocess(ctx, evmMsg); err != nil { + return []sdkacltypes.AccessOperation{}, err + } + ops := []sdkacltypes.AccessOperation{} + ops = appendRWBalanceOps(ops, state.GetCoinbaseAddress(ctx.TxIndex())) + sender := evmMsg.Derived.SenderSeiAddr + ops = appendRWBalanceOps(ops, sender) + ops = append(ops, + sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_BANK_WEI_BALANCE, + IdentifierTemplate: hex.EncodeToString(append(banktypes.WeiBalancesPrefix, sender...)), + }, + ) + + tx, _ := evmMsg.AsTransaction() + toAddress := tx.To() + if toAddress != nil { + seiAddress := evmKeeper.GetSeiAddressOrDefault(ctx, *toAddress) + ops = appendRWBalanceOps(ops, seiAddress) + ops = append(ops, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_E2S, + IdentifierTemplate: hex.EncodeToString(evmtypes.EVMAddressToSeiAddressKey(*toAddress)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_CODE_HASH, + IdentifierTemplate: hex.EncodeToString(append(evmtypes.CodeHashKeyPrefix, toAddress[:]...)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_CODE, + IdentifierTemplate: hex.EncodeToString(append(evmtypes.CodeKeyPrefix, toAddress[:]...)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_CODE_SIZE, + IdentifierTemplate: hex.EncodeToString(append(evmtypes.CodeSizeKeyPrefix, toAddress[:]...)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_NONCE, + IdentifierTemplate: hex.EncodeToString(append(evmtypes.NonceKeyPrefix, toAddress[:]...)), + }) + } + + evmAddr := evmMsg.Derived.SenderEVMAddr + return append(ops, []sdkacltypes.AccessOperation{ + { + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_NONCE, + IdentifierTemplate: hex.EncodeToString(append(evmtypes.NonceKeyPrefix, evmAddr[:]...)), + }, + { + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_EVM_NONCE, + IdentifierTemplate: hex.EncodeToString(append(evmtypes.NonceKeyPrefix, evmAddr[:]...)), + }, + { + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_EVM_RECEIPT, + IdentifierTemplate: hex.EncodeToString(evmtypes.ReceiptKey(tx.Hash())), + }, + { + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_S2E, + IdentifierTemplate: hex.EncodeToString(evmtypes.SeiAddressToEVMAddressKey(evmKeeper.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName))), + }, + { + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_E2S, + IdentifierTemplate: hex.EncodeToString(evmtypes.EVMAddressToSeiAddressKey(evmAddr)), + }, + { + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_S2E, + IdentifierTemplate: hex.EncodeToString(evmtypes.SeiAddressToEVMAddressKey(evmMsg.Derived.SenderSeiAddr)), + }, + { + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_CODE_HASH, + IdentifierTemplate: hex.EncodeToString(append(evmtypes.CodeHashKeyPrefix, evmAddr[:]...)), + }, + // TODO: maybe we modify this in the future but for now because evm doesnt use parallelv1 its fine to do this way + {AccessType: sdkacltypes.AccessType_UNKNOWN, ResourceType: sdkacltypes.ResourceType_ANY, IdentifierTemplate: "*"}, + + // Last Operation should always be a commit + *acltypes.CommitAccessOp(), + }...), nil +} + +func appendRWBalanceOps(ops []sdkacltypes.AccessOperation, addr sdk.AccAddress) []sdkacltypes.AccessOperation { + idTempl := hex.EncodeToString(banktypes.CreateAccountBalancesPrefix(addr)) + return append(ops, + sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, + IdentifierTemplate: idTempl, + }, + sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, + IdentifierTemplate: idTempl, + }, + sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_AUTH_ADDRESS_STORE, + IdentifierTemplate: hex.EncodeToString(authtypes.AddressStoreKey(addr)), + }) +} diff --git a/aclmapping/evm/mappings_test.go b/aclmapping/evm/mappings_test.go new file mode 100644 index 0000000000..fb56460aa1 --- /dev/null +++ b/aclmapping/evm/mappings_test.go @@ -0,0 +1,143 @@ +package evm_test + +import ( + "crypto/ecdsa" + "encoding/hex" + "fmt" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" + "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/aclmapping/evm" + aclutils "github.com/sei-protocol/sei-chain/aclmapping/utils" + "github.com/sei-protocol/sei-chain/app/apptesting" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/suite" +) + +type KeeperTestSuite struct { + apptesting.KeeperTestHelper + + queryClient types.QueryClient + msgServer types.MsgServer + preprocessor sdk.AnteDecorator + + sender *ecdsa.PrivateKey + associatedAcc common.Address + unassociatedAcc common.Address +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +// Runs before each test case +func (suite *KeeperTestSuite) SetupTest() { + suite.Setup() +} + +// Explicitly only run once during setup +func (suite *KeeperTestSuite) PrepareTest() { + pk := testkeeper.MockPrivateKey() + key, err := crypto.HexToECDSA(hex.EncodeToString(pk.Bytes())) + if err != nil { + panic(err) + } + suite.sender = key + _, suite.unassociatedAcc = testkeeper.MockAddressPair() + seiAddr, associatedAcc := testkeeper.MockAddressPair() + suite.App.EvmKeeper.SetAddressMapping(suite.Ctx, seiAddr, associatedAcc) + suite.associatedAcc = associatedAcc + suite.msgServer = keeper.NewMsgServerImpl(&suite.App.EvmKeeper) + suite.preprocessor = ante.NewEVMPreprocessDecorator(&suite.App.EvmKeeper, &suite.App.AccountKeeper) + amt := sdk.NewCoins(sdk.NewCoin(suite.App.EvmKeeper.GetBaseDenom(suite.Ctx), sdk.NewInt(1000000))) + suite.App.EvmKeeper.BankKeeper().MintCoins(suite.Ctx, types.ModuleName, amt) + suite.App.EvmKeeper.BankKeeper().SendCoinsFromModuleToAccount(suite.Ctx, types.ModuleName, sdk.AccAddress(pk.PubKey().Address()), amt) + + msgValidator := sdkacltypes.NewMsgValidator(aclutils.StoreKeyToResourceTypePrefixMap) + suite.Ctx = suite.Ctx.WithMsgValidator(msgValidator) +} + +func cacheTxContext(ctx sdk.Context) (sdk.Context, sdk.CacheMultiStore) { + ms := ctx.MultiStore() + msCache := ms.CacheMultiStore() + return ctx.WithMultiStore(msCache), msCache +} + +func (suite *KeeperTestSuite) buildSendMsgTo(to common.Address, amt *big.Int) *types.MsgEVMTransaction { + txData := ethtypes.DynamicFeeTx{ + Nonce: 0, + GasFeeCap: big.NewInt(1000000000), + Gas: 30000, + To: &to, + Value: amt, + Data: []byte(""), + ChainID: suite.App.EvmKeeper.ChainID(suite.Ctx), + } + ethCfg := types.DefaultChainConfig().EthereumConfig(suite.App.EvmKeeper.ChainID(suite.Ctx)) + signer := ethtypes.MakeSigner(ethCfg, big.NewInt(suite.Ctx.BlockHeight()), uint64(suite.Ctx.BlockTime().Unix())) + tx := ethtypes.NewTx(&txData) + tx, err := ethtypes.SignTx(tx, signer, suite.sender) + if err != nil { + panic(err) + } + typedTxData, err := ethtx.NewTxDataFromTx(tx) + if err != nil { + panic(err) + } + msg, err := types.NewMsgEVMTransaction(typedTxData) + if err != nil { + panic(err) + } + + return msg +} + +func (suite *KeeperTestSuite) TestMsgEVMTransaction() { + suite.PrepareTest() + + tests := []struct { + name string + msg *types.MsgEVMTransaction + }{ + { + name: "associated to", + msg: suite.buildSendMsgTo(suite.associatedAcc, big.NewInt(1000000000000)), + }, + { + name: "unassociated to", + msg: suite.buildSendMsgTo(suite.unassociatedAcc, big.NewInt(1000000000000)), + }, + } + for _, tc := range tests { + suite.Run(fmt.Sprintf("Test Case: %s", tc.name), func() { + handlerCtx, cms := cacheTxContext(suite.Ctx) + tx := suite.App.GetTxConfig().NewTxBuilder() + err := tx.SetMsgs(tc.msg) + suite.Require().Nil(err) + ctx, err := suite.preprocessor.AnteHandle(handlerCtx, tx.GetTx(), false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { return ctx, nil }) + suite.Require().Nil(err) + cms.ResetEvents() + _, err = suite.msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), tc.msg) + suite.Require().Nil(err) + + dependencies, _ := evm.TransactionDependencyGenerator( + suite.App.AccessControlKeeper, + suite.App.EvmKeeper, + handlerCtx, + tc.msg, + ) + + missing := handlerCtx.MsgValidator().ValidateAccessOperations(dependencies, cms.GetEvents()) + suite.Require().Empty(missing) + }) + } +} diff --git a/aclmapping/oracle/mappings_test.go b/aclmapping/oracle/mappings_test.go index 8c67854dd3..86d034f9df 100644 --- a/aclmapping/oracle/mappings_test.go +++ b/aclmapping/oracle/mappings_test.go @@ -129,7 +129,7 @@ func TestMsgVoteDependencyGenerator(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) oracleVote := oracletypes.MsgAggregateExchangeRateVote{ ExchangeRates: "1usei", @@ -147,7 +147,7 @@ func TestMsgVoteDependencyGeneratorInvalidMsgType(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) _, err := oracleacl.MsgVoteDependencyGenerator(testWrapper.App.AccessControlKeeper, testWrapper.Ctx, &banktypes.MsgSend{}) require.Error(t, err) } diff --git a/aclmapping/staking/mappings_test.go b/aclmapping/staking/mappings_test.go index 14ac839da6..3e0332771c 100644 --- a/aclmapping/staking/mappings_test.go +++ b/aclmapping/staking/mappings_test.go @@ -279,7 +279,7 @@ func (suite *KeeperTestSuite) TestMsgDelegateDependencies() { func TestGeneratorInvalidMessageTypes(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) stakingDelegate := stakingtypes.MsgDelegate{ DelegatorAddress: "delegator", diff --git a/aclmapping/utils/resource_type.go b/aclmapping/utils/resource_type.go index 3d168a90e7..34fd3cbd60 100644 --- a/aclmapping/utils/resource_type.go +++ b/aclmapping/utils/resource_type.go @@ -14,6 +14,7 @@ import ( dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" dextypes "github.com/sei-protocol/sei-chain/x/dex/types" epochtypes "github.com/sei-protocol/sei-chain/x/epoch/types" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" tokenfactorytypes "github.com/sei-protocol/sei-chain/x/tokenfactory/types" ) @@ -63,10 +64,11 @@ var StoreKeyToResourceTypePrefixMap = aclsdktypes.StoreKeyToResourceTypePrefixMa aclsdktypes.ResourceType_KV_DEX_MEM_DOWNSTREAM_CONTRACTS: dextypes.KeyPrefix(dextypes.MemDownstreamContracts), }, banktypes.StoreKey: { - aclsdktypes.ResourceType_KV_BANK: aclsdktypes.EmptyPrefix, - aclsdktypes.ResourceType_KV_BANK_BALANCES: banktypes.BalancesPrefix, - aclsdktypes.ResourceType_KV_BANK_SUPPLY: banktypes.SupplyKey, - aclsdktypes.ResourceType_KV_BANK_DENOM: banktypes.DenomMetadataPrefix, + aclsdktypes.ResourceType_KV_BANK: aclsdktypes.EmptyPrefix, + aclsdktypes.ResourceType_KV_BANK_BALANCES: banktypes.BalancesPrefix, + aclsdktypes.ResourceType_KV_BANK_SUPPLY: banktypes.SupplyKey, + aclsdktypes.ResourceType_KV_BANK_DENOM: banktypes.DenomMetadataPrefix, + aclsdktypes.ResourceType_KV_BANK_WEI_BALANCE: banktypes.WeiBalancesPrefix, }, banktypes.DeferredCacheStoreKey: { aclsdktypes.ResourceType_KV_BANK_DEFERRED: aclsdktypes.EmptyPrefix, @@ -152,6 +154,20 @@ var StoreKeyToResourceTypePrefixMap = aclsdktypes.StoreKeyToResourceTypePrefixMa aclsdktypes.ResourceType_KV_WASM_CONTRACT_BY_CODE_ID: wasmtypes.ContractByCodeIDAndCreatedSecondaryIndexPrefix, aclsdktypes.ResourceType_KV_WASM_PINNED_CODE_INDEX: wasmtypes.PinnedCodeIndexPrefix, }, + evmtypes.StoreKey: { + aclsdktypes.ResourceType_KV_EVM: aclsdktypes.EmptyPrefix, + aclsdktypes.ResourceType_KV_EVM_BALANCE: aclsdktypes.EmptyPrefix, // EVM_BALANCE is deprecated and not used anymore + aclsdktypes.ResourceType_KV_EVM_TRANSIENT: evmtypes.TransientStateKeyPrefix, + aclsdktypes.ResourceType_KV_EVM_ACCOUNT_TRANSIENT: evmtypes.AccountTransientStateKeyPrefix, + aclsdktypes.ResourceType_KV_EVM_MODULE_TRANSIENT: evmtypes.TransientModuleStateKeyPrefix, + aclsdktypes.ResourceType_KV_EVM_NONCE: evmtypes.NonceKeyPrefix, + aclsdktypes.ResourceType_KV_EVM_RECEIPT: evmtypes.ReceiptKeyPrefix, + aclsdktypes.ResourceType_KV_EVM_S2E: evmtypes.SeiAddressToEVMAddressKeyPrefix, + aclsdktypes.ResourceType_KV_EVM_E2S: evmtypes.EVMAddressToSeiAddressKeyPrefix, + aclsdktypes.ResourceType_KV_EVM_CODE_HASH: evmtypes.CodeHashKeyPrefix, + aclsdktypes.ResourceType_KV_EVM_CODE: evmtypes.CodeKeyPrefix, + aclsdktypes.ResourceType_KV_EVM_CODE_SIZE: evmtypes.CodeSizeKeyPrefix, + }, } // ResourceTypeToStoreKeyMap this maps between resource types and their respective storekey @@ -192,10 +208,11 @@ var ResourceTypeToStoreKeyMap = aclsdktypes.ResourceTypeToStoreKeyMap{ aclsdktypes.ResourceType_KV_DEX_MEM_DOWNSTREAM_CONTRACTS: dextypes.MemStoreKey, // ~~~~ BANK Resource Types ~~~~ - aclsdktypes.ResourceType_KV_BANK: banktypes.StoreKey, - aclsdktypes.ResourceType_KV_BANK_BALANCES: banktypes.StoreKey, - aclsdktypes.ResourceType_KV_BANK_SUPPLY: banktypes.StoreKey, - aclsdktypes.ResourceType_KV_BANK_DENOM: banktypes.StoreKey, + aclsdktypes.ResourceType_KV_BANK: banktypes.StoreKey, + aclsdktypes.ResourceType_KV_BANK_BALANCES: banktypes.StoreKey, + aclsdktypes.ResourceType_KV_BANK_SUPPLY: banktypes.StoreKey, + aclsdktypes.ResourceType_KV_BANK_DENOM: banktypes.StoreKey, + aclsdktypes.ResourceType_KV_BANK_WEI_BALANCE: banktypes.StoreKey, // ~~~~ BANK DEFERRED Resource Types ~~~~ aclsdktypes.ResourceType_KV_BANK_DEFERRED: banktypes.DeferredCacheStoreKey, @@ -280,4 +297,18 @@ var ResourceTypeToStoreKeyMap = aclsdktypes.ResourceTypeToStoreKeyMap{ aclsdktypes.ResourceType_KV_WASM_CONTRACT_CODE_HISTORY: wasmtypes.StoreKey, aclsdktypes.ResourceType_KV_WASM_CONTRACT_BY_CODE_ID: wasmtypes.StoreKey, aclsdktypes.ResourceType_KV_WASM_PINNED_CODE_INDEX: wasmtypes.StoreKey, + + // ~~~~ EVM Resource Types ~~~~ + aclsdktypes.ResourceType_KV_EVM: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_BALANCE: evmtypes.StoreKey, // EVM_BALANCE is deprecated and not used anymore + aclsdktypes.ResourceType_KV_EVM_TRANSIENT: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_ACCOUNT_TRANSIENT: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_MODULE_TRANSIENT: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_NONCE: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_RECEIPT: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_S2E: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_E2S: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_CODE_HASH: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_CODE: evmtypes.StoreKey, + aclsdktypes.ResourceType_KV_EVM_CODE_SIZE: evmtypes.StoreKey, } diff --git a/app/abci.go b/app/abci.go index ab50ffb9ed..b01e210e16 100644 --- a/app/abci.go +++ b/app/abci.go @@ -32,13 +32,13 @@ func (app *App) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) (res abci.Re return app.BaseApp.EndBlock(ctx, req) } -func (app *App) CheckTx(ctx context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { +func (app *App) CheckTx(ctx context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTxV2, error) { _, span := app.GetBaseApp().TracingInfo.Start("CheckTx") defer span.End() return app.BaseApp.CheckTx(ctx, req) } -func (app *App) DeliverTx(ctx sdk.Context, req abci.RequestDeliverTx) abci.ResponseDeliverTx { +func (app *App) DeliverTx(ctx sdk.Context, req abci.RequestDeliverTx, tx sdk.Tx, checksum [32]byte) abci.ResponseDeliverTx { defer metrics.MeasureDeliverTxDuration(time.Now()) // ensure we carry the initial context from tracer here ctx = ctx.WithTraceSpanContext(app.GetBaseApp().TracingInfo.GetContext()) @@ -46,7 +46,7 @@ func (app *App) DeliverTx(ctx sdk.Context, req abci.RequestDeliverTx) abci.Respo defer span.End() // update context with trace span new context ctx = ctx.WithTraceSpanContext(spanCtx) - return app.BaseApp.DeliverTx(ctx, req) + return app.BaseApp.DeliverTx(ctx, req, tx, checksum) } // DeliverTxBatch is not part of the ABCI specification, but this is here for code convention diff --git a/app/ante.go b/app/ante.go index 84df9f88f7..3daab30e00 100644 --- a/app/ante.go +++ b/app/ante.go @@ -17,6 +17,8 @@ import ( "github.com/sei-protocol/sei-chain/x/dex" dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" + evmante "github.com/sei-protocol/sei-chain/x/evm/ante" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" "github.com/sei-protocol/sei-chain/x/oracle" oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper" ) @@ -32,8 +34,10 @@ type HandlerOptions struct { OracleKeeper *oraclekeeper.Keeper DexKeeper *dexkeeper.Keeper AccessControlKeeper *aclkeeper.Keeper + EVMKeeper *evmkeeper.Keeper TXCounterStoreKey sdk.StoreKey CheckTxMemState *dexcache.MemState + LatestCtxGetter func() sdk.Context TracingInfo *tracing.Info } @@ -66,6 +70,15 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk if options.CheckTxMemState == nil { return nil, nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "checktx memstate is required for ante builder") } + if options.EVMKeeper == nil { + return nil, nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "evm keeper is required for ante builder") + } + if options.ParamsKeeper == nil { + return nil, nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "params keeper is required for ante builder") + } + if options.LatestCtxGetter == nil { + return nil, nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "latest context getter is required for ante builder") + } sigGasConsumer := options.SigGasConsumer if sigGasConsumer == nil { @@ -75,9 +88,9 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk sequentialVerifyDecorator := ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler) anteDecorators := []sdk.AnteFullDecorator{ - sdk.CustomDepWrappedAnteDecorator(ante.NewSetUpContextDecorator(antedecorators.GetGasMeterSetter(*options.AccessControlKeeper)), depdecorators.GasMeterSetterDecorator{}), // outermost AnteDecorator. SetUpContext must be called first + sdk.CustomDepWrappedAnteDecorator(ante.NewSetUpContextDecorator(antedecorators.GetGasMeterSetter(options.ParamsKeeper.(paramskeeper.Keeper))), depdecorators.GasMeterSetterDecorator{}), // outermost AnteDecorator. SetUpContext must be called first antedecorators.NewGaslessDecorator([]sdk.AnteFullDecorator{ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.ParamsKeeper.(paramskeeper.Keeper), options.TxFeeChecker)}, *options.OracleKeeper), - sdk.DefaultWrappedAnteDecorator(wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit)), // after setup context to enforce limits early + sdk.DefaultWrappedAnteDecorator(wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit, antedecorators.GetGasMeterSetter(options.ParamsKeeper.(paramskeeper.Keeper)))), // after setup context to enforce limits early sdk.DefaultWrappedAnteDecorator(ante.NewRejectExtensionOptionsDecorator()), oracle.NewSpammingPreventionDecorator(*options.OracleKeeper), oracle.NewOracleVoteAloneDecorator(), @@ -93,6 +106,8 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk sdk.CustomDepWrappedAnteDecorator(ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), depdecorators.SignerDepDecorator{ReadOnly: true}), sdk.CustomDepWrappedAnteDecorator(sequentialVerifyDecorator, depdecorators.SignerDepDecorator{ReadOnly: true}), sdk.CustomDepWrappedAnteDecorator(ante.NewIncrementSequenceDecorator(options.AccountKeeper), depdecorators.SignerDepDecorator{ReadOnly: false}), + sdk.DefaultWrappedAnteDecorator(evmante.NewEVMAddressDecorator(options.EVMKeeper, options.EVMKeeper.AccountKeeper())), + sdk.DefaultWrappedAnteDecorator(antedecorators.NewAuthzNestedMessageDecorator()), sdk.DefaultWrappedAnteDecorator(ibcante.NewAnteDecorator(options.IBCKeeper)), sdk.DefaultWrappedAnteDecorator(dex.NewTickSizeMultipleDecorator(*options.DexKeeper)), dex.NewCheckDexGasDecorator(*options.DexKeeper, options.CheckTxMemState), @@ -101,5 +116,17 @@ func NewAnteHandlerAndDepGenerator(options HandlerOptions) (sdk.AnteHandler, sdk anteHandler, anteDepGenerator := sdk.ChainAnteDecorators(anteDecorators...) - return anteHandler, anteDepGenerator, nil + evmAnteDecorators := []sdk.AnteFullDecorator{ + evmante.NewEVMPreprocessDecorator(options.EVMKeeper, options.EVMKeeper.AccountKeeper()), + sdk.DefaultWrappedAnteDecorator(evmante.NewBasicDecorator()), + sdk.DefaultWrappedAnteDecorator(evmante.NewEVMFeeCheckDecorator(options.EVMKeeper)), + sdk.DefaultWrappedAnteDecorator(evmante.NewEVMSigVerifyDecorator(options.EVMKeeper, options.LatestCtxGetter)), + sdk.DefaultWrappedAnteDecorator(evmante.NewGasLimitDecorator(options.EVMKeeper)), + } + evmAnteHandler, evmAnteDepGenerator := sdk.ChainAnteDecorators(evmAnteDecorators...) + evmAnteHandler = evmante.NewAnteErrorHandler(evmAnteHandler, options.EVMKeeper).Handle + + router := evmante.NewEVMRouterDecorator(anteHandler, evmAnteHandler, anteDepGenerator, evmAnteDepGenerator) + + return router.AnteHandle, router.AnteDeps, nil } diff --git a/app/ante_test.go b/app/ante_test.go index 19856499e3..91b6bc9324 100644 --- a/app/ante_test.go +++ b/app/ante_test.go @@ -2,6 +2,9 @@ package app_test import ( "context" + "crypto/sha256" + "encoding/hex" + "math/big" "testing" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" @@ -18,11 +21,18 @@ import ( "github.com/cosmos/cosmos-sdk/utils/tracing" "github.com/cosmos/cosmos-sdk/x/auth/ante" xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" aclutils "github.com/sei-protocol/sei-chain/aclmapping/utils" app "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/app/apptesting" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" "go.opentelemetry.io/otel" ) @@ -93,6 +103,8 @@ func (suite *AnteTestSuite) SetupTest(isCheckTx bool) { AccessControlKeeper: &suite.App.AccessControlKeeper, TracingInfo: tracingInfo, CheckTxMemState: suite.App.CheckTxMemState, + EVMKeeper: &suite.App.EvmKeeper, + LatestCtxGetter: func() sdk.Context { return suite.Ctx }, }, ) @@ -210,3 +222,45 @@ func (suite *AnteTestSuite) TestValidateDepedencies() { suite.Require().Nil(err, "ValidateBasicDecorator ran on ReCheck") } + +func TestEvmAnteErrorHandler(t *testing.T) { + ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{}) + 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: []byte{}, + Nonce: 1, // will cause ante error + } + chainID := testkeeper.EVMTestApp.EvmKeeper.ChainID(ctx) + chainCfg := evmtypes.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) + builder := testkeeper.EVMTestApp.GetTxConfig().NewTxBuilder() + builder.SetMsgs(req) + txToSend := builder.GetTx() + encodedTx, err := testkeeper.EVMTestApp.GetTxConfig().TxEncoder()(txToSend) + require.Nil(t, err) + + addr, _ := testkeeper.PrivateKeyToAddresses(privKey) + testkeeper.EVMTestApp.BankKeeper.AddCoins(ctx, addr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100000000000))), true) + res := testkeeper.EVMTestApp.DeliverTx(ctx, abci.RequestDeliverTx{Tx: encodedTx}, txToSend, sha256.Sum256(encodedTx)) + require.NotEqual(t, 0, res.Code) + testkeeper.EVMTestApp.EvmKeeper.SetTxResults([]*abci.ExecTxResult{{ + Code: res.Code, + }}) + deferredInfo := testkeeper.EVMTestApp.EvmKeeper.GetEVMTxDeferredInfo(ctx) + require.Equal(t, 1, len(deferredInfo)) + require.Equal(t, "incorrect account sequence", deferredInfo[0].Error) +} diff --git a/app/antedecorators/authz_nested_message.go b/app/antedecorators/authz_nested_message.go new file mode 100644 index 0000000000..a7d4957e96 --- /dev/null +++ b/app/antedecorators/authz_nested_message.go @@ -0,0 +1,63 @@ +package antedecorators + +import ( + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" +) + +type AuthzNestedMessageDecorator struct{} + +func NewAuthzNestedMessageDecorator() AuthzNestedMessageDecorator { + return AuthzNestedMessageDecorator{} +} + +func (ad AuthzNestedMessageDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + for _, msg := range tx.GetMsgs() { + switch m := msg.(type) { + case *authz.MsgExec: + // find nested evm messages + containsEvm, err := ad.CheckAuthzContainsEvm(ctx, m) + if err != nil { + return ctx, err + } + if containsEvm { + return ctx, errors.New("permission denied, authz tx contains evm message") + } + default: + continue + } + } + + return next(ctx, tx, simulate) +} + +func (ad AuthzNestedMessageDecorator) CheckAuthzContainsEvm(ctx sdk.Context, authzMsg *authz.MsgExec) (bool, error) { + msgs, err := authzMsg.GetMessages() + if err != nil { + return false, err + } + for _, msg := range msgs { + // check if message type is authz exec or evm + switch m := msg.(type) { + case *evmtypes.MsgEVMTransaction: + return true, nil + case *authz.MsgExec: + // find nested to check for evm + valid, err := ad.CheckAuthzContainsEvm(ctx, m) + + if err != nil { + return false, err + } + + if valid { + return true, nil + } + default: + continue + } + } + return false, nil +} diff --git a/app/antedecorators/authz_nested_message_test.go b/app/antedecorators/authz_nested_message_test.go new file mode 100644 index 0000000000..a1da2ea600 --- /dev/null +++ b/app/antedecorators/authz_nested_message_test.go @@ -0,0 +1,58 @@ +package antedecorators_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/sei-protocol/sei-chain/app/antedecorators" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/secp256k1" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestAuthzNestedEvmMessage(t *testing.T) { + priv1 := secp256k1.GenPrivKey() + addr1 := sdk.AccAddress(priv1.PubKey().Address()) + output = "" + anteDecorators := []sdk.AnteFullDecorator{ + sdk.DefaultWrappedAnteDecorator(antedecorators.NewAuthzNestedMessageDecorator()), + } + ctx := sdk.NewContext(nil, tmproto.Header{}, false, nil) + chainedHandler, _ := sdk.ChainAnteDecorators(anteDecorators...) + + nestedEvmMessage := authz.NewMsgExec(addr1, []sdk.Msg{&evmtypes.MsgEVMTransaction{}}) + // test with nested evm message + _, err := chainedHandler( + ctx.WithPriority(0), + FakeTx{ + FakeMsgs: []sdk.Msg{&nestedEvmMessage}, + }, + false, + ) + require.NotNil(t, err) + + // Multiple nested layers to evm message + doubleNestedEvmMessage := authz.NewMsgExec(addr1, []sdk.Msg{&nestedEvmMessage}) + _, err = chainedHandler( + ctx.WithPriority(0), + FakeTx{ + FakeMsgs: []sdk.Msg{&doubleNestedEvmMessage}, + }, + false, + ) + require.NotNil(t, err) + + // No error + nestedMessage := authz.NewMsgExec(addr1, []sdk.Msg{&banktypes.MsgSend{}}) + _, err = chainedHandler( + ctx.WithPriority(0), + FakeTx{ + FakeMsgs: []sdk.Msg{&nestedMessage}, + }, + false, + ) + require.Nil(t, err) +} diff --git a/app/antedecorators/depdecorators/gas.go b/app/antedecorators/depdecorators/gas.go index 2bfd7e74b8..ef9d479189 100644 --- a/app/antedecorators/depdecorators/gas.go +++ b/app/antedecorators/depdecorators/gas.go @@ -10,6 +10,7 @@ type GasMeterSetterDecorator struct { } func (d GasMeterSetterDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int, next sdk.AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { + // TODO: Remove below since no more wasm dependency discount for _, msg := range tx.GetMsgs() { if _, ok := msg.(*wasmtypes.MsgExecuteContract); ok { // if we have a wasm execute message, we need to declare the dependency to read accesscontrol for giving gas discount diff --git a/app/antedecorators/gas.go b/app/antedecorators/gas.go index 63549d9f19..944449c1a1 100644 --- a/app/antedecorators/gas.go +++ b/app/antedecorators/gas.go @@ -1,82 +1,24 @@ package antedecorators import ( - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" - aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" - acltypes "github.com/cosmos/cosmos-sdk/x/accesscontrol/types" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" ) -const ( - GasMultiplierNumerator uint64 = 1 - DefaultGasMultiplierDenominator uint64 = 1 - WasmCorrectDependencyDiscountDenominator uint64 = 2 -) - -func GetGasMeterSetter(aclkeeper aclkeeper.Keeper) func(bool, sdk.Context, uint64, sdk.Tx) sdk.Context { +func GetGasMeterSetter(pk paramskeeper.Keeper) func(bool, sdk.Context, uint64, sdk.Tx) sdk.Context { return func(simulate bool, ctx sdk.Context, gasLimit uint64, tx sdk.Tx) sdk.Context { - if simulate || ctx.BlockHeight() == 0 { + if ctx.BlockHeight() == 0 { return ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) } - denominator := uint64(1) - updatedGasDenominator := false - for _, msg := range tx.GetMsgs() { - candidateDenominator := getMessageMultiplierDenominator(ctx, msg, aclkeeper) - if !updatedGasDenominator || candidateDenominator < denominator { - updatedGasDenominator = true - denominator = candidateDenominator - } - } - return ctx.WithGasMeter(types.NewMultiplierGasMeter(gasLimit, DefaultGasMultiplierDenominator, denominator)) - } -} + cosmosGasParams := pk.GetCosmosGasParams(ctx) -func getMessageMultiplierDenominator(ctx sdk.Context, msg sdk.Msg, aclKeeper aclkeeper.Keeper) uint64 { - // TODO: reason through whether it's reasonable to require non-* identifier for all operations - // under the context of inter-contract changes - // only give gas discount if none of the dependency (except COMMIT) has id "*" - if wasmExecuteMsg, ok := msg.(*wasmtypes.MsgExecuteContract); ok { - msgInfo, err := acltypes.NewExecuteMessageInfo(wasmExecuteMsg.Msg) - if err != nil { - return DefaultGasMultiplierDenominator - } - if messageContainsNoWildcardDependencies( - ctx, - aclKeeper, - wasmExecuteMsg.Contract, - msgInfo, - wasmExecuteMsg.Sender, - ) { - return WasmCorrectDependencyDiscountDenominator + // In simulation, still use multiplier but with infinite gas limit + if simulate { + return ctx.WithGasMeter(types.NewInfiniteMultiplierGasMeter(cosmosGasParams.CosmosGasMultiplierNumerator, cosmosGasParams.CosmosGasMultiplierDenominator)) } - } - return DefaultGasMultiplierDenominator -} -// TODO: add tracing to measure latency -func messageContainsNoWildcardDependencies( - ctx sdk.Context, - aclKeeper aclkeeper.Keeper, - contractAddrStr string, - msgInfo *acltypes.WasmMessageInfo, - sender string, -) bool { - addr, err := sdk.AccAddressFromBech32(contractAddrStr) - if err != nil { - return false - } - accessOps, err := aclKeeper.GetWasmDependencyAccessOps(ctx, addr, sender, msgInfo, make(aclkeeper.ContractReferenceLookupMap)) - if err != nil { - return false + return ctx.WithGasMeter(types.NewMultiplierGasMeter(gasLimit, cosmosGasParams.CosmosGasMultiplierNumerator, cosmosGasParams.CosmosGasMultiplierDenominator)) } - for _, op := range accessOps { - if op.AccessType != sdkacltypes.AccessType_COMMIT && op.IdentifierTemplate == "*" { - return false - } - } - - return true } diff --git a/app/antedecorators/gas_test.go b/app/antedecorators/gas_test.go index 6a32e48011..bc24607bfd 100644 --- a/app/antedecorators/gas_test.go +++ b/app/antedecorators/gas_test.go @@ -4,28 +4,40 @@ import ( "testing" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/accesscontrol" + sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" acltypes "github.com/cosmos/cosmos-sdk/x/accesscontrol/types" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/bank" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + aclbankmapping "github.com/sei-protocol/sei-chain/aclmapping/bank" + aclutils "github.com/sei-protocol/sei-chain/aclmapping/utils" "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/app/antedecorators" + "github.com/sei-protocol/sei-chain/app/antedecorators/depdecorators" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/secp256k1" "github.com/tendermint/tendermint/proto/tendermint/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) func TestMultiplierGasSetter(t *testing.T) { - testApp := app.Setup(false) + testApp := app.Setup(false, false) contractAddr, err := sdk.AccAddressFromBech32("sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw") require.NoError(t, err) - otherContractAddr, err := sdk.AccAddressFromBech32("sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m") - require.NoError(t, err) ctx := testApp.NewContext(false, types.Header{}).WithBlockHeight(2) + testApp.ParamsKeeper.SetCosmosGasParams(ctx, *paramtypes.DefaultCosmosGasParams()) + testApp.ParamsKeeper.SetFeesParams(ctx, paramtypes.DefaultGenesis().GetFeesParams()) testMsg := wasmtypes.MsgExecuteContract{ Contract: "sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw", Msg: []byte("{\"xyz\":{}}"), } testTx := app.NewTestTx([]sdk.Msg{&testMsg}) - // discounted mapping + testApp.AccessControlKeeper.SetWasmDependencyMapping(ctx, accesscontrol.WasmDependencyMapping{ ContractAddress: contractAddr.String(), BaseAccessOps: []*accesscontrol.WasmAccessOperation{ @@ -41,212 +53,126 @@ func TestMultiplierGasSetter(t *testing.T) { }, }, }) - // other contract not discounted - testApp.AccessControlKeeper.SetWasmDependencyMapping(ctx, accesscontrol.WasmDependencyMapping{ - ContractAddress: otherContractAddr.String(), - BaseAccessOps: []*accesscontrol.WasmAccessOperation{ - { - Operation: &accesscontrol.AccessOperation{ - AccessType: accesscontrol.AccessType_READ, - ResourceType: accesscontrol.ResourceType_KV, - IdentifierTemplate: "*", - }, - }, - { - Operation: acltypes.CommitAccessOp(), - }, - }, - }) - gasMeterSetter := antedecorators.GetGasMeterSetter(testApp.AccessControlKeeper) + // Test with 1/2 cosmos gas multiplier + testApp.ParamsKeeper.SetCosmosGasParams(ctx, paramtypes.CosmosGasParams{CosmosGasMultiplierNumerator: 1, CosmosGasMultiplierDenominator: 2}) + gasMeterSetter := antedecorators.GetGasMeterSetter(testApp.ParamsKeeper) ctxWithGasMeter := gasMeterSetter(false, ctx, 1000, testTx) ctxWithGasMeter.GasMeter().ConsumeGas(2, "") require.Equal(t, uint64(1), ctxWithGasMeter.GasMeter().GasConsumed()) - otherTestMsg := wasmtypes.MsgExecuteContract{ - Contract: "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m", - Msg: []byte("{\"xyz\":{}}"), - } - testTx2 := app.NewTestTx([]sdk.Msg{&testMsg, &otherTestMsg}) - ctxWithGasMeter = gasMeterSetter(false, ctx, 1000, testTx2) - ctxWithGasMeter.GasMeter().ConsumeGas(2, "") - // should still not give discount because of other contract being non-discounted - require.Equal(t, uint64(2), ctxWithGasMeter.GasMeter().GasConsumed()) - - // not discounted mapping - testApp.AccessControlKeeper.SetWasmDependencyMapping(ctx, accesscontrol.WasmDependencyMapping{ - ContractAddress: contractAddr.String(), - BaseAccessOps: []*accesscontrol.WasmAccessOperation{ - { - Operation: &accesscontrol.AccessOperation{ - AccessType: accesscontrol.AccessType_READ, - ResourceType: accesscontrol.ResourceType_KV, - IdentifierTemplate: "*", - }, - }, - { - Operation: acltypes.CommitAccessOp(), - }, - }, - }) + // Test with 1/4 cosmos gas multiplier + testApp.ParamsKeeper.SetCosmosGasParams(ctx, paramtypes.CosmosGasParams{CosmosGasMultiplierNumerator: 1, CosmosGasMultiplierDenominator: 4}) ctxWithGasMeter = gasMeterSetter(false, ctx, 1000, testTx) - ctxWithGasMeter.GasMeter().ConsumeGas(2, "") - require.Equal(t, uint64(2), ctxWithGasMeter.GasMeter().GasConsumed()) + ctxWithGasMeter.GasMeter().ConsumeGas(100, "") + require.Equal(t, uint64(25), ctxWithGasMeter.GasMeter().GasConsumed()) + + // Test over gas limit even with 1/4 gas multiplier + testApp.ParamsKeeper.SetCosmosGasParams(ctx, paramtypes.CosmosGasParams{CosmosGasMultiplierNumerator: 1, CosmosGasMultiplierDenominator: 4}) + ctxWithGasMeter = gasMeterSetter(false, ctx, 20, testTx) + require.Panics(t, func() { ctxWithGasMeter.GasMeter().ConsumeGas(100, "") }) + require.Equal(t, true, ctxWithGasMeter.GasMeter().IsOutOfGas()) + + // Simulation mode has infinite gas meter with multiplier + testApp.ParamsKeeper.SetCosmosGasParams(ctx, paramtypes.CosmosGasParams{CosmosGasMultiplierNumerator: 1, CosmosGasMultiplierDenominator: 4}) + // Gas limit is effectively ignored in simulation + ctxWithGasMeter = gasMeterSetter(true, ctx, 20, testTx) + require.NotPanics(t, func() { ctxWithGasMeter.GasMeter().ConsumeGas(100, "") }) + require.Equal(t, uint64(25), ctxWithGasMeter.GasMeter().GasConsumed()) + require.Equal(t, false, ctxWithGasMeter.GasMeter().IsOutOfGas()) + } -func TestMultiplierGasSetterWithWasmReference(t *testing.T) { - testApp := app.Setup(false) - contractAddr, err := sdk.AccAddressFromBech32("sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw") - referredContractAddr, err := sdk.AccAddressFromBech32("sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m") - require.NoError(t, err) - ctx := testApp.NewContext(false, types.Header{}).WithBlockHeight(2) - testMsg := wasmtypes.MsgExecuteContract{ - Contract: "sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw", - Msg: []byte("{\"xyz\":{}}"), - } - testTx := app.NewTestTx([]sdk.Msg{&testMsg}) - // discounted mapping - testApp.AccessControlKeeper.SetWasmDependencyMapping(ctx, accesscontrol.WasmDependencyMapping{ - ContractAddress: contractAddr.String(), - BaseAccessOps: []*accesscontrol.WasmAccessOperation{ - { - Operation: &accesscontrol.AccessOperation{ - AccessType: accesscontrol.AccessType_READ, - ResourceType: accesscontrol.ResourceType_KV, - IdentifierTemplate: "something", - }, - }, - { - Operation: acltypes.CommitAccessOp(), - }, - }, - BaseContractReferences: []*accesscontrol.WasmContractReference{ - { - ContractAddress: referredContractAddr.String(), - MessageType: accesscontrol.WasmMessageSubtype_EXECUTE, - MessageName: "abc", - }, - }, - }) - testApp.AccessControlKeeper.SetWasmDependencyMapping(ctx, accesscontrol.WasmDependencyMapping{ - ContractAddress: referredContractAddr.String(), - BaseAccessOps: []*accesscontrol.WasmAccessOperation{ - { - Operation: acltypes.CommitAccessOp(), - }, - }, - ExecuteAccessOps: []*accesscontrol.WasmAccessOperations{ - { - MessageName: "abc", - WasmOperations: []*accesscontrol.WasmAccessOperation{ - { - Operation: &accesscontrol.AccessOperation{ - AccessType: accesscontrol.AccessType_WRITE, - ResourceType: accesscontrol.ResourceType_KV, - IdentifierTemplate: "something else", - }, - }, - }, - }, - }, - }) - gasMeterSetter := antedecorators.GetGasMeterSetter(testApp.AccessControlKeeper) - ctxWithGasMeter := gasMeterSetter(false, ctx, 1000, testTx) - ctxWithGasMeter.GasMeter().ConsumeGas(2, "") - require.Equal(t, uint64(1), ctxWithGasMeter.GasMeter().GasConsumed()) - // not discounted mapping - testApp.AccessControlKeeper.SetWasmDependencyMapping(ctx, accesscontrol.WasmDependencyMapping{ - ContractAddress: referredContractAddr.String(), - BaseAccessOps: []*accesscontrol.WasmAccessOperation{ - { - Operation: acltypes.CommitAccessOp(), - }, - }, - ExecuteAccessOps: []*accesscontrol.WasmAccessOperations{ - { - MessageName: "abc", - WasmOperations: []*accesscontrol.WasmAccessOperation{ - { - Operation: &accesscontrol.AccessOperation{ - AccessType: accesscontrol.AccessType_WRITE, - ResourceType: accesscontrol.ResourceType_KV, - IdentifierTemplate: "*", - }, - }, - }, - }, - }, - }) - ctxWithGasMeter = gasMeterSetter(false, ctx, 1000, testTx) - ctxWithGasMeter.GasMeter().ConsumeGas(2, "") - require.Equal(t, uint64(2), ctxWithGasMeter.GasMeter().GasConsumed()) +func cacheTxContext(ctx sdk.Context) (sdk.Context, sdk.CacheMultiStore) { + ms := ctx.MultiStore() + msCache := ms.CacheMultiStore() + return ctx.WithMultiStore(msCache), msCache } -func TestMultiplierGasSetterWithWasmReferenceCycle(t *testing.T) { - testApp := app.Setup(false) - contractAddr, err := sdk.AccAddressFromBech32("sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw") - referredContractAddr, err := sdk.AccAddressFromBech32("sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m") - require.NoError(t, err) - ctx := testApp.NewContext(false, types.Header{}).WithBlockHeight(2) - testMsg := wasmtypes.MsgExecuteContract{ - Contract: "sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw", - Msg: []byte("{\"xyz\":{}}"), - } - testTx := app.NewTestTx([]sdk.Msg{&testMsg}) +func TestMultiplierGasMeterOps(t *testing.T) { + priv1 := secp256k1.GenPrivKey() + addr1 := sdk.AccAddress(priv1.PubKey().Address()) + priv2 := secp256k1.GenPrivKey() + addr2 := sdk.AccAddress(priv2.PubKey().Address()) + coins := sdk.Coins{sdk.NewInt64Coin("foocoin", 10)} - testApp.AccessControlKeeper.SetWasmDependencyMapping(ctx, accesscontrol.WasmDependencyMapping{ - ContractAddress: contractAddr.String(), - BaseAccessOps: []*accesscontrol.WasmAccessOperation{ - { - Operation: &accesscontrol.AccessOperation{ - AccessType: accesscontrol.AccessType_READ, - ResourceType: accesscontrol.ResourceType_KV, - IdentifierTemplate: "something", - }, - }, - { - Operation: acltypes.CommitAccessOp(), - }, + tests := []struct { + name string + expectedError error + msg *banktypes.MsgSend + dynamicDep bool + }{ + { + name: "default send", + msg: banktypes.NewMsgSend(addr1, addr2, coins), + expectedError: nil, + dynamicDep: true, }, - BaseContractReferences: []*accesscontrol.WasmContractReference{ - { - ContractAddress: referredContractAddr.String(), - MessageType: accesscontrol.WasmMessageSubtype_EXECUTE, - MessageName: "abc", - }, - }, - }) - testApp.AccessControlKeeper.SetWasmDependencyMapping(ctx, accesscontrol.WasmDependencyMapping{ - ContractAddress: referredContractAddr.String(), - BaseAccessOps: []*accesscontrol.WasmAccessOperation{ - { - Operation: acltypes.CommitAccessOp(), - }, + { + name: "dont check synchronous", + msg: banktypes.NewMsgSend(addr1, addr2, coins), + expectedError: nil, + dynamicDep: false, }, - ExecuteAccessOps: []*accesscontrol.WasmAccessOperations{ - { - MessageName: "abc", - WasmOperations: []*accesscontrol.WasmAccessOperation{ - { - Operation: &accesscontrol.AccessOperation{ - AccessType: accesscontrol.AccessType_WRITE, - ResourceType: accesscontrol.ResourceType_KV, - IdentifierTemplate: "something else", - }, - }, - }, - }, + } + + acc1 := &authtypes.BaseAccount{ + Address: addr1.String(), + } + acc2 := &authtypes.BaseAccount{ + Address: addr2.String(), + } + accs := authtypes.GenesisAccounts{acc1, acc2} + balances := []banktypes.Balance{ + { + Address: addr1.String(), + Coins: coins, }, - BaseContractReferences: []*accesscontrol.WasmContractReference{ - { - ContractAddress: contractAddr.String(), - MessageType: accesscontrol.WasmMessageSubtype_EXECUTE, - MessageName: "xyz", - }, + { + Address: addr2.String(), + Coins: coins, }, - }) - gasMeterSetter := antedecorators.GetGasMeterSetter(testApp.AccessControlKeeper) - ctxWithGasMeter := gasMeterSetter(false, ctx, 1000, testTx) - ctxWithGasMeter.GasMeter().ConsumeGas(2, "") - require.Equal(t, uint64(2), ctxWithGasMeter.GasMeter().GasConsumed()) + } + + app := simapp.SetupWithGenesisAccounts(accs, balances...) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + + handler := bank.NewHandler(app.BankKeeper) + msgValidator := sdkacltypes.NewMsgValidator(aclutils.StoreKeyToResourceTypePrefixMap) + ctx = ctx.WithMsgValidator(msgValidator) + anteDecorators := []sdk.AnteFullDecorator{ + sdk.CustomDepWrappedAnteDecorator(ante.NewSetUpContextDecorator(antedecorators.GetGasMeterSetter(app.ParamsKeeper)), depdecorators.GasMeterSetterDecorator{}), + } + chainedHandler, depGen := sdk.ChainAnteDecorators(anteDecorators...) + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + fakeTx := FakeTx{ + FakeMsgs: []sdk.Msg{ + tc.msg, + }, + } + ctx, err := chainedHandler(ctx, fakeTx, false) + require.Nil(t, err) + + handlerCtx, cms := cacheTxContext(ctx) + + dependencies, _ := aclbankmapping.MsgSendDependencyGenerator(app.AccessControlKeeper, handlerCtx, tc.msg) + + if !tc.dynamicDep { + dependencies = sdkacltypes.SynchronousAccessOps() + } + + newDeps, err := depGen(dependencies, fakeTx, 1) + require.Nil(t, err) + + _, err = handler(handlerCtx, tc.msg) + if tc.expectedError != nil { + require.EqualError(t, err, tc.expectedError.Error()) + } else { + require.NoError(t, err) + } + missing := handlerCtx.MsgValidator().ValidateAccessOperations(newDeps, cms.GetEvents()) + require.Empty(t, missing) + }) + } } diff --git a/app/antedecorators/priority.go b/app/antedecorators/priority.go index a8d741bcb5..0fe7b287a7 100644 --- a/app/antedecorators/priority.go +++ b/app/antedecorators/priority.go @@ -7,6 +7,13 @@ import ( oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" ) +const ( + OraclePriority = math.MaxInt64 - 100 + EVMAssociatePriority = math.MaxInt64 - 101 + // This is the max priority a non oracle or associate tx can take + MaxPriority = math.MaxInt64 - 1000 +) + type PriorityDecorator struct{} func NewPriorityDecorator() PriorityDecorator { @@ -22,12 +29,12 @@ func intMin(a, b int64) int64 { // Assigns higher priority to certain types of transactions including oracle func (pd PriorityDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { - // Cap priority to MAXINT64 - 1000 + // Cap priority // Use higher priorities for tiers including oracle tx's - priority := intMin(ctx.Priority(), math.MaxInt64-1000) + priority := intMin(ctx.Priority(), MaxPriority) if isOracleTx(tx) { - priority = math.MaxInt64 - 100 + priority = OraclePriority } newCtx := ctx.WithPriority(priority) diff --git a/app/app.go b/app/app.go index 96750228a5..2a3b57b2dc 100644 --- a/app/app.go +++ b/app/app.go @@ -3,6 +3,7 @@ package app import ( "bytes" "context" + "crypto/sha256" "encoding/json" "fmt" "io" @@ -12,7 +13,11 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/ethclient" + ethrpc "github.com/ethereum/go-ethereum/rpc" "github.com/sei-protocol/sei-chain/app/antedecorators" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/sei-protocol/sei-chain/precompiles" "go.opentelemetry.io/otel/trace" storetypes "github.com/cosmos/cosmos-sdk/store/types" @@ -113,6 +118,14 @@ import ( mintclient "github.com/sei-protocol/sei-chain/x/mint/client/cli" mintkeeper "github.com/sei-protocol/sei-chain/x/mint/keeper" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" + + "github.com/sei-protocol/sei-chain/x/evm" + evmante "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/blocktest" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/querier" + "github.com/sei-protocol/sei-chain/x/evm/replay" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" "github.com/spf13/cast" abci "github.com/tendermint/tendermint/abci/types" tmcfg "github.com/tendermint/tendermint/config" @@ -193,6 +206,7 @@ var ( transfer.AppModuleBasic{}, vesting.AppModuleBasic{}, oraclemodule.AppModuleBasic{}, + evm.AppModuleBasic{}, wasm.AppModuleBasic{}, dexmodule.AppModuleBasic{}, epochmodule.AppModuleBasic{}, @@ -212,6 +226,7 @@ var ( ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, oracletypes.ModuleName: nil, wasm.ModuleName: {authtypes.Burner}, + evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, dexmoduletypes.ModuleName: nil, tokenfactorytypes.ModuleName: {authtypes.Minter, authtypes.Burner}, // this line is used by starport scaffolding # stargate/app/maccPerms @@ -318,6 +333,7 @@ type App struct { FeeGrantKeeper feegrantkeeper.Keeper WasmKeeper wasm.Keeper OracleKeeper oraclekeeper.Keeper + EvmKeeper evmkeeper.Keeper // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -355,6 +371,9 @@ type App struct { MemState *dexcache.MemState HardForkManager *upgrades.HardForkManager + + encodingConfig appparams.EncodingConfig + evmRPCConfig evmrpc.Config } // New returns a reference to an initialized blockchain app @@ -366,6 +385,7 @@ func New( skipUpgradeHeights map[int64]bool, homePath string, invCheckPeriod uint, + enableCustomEVMPrecompiles bool, tmConfig *tmcfg.Config, encodingConfig appparams.EncodingConfig, enabledProposals []wasm.ProposalType, @@ -388,14 +408,15 @@ func New( acltypes.StoreKey, authtypes.StoreKey, authzkeeper.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, - evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, oracletypes.StoreKey, wasm.StoreKey, + evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, oracletypes.StoreKey, + evmtypes.StoreKey, wasm.StoreKey, dexmoduletypes.StoreKey, epochmoduletypes.StoreKey, tokenfactorytypes.StoreKey, // this line is used by starport scaffolding # stargate/app/storeKey ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) - memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, dexmoduletypes.MemStoreKey, banktypes.DeferredCacheStoreKey) + memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, dexmoduletypes.MemStoreKey, banktypes.DeferredCacheStoreKey, evmtypes.MemStoreKey) app := &App{ BaseApp: bApp, @@ -409,6 +430,7 @@ func New( txDecoder: encodingConfig.TxConfig.TxDecoder(), versionInfo: version.NewInfo(), metricCounter: &map[string]float32{}, + encodingConfig: encodingConfig, } app.ParamsKeeper = initParamsKeeper(appCodec, cdc, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) @@ -524,17 +546,6 @@ func New( app.DistrKeeper, ) - customDependencyGenerators := aclmapping.NewCustomDependencyGenerator() - aclOpts = append(aclOpts, aclkeeper.WithDependencyGeneratorMappings(customDependencyGenerators.GetCustomDependencyGenerators())) - aclOpts = append(aclOpts, aclkeeper.WithResourceTypeToStoreKeyMap(aclutils.ResourceTypeToStoreKeyMap)) - app.AccessControlKeeper = aclkeeper.NewKeeper( - appCodec, - app.keys[acltypes.StoreKey], - app.GetSubspace(acltypes.ModuleName), - app.AccountKeeper, - app.StakingKeeper, - aclOpts..., - ) // The last arguments can contain custom message handlers, and custom query handlers, // if we want to allow any custom callbacks supportedFeatures := "iterator,staking,stargate,sei" @@ -552,6 +563,7 @@ func New( appCodec, app.TransferKeeper, app.AccessControlKeeper, + &app.EvmKeeper, ), wasmOpts..., ) @@ -574,6 +586,49 @@ func New( supportedFeatures, wasmOpts..., ) + + 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.evmRPCConfig, err = evmrpc.ReadConfig(appOpts) + if err != nil { + panic(fmt.Sprintf("error reading EVM config due to %s", err)) + } + evmQueryConfig, err := querier.ReadConfig(appOpts) + if err != nil { + panic(fmt.Sprintf("error reading evm query config due to %s", err)) + } + app.EvmKeeper.QueryConfig = &evmQueryConfig + ethReplayConfig, err := replay.ReadConfig(appOpts) + if err != nil { + panic(fmt.Sprintf("error reading eth replay config due to %s", err)) + } + app.EvmKeeper.EthReplayConfig = ethReplayConfig + ethBlockTestConfig, err := blocktest.ReadConfig(appOpts) + if err != nil { + panic(fmt.Sprintf("error reading eth block test config due to %s", err)) + } + app.EvmKeeper.EthBlockTestConfig = ethBlockTestConfig + if ethReplayConfig.Enabled { + rpcclient, err := ethrpc.Dial(ethReplayConfig.EthRPC) + if err != nil { + panic(fmt.Sprintf("error dialing %s due to %s", ethReplayConfig.EthRPC, err)) + } + app.EvmKeeper.EthClient = ethclient.NewClient(rpcclient) + } + + customDependencyGenerators := aclmapping.NewCustomDependencyGenerator() + aclOpts = append(aclOpts, aclkeeper.WithResourceTypeToStoreKeyMap(aclutils.ResourceTypeToStoreKeyMap)) + aclOpts = append(aclOpts, aclkeeper.WithDependencyGeneratorMappings(customDependencyGenerators.GetCustomDependencyGenerators(app.EvmKeeper))) + app.AccessControlKeeper = aclkeeper.NewKeeper( + appCodec, + app.keys[acltypes.StoreKey], + app.GetSubspace(acltypes.ModuleName), + app.AccountKeeper, + app.StakingKeeper, + aclOpts..., + ) + app.DexKeeper.SetWasmKeeper(&app.WasmKeeper) dexModule := dexmodule.NewAppModule(appCodec, app.DexKeeper, app.AccountKeeper, app.BankKeeper, app.WasmKeeper, app.GetBaseApp().TracingInfo) epochModule := epochmodule.NewAppModule(appCodec, app.EpochKeeper, app.AccountKeeper, app.BankKeeper) @@ -588,7 +643,8 @@ func New( AddRoute(dexmoduletypes.RouterKey, dexmodule.NewProposalHandler(app.DexKeeper)). AddRoute(minttypes.RouterKey, mint.NewProposalHandler(app.MintKeeper)). AddRoute(tokenfactorytypes.RouterKey, tokenfactorymodule.NewProposalHandler(app.TokenFactoryKeeper)). - AddRoute(acltypes.ModuleName, aclmodule.NewProposalHandler(app.AccessControlKeeper)) + AddRoute(acltypes.ModuleName, aclmodule.NewProposalHandler(app.AccessControlKeeper)). + AddRoute(evmtypes.RouterKey, evm.NewProposalHandler(app.EvmKeeper)) if len(enabledProposals) != 0 { govRouter.AddRoute(wasm.RouterKey, wasm.NewWasmProposalHandler(app.WasmKeeper, enabledProposals)) } @@ -607,6 +663,22 @@ func New( // this line is used by starport scaffolding # ibc/app/router app.IBCKeeper.SetRouter(ibcRouter) + if enableCustomEVMPrecompiles { + if err := precompiles.InitializePrecompiles( + &app.EvmKeeper, + app.BankKeeper, + wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper), + app.WasmKeeper, + stakingkeeper.NewMsgServerImpl(app.StakingKeeper), + app.GovKeeper, + app.DistrKeeper, + app.OracleKeeper, + app.TransferKeeper, + ); err != nil { + panic(err) + } + } + /**** Module Options ****/ // NOTE: we may consider parsing `appOpts` inside module constructors. For the moment @@ -639,6 +711,7 @@ func New( params.NewAppModule(app.ParamsKeeper), oraclemodule.NewAppModule(appCodec, app.OracleKeeper, app.AccountKeeper, app.BankKeeper), wasm.NewAppModule(appCodec, &app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), + evm.NewAppModule(appCodec, &app.EvmKeeper), transferModule, dexModule, epochModule, @@ -673,6 +746,7 @@ func New( ibctransfertypes.ModuleName, oracletypes.ModuleName, dexmoduletypes.ModuleName, + evmtypes.ModuleName, wasm.ModuleName, tokenfactorytypes.ModuleName, acltypes.ModuleName, @@ -704,6 +778,7 @@ func New( oracletypes.ModuleName, epochmoduletypes.ModuleName, dexmoduletypes.ModuleName, + evmtypes.ModuleName, wasm.ModuleName, tokenfactorytypes.ModuleName, acltypes.ModuleName, @@ -738,6 +813,7 @@ func New( tokenfactorytypes.ModuleName, epochmoduletypes.ModuleName, wasm.ModuleName, + evmtypes.ModuleName, acltypes.ModuleName, // this line is used by starport scaffolding # stargate/app/initGenesis ) @@ -810,9 +886,13 @@ func New( WasmKeeper: &app.WasmKeeper, OracleKeeper: &app.OracleKeeper, DexKeeper: &app.DexKeeper, + EVMKeeper: &app.EvmKeeper, TracingInfo: app.GetBaseApp().TracingInfo, AccessControlKeeper: &app.AccessControlKeeper, CheckTxMemState: app.CheckTxMemState, + LatestCtxGetter: func() sdk.Context { + return app.GetCheckCtx() + }, }, ) if err != nil { @@ -1046,10 +1126,10 @@ func (app *App) FinalizeBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) return &resp, nil } -func (app *App) DeliverTxWithResult(ctx sdk.Context, tx []byte) *abci.ExecTxResult { +func (app *App) DeliverTxWithResult(ctx sdk.Context, tx []byte, typedTx sdk.Tx) *abci.ExecTxResult { deliverTxResp := app.DeliverTx(ctx, abci.RequestDeliverTx{ Tx: tx, - }) + }, typedTx, sha256.Sum256(tx)) metrics.IncrGasCounter("gas_used", deliverTxResp.GasUsed) metrics.IncrGasCounter("gas_wanted", deliverTxResp.GasWanted) @@ -1063,16 +1143,18 @@ func (app *App) DeliverTxWithResult(ctx sdk.Context, tx []byte) *abci.ExecTxResu GasUsed: deliverTxResp.GasUsed, Events: deliverTxResp.Events, Codespace: deliverTxResp.Codespace, + EvmTxInfo: deliverTxResp.EvmTxInfo, } } -func (app *App) ProcessBlockSynchronous(ctx sdk.Context, txs [][]byte) []*abci.ExecTxResult { +func (app *App) ProcessBlockSynchronous(ctx sdk.Context, txs [][]byte, typedTxs []sdk.Tx, absoluteTxIndices []int) []*abci.ExecTxResult { defer metrics.BlockProcessLatency(time.Now(), metrics.SYNCHRONOUS) txResults := []*abci.ExecTxResult{} for i, tx := range txs { - ctx := ctx.WithTxIndex(i) - txResults = append(txResults, app.DeliverTxWithResult(ctx, tx)) + ctx = ctx.WithTxIndex(absoluteTxIndices[i]) + res := app.DeliverTxWithResult(ctx, tx, typedTxs[i]) + txResults = append(txResults, res) metrics.IncrTxProcessTypeCounter(metrics.SYNCHRONOUS) } return txResults @@ -1113,7 +1195,9 @@ func (app *App) CacheContext(ctx sdk.Context) (sdk.Context, sdk.CacheMultiStore) func (app *App) ProcessTxConcurrent( ctx sdk.Context, txIndex int, + absoluateTxIndex int, txBytes []byte, + typedTx sdk.Tx, wg *sync.WaitGroup, resultChan chan<- ChannelResult, txCompletionSignalingMap acltypes.MessageCompletionSignalMapping, @@ -1128,27 +1212,31 @@ func (app *App) ProcessTxConcurrent( ctx = ctx.WithMsgValidator( sdkacltypes.NewMsgValidator(aclutils.StoreKeyToResourceTypePrefixMap), ) - ctx = ctx.WithTxIndex(txIndex) + ctx = ctx.WithTxIndex(absoluateTxIndex) // Deliver the transaction and store the result in the channel - resultChan <- ChannelResult{txIndex, app.DeliverTxWithResult(ctx, txBytes)} + resultChan <- ChannelResult{txIndex, app.DeliverTxWithResult(ctx, txBytes, typedTx)} metrics.IncrTxProcessTypeCounter(metrics.CONCURRENT) } type ProcessBlockConcurrentFunction func( ctx sdk.Context, txs [][]byte, + typedTxs []sdk.Tx, completionSignalingMap map[int]acltypes.MessageCompletionSignalMapping, blockingSignalsMap map[int]acltypes.MessageCompletionSignalMapping, txMsgAccessOpMapping map[int]acltypes.MsgIndexToAccessOpMapping, + absoluteTxIndices []int, ) ([]*abci.ExecTxResult, bool) func (app *App) ProcessBlockConcurrent( ctx sdk.Context, txs [][]byte, + typedTxs []sdk.Tx, completionSignalingMap map[int]acltypes.MessageCompletionSignalMapping, blockingSignalsMap map[int]acltypes.MessageCompletionSignalMapping, txMsgAccessOpMapping map[int]acltypes.MsgIndexToAccessOpMapping, + absoluteTxIndices []int, ) ([]*abci.ExecTxResult, bool) { defer metrics.BlockProcessLatency(time.Now(), metrics.CONCURRENT) @@ -1166,7 +1254,9 @@ func (app *App) ProcessBlockConcurrent( go app.ProcessTxConcurrent( ctx, txIndex, + absoluteTxIndices[txIndex], txBytes, + typedTxs[txIndex], &waitGroup, resultChan, completionSignalingMap[txIndex], @@ -1210,8 +1300,10 @@ func (app *App) ProcessBlockConcurrent( func (app *App) ProcessTxs( ctx sdk.Context, txs [][]byte, + typedTxs []sdk.Tx, dependencyDag *acltypes.Dag, processBlockConcurrentFunction ProcessBlockConcurrentFunction, + absoluteTxIndices []int, ) ([]*abci.ExecTxResult, sdk.Context) { // Only run concurrently if no error // Branch off the current context and pass a cached context to the concurrent delivered TXs that are shared. @@ -1223,9 +1315,11 @@ func (app *App) ProcessTxs( concurrentResults, ok := processBlockConcurrentFunction( processBlockCtx, txs, + typedTxs, dependencyDag.CompletionSignalingMap, dependencyDag.BlockingSignalsMap, dependencyDag.TxMsgAccessOpMapping, + absoluteTxIndices, ) oldDexMemState := dexutils.GetMemState(ctx.Context()).DeepCopy() if ok { @@ -1245,24 +1339,28 @@ func (app *App) ProcessTxs( dexMemState.Clear(ctx) dexMemState.ClearContractToDependencies(ctx) - txResults := app.ProcessBlockSynchronous(ctx, txs) + txResults := app.ProcessBlockSynchronous(ctx, txs, typedTxs, absoluteTxIndices) processBlockCache.Write() return txResults, ctx } -func (app *App) PartitionPrioritizedTxs(ctx sdk.Context, txs [][]byte) (prioritizedTxs, otherTxs [][]byte, prioritizedIndices, otherIndices []int) { +func (app *App) PartitionPrioritizedTxs(_ sdk.Context, txs [][]byte, typedTxs []sdk.Tx) ( + prioritizedTxs, otherTxs [][]byte, + prioritizedTypedTxs, otherTypedTxs []sdk.Tx, + prioritizedIndices, otherIndices []int, +) { for idx, tx := range txs { - decodedTx, err := app.txDecoder(tx) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("Error decoding tx for partitioning: %v", err)) - // if theres an issue decoding, add it to `otherTxs` for normal processing and continue + if typedTxs[idx] == nil { otherTxs = append(otherTxs, tx) + otherTypedTxs = append(otherTypedTxs, nil) + otherIndices = append(otherIndices, idx) continue } + prioritized := false // if all messages are prioritized, we want to add to prioritizedTxs msgLoop: - for _, msg := range decodedTx.GetMsgs() { + for _, msg := range typedTxs[idx].GetMsgs() { switch msg.(type) { case *oracletypes.MsgAggregateExchangeRateVote: prioritized = true @@ -1279,28 +1377,30 @@ func (app *App) PartitionPrioritizedTxs(ctx sdk.Context, txs [][]byte) (prioriti } if prioritized { prioritizedTxs = append(prioritizedTxs, tx) + prioritizedTypedTxs = append(prioritizedTypedTxs, typedTxs[idx]) prioritizedIndices = append(prioritizedIndices, idx) } else { otherTxs = append(otherTxs, tx) + otherTypedTxs = append(otherTypedTxs, typedTxs[idx]) otherIndices = append(otherIndices, idx) } } - return prioritizedTxs, otherTxs, prioritizedIndices, otherIndices + return prioritizedTxs, otherTxs, prioritizedTypedTxs, otherTypedTxs, prioritizedIndices, otherIndices } // ExecuteTxsConcurrently calls the appropriate function for processing transacitons -func (app *App) ExecuteTxsConcurrently(ctx sdk.Context, txs [][]byte) ([]*abci.ExecTxResult, sdk.Context) { +func (app *App) ExecuteTxsConcurrently(ctx sdk.Context, txs [][]byte, typedTxs []sdk.Tx, absoluteTxIndices []int) ([]*abci.ExecTxResult, sdk.Context) { // TODO after OCC release, remove this check and call ProcessTXsWithOCC directly if ctx.IsOCCEnabled() { - return app.ProcessTXsWithOCC(ctx, txs) + return app.ProcessTXsWithOCC(ctx, txs, typedTxs, absoluteTxIndices) } - results := app.ProcessBlockSynchronous(ctx, txs) + results := app.ProcessBlockSynchronous(ctx, txs, typedTxs, absoluteTxIndices) return results, ctx } // ProcessTXsWithOCC runs the transactions concurrently via OCC -func (app *App) ProcessTXsWithOCC(ctx sdk.Context, txs [][]byte) ([]*abci.ExecTxResult, sdk.Context) { +func (app *App) ProcessTXsWithOCC(ctx sdk.Context, txs [][]byte, typedTxs []sdk.Tx, absoluteTxIndices []int) ([]*abci.ExecTxResult, sdk.Context) { entries := make([]*sdk.DeliverTxEntry, len(txs)) var span trace.Span if app.TracingEnabled { @@ -1311,9 +1411,14 @@ func (app *App) ProcessTXsWithOCC(ctx sdk.Context, txs [][]byte) ([]*abci.ExecTx wg.Add(1) go func(txIndex int, tx []byte) { defer wg.Done() - deliverTxEntry := &sdk.DeliverTxEntry{Request: abci.RequestDeliverTx{Tx: tx}} + deliverTxEntry := &sdk.DeliverTxEntry{ + Request: abci.RequestDeliverTx{Tx: tx}, + SdkTx: typedTxs[txIndex], + Checksum: sha256.Sum256(tx), + AbsoluteIndex: absoluteTxIndices[txIndex], + } // get prefill estimate - estimatedWritesets, err := app.AccessControlKeeper.GenerateEstimatedWritesets(ctx, app.txDecoder, app.GetAnteDepGenerator(), txIndex, tx) + estimatedWritesets, err := app.AccessControlKeeper.GenerateEstimatedWritesets(ctx, app.GetAnteDepGenerator(), txIndex, typedTxs[txIndex]) // if no error, then we assign the mapped writesets for prefill estimate if err == nil { deliverTxEntry.EstimatedWritesets = estimatedWritesets @@ -1321,6 +1426,7 @@ func (app *App) ProcessTXsWithOCC(ctx sdk.Context, txs [][]byte) ([]*abci.ExecTx entries[txIndex] = deliverTxEntry }(txIndex, tx) } + wg.Wait() if app.TracingEnabled { @@ -1343,6 +1449,7 @@ func (app *App) ProcessTXsWithOCC(ctx sdk.Context, txs [][]byte) ([]*abci.ExecTx GasUsed: r.Response.GasUsed, Events: r.Response.Events, Codespace: r.Response.Codespace, + EvmTxInfo: r.Response.EvmTxInfo, }) } @@ -1351,25 +1458,23 @@ func (app *App) ProcessTXsWithOCC(ctx sdk.Context, txs [][]byte) ([]*abci.ExecTx // BuildDependenciesAndRunTxs deprecated, use ProcessTXsWithOCC instead // Deprecated: this will be removed after OCC releases -// TODO: remove after release -func (app *App) BuildDependenciesAndRunTxs(ctx sdk.Context, txs [][]byte) ([]*abci.ExecTxResult, sdk.Context) { - var txResults []*abci.ExecTxResult - - dependencyDag, err := app.AccessControlKeeper.BuildDependencyDag(ctx, app.txDecoder, app.GetAnteDepGenerator(), txs) - switch err { - case nil: - txResults, ctx = app.ProcessTxs(ctx, txs, dependencyDag, app.ProcessBlockConcurrent) - case acltypes.ErrGovMsgInBlock: - ctx.Logger().Info(fmt.Sprintf("Gov msg found while building DAG, processing synchronously: %s", err)) - txResults = app.ProcessBlockSynchronous(ctx, txs) - metrics.IncrDagBuildErrorCounter(metrics.GovMsgInBlock) - default: - ctx.Logger().Error(fmt.Sprintf("Error while building DAG, processing synchronously: %s", err)) - txResults = app.ProcessBlockSynchronous(ctx, txs) - metrics.IncrDagBuildErrorCounter(metrics.FailedToBuild) - } - - return txResults, ctx +func (app *App) BuildDependenciesAndRunTxs(ctx sdk.Context, txs [][]byte, typedTxs []sdk.Tx, absoluteTxIndices []int) ([]*abci.ExecTxResult, sdk.Context) { + // dependencyDag, err := app.AccessControlKeeper.BuildDependencyDag(ctx, app.GetAnteDepGenerator(), typedTxs) + + // switch err { + // case nil: + // txResults, ctx = app.ProcessTxs(ctx, txs, typedTxs, dependencyDag, app.ProcessBlockConcurrent, absoluteTxIndices) + // case acltypes.ErrGovMsgInBlock: + // ctx.Logger().Info(fmt.Sprintf("Gov msg found while building DAG, processing synchronously: %s", err)) + // txResults = app.ProcessBlockSynchronous(ctx, txs, typedTxs, absoluteTxIndices) + // metrics.IncrDagBuildErrorCounter(metrics.GovMsgInBlock) + // default: + // ctx.Logger().Error(fmt.Sprintf("Error while building DAG, processing synchronously: %s", err)) + // txResults = app.ProcessBlockSynchronous(ctx, txs, typedTxs, absoluteTxIndices) + // metrics.IncrDagBuildErrorCounter(metrics.FailedToBuild) + // } + + return app.ProcessBlockSynchronous(ctx, txs, typedTxs, absoluteTxIndices), ctx } func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequest, lastCommit abci.CommitInfo) ([]abci.Event, []*abci.ExecTxResult, abci.ResponseEndBlock, error) { @@ -1403,10 +1508,12 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ events = append(events, beginBlockResp.Events...) txResults := make([]*abci.ExecTxResult, len(txs)) - prioritizedTxs, otherTxs, prioritizedIndices, otherIndices := app.PartitionPrioritizedTxs(ctx, txs) + typedTxs := app.DecodeTransactionsConcurrently(ctx, txs) + + prioritizedTxs, otherTxs, prioritizedTypedTxs, otherTypedTxs, prioritizedIndices, otherIndices := app.PartitionPrioritizedTxs(ctx, txs, typedTxs) // run the prioritized txs - prioritizedResults, ctx := app.ExecuteTxsConcurrently(ctx, prioritizedTxs) + prioritizedResults, ctx := app.ExecuteTxsConcurrently(ctx, prioritizedTxs, prioritizedTypedTxs, prioritizedIndices) for relativePrioritizedIndex, originalIndex := range prioritizedIndices { txResults[originalIndex] = prioritizedResults[relativePrioritizedIndex] } @@ -1418,10 +1525,11 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ midBlockEvents := app.MidBlock(ctx, req.GetHeight()) events = append(events, midBlockEvents...) - otherResults, ctx := app.ExecuteTxsConcurrently(ctx, otherTxs) + otherResults, ctx := app.ExecuteTxsConcurrently(ctx, otherTxs, otherTypedTxs, otherIndices) for relativeOtherIndex, originalIndex := range otherIndices { txResults[originalIndex] = otherResults[relativeOtherIndex] } + app.EvmKeeper.SetTxResults(txResults) // Finalize all Bank Module Transfers here so that events are included lazyWriteEvents := app.BankKeeper.WriteDeferredBalances(ctx) @@ -1435,6 +1543,35 @@ func (app *App) ProcessBlock(ctx sdk.Context, txs [][]byte, req BlockProcessRequ return events, txResults, endBlockResp, nil } +func (app *App) DecodeTransactionsConcurrently(ctx sdk.Context, txs [][]byte) []sdk.Tx { + typedTxs := make([]sdk.Tx, len(txs)) + wg := sync.WaitGroup{} + for i, tx := range txs { + wg.Add(1) + go func(idx int, encodedTx []byte) { + defer wg.Done() + typedTx, err := app.txDecoder(encodedTx) + // get txkey from tx + if err != nil { + ctx.Logger().Error(fmt.Sprintf("error decoding transaction at index %d due to %s", idx, err)) + typedTxs[idx] = nil + } else { + if isEVM, _ := evmante.IsEVMMessage(typedTx); isEVM { + msg := evmtypes.MustGetEVMTransactionMessage(typedTx) + if err := evmante.Preprocess(ctx, msg); err != nil { + ctx.Logger().Error(fmt.Sprintf("error preprocessing EVM tx due to %s", err)) + typedTxs[idx] = nil + return + } + } + typedTxs[idx] = typedTx + } + }(i, tx) + } + wg.Wait() + return typedTxs +} + func (app *App) addBadWasmDependenciesToContext(ctx sdk.Context, txResults []*abci.ExecTxResult) sdk.Context { wasmContractsWithIncorrectDependencies := []sdk.AccAddress{} for _, txResult := range txResults { @@ -1458,6 +1595,9 @@ func (app *App) addBadWasmDependenciesToContext(ctx sdk.Context, txResults []*ab } func (app *App) getFinalizeBlockResponse(appHash []byte, events []abci.Event, txResults []*abci.ExecTxResult, endBlockResp abci.ResponseEndBlock) abci.ResponseFinalizeBlock { + if app.EvmKeeper.EthReplayConfig.Enabled || app.EvmKeeper.EthBlockTestConfig.Enabled { + return abci.ResponseFinalizeBlock{} + } return abci.ResponseFinalizeBlock{ Events: events, TxResults: txResults, @@ -1578,6 +1718,37 @@ func (app *App) RegisterTxService(clientCtx client.Context) { // RegisterTendermintService implements the Application.RegisterTendermintService method. func (app *App) RegisterTendermintService(clientCtx client.Context) { tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry) + + ctxProvider := func(i int64) sdk.Context { + if i == evmrpc.LatestCtxHeight { + return app.GetCheckCtx() + } + ctx, err := app.CreateQueryContext(i, false) + if err != nil { + app.Logger().Error(fmt.Sprintf("failed to create query context for EVM; using latest context instead: %v+", err.Error())) + return app.GetCheckCtx() + } + return ctx + } + if app.evmRPCConfig.HTTPEnabled { + evmHTTPServer, err := evmrpc.NewEVMHTTPServer(app.Logger(), app.evmRPCConfig, clientCtx.Client, &app.EvmKeeper, ctxProvider, app.encodingConfig.TxConfig, DefaultNodeHome) + if err != nil { + panic(err) + } + if err := evmHTTPServer.Start(); err != nil { + panic(err) + } + } + + if app.evmRPCConfig.WSEnabled { + evmWSServer, err := evmrpc.NewEVMWebSocketServer(app.Logger(), app.evmRPCConfig, clientCtx.Client, &app.EvmKeeper, ctxProvider, app.encodingConfig.TxConfig, DefaultNodeHome) + if err != nil { + panic(err) + } + if err := evmWSServer.Start(); err != nil { + panic(err) + } + } } func (app *App) checkTotalBlockGasWanted(ctx sdk.Context, txs [][]byte) bool { @@ -1610,6 +1781,10 @@ func (app *App) checkTotalBlockGasWanted(ctx sdk.Context, txs [][]byte) bool { return true } +func (app *App) GetTxConfig() client.TxConfig { + return app.encodingConfig.TxConfig +} + // GetMaccPerms returns a copy of the module account permissions func GetMaccPerms() map[string][]string { dupMaccPerms := make(map[string][]string) @@ -1636,6 +1811,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(ibchost.ModuleName) paramsKeeper.Subspace(oracletypes.ModuleName) paramsKeeper.Subspace(wasm.ModuleName) + paramsKeeper.Subspace(evmtypes.ModuleName) paramsKeeper.Subspace(dexmoduletypes.ModuleName) paramsKeeper.Subspace(epochmoduletypes.ModuleName) paramsKeeper.Subspace(tokenfactorytypes.ModuleName) diff --git a/app/app_test.go b/app/app_test.go index 9078456b13..ec48c50a0d 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -2,7 +2,9 @@ package app_test import ( "context" + "encoding/hex" "fmt" + "math/big" "testing" "time" @@ -12,9 +14,15 @@ import ( acltypes "github.com/cosmos/cosmos-sdk/x/accesscontrol/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/k0kubun/pp/v3" "github.com/sei-protocol/sei-chain/app" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" dextypes "github.com/sei-protocol/sei-chain/x/dex/types" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -27,7 +35,7 @@ func TestEmptyBlockIdempotency(t *testing.T) { valPub := secp256k1.GenPrivKey().PubKey() for i := 1; i <= 10; i++ { - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) res, _ := testWrapper.App.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{Height: 1}) testWrapper.App.Commit(context.Background()) data := res.AppHash @@ -109,7 +117,7 @@ func TestPartitionPrioritizedTxs(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) account := sdk.AccAddress(valPub.Address()).String() validator := sdk.ValAddress(valPub.Address()).String() @@ -192,12 +200,22 @@ func TestPartitionPrioritizedTxs(t *testing.T) { otherTx, mixedTx, } + typedTxs := []sdk.Tx{ + oracleTxBuilder.GetTx(), + contractRegisterBuilder.GetTx(), + contractUnregisterBuilder.GetTx(), + contractUnsuspendBuilder.GetTx(), + otherTxBuilder.GetTx(), + mixedTxBuilder.GetTx(), + } - prioritizedTxs, otherTxs, prioIdxs, otherIdxs := testWrapper.App.PartitionPrioritizedTxs(testWrapper.Ctx, txs) + prioritizedTxs, otherTxs, prioritizedTypedTxs, otherTypedTxs, prioIdxs, otherIdxs := testWrapper.App.PartitionPrioritizedTxs(testWrapper.Ctx, txs, typedTxs) require.Equal(t, [][]byte{oracleTx, contractRegisterTx, contractUnregisterTx, contractSuspendTx}, prioritizedTxs) require.Equal(t, [][]byte{otherTx, mixedTx}, otherTxs) require.Equal(t, []int{0, 1, 2, 3}, prioIdxs) require.Equal(t, []int{4, 5}, otherIdxs) + require.Equal(t, 4, len(prioritizedTypedTxs)) + require.Equal(t, 2, len(otherTypedTxs)) diffOrderTxs := [][]byte{ oracleTx, @@ -207,12 +225,22 @@ func TestPartitionPrioritizedTxs(t *testing.T) { mixedTx, contractSuspendTx, } + differOrderTypedTxs := []sdk.Tx{ + oracleTxBuilder.GetTx(), + otherTxBuilder.GetTx(), + contractRegisterBuilder.GetTx(), + contractUnregisterBuilder.GetTx(), + mixedTxBuilder.GetTx(), + contractUnsuspendBuilder.GetTx(), + } - prioritizedTxs, otherTxs, prioIdxs, otherIdxs = testWrapper.App.PartitionPrioritizedTxs(testWrapper.Ctx, diffOrderTxs) + prioritizedTxs, otherTxs, prioritizedTypedTxs, otherTypedTxs, prioIdxs, otherIdxs = testWrapper.App.PartitionPrioritizedTxs(testWrapper.Ctx, diffOrderTxs, differOrderTypedTxs) require.Equal(t, [][]byte{oracleTx, contractRegisterTx, contractUnregisterTx, contractSuspendTx}, prioritizedTxs) require.Equal(t, [][]byte{otherTx, mixedTx}, otherTxs) require.Equal(t, []int{0, 2, 3, 5}, prioIdxs) require.Equal(t, []int{1, 4}, otherIdxs) + require.Equal(t, 4, len(prioritizedTypedTxs)) + require.Equal(t, 2, len(otherTypedTxs)) } func TestProcessOracleAndOtherTxsSuccess(t *testing.T) { @@ -220,7 +248,7 @@ func TestProcessOracleAndOtherTxsSuccess(t *testing.T) { valPub := secp256k1.GenPrivKey().PubKey() secondAcc := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) account := sdk.AccAddress(valPub.Address()).String() account2 := sdk.AccAddress(secondAcc.Address()).String() @@ -306,7 +334,7 @@ func TestInvalidProposalWithExcessiveGasWanted(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) ap := testWrapper.App ctx := testWrapper.Ctx.WithConsensusParams(&types.ConsensusParams{ Block: &types.BlockParams{MaxGas: 10}, @@ -324,3 +352,55 @@ func TestInvalidProposalWithExcessiveGasWanted(t *testing.T) { require.Nil(t, err) require.Equal(t, abci.ResponseProcessProposal_REJECT, res.Status) } + +func TestDecodeTransactionsConcurrently(t *testing.T) { + tm := time.Now().UTC() + valPub := secp256k1.GenPrivKey().PubKey() + + testWrapper := app.NewTestWrapper(t, tm, valPub, false) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + to := new(common.Address) + copy(to[:], []byte("0x1234567890abcdef1234567890abcdef12345678")) + txData := ethtypes.LegacyTx{ + Nonce: 1, + GasPrice: big.NewInt(10), + Gas: 1000, + To: to, + Value: big.NewInt(1000), + Data: []byte("abc"), + } + chainCfg := evmtypes.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(big.NewInt(713715)) + signer := ethtypes.MakeSigner(ethCfg, big.NewInt(1), uint64(123)) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + ethtxdata, _ := ethtx.NewTxDataFromTx(tx) + if err != nil { + return + } + msg, _ := evmtypes.NewMsgEVMTransaction(ethtxdata) + txBuilder := testWrapper.App.GetTxConfig().NewTxBuilder() + txBuilder.SetMsgs(msg) + evmtxbz, _ := testWrapper.App.GetTxConfig().TxEncoder()(txBuilder.GetTx()) + + bankMsg := &banktypes.MsgSend{ + FromAddress: "", + ToAddress: "", + Amount: sdk.NewCoins(sdk.NewInt64Coin("usei", 2)), + } + + bankTxBuilder := testWrapper.App.GetTxConfig().NewTxBuilder() + bankTxBuilder.SetMsgs(bankMsg) + bankTxBuilder.SetGasLimit(200000) + bankTxBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewInt64Coin("usei", 20000))) + banktxbz, _ := testWrapper.App.GetTxConfig().TxEncoder()(bankTxBuilder.GetTx()) + + invalidbz := []byte("abc") + + typedTxs := testWrapper.App.DecodeTransactionsConcurrently(testWrapper.Ctx, [][]byte{evmtxbz, invalidbz, banktxbz}) + require.NotNil(t, typedTxs[0]) + require.NotNil(t, typedTxs[0].GetMsgs()[0].(*evmtypes.MsgEVMTransaction).Derived) + require.Nil(t, typedTxs[1]) + require.NotNil(t, typedTxs[2]) +} diff --git a/app/apptesting/test_suite.go b/app/apptesting/test_suite.go index 5d37134d1d..9d72cc9f64 100644 --- a/app/apptesting/test_suite.go +++ b/app/apptesting/test_suite.go @@ -38,7 +38,7 @@ type KeeperTestHelper struct { // Setup sets up basic environment for suite (App, Ctx, and test accounts) func (s *KeeperTestHelper) Setup() { - s.App = app.Setup(false) + s.App = app.Setup(false, false) s.Ctx = s.App.BaseApp.NewContext(false, tmtypes.Header{Height: 1, ChainID: "sei-test", Time: time.Now().UTC()}) s.Ctx = s.Ctx.WithContext(context.WithValue(s.Ctx.Context(), dexutils.DexMemStateContextKey, s.App.MemState)) s.QueryHelper = &baseapp.QueryServiceTestHelper{ diff --git a/app/eth_replay.go b/app/eth_replay.go new file mode 100644 index 0000000000..80b045068a --- /dev/null +++ b/app/eth_replay.go @@ -0,0 +1,236 @@ +package app + +import ( + "context" + "encoding/binary" + "fmt" + "math/big" + "path/filepath" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethcore "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/tracing" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + ethtests "github.com/ethereum/go-ethereum/tests" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/state" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" +) + +func Replay(a *App) { + h := a.EvmKeeper.GetReplayedHeight(a.GetCheckCtx()) + 1 + initHeight := a.EvmKeeper.GetReplayInitialHeight(a.GetCheckCtx()) + if h == 1 { + gendoc, err := tmtypes.GenesisDocFromFile(filepath.Join(DefaultNodeHome, "config/genesis.json")) + if err != nil { + panic(err) + } + _, err = a.InitChain(context.Background(), &abci.RequestInitChain{ + Time: time.Now(), + ChainId: gendoc.ChainID, + AppStateBytes: gendoc.AppState, + }) + if err != nil { + panic(err) + } + initHeight = a.EvmKeeper.GetReplayInitialHeight(a.GetContextForDeliverTx([]byte{})) + } else { + a.EvmKeeper.OpenEthDatabase() + } + for { + latestBlock, err := a.EvmKeeper.EthClient.BlockNumber(context.Background()) + if err != nil { + panic(err) + } + if latestBlock < uint64(h+initHeight) { + a.Logger().Info(fmt.Sprintf("Latest block is %d. Sleeping for a minute", latestBlock)) + time.Sleep(1 * time.Minute) + continue + } + a.Logger().Info(fmt.Sprintf("Replaying block height %d", h+initHeight)) + if h+initHeight >= 19426587 && evmtypes.DefaultChainConfig().CancunTime < 0 { + a.Logger().Error("Reaching Cancun upgrade height. Turn on Cancun by setting CancunTime in x/evm/types/config.go:DefaultChainConfig() to 0") + break + } else if h+initHeight < 19426587 && evmtypes.DefaultChainConfig().CancunTime >= 0 { + a.Logger().Error("Haven't reached Cancun upgrade height. Turn off Cancun by setting CancunTime in x/evm/types/config.go:DefaultChainConfig() to -1") + break + } + b, err := a.EvmKeeper.EthClient.BlockByNumber(context.Background(), big.NewInt(h+initHeight)) + if err != nil { + panic(err) + } + a.EvmKeeper.ReplayBlock = b + hash := make([]byte, 8) + binary.BigEndian.PutUint64(hash, uint64(h)) + _, err = a.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{ + Txs: utils.Map(b.Txs, func(tx *ethtypes.Transaction) []byte { return encodeTx(tx, a.GetTxConfig()) }), + DecidedLastCommit: abci.CommitInfo{Votes: []abci.VoteInfo{}}, + Height: h, + Hash: hash, + Time: time.Now(), + }) + if err != nil { + panic(err) + } + ctx := a.GetContextForDeliverTx([]byte{}) + s := state.NewDBImpl(ctx, &a.EvmKeeper, false) + for _, w := range b.Withdrawals() { + amount := new(big.Int).SetUint64(w.Amount) + amount = amount.Mul(amount, big.NewInt(params.GWei)) + s.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal) + } + _, _ = s.Finalize() + for _, tx := range b.Txs { + a.Logger().Info(fmt.Sprintf("Verifying tx %s", tx.Hash().Hex())) + if tx.To() != nil { + a.EvmKeeper.VerifyBalance(ctx, *tx.To()) + a.EvmKeeper.VerifyState(ctx, *tx.To()) + } + a.EvmKeeper.VerifyTxResult(ctx, tx.Hash()) + } + _, err = a.Commit(context.Background()) + if err != nil { + panic(err) + } + h++ + } +} + +func BlockTest(a *App, bt *ethtests.BlockTest) { + a.EvmKeeper.BlockTest = bt + a.EvmKeeper.EthBlockTestConfig.Enabled = true + + gendoc, err := tmtypes.GenesisDocFromFile(filepath.Join(DefaultNodeHome, "config/genesis.json")) + if err != nil { + panic(err) + } + _, err = a.InitChain(context.Background(), &abci.RequestInitChain{ + Time: time.Now(), + ChainId: gendoc.ChainID, + AppStateBytes: gendoc.AppState, + }) + if err != nil { + panic(err) + } + + for addr, genesisAccount := range a.EvmKeeper.BlockTest.Json.Pre { + usei, wei := state.SplitUseiWeiAmount(genesisAccount.Balance) + seiAddr := a.EvmKeeper.GetSeiAddressOrDefault(a.GetContextForDeliverTx([]byte{}), addr) + err := a.EvmKeeper.BankKeeper().AddCoins(a.GetContextForDeliverTx([]byte{}), seiAddr, sdk.NewCoins(sdk.NewCoin("usei", usei)), true) + if err != nil { + panic(err) + } + err = a.EvmKeeper.BankKeeper().AddWei(a.GetContextForDeliverTx([]byte{}), a.EvmKeeper.GetSeiAddressOrDefault(a.GetContextForDeliverTx([]byte{}), addr), wei) + if err != nil { + panic(err) + } + a.EvmKeeper.SetNonce(a.GetContextForDeliverTx([]byte{}), addr, genesisAccount.Nonce) + a.EvmKeeper.SetCode(a.GetContextForDeliverTx([]byte{}), addr, genesisAccount.Code) + for key, value := range genesisAccount.Storage { + a.EvmKeeper.SetState(a.GetContextForDeliverTx([]byte{}), addr, key, value) + } + params := a.EvmKeeper.GetParams(a.GetContextForDeliverTx([]byte{})) + params.MinimumFeePerGas = sdk.NewDecFromInt(sdk.NewInt(0)) + a.EvmKeeper.SetParams(a.GetContextForDeliverTx([]byte{}), params) + } + + if len(bt.Json.Blocks) == 0 { + panic("no blocks found") + } + + ethblocks := make([]*ethtypes.Block, 0) + for i, btBlock := range bt.Json.Blocks { + h := int64(i + 1) + b, err := btBlock.Decode() + if err != nil { + panic(err) + } + ethblocks = append(ethblocks, b) + hash := make([]byte, 8) + binary.BigEndian.PutUint64(hash, uint64(h)) + _, err = a.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{ + Txs: utils.Map(b.Txs, func(tx *ethtypes.Transaction) []byte { return encodeTx(tx, a.GetTxConfig()) }), + ProposerAddress: a.EvmKeeper.GetSeiAddressOrDefault(a.GetCheckCtx(), b.Coinbase()), + DecidedLastCommit: abci.CommitInfo{Votes: []abci.VoteInfo{}}, + Height: h, + Hash: hash, + Time: time.Now(), + }) + if err != nil { + panic(err) + } + _, err = a.Commit(context.Background()) + if err != nil { + panic(err) + } + } + + // Check post-state after all blocks are run + ctx := a.GetCheckCtx() + for addr, accountData := range bt.Json.Post { + if IsWithdrawalAddress(addr, ethblocks) { + fmt.Println("Skipping withdrawal address: ", addr) + continue + } + // Not checking compliance with EIP-4788 + if addr == params.BeaconRootsStorageAddress { + fmt.Println("Skipping beacon roots storage address: ", addr) + continue + } + a.EvmKeeper.VerifyAccount(ctx, addr, accountData) + fmt.Println("Successfully verified account: ", addr) + } +} + +func encodeTx(tx *ethtypes.Transaction, txConfig client.TxConfig) []byte { + var txData ethtx.TxData + var err error + switch tx.Type() { + case ethtypes.LegacyTxType: + txData, err = ethtx.NewLegacyTx(tx) + case ethtypes.DynamicFeeTxType: + txData, err = ethtx.NewDynamicFeeTx(tx) + case ethtypes.AccessListTxType: + txData, err = ethtx.NewAccessListTx(tx) + case ethtypes.BlobTxType: + txData, err = ethtx.NewBlobTx(tx) + } + if err != nil { + if strings.Contains(err.Error(), ethcore.ErrTipAboveFeeCap.Error()) { + return nil + } + panic(err) + } + msg, err := evmtypes.NewMsgEVMTransaction(txData) + if err != nil { + panic(err) + } + txBuilder := txConfig.NewTxBuilder() + if err = txBuilder.SetMsgs(msg); err != nil { + panic(err) + } + txbz, encodeErr := txConfig.TxEncoder()(txBuilder.GetTx()) + if encodeErr != nil { + panic(encodeErr) + } + return txbz +} + +func IsWithdrawalAddress(addr common.Address, blocks []*ethtypes.Block) bool { + for _, block := range blocks { + for _, w := range block.Withdrawals() { + if w.Address == addr { + return true + } + } + } + return false +} diff --git a/app/test_helpers.go b/app/test_helpers.go index e4b7e376fc..19823bf0b8 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -61,8 +61,8 @@ type TestWrapper struct { Ctx sdk.Context } -func NewTestWrapper(t *testing.T, tm time.Time, valPub crptotypes.PubKey, baseAppOptions ...func(*baseapp.BaseApp)) *TestWrapper { - appPtr := Setup(false, baseAppOptions...) +func NewTestWrapper(t *testing.T, tm time.Time, valPub crptotypes.PubKey, enableEVMCustomPrecompiles bool, baseAppOptions ...func(*baseapp.BaseApp)) *TestWrapper { + appPtr := Setup(false, enableEVMCustomPrecompiles, baseAppOptions...) ctx := appPtr.BaseApp.NewContext(false, tmproto.Header{Height: 1, ChainID: "sei-test", Time: tm}) ctx = ctx.WithContext(context.WithValue(ctx.Context(), dexutils.DexMemStateContextKey, appPtr.MemState)) wrapper := &TestWrapper{ @@ -155,7 +155,7 @@ func (s *TestWrapper) EndBlock() { s.App.EndBlocker(s.Ctx, reqEndBlock) } -func Setup(isCheckTx bool, baseAppOptions ...func(*baseapp.BaseApp)) *App { +func Setup(isCheckTx bool, enableEVMCustomPrecompiles bool, baseAppOptions ...func(*baseapp.BaseApp)) *App { db := dbm.NewMemDB() encodingConfig := MakeEncodingConfig() cdc := encodingConfig.Marshaler @@ -167,6 +167,7 @@ func Setup(isCheckTx bool, baseAppOptions ...func(*baseapp.BaseApp)) *App { map[int64]bool{}, DefaultNodeHome, 1, + enableEVMCustomPrecompiles, config.TestConfig(), encodingConfig, wasm.EnableAllProposals, @@ -197,7 +198,7 @@ func Setup(isCheckTx bool, baseAppOptions ...func(*baseapp.BaseApp)) *App { return app } -func SetupTestingAppWithLevelDb(isCheckTx bool) (*App, func()) { +func SetupTestingAppWithLevelDb(isCheckTx bool, enableEVMCustomPrecompiles bool) (*App, func()) { dir := "sei_testing" db, err := sdk.NewLevelDB("sei_leveldb_testing", dir) if err != nil { @@ -213,6 +214,7 @@ func SetupTestingAppWithLevelDb(isCheckTx bool) (*App, func()) { map[int64]bool{}, DefaultNodeHome, 5, + enableEVMCustomPrecompiles, nil, encodingConfig, wasm.EnableAllProposals, diff --git a/app/upgrade_test.go b/app/upgrade_test.go index d87c4dc714..1b1566c3ac 100644 --- a/app/upgrade_test.go +++ b/app/upgrade_test.go @@ -16,7 +16,7 @@ import ( func TestUpgradesListIsSorted(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) testWrapper.App.RegisterUpgradeHandlers() } @@ -24,7 +24,7 @@ func TestUpgradesListIsSorted(t *testing.T) { func TestDistributionCommunityTaxParamMigration(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) testWrapper.App.RegisterUpgradeHandlers() params := testWrapper.App.DistrKeeper.GetParams(testWrapper.Ctx) testWrapper.Require().Equal(params.CommunityTax, sdk.NewDec(0)) @@ -36,7 +36,7 @@ func TestSkipOptimisticProcessingOnUpgrade(t *testing.T) { t.Run("Test optimistic processing is skipped on upgrade", func(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) // No optimistic processing with upgrade scheduled testCtx := testWrapper.App.BaseApp.NewContext(false, tmproto.Header{Height: 3, ChainID: "sei-test", Time: tm}) @@ -59,7 +59,7 @@ func TestSkipOptimisticProcessingOnUpgrade(t *testing.T) { t.Run("Test optimistic processing if no upgrade", func(t *testing.T) { tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) testCtx := testWrapper.App.BaseApp.NewContext(false, tmproto.Header{Height: 3, ChainID: "sei-test", Time: tm}) testWrapper.App.UpgradeKeeper.ScheduleUpgrade(testWrapper.Ctx, types.Plan{ diff --git a/app/upgrades.go b/app/upgrades.go index 7347e98d96..5ab0017cc0 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -69,6 +69,24 @@ var upgradesList = []string{ "v3.6.1", "v3.7.0", "v3.8.0", + "v4.0.0-evm-devnet", + "v4.0.1-evm-devnet", + "v4.0.3-evm-devnet", + "v4.0.4-evm-devnet", + "v4.0.5-evm-devnet", + "v4.0.6-evm-devnet", + "v4.0.7-evm-devnet", + "v4.0.8-evm-devnet", + "v4.0.9-evm-devnet", + "v4.1.0-evm-devnet", + "v4.1.1-evm-devnet", + "v4.1.2-evm-devnet", + "v4.1.3-evm-devnet", + "v4.1.4-evm-devnet", + "v4.1.5-evm-devnet", + "v4.1.6-evm-devnet", + "v4.1.7-evm-devnet", + "v4.1.8-evm-devnet", } // if there is an override list, use that instead, for integration tests diff --git a/cmd/seid/cmd/blocktest.go b/cmd/seid/cmd/blocktest.go new file mode 100644 index 0000000000..10820a0968 --- /dev/null +++ b/cmd/seid/cmd/blocktest.go @@ -0,0 +1,118 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/CosmWasm/wasmd/x/wasm" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/spf13/cast" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/store" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" + ethtests "github.com/ethereum/go-ethereum/tests" + "github.com/sei-protocol/sei-chain/app" + "github.com/tendermint/tendermint/libs/log" + + //nolint:gosec,G108 + _ "net/http/pprof" +) + +//nolint:gosec +func BlocktestCmd(defaultNodeHome string) *cobra.Command { + cmd := &cobra.Command{ + Use: "blocktest", + Short: "run EF blocktest", + Long: "run EF blocktest", + RunE: func(cmd *cobra.Command, _ []string) error { + blockTestFileName, err := cmd.Flags().GetString("block-test") + if err != nil { + panic(fmt.Sprintf("Error with retrieving block test path: %v", err.Error())) + } + testName, err := cmd.Flags().GetString("test-name") + if err != nil { + panic(fmt.Sprintf("Error with retrieving test name: %v", err.Error())) + } + if blockTestFileName == "" || testName == "" { + panic("block test file name or test name not set") + } + + serverCtx := server.GetServerContextFromCmd(cmd) + if err := serverCtx.Viper.BindPFlags(cmd.Flags()); err != nil { + return err + } + home := serverCtx.Viper.GetString(flags.FlagHome) + db, err := openDB(home) + if err != nil { + return err + } + + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + cache := store.NewCommitKVStoreCacheManager() + wasmGasRegisterConfig := wasmkeeper.DefaultGasRegisterConfig() + wasmGasRegisterConfig.GasMultiplier = 21_000_000 + a := app.New( + logger, + db, + nil, + true, + map[int64]bool{}, + home, + 0, + true, + nil, + app.MakeEncodingConfig(), + wasm.EnableAllProposals, + serverCtx.Viper, + []wasm.Option{ + wasmkeeper.WithGasRegister( + wasmkeeper.NewWasmGasRegister( + wasmGasRegisterConfig, + ), + ), + }, + []aclkeeper.Option{}, + baseapp.SetPruning(storetypes.PruneEverything), + baseapp.SetMinGasPrices(cast.ToString(serverCtx.Viper.Get(server.FlagMinGasPrices))), + baseapp.SetMinRetainBlocks(cast.ToUint64(serverCtx.Viper.Get(server.FlagMinRetainBlocks))), + baseapp.SetInterBlockCache(cache), + ) + bt := testIngester(blockTestFileName, testName) + app.BlockTest(a, bt) + return nil + }, + } + + cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The database home directory") + cmd.Flags().String(flags.FlagChainID, "sei-chain", "chain ID") + cmd.Flags().String("block-test", "", "path to a block test json file") + cmd.Flags().String("test-name", "", "individual test name") + + return cmd +} + +func testIngester(testFilePath string, testName string) *ethtests.BlockTest { + file, err := os.Open(testFilePath) + if err != nil { + panic(err) + } + var tests map[string]ethtests.BlockTest + decoder := json.NewDecoder(file) + err = decoder.Decode(&tests) + if err != nil { + panic(err) + } + + res, ok := tests[testName] + if !ok { + panic(fmt.Sprintf("Unable to find test name %v at test file path %v", testName, testFilePath)) + } + + return &res +} diff --git a/cmd/seid/cmd/ethreplay.go b/cmd/seid/cmd/ethreplay.go new file mode 100644 index 0000000000..5c331393cb --- /dev/null +++ b/cmd/seid/cmd/ethreplay.go @@ -0,0 +1,98 @@ +package cmd + +import ( + "os" + "path/filepath" + + "github.com/CosmWasm/wasmd/x/wasm" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/spf13/cast" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/store" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" + "github.com/sei-protocol/sei-chain/app" + "github.com/tendermint/tendermint/libs/log" + dbm "github.com/tendermint/tm-db" + + "net/http" + //nolint:gosec,G108 + _ "net/http/pprof" +) + +//nolint:gosec +func ReplayCmd(defaultNodeHome string) *cobra.Command { + cmd := &cobra.Command{ + Use: "ethreplay", + Short: "replay EVM transactions", + Long: "replay EVM transactions", + RunE: func(cmd *cobra.Command, _ []string) error { + + serverCtx := server.GetServerContextFromCmd(cmd) + if err := serverCtx.Viper.BindPFlags(cmd.Flags()); err != nil { + return err + } + go func() { + serverCtx.Logger.Info("Listening for profiling at http://localhost:6060/debug/pprof/") + err := http.ListenAndServe(":6060", nil) + if err != nil { + serverCtx.Logger.Error("Error from profiling server", "error", err) + } + }() + + home := serverCtx.Viper.GetString(flags.FlagHome) + db, err := openDB(home) + if err != nil { + return err + } + + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + cache := store.NewCommitKVStoreCacheManager() + wasmGasRegisterConfig := wasmkeeper.DefaultGasRegisterConfig() + wasmGasRegisterConfig.GasMultiplier = 21_000_000 + a := app.New( + logger, + db, + nil, + true, + map[int64]bool{}, + home, + 0, + true, + nil, + app.MakeEncodingConfig(), + wasm.EnableAllProposals, + serverCtx.Viper, + []wasm.Option{ + wasmkeeper.WithGasRegister( + wasmkeeper.NewWasmGasRegister( + wasmGasRegisterConfig, + ), + ), + }, + []aclkeeper.Option{}, + baseapp.SetPruning(storetypes.PruneEverything), + baseapp.SetMinGasPrices(cast.ToString(serverCtx.Viper.Get(server.FlagMinGasPrices))), + baseapp.SetMinRetainBlocks(cast.ToUint64(serverCtx.Viper.Get(server.FlagMinRetainBlocks))), + baseapp.SetInterBlockCache(cache), + ) + app.Replay(a) + return nil + }, + } + + cmd.Flags().String(flags.FlagHome, defaultNodeHome, "The database home directory") + cmd.Flags().String(flags.FlagChainID, "sei-chain", "chain ID") + + return cmd +} + +func openDB(rootDir string) (dbm.DB, error) { + dataDir := filepath.Join(rootDir, "data") + return sdk.NewLevelDB("application", dataDir) +} diff --git a/cmd/seid/cmd/genaccounts.go b/cmd/seid/cmd/genaccounts.go index 13be456120..f7264452d6 100644 --- a/cmd/seid/cmd/genaccounts.go +++ b/cmd/seid/cmd/genaccounts.go @@ -2,14 +2,19 @@ package cmd import ( "bufio" + "crypto/ecdsa" + "encoding/hex" "encoding/json" "errors" "fmt" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" @@ -18,6 +23,8 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/sei-protocol/sei-chain/x/evm" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" ) const ( @@ -35,6 +42,7 @@ func AddGenesisAccountCmd(defaultNodeHome string) *cobra.Command { the account address or key name and a list of initial coins. If a key name is given, the address will be looked up in the local Keybase. The list of initial tokens must contain valid denominations. Accounts may optionally be supplied with vesting parameters. +The association between the sei address and the eth address will also be created here if using keyring-backend test. `, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { @@ -47,17 +55,17 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa config.SetRoot(clientCtx.HomeDir) - addr, err := sdk.AccAddressFromBech32(args[0]) - if err != nil { - inBuf := bufio.NewReader(cmd.InOrStdin()) - keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) + inBuf := bufio.NewReader(cmd.InOrStdin()) + keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend) - // attempt to lookup address from Keybase if no address was provided - kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf) - if err != nil { - return err - } + kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf) + if err != nil { + return err + } + addr, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + // this args[0] is for the key name so "admin" info, err := kb.Key(args[0]) if err != nil { return fmt.Errorf("failed to get address from Keybase: %w", err) @@ -65,6 +73,14 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa addr = info.GetAddress() } + var ethAddr common.Address + if keyringBackend == keyring.BackendTest { + pk, err := getPrivateKeyOfAddr(kb, addr) + if err != nil { + return err + } + ethAddr = crypto.PubkeyToAddress(pk.PublicKey) + } coins, err := sdk.ParseCoinsNormalized(args[1]) if err != nil { @@ -117,6 +133,20 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa if err != nil { return fmt.Errorf("failed to unmarshal genesis state: %w", err) } + if keyringBackend == keyring.BackendTest { + // associate the eth address with the sei address through the genesis file + evmGenState := evm.GetGenesisStateFromAppState(depCdc, appState) + seiEthAddrAssociation := evmtypes.AddressAssociation{ + SeiAddress: addr.String(), + EthAddress: ethAddr.Hex(), + } + evmGenState.AddressAssociations = append(evmGenState.AddressAssociations, &seiEthAddrAssociation) + evmGenStateBz, err := cdc.MarshalJSON(evmGenState) + if err != nil { + return fmt.Errorf("failed to marshal evm genesis state: %w", err) + } + appState[evmtypes.ModuleName] = evmGenStateBz + } authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState) @@ -164,6 +194,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa } genDoc.AppState = appStateJSON + return genutil.ExportGenesisFile(genDoc, genFile) }, } @@ -177,3 +208,31 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa return cmd } + +func getPrivateKeyOfAddr(kb keyring.Keyring, addr sdk.Address) (*ecdsa.PrivateKey, error) { + keys, err := kb.List() + if err != nil { + return nil, err + } + for _, key := range keys { + localInfo, ok := key.(keyring.LocalInfo) + if !ok { + // will only show local key + return nil, errors.New("not local key") + } + if localInfo.GetAddress().Equals(addr) { + priv, err := legacy.PrivKeyFromBytes([]byte(localInfo.PrivKeyArmor)) + if err != nil { + return nil, err + } + privHex := hex.EncodeToString(priv.Bytes()) + // Need to use private key to convert to sei address here + privKey, err := crypto.HexToECDSA(privHex) + if err != nil { + return nil, err + } + return privKey, nil + } + } + return nil, errors.New("not found") +} diff --git a/cmd/seid/cmd/root.go b/cmd/seid/cmd/root.go index aefb6d4b16..1d86266add 100644 --- a/cmd/seid/cmd/root.go +++ b/cmd/seid/cmd/root.go @@ -36,7 +36,11 @@ import ( genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" "github.com/sei-protocol/sei-chain/app" "github.com/sei-protocol/sei-chain/app/params" + "github.com/sei-protocol/sei-chain/evmrpc" "github.com/sei-protocol/sei-chain/tools" + "github.com/sei-protocol/sei-chain/x/evm/blocktest" + "github.com/sei-protocol/sei-chain/x/evm/querier" + "github.com/sei-protocol/sei-chain/x/evm/replay" "github.com/spf13/cast" "github.com/spf13/cobra" tmcfg "github.com/tendermint/tendermint/config" @@ -157,6 +161,8 @@ func initRootCmd( queryCommand(), txCommand(), keys.Commands(app.DefaultNodeHome), + ReplayCmd(app.DefaultNodeHome), + BlocktestCmd(app.DefaultNodeHome), ) } @@ -268,6 +274,7 @@ func newApp( skipUpgradeHeights, cast.ToString(appOpts.Get(flags.FlagHome)), cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), + true, tmConfig, app.MakeEncodingConfig(), wasm.EnableAllProposals, @@ -317,12 +324,12 @@ func appExport( } if height != -1 { - exportableApp = app.New(logger, db, traceStore, false, map[int64]bool{}, cast.ToString(appOpts.Get(flags.FlagHome)), uint(1), nil, encCfg, app.GetWasmEnabledProposals(), appOpts, app.EmptyWasmOpts, app.EmptyACLOpts) + exportableApp = app.New(logger, db, traceStore, false, map[int64]bool{}, cast.ToString(appOpts.Get(flags.FlagHome)), uint(1), true, nil, encCfg, app.GetWasmEnabledProposals(), appOpts, app.EmptyWasmOpts, app.EmptyACLOpts) if err := exportableApp.LoadHeight(height); err != nil { return servertypes.ExportedApp{}, err } } else { - exportableApp = app.New(logger, db, traceStore, true, map[int64]bool{}, cast.ToString(appOpts.Get(flags.FlagHome)), uint(1), nil, encCfg, app.GetWasmEnabledProposals(), appOpts, app.EmptyWasmOpts, app.EmptyACLOpts) + exportableApp = app.New(logger, db, traceStore, true, map[int64]bool{}, cast.ToString(appOpts.Get(flags.FlagHome)), uint(1), true, nil, encCfg, app.GetWasmEnabledProposals(), appOpts, app.EmptyWasmOpts, app.EmptyACLOpts) } return exportableApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs) @@ -366,6 +373,14 @@ func initAppConfig() (string, interface{}) { serverconfig.Config WASM WASMConfig `mapstructure:"wasm"` + + EVM evmrpc.Config `mapstructure:"evm"` + + ETHReplay replay.Config `mapstructure:"eth_replay"` + + ETHBlockTest blocktest.Config `mapstructure:"eth_block_test"` + + EvmQuery querier.Config `mapstructure:"evm_query"` } // Optionally allow the chain developer to overwrite the SDK's default @@ -392,8 +407,8 @@ func initAppConfig() (string, interface{}) { // - random: if everyone has the same value, the block that everyone prunes will be slow // - prime: no overlap primes := getPrimeNums(2500, 4000) - rand.Seed(time.Now().Unix()) - pruningInterval := primes[rand.Intn(len(primes))] + r := rand.New(rand.NewSource(time.Now().Unix())) + pruningInterval := primes[r.Intn(len(primes))] srvCfg.PruningInterval = fmt.Sprintf("%d", pruningInterval) // Metrics @@ -405,6 +420,10 @@ func initAppConfig() (string, interface{}) { LruSize: 1, QueryGasLimit: 300000, }, + EVM: evmrpc.DefaultConfig, + ETHReplay: replay.DefaultConfig, + ETHBlockTest: blocktest.DefaultConfig, + EvmQuery: querier.DefaultConfig, } customAppTemplate := serverconfig.DefaultConfigTemplate + ` @@ -413,7 +432,78 @@ func initAppConfig() (string, interface{}) { query_gas_limit = 300000 # This is the number of wasm vm instances we keep cached in memory for speed-up # Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally -lru_size = 0` +lru_size = 0 + +[evm] +# controls whether an HTTP EVM server is enabled +http_enabled = {{ .EVM.HTTPEnabled }} +http_port = {{ .EVM.HTTPPort }} + +# controls whether a websocket server is enabled +ws_enabled = {{ .EVM.WSEnabled }} +ws_port = {{ .EVM.WSPort }} + +# ReadTimeout is the maximum duration for reading the entire +# request, including the body. +# Because ReadTimeout does not let Handlers make per-request +# decisions on each request body's acceptable deadline or +# upload rate, most users will prefer to use +# ReadHeaderTimeout. It is valid to use them both. +read_timeout = "{{ .EVM.ReadTimeout }}" + +# ReadHeaderTimeout is the amount of time allowed to read +# request headers. The connection's read deadline is reset +# after reading the headers and the Handler can decide what +# is considered too slow for the body. If ReadHeaderTimeout +# is zero, the value of ReadTimeout is used. If both are +# zero, there is no timeout. +read_header_timeout = "{{ .EVM.ReadHeaderTimeout }}" + +# WriteTimeout is the maximum duration before timing out +# writes of the response. It is reset whenever a new +# request's header is read. Like ReadTimeout, it does not +# let Handlers make decisions on a per-request basis. +write_timeout = "{{ .EVM.WriteTimeout }}" + +# IdleTimeout is the maximum amount of time to wait for the +# next request when keep-alives are enabled. If IdleTimeout +# is zero, the value of ReadTimeout is used. If both are +# zero, ReadHeaderTimeout is used. +idle_timeout = "{{ .EVM.IdleTimeout }}" + +# Maximum gas limit for simulation +simulation_gas_limit = {{ .EVM.SimulationGasLimit }} + +# Timeout for EVM call in simulation +simulation_evm_timeout = "{{ .EVM.SimulationEVMTimeout }}" + +# list of CORS allowed origins, separated by comma +cors_origins = "{{ .EVM.CORSOrigins }}" + +# list of WS origins, separated by comma +ws_origins = "{{ .EVM.WSOrigins }}" + +# timeout for filters +filter_timeout = "{{ .EVM.FilterTimeout }}" + +# checkTx timeout for sig verify +checktx_timeout = "{{ .EVM.CheckTxTimeout }}" + +# controls whether to have txns go through one by one +slow = {{ .EVM.Slow }} + +[eth_replay] +eth_replay_enabled = {{ .ETHReplay.Enabled }} +eth_rpc = "{{ .ETHReplay.EthRPC }}" +eth_data_dir = "{{ .ETHReplay.EthDataDir }}" + +[eth_blocktest] +eth_blocktest_enabled = {{ .ETHBlockTest.Enabled }} +eth_blocktest_test_data_path = "{{ .ETHBlockTest.TestDataPath }}" + +[evm_query] +evm_query_gas_limit = {{ .EvmQuery.GasLimit }} +` return customAppTemplate, customAppConfig } diff --git a/contracts/.gitignore b/contracts/.gitignore new file mode 100644 index 0000000000..d6abde7f32 --- /dev/null +++ b/contracts/.gitignore @@ -0,0 +1,15 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env +.openzeppelin diff --git a/contracts/README.md b/contracts/README.md new file mode 100644 index 0000000000..9265b45584 --- /dev/null +++ b/contracts/README.md @@ -0,0 +1,66 @@ +## Foundry + +**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** + +Foundry consists of: + +- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). +- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. +- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. +- **Chisel**: Fast, utilitarian, and verbose solidity REPL. + +## Documentation + +https://book.getfoundry.sh/ + +## Usage + +### Build + +```shell +$ forge build +``` + +### Test + +```shell +$ forge test +``` + +### Format + +```shell +$ forge fmt +``` + +### Gas Snapshots + +```shell +$ forge snapshot +``` + +### Anvil + +```shell +$ anvil +``` + +### Deploy + +```shell +$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key +``` + +### Cast + +```shell +$ cast +``` + +### Help + +```shell +$ forge --help +$ anvil --help +$ cast --help +``` diff --git a/contracts/config/client.toml b/contracts/config/client.toml new file mode 100644 index 0000000000..222695a3f8 --- /dev/null +++ b/contracts/config/client.toml @@ -0,0 +1,17 @@ +# This is a TOML config file. +# For more information, see https://github.com/toml-lang/toml + +############################################################################### +### Client Configuration ### +############################################################################### + +# The network chain ID +chain-id = "" +# The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory) +keyring-backend = "os" +# CLI output format (text|json) +output = "text" +# : to Tendermint RPC interface for this chain +node = "tcp://localhost:26657" +# Transaction broadcasting mode (sync|async|block) +broadcast-mode = "sync" diff --git a/contracts/hardhat.config.js b/contracts/hardhat.config.js new file mode 100644 index 0000000000..5160e48ffd --- /dev/null +++ b/contracts/hardhat.config.js @@ -0,0 +1,36 @@ +require('dotenv').config({path:__dirname+'/.env'}) +require("@nomicfoundation/hardhat-toolbox"); +require('@openzeppelin/hardhat-upgrades'); + +/** @type import('hardhat/config').HardhatUserConfig */ +module.exports = { + solidity: { + version: "0.8.20", + settings: { + optimizer: { + enabled: true, + runs: 1000, + }, + }, + }, + paths: { + sources: "./src", // contracts are in ./src + }, + networks: { + goerli: { + url: "https://eth-goerli.g.alchemy.com/v2/NHwLuOObixEHj3aKD4LzN5y7l21bopga", // Replace with your JSON-RPC URL + address: ["0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52"], + accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e"], // Replace with your private key + }, + sei: { + url: "https://evm-devnet.seinetwork.io", // Replace with your JSON-RPC URL + address: ["0x07dc55085b721947d5c1645a07929eac9f1cc750"], + accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e"], // Replace with your private key + }, + seilocal: { + url: "http://127.0.0.1:8545", + address: ["0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"], + accounts: ["0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e", "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"], // Replace with your private key + } + }, +}; diff --git a/contracts/lib/forge-std b/contracts/lib/forge-std new file mode 160000 index 0000000000..bdea49f9bb --- /dev/null +++ b/contracts/lib/forge-std @@ -0,0 +1 @@ +Subproject commit bdea49f9bb3c58c8c35850c3bdc17eaeea756e9a diff --git a/contracts/lib/openzeppelin-contracts b/contracts/lib/openzeppelin-contracts new file mode 160000 index 0000000000..932fddf69a --- /dev/null +++ b/contracts/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 932fddf69a699a9a80fd2396fd1a2ab91cdda123 diff --git a/contracts/package-lock.json b/contracts/package-lock.json new file mode 100644 index 0000000000..a4d1415c18 --- /dev/null +++ b/contracts/package-lock.json @@ -0,0 +1,25179 @@ +{ + "name": "sei-chain", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "sei-chain", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@openzeppelin/contracts": "^5.0.1", + "@openzeppelin/upgrades-core": "^1.32.3", + "dotenv": "^16.3.1", + "lodash": "^4.17.21" + }, + "devDependencies": { + "@nomicfoundation/hardhat-foundry": "^1.1.1", + "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "@openzeppelin/hardhat-upgrades": "^3.0.2", + "@openzeppelin/test-helpers": "^0.5.16", + "dotenv": "^16.3.1", + "ethers": "^6.11.1", + "hardhat": "^2.20.1" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", + "dev": true + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz", + "integrity": "sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==", + "dev": true, + "dependencies": { + "@aws-crypto/util": "^1.2.2", + "@aws-sdk/types": "^3.1.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-1.2.2.tgz", + "integrity": "sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==", + "dev": true, + "dependencies": { + "@aws-sdk/types": "^3.1.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dev": true, + "dependencies": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "dev": true, + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/util-utf8-browser/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@ensdomains/address-encoder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", + "integrity": "sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==", + "dev": true, + "dependencies": { + "bech32": "^1.1.3", + "blakejs": "^1.1.0", + "bn.js": "^4.11.8", + "bs58": "^4.0.1", + "crypto-addr-codec": "^0.1.7", + "nano-base32": "^1.0.1", + "ripemd160": "^2.0.2" + } + }, + "node_modules/@ensdomains/address-encoder/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/@ensdomains/ens": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.4.5.tgz", + "integrity": "sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true, + "dependencies": { + "bluebird": "^3.5.2", + "eth-ens-namehash": "^2.0.8", + "solc": "^0.4.20", + "testrpc": "0.0.1", + "web3-utils": "^1.0.0-beta.31" + } + }, + "node_modules/@ensdomains/ens/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/@ensdomains/ens/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/@ensdomains/ens/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@ensdomains/ens/node_modules/require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@ensdomains/ens/node_modules/solc": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.26.tgz", + "integrity": "sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==", + "dev": true, + "dependencies": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" + }, + "bin": { + "solcjs": "solcjs" + } + }, + "node_modules/@ensdomains/ens/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ensdomains/ens/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/@ensdomains/ens/node_modules/yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dev": true, + "dependencies": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "node_modules/@ensdomains/ens/node_modules/yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + }, + "node_modules/@ensdomains/ensjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ensdomains/ensjs/-/ensjs-2.1.0.tgz", + "integrity": "sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.4.4", + "@ensdomains/address-encoder": "^0.1.7", + "@ensdomains/ens": "0.4.5", + "@ensdomains/resolver": "0.2.4", + "content-hash": "^2.5.2", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.0.13", + "js-sha3": "^0.8.0" + } + }, + "node_modules/@ensdomains/ensjs/node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/@ensdomains/resolver": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true + }, + "node_modules/@ethereumjs/common": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz", + "integrity": "sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/common/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@ethereumjs/common/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz", + "integrity": "sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "^2.6.4", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/tx/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@ethereumjs/tx/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "dev": true, + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.3.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nomicfoundation/edr": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.3.1.tgz", + "integrity": "sha512-uPg1/CvIJpsCe7Ipe80bYnC/Q2Bt/O55KB2ssLx7Z0os4jwDvWBZas8tLMopT+hpOQnv8cZkHJap1iNDTwAfQg==", + "dev": true, + "engines": { + "node": ">= 18" + }, + "optionalDependencies": { + "@nomicfoundation/edr-darwin-arm64": "0.3.1", + "@nomicfoundation/edr-darwin-x64": "0.3.1", + "@nomicfoundation/edr-linux-arm64-gnu": "0.3.1", + "@nomicfoundation/edr-linux-arm64-musl": "0.3.1", + "@nomicfoundation/edr-linux-x64-gnu": "0.3.1", + "@nomicfoundation/edr-linux-x64-musl": "0.3.1", + "@nomicfoundation/edr-win32-arm64-msvc": "0.3.1", + "@nomicfoundation/edr-win32-ia32-msvc": "0.3.1", + "@nomicfoundation/edr-win32-x64-msvc": "0.3.1" + } + }, + "node_modules/@nomicfoundation/edr-darwin-arm64": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.1.tgz", + "integrity": "sha512-qsdGS1Kfp6bVH4fk4hUzbsEm0fH7hGurraKk+IWby7Ecv+u7BuNaLVqeoYauYRFLYnGg8XZmcKOJ9BW35Y96Jg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-darwin-x64": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.1.tgz", + "integrity": "sha512-vtS2yuXIgjte42KEg/Aw/xmLRneVrIaDFhFMk578zg3m1UjNP+a29Lirw5fRXaqaL8aPyhRFmUy+1/V4MGaH+g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.1.tgz", + "integrity": "sha512-GrbQcrVjTFLm/x8HdUzmJ1F8Juau9UEZM/YNr4sAxxTGvBHJlq73VaDZfArxj9Anq/u6aImPbs1ksu28D6XC3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.1.tgz", + "integrity": "sha512-wOqugcbugmbZkh58PcIC5naT0ilwkZ0/qH86AniENxsviOaPSrL4aMYhtfypQ3MNxlfrlgLZFCC+D5eJTsNsgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.1.tgz", + "integrity": "sha512-V+kyUVqbt52dQRgaZK+EWuPWJ5h/PsCYZmiK18A+DQynZvird7jrTsDppcTvlv1Dvny8UAAP0q/ue7G67OoLJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-linux-x64-musl": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.1.tgz", + "integrity": "sha512-vwrzLW40jQBDZVYmoJUBMwl36i7muB9AfT4F2fMRsb1JoOMgoeOBp8R+IAxbA6mjIJGwAClkRz5W5hCb3zMtMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-win32-arm64-msvc": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.1.tgz", + "integrity": "sha512-7G29vUGrkwfbJqxo1V+QTxD976gVHx3Z0P5kwb1bErLmlP89cRNX3UN3/dzXpbKH9mp8ZcAjIcIbRUd4C+vH/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/edr-win32-ia32-msvc": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.1.tgz", + "integrity": "sha512-Q39eAkk/j1ZlvHcxQRTAzdY9qlckDNfiuJDgLYTlxdubpmX6KZucuUin/1A5NVhhCToTxw7aFwSglUROY3ejJw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.1.tgz", + "integrity": "sha512-8WzEzWUshw28xowVBhEyu4EQpx0TqNmDa70C3L1MWl5waym4U/VwbijFrI0Sb6Y1kdoNCdBTMvfr8OJNF2qJ/A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 18" + } + }, + "node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", + "integrity": "sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.4" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz", + "integrity": "sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==", + "dev": true, + "bin": { + "rlp": "bin/rlp.cjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz", + "integrity": "sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", + "integrity": "sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/hardhat-chai-matchers": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.3.tgz", + "integrity": "sha512-A40s7EAK4Acr8UP1Yudgi9GGD9Cca/K3LHt3DzmRIje14lBfHtg9atGQ7qK56vdPcTwKmeaGn30FzxMUfPGEMw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/chai-as-promised": "^7.1.3", + "chai-as-promised": "^7.1.1", + "deep-eql": "^4.0.1", + "ordinal": "^1.0.3" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "chai": "^4.2.0", + "ethers": "^6.1.0", + "hardhat": "^2.9.4" + } + }, + "node_modules/@nomicfoundation/hardhat-ethers": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.5.tgz", + "integrity": "sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==", + "dev": true, + "peer": true, + "dependencies": { + "debug": "^4.1.1", + "lodash.isequal": "^4.5.0" + }, + "peerDependencies": { + "ethers": "^6.1.0", + "hardhat": "^2.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-foundry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-foundry/-/hardhat-foundry-1.1.1.tgz", + "integrity": "sha512-cXGCBHAiXas9Pg9MhMOpBVQCkWRYoRFG7GJJAph+sdQsfd22iRs5U5Vs9XmpGEQd1yEvYISQZMeE68Nxj65iUQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "peerDependencies": { + "hardhat": "^2.17.2" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.10.tgz", + "integrity": "sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==", + "dev": true, + "peer": true, + "dependencies": { + "ethereumjs-util": "^7.1.4" + }, + "peerDependencies": { + "hardhat": "^2.9.5" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "peer": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@nomicfoundation/hardhat-toolbox": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-4.0.0.tgz", + "integrity": "sha512-jhcWHp0aHaL0aDYj8IJl80v4SZXWMS1A2XxXa1CA6pBiFfJKuZinCkO6wb+POAt0LIfXB3gA3AgdcOccrcwBwA==", + "dev": true, + "peerDependencies": { + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-network-helpers": "^1.0.0", + "@nomicfoundation/hardhat-verify": "^2.0.0", + "@typechain/ethers-v6": "^0.5.0", + "@typechain/hardhat": "^9.0.0", + "@types/chai": "^4.2.0", + "@types/mocha": ">=9.1.0", + "@types/node": ">=16.0.0", + "chai": "^4.2.0", + "ethers": "^6.4.0", + "hardhat": "^2.11.0", + "hardhat-gas-reporter": "^1.0.8", + "solidity-coverage": "^0.8.1", + "ts-node": ">=8.0.0", + "typechain": "^8.3.0", + "typescript": ">=4.5.0" + } + }, + "node_modules/@nomicfoundation/hardhat-verify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.3.tgz", + "integrity": "sha512-ESbRu9by53wu6VvgwtMtm108RSmuNsVqXtzg061D+/4R7jaWh/Wl/8ve+p6SdDX7vA1Z3L02hDO1Q3BY4luLXQ==", + "dev": true, + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@ethersproject/address": "^5.0.2", + "cbor": "^8.1.0", + "chalk": "^2.4.2", + "debug": "^4.1.1", + "lodash.clonedeep": "^4.5.0", + "semver": "^6.3.0", + "table": "^6.8.0", + "undici": "^5.14.0" + }, + "peerDependencies": { + "hardhat": "^2.0.4" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", + "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", + "dev": true, + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", + "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", + "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", + "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", + "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", + "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", + "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", + "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@openzeppelin/contract-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz", + "integrity": "sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/contracts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.1.tgz", + "integrity": "sha512-yQJaT5HDp9hYOOp4jTYxMsR02gdFZFXhewX5HW9Jo4fsqSVqqyIO/xTHdWDaKX5a3pv1txmf076Lziz+sO7L1w==" + }, + "node_modules/@openzeppelin/defender-admin-client": { + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/defender-admin-client/-/defender-admin-client-1.54.1.tgz", + "integrity": "sha512-kRpSUdTsnSqntp4FOXIm95t+6VKHc8CUY2Si71VDuxs0q7HSPZkdpRPSntcolwEzWy9L4a8NS/QMwDF5NJ4X1g==", + "dev": true, + "dependencies": { + "@openzeppelin/defender-base-client": "1.54.1", + "axios": "^1.4.0", + "ethers": "^5.7.2", + "lodash": "^4.17.19", + "node-fetch": "^2.6.0" + } + }, + "node_modules/@openzeppelin/defender-admin-client/node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/@openzeppelin/defender-base-client": { + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/defender-base-client/-/defender-base-client-1.54.1.tgz", + "integrity": "sha512-DRGz/7KN3ZQwu28YWMOaojrC7jjPkz/uCwkC8/C8B11qwZhA5qIVvyhYHhhFOCl0J84+E3TNdvkPD2q3p2WaJw==", + "dev": true, + "dependencies": { + "amazon-cognito-identity-js": "^6.0.1", + "async-retry": "^1.3.3", + "axios": "^1.4.0", + "lodash": "^4.17.19", + "node-fetch": "^2.6.0" + } + }, + "node_modules/@openzeppelin/defender-sdk-base-client": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.8.0.tgz", + "integrity": "sha512-XIJat6BW2CTM74AwG5IL0Q/aE6RXj8x7smnVKmBql4wMvmirVW+njfwzZCLhUTiBXg9AlHxIInEF14SabfIisg==", + "dev": true, + "dependencies": { + "amazon-cognito-identity-js": "^6.3.6", + "async-retry": "^1.3.3" + } + }, + "node_modules/@openzeppelin/defender-sdk-deploy-client": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.8.0.tgz", + "integrity": "sha512-/tNS2EnHuA5l095wzMbIkGMDNHZLcZQ2eLUP8z+AeKaAUeR2z4qzZ1ul21kR3EJURAyoy8aULFZanLggoBWHrA==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@openzeppelin/defender-sdk-base-client": "^1.8.0", + "axios": "^1.4.0", + "lodash": "^4.17.21" + } + }, + "node_modules/@openzeppelin/hardhat-upgrades": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-3.0.2.tgz", + "integrity": "sha512-Fk940cxwew++bfSZKWHEXVUCr3tRBiRZZBw1nl1wUVq29cq7BrlwDkZ6hTab/+p0IOnx0l6HJHLu3amDxxs3/w==", + "dev": true, + "dependencies": { + "@openzeppelin/defender-admin-client": "^1.52.0", + "@openzeppelin/defender-base-client": "^1.52.0", + "@openzeppelin/defender-sdk-base-client": "^1.8.0", + "@openzeppelin/defender-sdk-deploy-client": "^1.8.0", + "@openzeppelin/upgrades-core": "^1.32.0", + "chalk": "^4.1.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.1.5", + "proper-lockfile": "^4.1.1", + "undici": "^5.28.2" + }, + "bin": { + "migrate-oz-cli-project": "dist/scripts/migrate-oz-cli-project.js" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^2.0.0", + "ethers": "^6.6.0", + "hardhat": "^2.0.2" + }, + "peerDependenciesMeta": { + "@nomicfoundation/hardhat-verify": { + "optional": true + } + } + }, + "node_modules/@openzeppelin/hardhat-upgrades/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@openzeppelin/hardhat-upgrades/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@openzeppelin/hardhat-upgrades/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@openzeppelin/hardhat-upgrades/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@openzeppelin/hardhat-upgrades/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@openzeppelin/hardhat-upgrades/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@openzeppelin/hardhat-upgrades/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/hardhat-upgrades/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/test-helpers": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.16.tgz", + "integrity": "sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==", + "dev": true, + "dependencies": { + "@openzeppelin/contract-loader": "^0.6.2", + "@truffle/contract": "^4.0.35", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.5", + "web3-utils": "^1.2.5" + } + }, + "node_modules/@openzeppelin/test-helpers/node_modules/ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@openzeppelin/test-helpers/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true, + "peer": true + }, + "node_modules/@openzeppelin/test-helpers/node_modules/chai-bn": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.2.tgz", + "integrity": "sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==", + "dev": true, + "peerDependencies": { + "bn.js": "^4.11.0", + "chai": "^4.0.0" + } + }, + "node_modules/@openzeppelin/test-helpers/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@openzeppelin/upgrades-core": { + "version": "1.32.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.32.3.tgz", + "integrity": "sha512-v04RbrBOTRiIhfkTRfY4M34I2wIcuz+K1cUk/6duulsMXvRpM6/IPWeXh+1Xr1K+xedJi7gcS/pNSXfYhYNXIg==", + "dependencies": { + "cbor": "^9.0.0", + "chalk": "^4.1.0", + "compare-versions": "^6.0.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.0.3", + "minimist": "^1.2.7", + "proper-lockfile": "^4.1.1", + "solidity-ast": "^0.4.51" + }, + "bin": { + "openzeppelin-upgrades-core": "dist/cli/cli.js" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/cbor": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-9.0.1.tgz", + "integrity": "sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ==", + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@openzeppelin/upgrades-core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@scure/base": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", + "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==", + "dev": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@smithy/types": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.9.1.tgz", + "integrity": "sha512-vjXlKNXyprDYDuJ7UW5iobdmyDm6g8dDG+BFUncAg/3XJaN45Gy5RWWWUVgrzIK7S4R1KWgIX5LeJcfvSI24bw==", + "dev": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "peer": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@truffle/abi-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-1.0.3.tgz", + "integrity": "sha512-AWhs01HCShaVKjml7Z4AbVREr/u4oiWxCcoR7Cktm0mEvtT04pvnxW5xB/cI4znRkrbPdFQlFt67kgrAjesYkw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "change-case": "3.0.2", + "fast-check": "3.1.1", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/abi-utils/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@truffle/abi-utils/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@truffle/abi-utils/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/blockchain-utils": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.9.tgz", + "integrity": "sha512-RHfumgbIVo68Rv9ofDYfynjnYZIfP/f1vZy4RoqkfYAO+fqfc58PDRzB1WAGq2U6GPuOnipOJxQhnqNnffORZg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/codec": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.17.3.tgz", + "integrity": "sha512-Ko/+dsnntNyrJa57jUD9u4qx9nQby+H4GsUO6yjiCPSX0TQnEHK08XWqBSg0WdmCH2+h0y1nr2CXSx8gbZapxg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "@truffle/abi-utils": "^1.0.3", + "@truffle/compile-common": "^0.9.8", + "big.js": "^6.0.3", + "bn.js": "^5.1.3", + "cbor": "^5.2.0", + "debug": "^4.3.1", + "lodash": "^4.17.21", + "semver": "^7.5.4", + "utf8": "^3.0.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/codec/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/codec/node_modules/cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "dev": true, + "dependencies": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@truffle/codec/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@truffle/codec/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@truffle/codec/node_modules/nofilter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", + "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@truffle/codec/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@truffle/codec/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/compile-common": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.8.tgz", + "integrity": "sha512-DTpiyo32t/YhLI1spn84D3MHYHrnoVqO+Gp7ZHrYNwDs86mAxtNiH5lsVzSb8cPgiqlvNsRCU9nm9R0YmKMTBQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "@truffle/error": "^0.2.2", + "colors": "1.4.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract": { + "version": "4.6.31", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.31.tgz", + "integrity": "sha512-s+oHDpXASnZosiCdzu+X1Tx5mUJUs1L1CYXIcgRmzMghzqJkaUFmR6NpNo7nJYliYbO+O9/aW8oCKqQ7rCHfmQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "@ensdomains/ensjs": "^2.1.0", + "@truffle/blockchain-utils": "^0.1.9", + "@truffle/contract-schema": "^3.4.16", + "@truffle/debug-utils": "^6.0.57", + "@truffle/error": "^0.2.2", + "@truffle/interface-adapter": "^0.5.37", + "bignumber.js": "^7.2.1", + "debug": "^4.3.1", + "ethers": "^4.0.32", + "web3": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract-schema": { + "version": "3.4.16", + "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.16.tgz", + "integrity": "sha512-g0WNYR/J327DqtJPI70ubS19K1Fth/1wxt2jFqLsPmz5cGZVjCwuhiie+LfBde4/Mc9QR8G+L3wtmT5cyoBxAg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "ajv": "^6.10.0", + "debug": "^4.3.1" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract-schema/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@truffle/contract-schema/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "node_modules/@truffle/contract/node_modules/@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "node_modules/@truffle/contract/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@truffle/contract/node_modules/eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/@truffle/contract/node_modules/eth-lib/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@truffle/contract/node_modules/ethereum-cryptography/node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/@truffle/contract/node_modules/ethereum-cryptography/node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/ethereum-cryptography/node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "dependencies": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "node_modules/@truffle/contract/node_modules/ethers/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-accounts/node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/@truffle/contract/node_modules/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/debug-utils": { + "version": "6.0.57", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.57.tgz", + "integrity": "sha512-Q6oI7zLaeNLB69ixjwZk2UZEWBY6b2OD1sjLMGDKBGR7GaHYiw96GLR2PFgPH1uwEeLmV4N78LYaQCrDsHbNeA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "@truffle/codec": "^0.17.3", + "@trufflesuite/chromafi": "^3.0.0", + "bn.js": "^5.1.3", + "chalk": "^2.4.2", + "debug": "^4.3.1", + "highlightjs-solidity": "^2.0.6" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/error": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.2.tgz", + "integrity": "sha512-TqbzJ0O8DHh34cu8gDujnYl4dUl6o2DE4PR6iokbybvnIm/L2xl6+Gv1VC+YJS45xfH83Yo3/Zyg/9Oq8/xZWg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/interface-adapter": { + "version": "0.5.37", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.37.tgz", + "integrity": "sha512-lPH9MDgU+7sNDlJSClwyOwPCfuOimqsCx0HfGkznL3mcFRymc1pukAR1k17zn7ErHqBwJjiKAZ6Ri72KkS+IWw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "bn.js": "^5.1.3", + "ethers": "^4.0.32", + "web3": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/eth-lib/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/ethereum-cryptography/node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/ethereum-cryptography/node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/ethereum-cryptography/node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "dependencies": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/ethers/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-accounts/node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@trufflesuite/chromafi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@trufflesuite/chromafi/-/chromafi-3.0.0.tgz", + "integrity": "sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==", + "dev": true, + "dependencies": { + "camelcase": "^4.1.0", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "detect-indent": "^5.0.0", + "highlight.js": "^10.4.1", + "lodash.merge": "^4.6.2", + "strip-ansi": "^4.0.0", + "strip-indent": "^2.0.0" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@trufflesuite/chromafi/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true, + "peer": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "peer": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "peer": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "peer": true + }, + "node_modules/@typechain/ethers-v6": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz", + "integrity": "sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA==", + "dev": true, + "peer": true, + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "ethers": "6.x", + "typechain": "^8.3.2", + "typescript": ">=4.7.0" + } + }, + "node_modules/@typechain/hardhat": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-9.1.0.tgz", + "integrity": "sha512-mtaUlzLlkqTlfPwB3FORdejqBskSnh+Jl8AIJGjXNAQfRQ4ofHADPl1+oU7Z3pAJzmZbUXII8MhOLQltcHgKnA==", + "dev": true, + "peer": true, + "dependencies": { + "fs-extra": "^9.1.0" + }, + "peerDependencies": { + "@typechain/ethers-v6": "^0.5.1", + "ethers": "^6.1.0", + "hardhat": "^2.9.9", + "typechain": "^8.3.2" + } + }, + "node_modules/@typechain/hardhat/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "peer": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typechain/hardhat/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@typechain/hardhat/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", + "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", + "dev": true, + "peer": true + }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", + "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "peer": true + }, + "node_modules/@types/mocha": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", + "dev": true, + "peer": true + }, + "node_modules/@types/node": { + "version": "20.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", + "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true, + "peer": true + }, + "node_modules/@types/qs": { + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", + "dev": true, + "peer": true + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", + "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true, + "peer": true + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "dev": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amazon-cognito-identity-js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.7.tgz", + "integrity": "sha512-tSjnM7KyAeOZ7UMah+oOZ6cW4Gf64FFcc7BE2l7MTcp7ekAPrXaCbpcW2xEpH1EiDS4cPcAouHzmCuc2tr72vQ==", + "dev": true, + "dependencies": { + "@aws-crypto/sha256-js": "1.2.2", + "buffer": "4.9.2", + "fast-base64-decode": "^1.0.0", + "isomorphic-unfetch": "^3.0.0", + "js-cookie": "^2.2.1" + } + }, + "node_modules/amazon-cognito-identity-js/node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true, + "peer": true, + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true, + "peer": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "peer": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.3.tgz", + "integrity": "sha512-kcBubumjciBg4JKp5KTKtI7ec7tRefPk88yjkWJwaVKYd9QfTaxcsOxoMNKd7iBr447zCfDV0z1kOF47umv42g==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "peer": true + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true, + "peer": true + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dev": true, + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "node_modules/axios": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.4.tgz", + "integrity": "sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "node_modules/big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz", + "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/boxen/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "peer": true, + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=12.19" + } + }, + "node_modules/chai": { + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "peer": true, + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 5" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/change-case": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "constant-case": "^2.0.0", + "dot-case": "^2.1.0", + "header-case": "^1.0.0", + "is-lower-case": "^1.1.0", + "is-upper-case": "^1.1.0", + "lower-case": "^1.1.1", + "lower-case-first": "^1.0.0", + "no-case": "^2.3.2", + "param-case": "^2.1.0", + "pascal-case": "^2.0.0", + "path-case": "^2.1.0", + "sentence-case": "^2.1.0", + "snake-case": "^2.1.0", + "swap-case": "^1.1.0", + "title-case": "^2.1.0", + "upper-case": "^1.1.1", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "engines": { + "node": ">=4.0.0", + "npm": ">=3.0.0" + } + }, + "node_modules/cids/node_modules/multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "dev": true + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "peer": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cli-table3/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "node_modules/compare-versions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dev": true, + "dependencies": { + "snake-case": "^2.1.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dev": true, + "dependencies": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "peer": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "peer": true + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-addr-codec": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.8.tgz", + "integrity": "sha512-GqAK90iLLgP3FvhNmHbpT3wR6dEdaM8hZyZtLX29SPardh3OA13RFLHDR6sntGCgRWOfiHqW6sIyohpNqOtV/g==", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + } + }, + "node_modules/crypto-addr-codec/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true, + "peer": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "peer": true + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "peer": true, + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "peer": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "peer": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dev": true, + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "peer": true, + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "dev": true, + "dependencies": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "node_modules/eth-ens-namehash/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/eth-gas-reporter": { + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz", + "integrity": "sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==", + "dev": true, + "peer": true, + "dependencies": { + "@solidity-parser/parser": "^0.14.0", + "axios": "^1.5.1", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^5.7.2", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^10.2.0", + "req-cwd": "^2.0.0", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "peerDependencies": { + "@codechecks/client": "^0.1.0" + }, + "peerDependenciesMeta": { + "@codechecks/client": { + "optional": true + } + } + }, + "node_modules/eth-gas-reporter/node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "peer": true, + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/eth-lib/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/eth-lib/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "dependencies": { + "js-sha3": "^0.8.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-util/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/ethereumjs-util/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethers": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", + "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", + "dev": true + }, + "node_modules/ethers/node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/ethers/node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-abi/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-abi/node_modules/js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==", + "dev": true + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/express": { + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-base64-decode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", + "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==", + "dev": true + }, + "node_modules/fast-check": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.1.1.tgz", + "integrity": "sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==", + "dev": true, + "dependencies": { + "pure-rand": "^5.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "peer": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "peer": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", + "dev": true + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true, + "peer": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + }, + "bin": { + "testrpc-sc": "index.js" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "peer": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "peer": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-validator/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/har-validator/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/hardhat": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.1.tgz", + "integrity": "sha512-cTWYIJc5jQ132XUI8oRI/TO9L6oavPoJRCTRU9sIjkVxvkxz0Axz0K83Z3BEdJTqBQ2W84ZRoTekti84kBwCjg==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/edr": "^0.3.1", + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-tx": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "boxen": "^5.1.2", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "peer": true, + "dependencies": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + }, + "peerDependencies": { + "hardhat": "^2.0.2" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.3" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true, + "peer": true + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/highlightjs-solidity": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.6.tgz", + "integrity": "sha512-DySXWfQghjm2l6a/flF+cteroJqD4gI8GSdL4PtvxZSsAHie8m3yVe2JFoRg03ROKT6hp2Lc/BxXkqerNmtQYg==", + "dev": true + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "peer": true, + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", + "dev": true + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true, + "peer": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dev": true, + "dependencies": { + "punycode": "2.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/idna-uts46-hx/node_modules/punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "peer": true + }, + "node_modules/internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "dependencies": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "peer": true + }, + "node_modules/isomorphic-unfetch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", + "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.1", + "unfetch": "^4.2.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==", + "dev": true + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "peer": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "dev": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "peer": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "peer": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "dev": true, + "peer": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "peer": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, + "node_modules/lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.2" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lru-cache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "peer": true + }, + "node_modules/markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true, + "peer": true + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "peer": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "deprecated": "This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.", + "dev": true, + "dependencies": { + "mkdirp": "*" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mock-fs": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", + "dev": true + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "varint": "^5.0.0" + } + }, + "node_modules/multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "node_modules/multihashes/node_modules/multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/nano-base32": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", + "integrity": "sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==", + "dev": true + }, + "node_modules/nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "peer": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "peer": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.1.tgz", + "integrity": "sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "engines": { + "node": ">=12.19" + } + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "peer": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "node_modules/oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dev": true, + "dependencies": { + "http-https": "^1.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "peer": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ordinal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", + "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", + "dev": true, + "peer": true + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true, + "peer": true + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "dev": true + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "peer": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "peer": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "peer": true + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "peer": true, + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "peer": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "dependencies": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg/node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "peer": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "peer": true, + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "peer": true, + "dependencies": { + "req-from": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "peer": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/responselike/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "peer": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true, + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex-test": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "peer": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "node_modules/sc-istanbul/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/sc-istanbul/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "peer": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sc-istanbul/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/sc-istanbul/node_modules/js-yaml/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sc-istanbul/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true, + "peer": true + }, + "node_modules/sc-istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case-first": "^1.1.2" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dev": true, + "dependencies": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "peer": true, + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dev": true, + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/sha3/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "peer": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "dev": true, + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-get/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "node_modules/snake-case": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solidity-ast": { + "version": "0.4.55", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.55.tgz", + "integrity": "sha512-qeEU/r/K+V5lrAw8iswf2/yfWAnSGs3WKPHI+zAFKFjX0dIBVXEU/swQ8eJQYHf6PJWUZFO2uWV4V1wEOkeQbA==", + "dependencies": { + "array.prototype.findlast": "^1.2.2" + } + }, + "node_modules/solidity-coverage": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.5.tgz", + "integrity": "sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==", + "dev": true, + "peer": true, + "dependencies": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.16.0", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "10.2.0", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "bin": { + "solidity-coverage": "plugins/bin.js" + }, + "peerDependencies": { + "hardhat": "^2.11.0" + } + }, + "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", + "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", + "dev": true, + "peer": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/solidity-coverage/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/solidity-coverage/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "peer": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "peer": true + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "dev": true, + "peer": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1", + "upper-case": "^1.1.1" + } + }, + "node_modules/swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + } + }, + "node_modules/swarm-js/node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swarm-js/node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/swarm-js/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/swarm-js/node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/swarm-js/node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/swarm-js/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "peer": true, + "dependencies": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "peer": true, + "dependencies": { + "get-port": "^3.1.0" + } + }, + "node_modules/table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "peer": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "peer": true, + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/tar/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/testrpc": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/testrpc/-/testrpc-0.0.1.tgz", + "integrity": "sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==", + "deprecated": "testrpc has been renamed to ganache-cli, please use this package from now on.", + "dev": true + }, + "node_modules/then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "peer": true, + "dependencies": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/then-request/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true, + "peer": true + }, + "node_modules/then-request/node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "peer": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/ts-command-line-args": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", + "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", + "dev": true, + "peer": true, + "dependencies": { + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "bin": { + "write-markdown": "dist/write-markdown.js" + } + }, + "node_modules/ts-command-line-args/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-command-line-args/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-command-line-args/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "node_modules/ts-command-line-args/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-command-line-args/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "typescript": ">=3.7.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "peer": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "peer": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typechain": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz", + "integrity": "sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==", + "dev": true, + "peer": true, + "dependencies": { + "@types/prettier": "^2.1.1", + "debug": "^4.3.1", + "fs-extra": "^7.0.0", + "glob": "7.1.7", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "prettier": "^2.3.1", + "ts-command-line-args": "^2.2.0", + "ts-essentials": "^7.0.1" + }, + "bin": { + "typechain": "dist/cli/cli.js" + }, + "peerDependencies": { + "typescript": ">=4.3.0" + } + }, + "node_modules/typechain/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "peer": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typechain/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "peer": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "5.28.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", + "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", + "dev": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", + "dev": true + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, + "node_modules/upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", + "dev": true + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "peer": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/web3": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.4.tgz", + "integrity": "sha512-kgJvQZjkmjOEKimx/tJQsqWfRDPTTcBfYPa9XletxuHLpHcXdx67w8EFn5AW3eVxCutE9dTVHgGa9VYe8vgsEA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.4", + "web3-core": "1.10.4", + "web3-eth": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-shh": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.4.tgz", + "integrity": "sha512-ZZ/X4sJ0Uh2teU9lAGNS8EjveEppoHNQiKlOXAjedsrdWuaMErBPdLQjXfcrYvN6WM6Su9PMsAxf3FXXZ+HwQw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "node_modules/web3-core": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.4.tgz", + "integrity": "sha512-B6elffYm81MYZDTrat7aEhnhdtVE3lDBUZft16Z8awYMZYJDbnykEbJVS+l3mnA7AQTnSDr/1MjWofGDLBJPww==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-requestmanager": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.0.tgz", + "integrity": "sha512-pIxAzFDS5vnbXvfvLSpaA1tfRykAe9adw43YCKsEYQwH0gCLL0kMLkaCX3q+Q8EVmAh+e1jWL/nl9U0de1+++g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/web3-core-helpers/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web3-core-helpers/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.4.tgz", + "integrity": "sha512-uZTb7flr+Xl6LaDsyTeE2L1TylokCJwTDrIVfIfnrGmnwLc6bmTWCCrm71sSrQ0hqs6vp/MKbQYIYqUN0J8WyA==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/node_modules/web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-promievent": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.0.tgz", + "integrity": "sha512-68N7k5LWL5R38xRaKFrTFT2pm2jBNFaM4GioS00YjAKXRQ3KjmhijOMG3TICz6Aa5+6GDWYelDNx21YAeZ4YTg==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.4.tgz", + "integrity": "sha512-vqP6pKH8RrhT/2MoaU+DY/OsYK9h7HmEBNCdoMj+4ZwujQtw/Mq2JifjwsJ7gits7Q+HWJwx8q6WmQoVZAWugg==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.4", + "web3-providers-http": "1.10.4", + "web3-providers-ipc": "1.10.4", + "web3-providers-ws": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.4.tgz", + "integrity": "sha512-o0lSQo/N/f7/L76C0HV63+S54loXiE9fUPfHFcTtpJRQNDBVsSDdWRdePbWwR206XlsBqD5VHApck1//jEafTw==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "node_modules/web3-core/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/web3-core/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.4.tgz", + "integrity": "sha512-Sql2kYKmgt+T/cgvg7b9ce24uLS7xbFrxE4kuuor1zSCGrjhTJ5rRNG8gTJUkAJGKJc7KgnWmgW+cOfMBPUDSA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-accounts": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-eth-ens": "1.10.4", + "web3-eth-iban": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-abi": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.0.tgz", + "integrity": "sha512-cwS+qRBWpJ43aI9L3JS88QYPfFcSJJ3XapxOQ4j40v6mk7ATpA8CVK1vGTzpihNlOfMVRBkR95oAj7oL6aiDOg==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-abi/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/web3-eth-abi/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web3-eth-abi/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.4.tgz", + "integrity": "sha512-ysy5sVTg9snYS7tJjxVoQAH6DTOTkRGR8emEVCWNGLGiB9txj+qDvSeT0izjurS/g7D5xlMAgrEHLK1Vi6I3yg==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "2.6.5", + "@ethereumjs/tx": "3.5.2", + "@ethereumjs/util": "^8.1.0", + "eth-lib": "0.2.8", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/web3-eth-accounts/node_modules/eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-eth-iban/node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "node_modules/web3-eth-contract": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.4.tgz", + "integrity": "sha512-Q8PfolOJ4eV9TvnTj1TGdZ4RarpSLmHnUnzVxZ/6/NiTfe4maJz99R0ISgwZkntLhLRtw0C7LRJuklzGYCNN3A==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.4.tgz", + "integrity": "sha512-LLrvxuFeVooRVZ9e5T6OWKVflHPFgrVjJ/jtisRWcmI7KN/b64+D/wJzXqgmp6CNsMQcE7rpmf4CQmJCrTdsgg==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-iban": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.0.tgz", + "integrity": "sha512-0l+SP3IGhInw7Q20LY3IVafYEuufo4Dn75jAHT7c2aDJsIolvf2Lc6ugHkBajlwUneGfbRQs/ccYPQ9JeMUbrg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-iban/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/web3-eth-iban/node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web3-eth-iban/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.4.tgz", + "integrity": "sha512-BRa/hs6jU1hKHz+AC/YkM71RP3f0Yci1dPk4paOic53R4ZZG4MgwKRkJhgt3/GPuPliwS46f/i5A7fEGBT4F9w==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "node_modules/web3-eth-personal/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/node_modules/web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-net": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.4.tgz", + "integrity": "sha512-mKINnhOOnZ4koA+yV2OT5s5ztVjIx7IY9a03w6s+yao/BUn+Luuty0/keNemZxTr1E8Ehvtn28vbOtW7Ids+Ow==", + "dev": true, + "dependencies": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.4.tgz", + "integrity": "sha512-m2P5Idc8hdiO0l60O6DSCPw0kw64Zgi0pMjbEFRmxKIck2Py57RQMu4bxvkxJwkF06SlGaEQF8rFZBmuX7aagQ==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.5", + "cross-fetch": "^4.0.0", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.4.tgz", + "integrity": "sha512-YRF/bpQk9z3WwjT+A6FI/GmWRCASgd+gC0si7f9zbBWLXjwzYAKG73bQBaFRAHex1hl4CVcM5WUMaQXf3Opeuw==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.4.tgz", + "integrity": "sha512-j3FBMifyuFFmUIPVQR4pj+t5ILhAexAui0opgcpu9R5LxQrLRUZxHSnU+YO25UycSOa/NAX8A+qkqZNpcFAlxA==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws/node_modules/web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws/node_modules/web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-shh": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.4.tgz", + "integrity": "sha512-cOH6iFFM71lCNwSQrC3niqDXagMqrdfFW85hC9PFUrAr3PUrIem8TNstTc3xna2bwZeWG6OBy99xSIhBvyIACw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-net": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", + "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", + "dev": true, + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils/node_modules/@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.3.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dev": true, + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/websocket/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "peer": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "dev": true, + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "peer": true + }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "peer": true, + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dev": true, + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dev": true, + "dependencies": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "node_modules/xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dev": true, + "dependencies": { + "xhr-request": "^1.1.0" + } + }, + "node_modules/xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "dev": true, + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", + "dev": true + }, + "@aws-crypto/sha256-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz", + "integrity": "sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==", + "dev": true, + "requires": { + "@aws-crypto/util": "^1.2.2", + "@aws-sdk/types": "^3.1.0", + "tslib": "^1.11.1" + } + }, + "@aws-crypto/util": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-1.2.2.tgz", + "integrity": "sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==", + "dev": true, + "requires": { + "@aws-sdk/types": "^3.1.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "@aws-sdk/types": { + "version": "3.496.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.496.0.tgz", + "integrity": "sha512-umkGadK4QuNQaMoDICMm7NKRI/mYSXiyPjcn3d53BhsuArYU/52CebGQKdt4At7SwwsiVJZw9RNBHyN5Mm0HVw==", + "dev": true, + "requires": { + "@smithy/types": "^2.9.1", + "tslib": "^2.5.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "dev": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@ensdomains/address-encoder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", + "integrity": "sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==", + "dev": true, + "requires": { + "bech32": "^1.1.3", + "blakejs": "^1.1.0", + "bn.js": "^4.11.8", + "bs58": "^4.0.1", + "crypto-addr-codec": "^0.1.7", + "nano-base32": "^1.0.1", + "ripemd160": "^2.0.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "@ensdomains/ens": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.4.5.tgz", + "integrity": "sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==", + "dev": true, + "requires": { + "bluebird": "^3.5.2", + "eth-ens-namehash": "^2.0.8", + "solc": "^0.4.20", + "testrpc": "0.0.1", + "web3-utils": "^1.0.0-beta.31" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true + }, + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==", + "dev": true + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, + "solc": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.26.tgz", + "integrity": "sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==", + "dev": true, + "requires": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dev": true, + "requires": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + } + } + }, + "@ensdomains/ensjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ensdomains/ensjs/-/ensjs-2.1.0.tgz", + "integrity": "sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "@ensdomains/address-encoder": "^0.1.7", + "@ensdomains/ens": "0.4.5", + "@ensdomains/resolver": "0.2.4", + "content-hash": "^2.5.2", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.0.13", + "js-sha3": "^0.8.0" + }, + "dependencies": { + "ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "requires": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + } + } + }, + "@ensdomains/resolver": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", + "dev": true + }, + "@ethereumjs/common": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz", + "integrity": "sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.5" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + } + } + }, + "@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "dev": true + }, + "@ethereumjs/tx": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz", + "integrity": "sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw==", + "dev": true, + "requires": { + "@ethereumjs/common": "^2.6.4", + "ethereumjs-util": "^7.1.5" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + } + } + }, + "@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "dev": true, + "requires": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "dependencies": { + "@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dev": true, + "requires": { + "@noble/hashes": "1.3.1" + } + }, + "@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "dev": true + }, + "@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dev": true, + "requires": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + } + }, + "@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dev": true, + "requires": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + } + }, + "ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "requires": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + } + } + }, + "@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + }, + "dependencies": { + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + } + } + }, + "@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true + }, + "@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + }, + "dependencies": { + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "requires": {} + } + } + }, + "@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "requires": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "dev": true + }, + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "peer": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "peer": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "peer": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "requires": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + } + }, + "@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "dev": true, + "requires": { + "@noble/hashes": "1.3.2" + }, + "dependencies": { + "@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true + } + } + }, + "@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "dev": true + }, + "@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "peer": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "peer": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "peer": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@nomicfoundation/edr": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.3.1.tgz", + "integrity": "sha512-uPg1/CvIJpsCe7Ipe80bYnC/Q2Bt/O55KB2ssLx7Z0os4jwDvWBZas8tLMopT+hpOQnv8cZkHJap1iNDTwAfQg==", + "dev": true, + "requires": { + "@nomicfoundation/edr-darwin-arm64": "0.3.1", + "@nomicfoundation/edr-darwin-x64": "0.3.1", + "@nomicfoundation/edr-linux-arm64-gnu": "0.3.1", + "@nomicfoundation/edr-linux-arm64-musl": "0.3.1", + "@nomicfoundation/edr-linux-x64-gnu": "0.3.1", + "@nomicfoundation/edr-linux-x64-musl": "0.3.1", + "@nomicfoundation/edr-win32-arm64-msvc": "0.3.1", + "@nomicfoundation/edr-win32-ia32-msvc": "0.3.1", + "@nomicfoundation/edr-win32-x64-msvc": "0.3.1" + } + }, + "@nomicfoundation/edr-darwin-arm64": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.3.1.tgz", + "integrity": "sha512-qsdGS1Kfp6bVH4fk4hUzbsEm0fH7hGurraKk+IWby7Ecv+u7BuNaLVqeoYauYRFLYnGg8XZmcKOJ9BW35Y96Jg==", + "dev": true, + "optional": true + }, + "@nomicfoundation/edr-darwin-x64": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.3.1.tgz", + "integrity": "sha512-vtS2yuXIgjte42KEg/Aw/xmLRneVrIaDFhFMk578zg3m1UjNP+a29Lirw5fRXaqaL8aPyhRFmUy+1/V4MGaH+g==", + "dev": true, + "optional": true + }, + "@nomicfoundation/edr-linux-arm64-gnu": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.3.1.tgz", + "integrity": "sha512-GrbQcrVjTFLm/x8HdUzmJ1F8Juau9UEZM/YNr4sAxxTGvBHJlq73VaDZfArxj9Anq/u6aImPbs1ksu28D6XC3A==", + "dev": true, + "optional": true + }, + "@nomicfoundation/edr-linux-arm64-musl": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.3.1.tgz", + "integrity": "sha512-wOqugcbugmbZkh58PcIC5naT0ilwkZ0/qH86AniENxsviOaPSrL4aMYhtfypQ3MNxlfrlgLZFCC+D5eJTsNsgQ==", + "dev": true, + "optional": true + }, + "@nomicfoundation/edr-linux-x64-gnu": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.3.1.tgz", + "integrity": "sha512-V+kyUVqbt52dQRgaZK+EWuPWJ5h/PsCYZmiK18A+DQynZvird7jrTsDppcTvlv1Dvny8UAAP0q/ue7G67OoLJQ==", + "dev": true, + "optional": true + }, + "@nomicfoundation/edr-linux-x64-musl": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.3.1.tgz", + "integrity": "sha512-vwrzLW40jQBDZVYmoJUBMwl36i7muB9AfT4F2fMRsb1JoOMgoeOBp8R+IAxbA6mjIJGwAClkRz5W5hCb3zMtMQ==", + "dev": true, + "optional": true + }, + "@nomicfoundation/edr-win32-arm64-msvc": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-arm64-msvc/-/edr-win32-arm64-msvc-0.3.1.tgz", + "integrity": "sha512-7G29vUGrkwfbJqxo1V+QTxD976gVHx3Z0P5kwb1bErLmlP89cRNX3UN3/dzXpbKH9mp8ZcAjIcIbRUd4C+vH/A==", + "dev": true, + "optional": true + }, + "@nomicfoundation/edr-win32-ia32-msvc": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-ia32-msvc/-/edr-win32-ia32-msvc-0.3.1.tgz", + "integrity": "sha512-Q39eAkk/j1ZlvHcxQRTAzdY9qlckDNfiuJDgLYTlxdubpmX6KZucuUin/1A5NVhhCToTxw7aFwSglUROY3ejJw==", + "dev": true, + "optional": true + }, + "@nomicfoundation/edr-win32-x64-msvc": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.3.1.tgz", + "integrity": "sha512-8WzEzWUshw28xowVBhEyu4EQpx0TqNmDa70C3L1MWl5waym4U/VwbijFrI0Sb6Y1kdoNCdBTMvfr8OJNF2qJ/A==", + "dev": true, + "optional": true + }, + "@nomicfoundation/ethereumjs-common": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", + "integrity": "sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-util": "9.0.4" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz", + "integrity": "sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==", + "dev": true + }, + "@nomicfoundation/ethereumjs-tx": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz", + "integrity": "sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/ethereumjs-util": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", + "integrity": "sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-rlp": "5.0.4", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@nomicfoundation/hardhat-chai-matchers": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.3.tgz", + "integrity": "sha512-A40s7EAK4Acr8UP1Yudgi9GGD9Cca/K3LHt3DzmRIje14lBfHtg9atGQ7qK56vdPcTwKmeaGn30FzxMUfPGEMw==", + "dev": true, + "peer": true, + "requires": { + "@types/chai-as-promised": "^7.1.3", + "chai-as-promised": "^7.1.1", + "deep-eql": "^4.0.1", + "ordinal": "^1.0.3" + } + }, + "@nomicfoundation/hardhat-ethers": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.5.tgz", + "integrity": "sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==", + "dev": true, + "peer": true, + "requires": { + "debug": "^4.1.1", + "lodash.isequal": "^4.5.0" + } + }, + "@nomicfoundation/hardhat-foundry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-foundry/-/hardhat-foundry-1.1.1.tgz", + "integrity": "sha512-cXGCBHAiXas9Pg9MhMOpBVQCkWRYoRFG7GJJAph+sdQsfd22iRs5U5Vs9XmpGEQd1yEvYISQZMeE68Nxj65iUQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "@nomicfoundation/hardhat-network-helpers": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.10.tgz", + "integrity": "sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==", + "dev": true, + "peer": true, + "requires": { + "ethereumjs-util": "^7.1.4" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "peer": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "peer": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + } + } + }, + "@nomicfoundation/hardhat-toolbox": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-4.0.0.tgz", + "integrity": "sha512-jhcWHp0aHaL0aDYj8IJl80v4SZXWMS1A2XxXa1CA6pBiFfJKuZinCkO6wb+POAt0LIfXB3gA3AgdcOccrcwBwA==", + "dev": true, + "requires": {} + }, + "@nomicfoundation/hardhat-verify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.3.tgz", + "integrity": "sha512-ESbRu9by53wu6VvgwtMtm108RSmuNsVqXtzg061D+/4R7jaWh/Wl/8ve+p6SdDX7vA1Z3L02hDO1Q3BY4luLXQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abi": "^5.1.2", + "@ethersproject/address": "^5.0.2", + "cbor": "^8.1.0", + "chalk": "^2.4.2", + "debug": "^4.1.1", + "lodash.clonedeep": "^4.5.0", + "semver": "^6.3.0", + "table": "^6.8.0", + "undici": "^5.14.0" + } + }, + "@nomicfoundation/solidity-analyzer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz", + "integrity": "sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==", + "dev": true, + "requires": { + "@nomicfoundation/solidity-analyzer-darwin-arm64": "0.1.1", + "@nomicfoundation/solidity-analyzer-darwin-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-freebsd-x64": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": "0.1.1", + "@nomicfoundation/solidity-analyzer-linux-x64-musl": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": "0.1.1", + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": "0.1.1" + } + }, + "@nomicfoundation/solidity-analyzer-darwin-arm64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz", + "integrity": "sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-darwin-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz", + "integrity": "sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-freebsd-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz", + "integrity": "sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz", + "integrity": "sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz", + "integrity": "sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz", + "integrity": "sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz", + "integrity": "sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", + "dev": true, + "optional": true + }, + "@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", + "dev": true, + "optional": true + }, + "@openzeppelin/contract-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz", + "integrity": "sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, + "@openzeppelin/contracts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.1.tgz", + "integrity": "sha512-yQJaT5HDp9hYOOp4jTYxMsR02gdFZFXhewX5HW9Jo4fsqSVqqyIO/xTHdWDaKX5a3pv1txmf076Lziz+sO7L1w==" + }, + "@openzeppelin/defender-admin-client": { + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/defender-admin-client/-/defender-admin-client-1.54.1.tgz", + "integrity": "sha512-kRpSUdTsnSqntp4FOXIm95t+6VKHc8CUY2Si71VDuxs0q7HSPZkdpRPSntcolwEzWy9L4a8NS/QMwDF5NJ4X1g==", + "dev": true, + "requires": { + "@openzeppelin/defender-base-client": "1.54.1", + "axios": "^1.4.0", + "ethers": "^5.7.2", + "lodash": "^4.17.19", + "node-fetch": "^2.6.0" + }, + "dependencies": { + "ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "requires": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + } + } + }, + "@openzeppelin/defender-base-client": { + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/@openzeppelin/defender-base-client/-/defender-base-client-1.54.1.tgz", + "integrity": "sha512-DRGz/7KN3ZQwu28YWMOaojrC7jjPkz/uCwkC8/C8B11qwZhA5qIVvyhYHhhFOCl0J84+E3TNdvkPD2q3p2WaJw==", + "dev": true, + "requires": { + "amazon-cognito-identity-js": "^6.0.1", + "async-retry": "^1.3.3", + "axios": "^1.4.0", + "lodash": "^4.17.19", + "node-fetch": "^2.6.0" + } + }, + "@openzeppelin/defender-sdk-base-client": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.8.0.tgz", + "integrity": "sha512-XIJat6BW2CTM74AwG5IL0Q/aE6RXj8x7smnVKmBql4wMvmirVW+njfwzZCLhUTiBXg9AlHxIInEF14SabfIisg==", + "dev": true, + "requires": { + "amazon-cognito-identity-js": "^6.3.6", + "async-retry": "^1.3.3" + } + }, + "@openzeppelin/defender-sdk-deploy-client": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.8.0.tgz", + "integrity": "sha512-/tNS2EnHuA5l095wzMbIkGMDNHZLcZQ2eLUP8z+AeKaAUeR2z4qzZ1ul21kR3EJURAyoy8aULFZanLggoBWHrA==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.7.0", + "@openzeppelin/defender-sdk-base-client": "^1.8.0", + "axios": "^1.4.0", + "lodash": "^4.17.21" + } + }, + "@openzeppelin/hardhat-upgrades": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-3.0.2.tgz", + "integrity": "sha512-Fk940cxwew++bfSZKWHEXVUCr3tRBiRZZBw1nl1wUVq29cq7BrlwDkZ6hTab/+p0IOnx0l6HJHLu3amDxxs3/w==", + "dev": true, + "requires": { + "@openzeppelin/defender-admin-client": "^1.52.0", + "@openzeppelin/defender-base-client": "^1.52.0", + "@openzeppelin/defender-sdk-base-client": "^1.8.0", + "@openzeppelin/defender-sdk-deploy-client": "^1.8.0", + "@openzeppelin/upgrades-core": "^1.32.0", + "chalk": "^4.1.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.1.5", + "proper-lockfile": "^4.1.1", + "undici": "^5.28.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@openzeppelin/test-helpers": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.16.tgz", + "integrity": "sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==", + "dev": true, + "requires": { + "@openzeppelin/contract-loader": "^0.6.2", + "@truffle/contract": "^4.0.35", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.5", + "web3-utils": "^1.2.5" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true, + "peer": true + }, + "chai-bn": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.2.tgz", + "integrity": "sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==", + "dev": true, + "requires": {} + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "@openzeppelin/upgrades-core": { + "version": "1.32.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.32.3.tgz", + "integrity": "sha512-v04RbrBOTRiIhfkTRfY4M34I2wIcuz+K1cUk/6duulsMXvRpM6/IPWeXh+1Xr1K+xedJi7gcS/pNSXfYhYNXIg==", + "requires": { + "cbor": "^9.0.0", + "chalk": "^4.1.0", + "compare-versions": "^6.0.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.0.3", + "minimist": "^1.2.7", + "proper-lockfile": "^4.1.1", + "solidity-ast": "^0.4.51" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "cbor": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-9.0.1.tgz", + "integrity": "sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ==", + "requires": { + "nofilter": "^3.1.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@scure/base": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", + "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==", + "dev": true + }, + "@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "requires": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "requires": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "requires": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + } + }, + "@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true + }, + "@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true + }, + "@smithy/types": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.9.1.tgz", + "integrity": "sha512-vjXlKNXyprDYDuJ7UW5iobdmyDm6g8dDG+BFUncAg/3XJaN45Gy5RWWWUVgrzIK7S4R1KWgIX5LeJcfvSI24bw==", + "dev": true, + "requires": { + "tslib": "^2.5.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "peer": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.1" + } + }, + "@truffle/abi-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-1.0.3.tgz", + "integrity": "sha512-AWhs01HCShaVKjml7Z4AbVREr/u4oiWxCcoR7Cktm0mEvtT04pvnxW5xB/cI4znRkrbPdFQlFt67kgrAjesYkw==", + "dev": true, + "requires": { + "change-case": "3.0.2", + "fast-check": "3.1.1", + "web3-utils": "1.10.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } + } + } + }, + "@truffle/blockchain-utils": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.9.tgz", + "integrity": "sha512-RHfumgbIVo68Rv9ofDYfynjnYZIfP/f1vZy4RoqkfYAO+fqfc58PDRzB1WAGq2U6GPuOnipOJxQhnqNnffORZg==", + "dev": true + }, + "@truffle/codec": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.17.3.tgz", + "integrity": "sha512-Ko/+dsnntNyrJa57jUD9u4qx9nQby+H4GsUO6yjiCPSX0TQnEHK08XWqBSg0WdmCH2+h0y1nr2CXSx8gbZapxg==", + "dev": true, + "requires": { + "@truffle/abi-utils": "^1.0.3", + "@truffle/compile-common": "^0.9.8", + "big.js": "^6.0.3", + "bn.js": "^5.1.3", + "cbor": "^5.2.0", + "debug": "^4.3.1", + "lodash": "^4.17.21", + "semver": "^7.5.4", + "utf8": "^3.0.0", + "web3-utils": "1.10.0" + }, + "dependencies": { + "bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true + }, + "cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "dev": true, + "requires": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + } + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "nofilter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", + "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==", + "dev": true + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } + } + } + }, + "@truffle/compile-common": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.8.tgz", + "integrity": "sha512-DTpiyo32t/YhLI1spn84D3MHYHrnoVqO+Gp7ZHrYNwDs86mAxtNiH5lsVzSb8cPgiqlvNsRCU9nm9R0YmKMTBQ==", + "dev": true, + "requires": { + "@truffle/error": "^0.2.2", + "colors": "1.4.0" + } + }, + "@truffle/contract": { + "version": "4.6.31", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.31.tgz", + "integrity": "sha512-s+oHDpXASnZosiCdzu+X1Tx5mUJUs1L1CYXIcgRmzMghzqJkaUFmR6NpNo7nJYliYbO+O9/aW8oCKqQ7rCHfmQ==", + "dev": true, + "requires": { + "@ensdomains/ensjs": "^2.1.0", + "@truffle/blockchain-utils": "^0.1.9", + "@truffle/contract-schema": "^3.4.16", + "@truffle/debug-utils": "^6.0.57", + "@truffle/error": "^0.2.2", + "@truffle/interface-adapter": "^0.5.37", + "bignumber.js": "^7.2.1", + "debug": "^4.3.1", + "ethers": "^4.0.32", + "web3": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "dependencies": { + "@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "requires": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "requires": { + "node-fetch": "^2.6.12" + } + }, + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + }, + "dependencies": { + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + } + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "dev": true + }, + "web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "dev": true, + "requires": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + } + }, + "web3-core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + }, + "dependencies": { + "bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true + } + } + }, + "web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dev": true, + "requires": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dev": true, + "requires": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + } + }, + "web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + } + }, + "web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dev": true, + "requires": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "dev": true, + "requires": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "dependencies": { + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true + } + } + }, + "web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dev": true, + "requires": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dev": true, + "requires": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dev": true, + "requires": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + } + }, + "web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dev": true, + "requires": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + } + }, + "web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + } + }, + "web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "dev": true, + "requires": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + } + }, + "web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } + } + } + }, + "@truffle/contract-schema": { + "version": "3.4.16", + "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.16.tgz", + "integrity": "sha512-g0WNYR/J327DqtJPI70ubS19K1Fth/1wxt2jFqLsPmz5cGZVjCwuhiie+LfBde4/Mc9QR8G+L3wtmT5cyoBxAg==", + "dev": true, + "requires": { + "ajv": "^6.10.0", + "debug": "^4.3.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "@truffle/debug-utils": { + "version": "6.0.57", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.57.tgz", + "integrity": "sha512-Q6oI7zLaeNLB69ixjwZk2UZEWBY6b2OD1sjLMGDKBGR7GaHYiw96GLR2PFgPH1uwEeLmV4N78LYaQCrDsHbNeA==", + "dev": true, + "requires": { + "@truffle/codec": "^0.17.3", + "@trufflesuite/chromafi": "^3.0.0", + "bn.js": "^5.1.3", + "chalk": "^2.4.2", + "debug": "^4.3.1", + "highlightjs-solidity": "^2.0.6" + } + }, + "@truffle/error": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.2.tgz", + "integrity": "sha512-TqbzJ0O8DHh34cu8gDujnYl4dUl6o2DE4PR6iokbybvnIm/L2xl6+Gv1VC+YJS45xfH83Yo3/Zyg/9Oq8/xZWg==", + "dev": true + }, + "@truffle/interface-adapter": { + "version": "0.5.37", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.37.tgz", + "integrity": "sha512-lPH9MDgU+7sNDlJSClwyOwPCfuOimqsCx0HfGkznL3mcFRymc1pukAR1k17zn7ErHqBwJjiKAZ6Ri72KkS+IWw==", + "dev": true, + "requires": { + "bn.js": "^5.1.3", + "ethers": "^4.0.32", + "web3": "1.10.0" + }, + "dependencies": { + "@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "requires": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true + }, + "cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "requires": { + "node-fetch": "^2.6.12" + } + }, + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + }, + "dependencies": { + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + } + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "dev": true + }, + "web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "dev": true, + "requires": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + } + }, + "web3-core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dev": true, + "requires": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dev": true, + "requires": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + } + }, + "web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + } + }, + "web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dev": true, + "requires": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "dev": true, + "requires": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "eth-lib": "0.2.8", + "ethereumjs-util": "^7.1.5", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "dependencies": { + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true + } + } + }, + "web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dev": true, + "requires": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dev": true, + "requires": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + } + }, + "web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dev": true, + "requires": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + } + }, + "web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dev": true, + "requires": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + } + }, + "web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + } + }, + "web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "dev": true, + "requires": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + } + }, + "web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } + } + } + }, + "@trufflesuite/chromafi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@trufflesuite/chromafi/-/chromafi-3.0.0.tgz", + "integrity": "sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "detect-indent": "^5.0.0", + "highlight.js": "^10.4.1", + "lodash.merge": "^4.6.2", + "strip-ansi": "^4.0.0", + "strip-indent": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true, + "peer": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "peer": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "peer": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "peer": true + }, + "@typechain/ethers-v6": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz", + "integrity": "sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA==", + "dev": true, + "peer": true, + "requires": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + } + }, + "@typechain/hardhat": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-9.1.0.tgz", + "integrity": "sha512-mtaUlzLlkqTlfPwB3FORdejqBskSnh+Jl8AIJGjXNAQfRQ4ofHADPl1+oU7Z3pAJzmZbUXII8MhOLQltcHgKnA==", + "dev": true, + "peer": true, + "requires": { + "fs-extra": "^9.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "peer": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "peer": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "peer": true + } + } + }, + "@types/bn.js": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", + "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", + "requires": { + "@types/node": "*" + } + }, + "@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "@types/chai": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", + "dev": true, + "peer": true + }, + "@types/chai-as-promised": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", + "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "dev": true, + "peer": true, + "requires": { + "@types/chai": "*" + } + }, + "@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "*" + } + }, + "@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "peer": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "peer": true + }, + "@types/mocha": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", + "dev": true, + "peer": true + }, + "@types/node": { + "version": "20.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", + "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", + "requires": { + "undici-types": "~5.26.4" + } + }, + "@types/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "requires": { + "@types/node": "*" + } + }, + "@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "dev": true, + "peer": true + }, + "@types/qs": { + "version": "6.9.11", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", + "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", + "dev": true, + "peer": true + }, + "@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/secp256k1": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", + "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", + "requires": { + "@types/node": "*" + } + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true, + "peer": true + }, + "abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "peer": true + }, + "acorn-walk": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", + "dev": true, + "peer": true + }, + "address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "peer": true + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true + }, + "aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "peer": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "amazon-cognito-identity-js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.7.tgz", + "integrity": "sha512-tSjnM7KyAeOZ7UMah+oOZ6cW4Gf64FFcc7BE2l7MTcp7ekAPrXaCbpcW2xEpH1EiDS4cPcAouHzmCuc2tr72vQ==", + "dev": true, + "requires": { + "@aws-crypto/sha256-js": "1.2.2", + "buffer": "4.9.2", + "fast-base64-decode": "^1.0.0", + "isomorphic-unfetch": "^3.0.0", + "js-cookie": "^2.2.1" + }, + "dependencies": { + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + } + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true, + "peer": true + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true, + "peer": true + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "peer": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true, + "peer": true + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "peer": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "peer": true + }, + "array.prototype.findlast": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.3.tgz", + "integrity": "sha512-kcBubumjciBg4JKp5KTKtI7ec7tRefPk88yjkWJwaVKYd9QfTaxcsOxoMNKd7iBr447zCfDV0z1kOF47umv42g==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "requires": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + } + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "peer": true + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "peer": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true, + "peer": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "dev": true, + "requires": { + "retry": "0.13.1" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "peer": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true + }, + "aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "axios": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.4.tgz", + "integrity": "sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==", + "dev": true, + "requires": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + } + } + }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "dev": true + }, + "big.js": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz", + "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==", + "dev": true + }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, + "bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "dev": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "dev": true + }, + "cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "cbor": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", + "integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==", + "dev": true, + "peer": true, + "requires": { + "nofilter": "^3.1.0" + } + }, + "chai": { + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + } + }, + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "peer": true, + "requires": { + "check-error": "^1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "change-case": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", + "dev": true, + "requires": { + "camel-case": "^3.0.0", + "constant-case": "^2.0.0", + "dot-case": "^2.1.0", + "header-case": "^1.0.0", + "is-lower-case": "^1.1.0", + "is-upper-case": "^1.1.0", + "lower-case": "^1.1.1", + "lower-case-first": "^1.0.0", + "no-case": "^2.3.2", + "param-case": "^2.1.0", + "pascal-case": "^2.0.0", + "path-case": "^2.1.0", + "sentence-case": "^2.1.0", + "snake-case": "^2.1.0", + "swap-case": "^1.1.0", + "title-case": "^2.1.0", + "upper-case": "^1.1.1", + "upper-case-first": "^1.1.0" + } + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "peer": true + }, + "check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "requires": { + "get-func-name": "^2.0.2" + } + }, + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "requires": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "dependencies": { + "multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + } + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "peer": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "peer": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "peer": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "peer": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "peer": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "peer": true, + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dev": true, + "peer": true, + "requires": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true + } + } + }, + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "compare-versions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "peer": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "peer": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "peer": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dev": true, + "requires": { + "snake-case": "^2.1.0", + "upper-case": "^1.1.1" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dev": true, + "requires": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "peer": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "peer": true + }, + "cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "requires": { + "node-fetch": "^2.6.12" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "peer": true + }, + "crypto-addr-codec": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.8.tgz", + "integrity": "sha512-GqAK90iLLgP3FvhNmHbpT3wR6dEdaM8hZyZtLX29SPardh3OA13RFLHDR6sntGCgRWOfiHqW6sIyohpNqOtV/g==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dev": true, + "requires": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true, + "peer": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + } + } + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "peer": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "peer": true + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true + }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-indent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "integrity": "sha512-rlpvsxUtM0PQvy9iZe640/IWwWYyBsTApREbA1pHOpmOUIl9MkP/U4z7vTtg4Oaojvqhxt7sdufnT0EzGaR31g==", + "dev": true + }, + "detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "peer": true, + "requires": { + "address": "^1.0.1", + "debug": "4" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "peer": true, + "requires": { + "heap": ">= 0.2.0" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "peer": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + } + }, + "dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + } + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "requires": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + } + }, + "es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "requires": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "requires": { + "hasown": "^2.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "dev": true, + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dev": true, + "requires": { + "d": "^1.0.2", + "ext": "^1.7.0" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "peer": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "peer": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "peer": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "peer": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "dev": true, + "requires": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + } + } + }, + "eth-gas-reporter": { + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz", + "integrity": "sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==", + "dev": true, + "peer": true, + "requires": { + "@solidity-parser/parser": "^0.14.0", + "axios": "^1.5.1", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^5.7.2", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^10.2.0", + "req-cwd": "^2.0.0", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "dependencies": { + "ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + } + } + }, + "eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "requires": { + "js-sha3": "^0.8.0" + } + }, + "ethereum-cryptography": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", + "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", + "dev": true, + "requires": { + "@noble/hashes": "1.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + }, + "dependencies": { + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "ethers": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.11.1.tgz", + "integrity": "sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==", + "dev": true, + "requires": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "dependencies": { + "@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true + }, + "@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", + "dev": true + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "dev": true, + "requires": {} + } + } + }, + "ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==", + "dev": true + } + } + }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "express": { + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "requires": { + "type": "^2.7.2" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true + }, + "fast-base64-decode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", + "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==", + "dev": true + }, + "fast-check": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.1.1.tgz", + "integrity": "sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==", + "dev": true, + "requires": { + "pure-rand": "^5.0.1" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "peer": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "peer": true + }, + "fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "peer": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "peer": true, + "requires": { + "array-back": "^3.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true, + "peer": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "peer": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "peer": true, + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "peer": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "peer": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "peer": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "hardhat": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.1.tgz", + "integrity": "sha512-cTWYIJc5jQ132XUI8oRI/TO9L6oavPoJRCTRU9sIjkVxvkxz0Axz0K83Z3BEdJTqBQ2W84ZRoTekti84kBwCjg==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/edr": "^0.3.1", + "@nomicfoundation/ethereumjs-common": "4.0.4", + "@nomicfoundation/ethereumjs-tx": "5.0.4", + "@nomicfoundation/ethereumjs-util": "9.0.4", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "boxen": "^5.1.2", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + } + }, + "hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "peer": true, + "requires": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "requires": { + "get-intrinsic": "^1.2.2" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.3" + } + }, + "heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true, + "peer": true + }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true + }, + "highlightjs-solidity": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.6.tgz", + "integrity": "sha512-DySXWfQghjm2l6a/flF+cteroJqD4gI8GSdL4PtvxZSsAHie8m3yVe2JFoRg03ROKT6hp2Lc/BxXkqerNmtQYg==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "peer": true, + "requires": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + } + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", + "dev": true + }, + "http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "peer": true, + "requires": { + "@types/node": "^10.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true, + "peer": true + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dev": true, + "requires": { + "punycode": "2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "dev": true + } + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "peer": true + }, + "immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "peer": true + }, + "internal-slot": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", + "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "requires": { + "get-intrinsic": "^1.2.2", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "peer": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true + }, + "io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "requires": { + "fp-ts": "^1.0.0" + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true + }, + "is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dev": true, + "requires": { + "lower-case": "^1.1.0" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dev": true, + "requires": { + "upper-case": "^1.1.0" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "peer": true + }, + "isomorphic-unfetch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz", + "integrity": "sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==", + "dev": true, + "requires": { + "node-fetch": "^2.6.1", + "unfetch": "^4.2.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==", + "dev": true + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "peer": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "peer": true + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + } + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "peer": true + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "peer": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "peer": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true, + "peer": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "dev": true, + "peer": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "peer": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.1" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, + "lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dev": true, + "requires": { + "lower-case": "^1.1.2" + } + }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, + "lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "peer": true + }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true, + "peer": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "peer": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "peer": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "requires": { + "dom-walk": "^0.1.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "dev": true, + "requires": { + "mkdirp": "*" + } + }, + "mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "requires": { + "obliterator": "^2.0.0" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "mock-fs": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "dev": true, + "requires": { + "varint": "^5.0.0" + } + }, + "multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + }, + "dependencies": { + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + }, + "nano-base32": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", + "integrity": "sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==", + "dev": true + }, + "nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "peer": true + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" + }, + "node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "peer": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-gyp-build": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.1.tgz", + "integrity": "sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==" + }, + "nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==" + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "peer": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true + }, + "number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "requires": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dev": true, + "requires": { + "http-https": "^1.0.0" + } + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "peer": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "ordinal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz", + "integrity": "sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==", + "dev": true, + "peer": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true, + "peer": true + }, + "parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dev": true, + "requires": { + "camel-case": "^3.0.0", + "upper-case-first": "^1.1.0" + } + }, + "path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "peer": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "peer": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "peer": true + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "peer": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "peer": true + }, + "promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "peer": true, + "requires": { + "asap": "~2.0.6" + } + }, + "proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "requires": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==" + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "dev": true + }, + "qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dev": true, + "peer": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "peer": true + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "dependencies": { + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + } + } + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "peer": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "peer": true, + "requires": { + "minimatch": "^3.0.5" + } + }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true, + "peer": true + }, + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + } + }, + "req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "peer": true, + "requires": { + "req-from": "^2.0.0" + } + }, + "req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "peer": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true, + "peer": true + }, + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "requires": { + "lowercase-keys": "^2.0.0" + }, + "dependencies": { + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "peer": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "dev": true + }, + "rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "requires": { + "bn.js": "^5.2.0" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "peer": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-array-concat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "requires": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "dependencies": { + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex-test": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", + "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "requires": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "peer": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "peer": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "peer": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "peer": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "peer": true + } + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "requires": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case-first": "^1.1.2" + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dev": true, + "requires": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "requires": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "peer": true, + "requires": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + } + }, + "sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dev": true, + "requires": { + "buffer": "6.0.3" + }, + "dependencies": { + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "peer": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "dev": true, + "requires": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + }, + "dependencies": { + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + } + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "peer": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + } + } + }, + "snake-case": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "requires": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "solidity-ast": { + "version": "0.4.55", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.55.tgz", + "integrity": "sha512-qeEU/r/K+V5lrAw8iswf2/yfWAnSGs3WKPHI+zAFKFjX0dIBVXEU/swQ8eJQYHf6PJWUZFO2uWV4V1wEOkeQbA==", + "requires": { + "array.prototype.findlast": "^1.2.2" + } + }, + "solidity-coverage": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.5.tgz", + "integrity": "sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==", + "dev": true, + "peer": true, + "requires": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.16.0", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "10.2.0", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "dependencies": { + "@solidity-parser/parser": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", + "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", + "dev": true, + "peer": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "peer": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "peer": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "peer": true + }, + "sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + } + } + }, + "stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "requires": { + "type-fest": "^0.7.1" + }, + "dependencies": { + "type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "dev": true, + "peer": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1", + "upper-case": "^1.1.1" + } + }, + "swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + }, + "dependencies": { + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true + } + } + }, + "sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "peer": true, + "requires": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + } + }, + "sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "peer": true, + "requires": { + "get-port": "^3.1.0" + } + }, + "table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", + "dev": true, + "peer": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + } + }, + "table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "peer": true, + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true, + "peer": true + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true + } + } + }, + "tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "requires": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "testrpc": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/testrpc/-/testrpc-0.0.1.tgz", + "integrity": "sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==", + "dev": true + }, + "then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "peer": true, + "requires": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true, + "peer": true + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "peer": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + } + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true + }, + "title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "ts-command-line-args": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", + "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", + "dev": true, + "peer": true, + "requires": { + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "peer": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "peer": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "peer": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "peer": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "dev": true, + "peer": true, + "requires": {} + }, + "ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "peer": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "peer": true + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "peer": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typechain": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz", + "integrity": "sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==", + "dev": true, + "peer": true, + "requires": { + "@types/prettier": "^2.1.1", + "debug": "^4.3.1", + "fs-extra": "^7.0.0", + "glob": "7.1.7", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "prettier": "^2.3.1", + "ts-command-line-args": "^2.2.0", + "ts-essentials": "^7.0.1" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "peer": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "peer": true + } + } + }, + "typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "peer": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "peer": true + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true, + "peer": true + }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "peer": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "undici": { + "version": "5.28.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.2.tgz", + "integrity": "sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w==", + "dev": true, + "requires": { + "@fastify/busboy": "^2.0.0" + } + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "unfetch": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", + "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, + "upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, + "requires": { + "upper-case": "^1.1.1" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", + "dev": true + }, + "utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "dev": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "peer": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + } + } + }, + "web3": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.4.tgz", + "integrity": "sha512-kgJvQZjkmjOEKimx/tJQsqWfRDPTTcBfYPa9XletxuHLpHcXdx67w8EFn5AW3eVxCutE9dTVHgGa9VYe8vgsEA==", + "dev": true, + "requires": { + "web3-bzz": "1.10.4", + "web3-core": "1.10.4", + "web3-eth": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-shh": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-bzz": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.4.tgz", + "integrity": "sha512-ZZ/X4sJ0Uh2teU9lAGNS8EjveEppoHNQiKlOXAjedsrdWuaMErBPdLQjXfcrYvN6WM6Su9PMsAxf3FXXZ+HwQw==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "dependencies": { + "@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + } + } + }, + "web3-core": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.4.tgz", + "integrity": "sha512-B6elffYm81MYZDTrat7aEhnhdtVE3lDBUZft16Z8awYMZYJDbnykEbJVS+l3mnA7AQTnSDr/1MjWofGDLBJPww==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-requestmanager": "1.10.4", + "web3-utils": "1.10.4" + }, + "dependencies": { + "@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true + }, + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-core-helpers": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.0.tgz", + "integrity": "sha512-pIxAzFDS5vnbXvfvLSpaA1tfRykAe9adw43YCKsEYQwH0gCLL0kMLkaCX3q+Q8EVmAh+e1jWL/nl9U0de1+++g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.0", + "web3-utils": "1.10.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } + } + } + }, + "web3-core-method": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.4.tgz", + "integrity": "sha512-uZTb7flr+Xl6LaDsyTeE2L1TylokCJwTDrIVfIfnrGmnwLc6bmTWCCrm71sSrQ0hqs6vp/MKbQYIYqUN0J8WyA==", + "dev": true, + "requires": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-utils": "1.10.4" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-core-promievent": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.0.tgz", + "integrity": "sha512-68N7k5LWL5R38xRaKFrTFT2pm2jBNFaM4GioS00YjAKXRQ3KjmhijOMG3TICz6Aa5+6GDWYelDNx21YAeZ4YTg==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4" + } + }, + "web3-core-requestmanager": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.4.tgz", + "integrity": "sha512-vqP6pKH8RrhT/2MoaU+DY/OsYK9h7HmEBNCdoMj+4ZwujQtw/Mq2JifjwsJ7gits7Q+HWJwx8q6WmQoVZAWugg==", + "dev": true, + "requires": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.4", + "web3-providers-http": "1.10.4", + "web3-providers-ipc": "1.10.4", + "web3-providers-ws": "1.10.4" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-core-subscriptions": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.4.tgz", + "integrity": "sha512-o0lSQo/N/f7/L76C0HV63+S54loXiE9fUPfHFcTtpJRQNDBVsSDdWRdePbWwR206XlsBqD5VHApck1//jEafTw==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-eth": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.4.tgz", + "integrity": "sha512-Sql2kYKmgt+T/cgvg7b9ce24uLS7xbFrxE4kuuor1zSCGrjhTJ5rRNG8gTJUkAJGKJc7KgnWmgW+cOfMBPUDSA==", + "dev": true, + "requires": { + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-accounts": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-eth-ens": "1.10.4", + "web3-eth-iban": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-eth-abi": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.0.tgz", + "integrity": "sha512-cwS+qRBWpJ43aI9L3JS88QYPfFcSJJ3XapxOQ4j40v6mk7ATpA8CVK1vGTzpihNlOfMVRBkR95oAj7oL6aiDOg==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } + } + } + }, + "web3-eth-accounts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.4.tgz", + "integrity": "sha512-ysy5sVTg9snYS7tJjxVoQAH6DTOTkRGR8emEVCWNGLGiB9txj+qDvSeT0izjurS/g7D5xlMAgrEHLK1Vi6I3yg==", + "dev": true, + "requires": { + "@ethereumjs/common": "2.6.5", + "@ethereumjs/tx": "3.5.2", + "@ethereumjs/util": "^8.1.0", + "eth-lib": "0.2.8", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "eth-lib": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", + "integrity": "sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true + }, + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "dependencies": { + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + } + } + } + } + }, + "web3-eth-contract": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.4.tgz", + "integrity": "sha512-Q8PfolOJ4eV9TvnTj1TGdZ4RarpSLmHnUnzVxZ/6/NiTfe4maJz99R0ISgwZkntLhLRtw0C7LRJuklzGYCNN3A==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-utils": "1.10.4" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4" + } + }, + "web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-eth-ens": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.4.tgz", + "integrity": "sha512-LLrvxuFeVooRVZ9e5T6OWKVflHPFgrVjJ/jtisRWcmI7KN/b64+D/wJzXqgmp6CNsMQcE7rpmf4CQmJCrTdsgg==", + "dev": true, + "requires": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-utils": "1.10.4" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-core-promievent": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.4.tgz", + "integrity": "sha512-2de5WnJQ72YcIhYwV/jHLc4/cWJnznuoGTJGD29ncFQHAfwW/MItHFSVKPPA5v8AhJe+r6y4Y12EKvZKjQVBvQ==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4" + } + }, + "web3-eth-abi": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.4.tgz", + "integrity": "sha512-cZ0q65eJIkd/jyOlQPDjr8X4fU6CRL1eWgdLwbWEpo++MPU/2P4PFk5ZLAdye9T5Sdp+MomePPJ/gHjLMj2VfQ==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-eth-iban": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.0.tgz", + "integrity": "sha512-0l+SP3IGhInw7Q20LY3IVafYEuufo4Dn75jAHT7c2aDJsIolvf2Lc6ugHkBajlwUneGfbRQs/ccYPQ9JeMUbrg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + } + } + } + }, + "web3-eth-personal": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.4.tgz", + "integrity": "sha512-BRa/hs6jU1hKHz+AC/YkM71RP3f0Yci1dPk4paOic53R4ZZG4MgwKRkJhgt3/GPuPliwS46f/i5A7fEGBT4F9w==", + "dev": true, + "requires": { + "@types/node": "^12.12.6", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "dependencies": { + "@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true + }, + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-net": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.4.tgz", + "integrity": "sha512-mKINnhOOnZ4koA+yV2OT5s5ztVjIx7IY9a03w6s+yao/BUn+Luuty0/keNemZxTr1E8Ehvtn28vbOtW7Ids+Ow==", + "dev": true, + "requires": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-providers-http": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.4.tgz", + "integrity": "sha512-m2P5Idc8hdiO0l60O6DSCPw0kw64Zgi0pMjbEFRmxKIck2Py57RQMu4bxvkxJwkF06SlGaEQF8rFZBmuX7aagQ==", + "dev": true, + "requires": { + "abortcontroller-polyfill": "^1.7.5", + "cross-fetch": "^4.0.0", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.4" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-providers-ipc": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.4.tgz", + "integrity": "sha512-YRF/bpQk9z3WwjT+A6FI/GmWRCASgd+gC0si7f9zbBWLXjwzYAKG73bQBaFRAHex1hl4CVcM5WUMaQXf3Opeuw==", + "dev": true, + "requires": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.4" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-providers-ws": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.4.tgz", + "integrity": "sha512-j3FBMifyuFFmUIPVQR4pj+t5ILhAexAui0opgcpu9R5LxQrLRUZxHSnU+YO25UycSOa/NAX8A+qkqZNpcFAlxA==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4", + "websocket": "^1.0.32" + }, + "dependencies": { + "web3-core-helpers": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.4.tgz", + "integrity": "sha512-r+L5ylA17JlD1vwS8rjhWr0qg7zVoVMDvWhajWA5r5+USdh91jRUYosp19Kd1m2vE034v7Dfqe1xYRoH2zvG0g==", + "dev": true, + "requires": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + } + }, + "web3-eth-iban": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.4.tgz", + "integrity": "sha512-0gE5iNmOkmtBmbKH2aTodeompnNE8jEyvwFJ6s/AF6jkw9ky9Op9cqfzS56AYAbrqEFuClsqB/AoRves7LDELw==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + } + } + } + }, + "web3-shh": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.4.tgz", + "integrity": "sha512-cOH6iFFM71lCNwSQrC3niqDXagMqrdfFW85hC9PFUrAr3PUrIem8TNstTc3xna2bwZeWG6OBy99xSIhBvyIACw==", + "dev": true, + "requires": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-net": "1.10.4" + } + }, + "web3-utils": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", + "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", + "dev": true, + "requires": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "dependencies": { + "@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dev": true, + "requires": { + "@noble/hashes": "1.3.1" + } + }, + "@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "dev": true + }, + "@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dev": true, + "requires": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + } + }, + "@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dev": true, + "requires": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + } + }, + "ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "requires": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + } + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dev": true, + "requires": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "peer": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, + "which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "dev": true + }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "peer": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "peer": true + }, + "wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "peer": true, + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "dependencies": { + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true, + "peer": true + } + } + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + }, + "xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dev": true, + "requires": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dev": true, + "requires": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dev": true, + "requires": { + "xhr-request": "^1.1.0" + } + }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "peer": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/contracts/package.json b/contracts/package.json new file mode 100644 index 0000000000..38332f44e5 --- /dev/null +++ b/contracts/package.json @@ -0,0 +1,30 @@ +{ + "name": "sei-chain", + "version": "1.0.0", + "description": "\"Contracts for Sei Chain\"", + "main": "index.js", + "directories": { + "lib": "lib", + "test": "test" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@nomicfoundation/hardhat-foundry": "^1.1.1", + "@nomicfoundation/hardhat-toolbox": "^4.0.0", + "@openzeppelin/hardhat-upgrades": "^3.0.2", + "@openzeppelin/test-helpers": "^0.5.16", + "dotenv": "^16.3.1", + "ethers": "^6.11.1", + "hardhat": "^2.20.1" + }, + "dependencies": { + "@openzeppelin/contracts": "^5.0.1", + "@openzeppelin/upgrades-core": "^1.32.3", + "dotenv": "^16.3.1", + "lodash": "^4.17.21" + } +} diff --git a/contracts/scripts/deploy.js b/contracts/scripts/deploy.js new file mode 100644 index 0000000000..173fc0269c --- /dev/null +++ b/contracts/scripts/deploy.js @@ -0,0 +1,136 @@ +const hre = require("hardhat"); +const { exec } = require("child_process"); + +const CW20_BASE_WASM_LOCATION = "../cw20_base.wasm"; + +async function main() { + let codeId = await deployWasm(); + console.log(`codeId: ${codeId}`); + let adminAddr = await getAdmin(); + console.log(`adminAddr: ${adminAddr}`); + let contractAddress = await instantiateWasm(codeId, adminAddr); + console.log(`contractAddress: ${contractAddress}`) + // deploy the CW20ERC20Wrapper solidity contract with the contractAddress passed in + const [deployer] = await hre.ethers.getSigners(); + await fundDeployer(deployer.address); + + console.log( + "Deploying contracts with the account:", + deployer.address + ); + const CW20ERC20Wrapper = await ethers.getContractFactory("CW20ERC20Wrapper"); + let cW20ERC20Wrapper = await CW20ERC20Wrapper.deploy(contractAddress, "BTOK", "TOK"); + await cW20ERC20Wrapper.waitForDeployment() + let addressToCheck = await deployer.getAddress(); + let balance = await cW20ERC20Wrapper.balanceOf(addressToCheck); + console.log(`Balance of ${addressToCheck}: ${balance}`); +} + +async function fundDeployer(deployerAddress) { + // Wrap the exec function in a Promise + await new Promise((resolve, reject) => { + exec(`seid tx evm send ${deployerAddress} 10000000000000000000 --from admin`, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + reject(new Error(stderr)); + return; + } + resolve(); + }); + }); +} + + + +async function deployWasm() { + // Wrap the exec function in a Promise + let codeId = await new Promise((resolve, reject) => { + exec(`seid tx wasm store ${CW20_BASE_WASM_LOCATION} --from admin --gas=5000000 --fees=1000000usei -y --broadcast-mode block`, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + reject(new Error(stderr)); + return; + } + + // Regular expression to find the 'code_id' value + const regex = /key: code_id\s+value: "(\d+)"/; + + // Searching for the pattern in the string + const match = stdout.match(regex); + + let cId = null; + if (match && match[1]) { + // The captured group is the code_id value + cId = match[1]; + } + + console.log(`cId: ${cId}`); + resolve(cId); + }); + }); + + return codeId; +} + +async function getAdmin() { + // Wrap the exec function in a Promise + let adminAddr = await new Promise((resolve, reject) => { + exec(`seid keys show admin -a`, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + reject(new Error(stderr)); + return; + } + resolve(stdout.trim()); + }); + }); + return adminAddr; +} + +async function instantiateWasm(codeId, adminAddr) { + // Wrap the exec function in a Promise + let contractAddress = await new Promise((resolve, reject) => { + exec(`seid tx wasm instantiate ${codeId} '{ "name": "BTOK", "symbol": "BTOK", "decimals": 6, "initial_balances": [ { "address": "${adminAddr}", "amount": "1000000" } ], "mint": { "minter": "${adminAddr}", "cap": "99900000000" } }' --label cw20-test --admin ${adminAddr} --from admin --gas=5000000 --fees=1000000usei -y --broadcast-mode block`, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + reject(new Error(stderr)); + return; + } + const regex = /_contract_address\s*value:\s*(\w+)/; + const match = stdout.match(regex); + if (match && match[1]) { + resolve(match[1]); + } else { + reject(new Error('Contract address not found')); + } + }); + }); + return contractAddress; +} + +// We recommend this pattern to be able to use async/await everywhere +// and properly handle errors. +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/contracts/src/Box.sol b/contracts/src/Box.sol new file mode 100644 index 0000000000..2d0047f685 --- /dev/null +++ b/contracts/src/Box.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Box { + uint256 private _value; + + event ValueChanged(uint256 value); + + function store(uint256 value) public { + _value = value; + emit ValueChanged(value); + } + + function retrieve() public view returns (uint256) { + return _value; + } + + function boxIncr() public { + _value = _value + 1; + emit ValueChanged(_value); + } +} \ No newline at end of file diff --git a/contracts/src/BoxV2.sol b/contracts/src/BoxV2.sol new file mode 100644 index 0000000000..86b681b0ed --- /dev/null +++ b/contracts/src/BoxV2.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract BoxV2 { + uint256 private _value; + uint256 private _value2; + + event ValueChanged(uint256 value); + + function store(uint256 value) public { + _value = value; + emit ValueChanged(value); + } + + function retrieve() public view returns (uint256) { + return _value; + } + + function boxV2Incr() public { + _value = _value + 1; + emit ValueChanged(_value); + } + + function store2(uint256 value) public { + _value2 = value; + emit ValueChanged(value); + } + + function retrieve2() public view returns (uint256) { + return _value2; + } +} \ No newline at end of file diff --git a/contracts/src/CW20ERC20Pointer.sol b/contracts/src/CW20ERC20Pointer.sol new file mode 100644 index 0000000000..b5251a8f63 --- /dev/null +++ b/contracts/src/CW20ERC20Pointer.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; +import {IWasmd} from "./precompiles/IWasmd.sol"; +import {IJson} from "./precompiles/IJson.sol"; +import {IAddr} from "./precompiles/IAddr.sol"; + +contract CW20ERC20Pointer is ERC20 { + + address constant WASMD_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001002; + address constant JSON_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001003; + address constant ADDR_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001004; + + string public Cw20Address; + IWasmd public WasmdPrecompile; + IJson public JsonPrecompile; + IAddr public AddrPrecompile; + + constructor(string memory Cw20Address_, string memory name_, string memory symbol_) ERC20(name_, symbol_) { + WasmdPrecompile = IWasmd(WASMD_PRECOMPILE_ADDRESS); + JsonPrecompile = IJson(JSON_PRECOMPILE_ADDRESS); + AddrPrecompile = IAddr(ADDR_PRECOMPILE_ADDRESS); + Cw20Address = Cw20Address_; + } + + // Queries + function decimals() public view override returns (uint8) { + string memory req = _curlyBrace(_formatPayload("token_info", "{}")); + bytes memory response = WasmdPrecompile.query(Cw20Address, bytes(req)); + return uint8(JsonPrecompile.extractAsUint256(response, "decimals")); + } + + function balanceOf(address owner) public view override returns (uint256) { + require(owner != address(0), "ERC20: balance query for the zero address"); + string memory ownerAddr = _formatPayload("address", _doubleQuotes(AddrPrecompile.getSeiAddr(owner))); + string memory req = _curlyBrace(_formatPayload("balance", _curlyBrace(ownerAddr))); + bytes memory response = WasmdPrecompile.query(Cw20Address, bytes(req)); + return JsonPrecompile.extractAsUint256(response, "balance"); + } + + function totalSupply() public view override returns (uint256) { + string memory req = _curlyBrace(_formatPayload("token_info", "{}")); + bytes memory response = WasmdPrecompile.query(Cw20Address, bytes(req)); + return JsonPrecompile.extractAsUint256(response, "total_supply"); + } + + function allowance(address owner, address spender) public view override returns (uint256) { + string memory o = _formatPayload("owner", _doubleQuotes(AddrPrecompile.getSeiAddr(owner))); + string memory s = _formatPayload("spender", _doubleQuotes(AddrPrecompile.getSeiAddr(spender))); + string memory req = _curlyBrace(_formatPayload("allowance", _curlyBrace(_join(o, s, ",")))); + bytes memory response = WasmdPrecompile.query(Cw20Address, bytes(req)); + return JsonPrecompile.extractAsUint256(response, "allowance"); + } + + // Transactions + function approve(address spender, uint256 amount) public override returns (bool) { + uint256 currentAllowance = allowance(msg.sender, spender); + if (currentAllowance > amount) { + string memory spenderAddr = _formatPayload("spender", _doubleQuotes(AddrPrecompile.getSeiAddr(spender))); + string memory amt = _formatPayload("amount", _doubleQuotes(Strings.toString(currentAllowance - amount))); + string memory req = _curlyBrace(_formatPayload("decrease_allowance", _curlyBrace(_join(spenderAddr, amt, ",")))); + _execute(bytes(req)); + } else if (currentAllowance < amount) { + string memory spenderAddr = _formatPayload("spender", _doubleQuotes(AddrPrecompile.getSeiAddr(spender))); + string memory amt = _formatPayload("amount", _doubleQuotes(Strings.toString(amount - currentAllowance))); + string memory req = _curlyBrace(_formatPayload("increase_allowance", _curlyBrace(_join(spenderAddr, amt, ",")))); + _execute(bytes(req)); + } + emit Approval(msg.sender, spender, amount); + return true; + } + + function transfer(address to, uint256 amount) public override returns (bool) { + require(to != address(0), "ERC20: transfer to the zero address"); + string memory recipient = _formatPayload("recipient", _doubleQuotes(AddrPrecompile.getSeiAddr(to))); + string memory amt = _formatPayload("amount", _doubleQuotes(Strings.toString(amount))); + string memory req = _curlyBrace(_formatPayload("transfer", _curlyBrace(_join(recipient, amt, ",")))); + _execute(bytes(req)); + emit Transfer(msg.sender, to, amount); + return true; + } + + function transferFrom(address from, address to, uint256 amount) public override returns (bool) { + require(to != address(0), "ERC20: transfer to the zero address"); + string memory sender = _formatPayload("owner", _doubleQuotes(AddrPrecompile.getSeiAddr(from))); + string memory recipient = _formatPayload("recipient", _doubleQuotes(AddrPrecompile.getSeiAddr(to))); + string memory amt = _formatPayload("amount", _doubleQuotes(Strings.toString(amount))); + string memory req = _curlyBrace(_formatPayload("transfer_from", _curlyBrace(_join(_join(sender, recipient, ","), amt, ",")))); + _execute(bytes(req)); + emit Transfer(from, to, amount); + return true; + } + + function _execute(bytes memory req) internal returns (bytes memory) { + (bool success, bytes memory ret) = WASMD_PRECOMPILE_ADDRESS.delegatecall( + abi.encodeWithSignature( + "execute(string,bytes,bytes)", + Cw20Address, + bytes(req), + bytes("[]") + ) + ); + require(success, "CosmWasm execute failed"); + return ret; + } + + function _formatPayload(string memory key, string memory value) internal pure returns (string memory) { + return _join(_doubleQuotes(key), value, ":"); + } + + function _curlyBrace(string memory s) internal pure returns (string memory) { + return string.concat("{", string.concat(s, "}")); + } + + function _doubleQuotes(string memory s) internal pure returns (string memory) { + return string.concat("\"", string.concat(s, "\"")); + } + + function _join(string memory a, string memory b, string memory separator) internal pure returns (string memory) { + return string.concat(a, string.concat(separator, b)); + } +} \ No newline at end of file diff --git a/contracts/src/CW721ERC721Pointer.sol b/contracts/src/CW721ERC721Pointer.sol new file mode 100644 index 0000000000..a8c614e189 --- /dev/null +++ b/contracts/src/CW721ERC721Pointer.sol @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; +import {IWasmd} from "./precompiles/IWasmd.sol"; +import {IJson} from "./precompiles/IJson.sol"; +import {IAddr} from "./precompiles/IAddr.sol"; + +contract CW721ERC721Pointer is ERC721 { + + address constant WASMD_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001002; + address constant JSON_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001003; + address constant ADDR_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001004; + + string public Cw721Address; + IWasmd public WasmdPrecompile; + IJson public JsonPrecompile; + IAddr public AddrPrecompile; + + constructor(string memory Cw721Address_, string memory name_, string memory symbol_) ERC721(name_, symbol_) { + WasmdPrecompile = IWasmd(WASMD_PRECOMPILE_ADDRESS); + JsonPrecompile = IJson(JSON_PRECOMPILE_ADDRESS); + AddrPrecompile = IAddr(ADDR_PRECOMPILE_ADDRESS); + Cw721Address = Cw721Address_; + } + + // 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))); + bytes memory response = WasmdPrecompile.query(Cw721Address, bytes(req)); + bytes[] memory tokens = JsonPrecompile.extractAsBytesList(response, "tokens"); + return tokens.length; + } + + function ownerOf(uint256 tokenId) public view override returns (address) { + string memory tId = _formatPayload("token_id", _doubleQuotes(Strings.toString(tokenId))); + string memory req = _curlyBrace(_formatPayload("owner_of", _curlyBrace(tId))); + bytes memory response = WasmdPrecompile.query(Cw721Address, bytes(req)); + bytes memory owner = JsonPrecompile.extractAsBytes(response, "owner"); + return AddrPrecompile.getEvmAddr(string(owner)); + } + + function getApproved(uint256 tokenId) public view override returns (address) { + string memory tId = _formatPayload("token_id", _doubleQuotes(Strings.toString(tokenId))); + string memory req = _curlyBrace(_formatPayload("approvals", _curlyBrace(tId))); + bytes memory response = WasmdPrecompile.query(Cw721Address, bytes(req)); + bytes[] memory approvals = JsonPrecompile.extractAsBytesList(response, "approvals"); + if (approvals.length > 0) { + bytes memory res = JsonPrecompile.extractAsBytes(approvals[0], "spender"); + return AddrPrecompile.getEvmAddr(string(res)); + } + return address(0); + } + + function isApprovedForAll(address owner, address operator) public view override returns (bool) { + string memory o = _formatPayload("owner", _doubleQuotes(AddrPrecompile.getSeiAddr(owner))); + string memory req = _curlyBrace(_formatPayload("all_operators", _curlyBrace(o))); + bytes memory response = WasmdPrecompile.query(Cw721Address, bytes(req)); + bytes[] memory approvals = JsonPrecompile.extractAsBytesList(response, "operators"); + for (uint i=0; i address) internal _ownerOf; + + // Mapping owner address to token count + mapping(address => uint) internal _balanceOf; + + // Mapping from token ID to approved address + mapping(uint => address) internal _approvals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) public isApprovedForAll; + + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC165).interfaceId; + } + + function ownerOf(uint id) external view returns (address owner) { + owner = _ownerOf[id]; + require(owner != address(0), "token doesn't exist"); + } + + function balanceOf(address owner) external view returns (uint) { + require(owner != address(0), "owner = zero address"); + return _balanceOf[owner]; + } + + function setApprovalForAll(address operator, bool approved) external { + isApprovedForAll[msg.sender][operator] = approved; + emit ApprovalForAll(msg.sender, operator, approved); + } + + function approve(address spender, uint id) external { + address owner = _ownerOf[id]; + require( + msg.sender == owner || isApprovedForAll[owner][msg.sender], + "not authorized" + ); + + _approvals[id] = spender; + + emit Approval(owner, spender, id); + } + + function getApproved(uint id) external view returns (address) { + require(_ownerOf[id] != address(0), "token doesn't exist"); + return _approvals[id]; + } + + function _isApprovedOrOwner( + address owner, + address spender, + uint id + ) internal view returns (bool) { + return (spender == owner || + isApprovedForAll[owner][spender] || + spender == _approvals[id]); + } + + function transferFrom(address from, address to, uint id) public { + require(from == _ownerOf[id], "from != owner"); + require(to != address(0), "transfer to zero address"); + + require(_isApprovedOrOwner(from, msg.sender, id), "not authorized"); + + _balanceOf[from]--; + _balanceOf[to]++; + _ownerOf[id] = to; + + delete _approvals[id]; + + emit Transfer(from, to, id); + } + + function safeTransferFrom(address from, address to, uint id) external { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + IERC721Receiver(to).onERC721Received(msg.sender, from, id, "") == + IERC721Receiver.onERC721Received.selector, + "unsafe recipient" + ); + } + + function safeTransferFrom( + address from, + address to, + uint id, + bytes calldata data + ) external { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + IERC721Receiver(to).onERC721Received(msg.sender, from, id, data) == + IERC721Receiver.onERC721Received.selector, + "unsafe recipient" + ); + } + + function _mint(address to, uint id) internal { + require(to != address(0), "mint to zero address"); + require(_ownerOf[id] == address(0), "already minted"); + + _balanceOf[to]++; + _ownerOf[id] = to; + + emit Transfer(address(0), to, id); + } + + function _burn(uint id) internal { + address owner = _ownerOf[id]; + require(owner != address(0), "not minted"); + + _balanceOf[owner] -= 1; + + delete _ownerOf[id]; + delete _approvals[id]; + + emit Transfer(owner, address(0), id); + } +} + +contract MyNFT is ERC721 { + function mint(address to, uint id) external { + _mint(to, id); + } + + function burn(uint id) external { + require(msg.sender == _ownerOf[id], "not owner"); + _burn(id); + } +} diff --git a/contracts/src/EVMCompatibilityTester.sol b/contracts/src/EVMCompatibilityTester.sol new file mode 100644 index 0000000000..ca0f193a4c --- /dev/null +++ b/contracts/src/EVMCompatibilityTester.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "./TestToken.sol"; + +contract EVMCompatibilityTester { + // verify different events with var types + event DummyEvent(string indexed str, bool flag, address indexed addr, uint256 indexed num, bytes data); + event ActionPerformed(string action, address indexed performer); + event BoolSet(address performer, bool value); + event AddressSet(address indexed performer); + event Uint256Set(address indexed performer, uint256 value); + event StringSet(address indexed performer, string value); + event LogIndexEvent(address indexed performer, uint256 value); + + struct MsgDetails { + address sender; + uint256 value; + bytes data; + uint256 gas; + } + + // Example of contract storing and retrieving data + uint256 private storedData; + + // deployer of the contract + address public owner; + + // one of each type + address public addressVar; + bool public boolVar; + uint256 public uint256Var; + string public stringVar; + uint256 public lastTimestamp; + + // State variable to store the details + MsgDetails public lastMsgDetails; + + mapping(address => uint256) public balances; + + constructor() { + owner = msg.sender; + } + + function storeData(uint256 data) public { + storedData = data; + emit ActionPerformed("Data Stored", msg.sender); + } + + // Function to set a balance for a specific address + function setBalance(address user, uint256 amount) public { + balances[user] = amount; + emit ActionPerformed("Balance Set", msg.sender); + } + + function setAddressVar() public { + addressVar = msg.sender; + emit AddressSet(msg.sender); + } + + function setBoolVar(bool value) public { + boolVar = value; + emit BoolSet(msg.sender, value); + } + + function emitMultipleLogs(uint256 count) public { + for (uint256 i = 0; i < count; i++) { + emit LogIndexEvent(msg.sender, i); + } + } + + function setStringVar(string memory value) public { + stringVar = value; + emit StringSet(msg.sender, value); + } + + function setUint256Var(uint256 value) public { + uint256Var = value; + emit Uint256Set(msg.sender, value); + } + + // verify returning of private var + function retrieveData() public view returns (uint256) { + return storedData; + } + + // Example of inter-contract calls + function callAnotherContract(address contractAddress, bytes memory data) public { + (bool success, ) = contractAddress.call(data); + require(success, "Call failed"); + emit ActionPerformed("Inter-Contract Call", msg.sender); + } + + // Example of creating a new contract from a contract + function createToken(string memory name, string memory symbol) public { + TestToken token = new TestToken(name, symbol); + token.transfer(msg.sender, 100); + } + + // Example of inline assembly: a simple function to add two numbers + function addNumbers(uint256 a, uint256 b) public pure returns (uint256 sum) { + assembly { + sum := add(a, b) + } + } + + // Inline assembly for accessing contract balance + function getContractBalance() public view returns (uint256 contractBalance) { + assembly { + contractBalance := selfbalance() + } + } + + function getBlockProperties() public view returns (bytes32 blockHash, address payable coinbase, uint prevrandao, uint gaslimit, uint number, uint timestamp) { + blockHash = blockhash(block.number - 1); + coinbase = block.coinbase; + prevrandao = block.prevrandao; + gaslimit = block.gaslimit; + number = block.number; + timestamp = block.timestamp; + + return (blockHash, coinbase, prevrandao, gaslimit, number, timestamp); + } + + function setTimestamp() public { + lastTimestamp = block.timestamp; + } + + function revertIfFalse(bool value) public { + boolVar = value; + require(value == true, "value must be true"); + } + + // More complex example: Inline assembly to read from storage directly + function readFromStorage(uint256 storageIndex) public view returns (uint256 data) { + assembly { + data := sload(storageIndex) + } + } + + // Function to store some properties of 'msg' + function storeMsgProperties() public payable { + // Storing the properties of 'msg' + lastMsgDetails = MsgDetails({ + sender: msg.sender, + value: msg.value, + data: msg.data, + gas: gasleft() + }); + } + + function depositEther() external payable { + require(msg.value > 0, "No Ether sent"); + } + + function sendEther(address payable recipient, uint256 amount) external payable { + require(msg.sender == owner, "Only owner can send Ether"); + require(address(this).balance >= amount, "Insufficient balance"); + recipient.transfer(amount); + } + + function emitDummyEvent(string memory str, uint256 num) external { + bytes memory bytes_ = bytes(string(abi.encodePacked(str, "Bytes"))); + emit DummyEvent(str, true, msg.sender, num, bytes_); + } +} + diff --git a/contracts/src/NativeSeiTokensERC20.sol b/contracts/src/NativeSeiTokensERC20.sol new file mode 100644 index 0000000000..278f95bf0b --- /dev/null +++ b/contracts/src/NativeSeiTokensERC20.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {IBank} from "./precompiles/IBank.sol"; + +contract NativeSeiTokensERC20 is ERC20 { + + address constant BANK_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001001; + + string public denom; + string public nname; + string public ssymbol; + uint8 public ddecimals; + IBank public BankPrecompile; + + constructor(string memory denom_, string memory name_, string memory symbol_, uint8 decimals_) ERC20("", "") { + BankPrecompile = IBank(BANK_PRECOMPILE_ADDRESS); + denom = denom_; + nname = name_; + ssymbol = symbol_; + ddecimals = decimals_; + } + + function name() public view override returns (string memory) { + return nname; + } + + function symbol() public view override returns (string memory) { + return ssymbol; + } + + function balanceOf(address account) public view override returns (uint256) { + return BankPrecompile.balance(account, denom); + } + + function decimals() public view override returns (uint8) { + return ddecimals; + } + + function totalSupply() public view override returns (uint256) { + return BankPrecompile.supply(denom); + } + + function _update(address from, address to, uint256 value) internal override { + bool success = BankPrecompile.send(from, to, denom, value); + require(success, "NativeSeiTokensERC20: transfer failed"); + emit Transfer(from, to, value); + } +} diff --git a/contracts/src/TestToken.sol b/contracts/src/TestToken.sol new file mode 100644 index 0000000000..b4d7596df7 --- /dev/null +++ b/contracts/src/TestToken.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract TestToken is ERC20, Ownable { + constructor(string memory name, string memory symbol) Ownable(msg.sender) ERC20(name, symbol) { + _mint(msg.sender, 1000 * (10 ** uint256(decimals()))); + } + + // setBalance verifies modifier works + function setBalance(address account, uint256 amount) public onlyOwner { + uint256 currentBalance = balanceOf(account); + if (amount > currentBalance) { + _mint(account, amount - currentBalance); + } else if (amount < currentBalance) { + _burn(account, currentBalance - amount); + } + } +} diff --git a/contracts/src/WSEI.sol b/contracts/src/WSEI.sol new file mode 100644 index 0000000000..02d9ec833e --- /dev/null +++ b/contracts/src/WSEI.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract WSEI { + string public name = "Wrapped Sei"; + string public symbol = "WSEI"; + uint8 public decimals = 18; + + event Approval(address indexed src, address indexed guy, uint wad); + event Transfer(address indexed src, address indexed dst, uint wad); + event Deposit(address indexed dst, uint wad); + event Withdrawal(address indexed src, uint wad); + + mapping (address => uint) public balanceOf; + mapping (address => mapping (address => uint)) public allowance; + + fallback() external payable { + deposit(); + } + receive() external payable { + deposit(); + } + function deposit() public payable { + balanceOf[msg.sender] += msg.value; + emit Deposit(msg.sender, msg.value); + } + function withdraw(uint wad) public { + require(balanceOf[msg.sender] >= wad); + balanceOf[msg.sender] -= wad; + payable(msg.sender).transfer(wad); + emit Withdrawal(msg.sender, wad); + } + + function totalSupply() public view returns (uint) { + return address(this).balance; + } + + function approve(address guy, uint wad) public returns (bool) { + allowance[msg.sender][guy] = wad; + emit Approval(msg.sender, guy, wad); + return true; + } + + function transfer(address dst, uint wad) public returns (bool) { + return transferFrom(msg.sender, dst, wad); + } + + function transferFrom(address src, address dst, uint wad) + public + returns (bool) + { + require(balanceOf[src] >= wad); + + if (src != msg.sender && allowance[src][msg.sender] != type(uint).max) { + require(allowance[src][msg.sender] >= wad); + allowance[src][msg.sender] -= wad; + } + + balanceOf[src] -= wad; + balanceOf[dst] += wad; + + emit Transfer(src, dst, wad); + + return true; + } +} diff --git a/contracts/src/precompiles/IAddr.sol b/contracts/src/precompiles/IAddr.sol new file mode 100644 index 0000000000..d479747daf --- /dev/null +++ b/contracts/src/precompiles/IAddr.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant ADDR_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001004; + +IAddr constant ADDR_CONTRACT = IAddr( + ADDR_PRECOMPILE_ADDRESS +); + +interface IAddr { + // Queries + function getSeiAddr(address addr) external view returns (string memory response); + function getEvmAddr(string memory addr) external view returns (address response); +} diff --git a/contracts/src/precompiles/IBank.sol b/contracts/src/precompiles/IBank.sol new file mode 100644 index 0000000000..ab800c1521 --- /dev/null +++ b/contracts/src/precompiles/IBank.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant BANK_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001001; + +IBank constant BANK_CONTRACT = IBank( + BANK_PRECOMPILE_ADDRESS +); + +interface IBank { + // Transactions + function send( + address fromAddress, + address toAddress, + string memory denom, + uint256 amount + ) external returns (bool success); + + function sendFromCaller( + address toAddress, + string memory denom, + uint256 amount + ) external returns (bool success); + + function sendFromOrigin( + address toAddress, + string memory denom, + uint256 amount + ) external returns (bool success); + + // Queries + function balance( + address acc, + string memory denom + ) external view returns (uint256 amount); + + function name( + string memory denom + ) external view returns (string memory response); + + function symbol( + string memory denom + ) external view returns (string memory response); + + function decimals( + string memory denom + ) external view returns (uint8 response); + + function supply( + string memory denom + ) external view returns (uint256 response); +} diff --git a/contracts/src/precompiles/IJson.sol b/contracts/src/precompiles/IJson.sol new file mode 100644 index 0000000000..18a7c2b433 --- /dev/null +++ b/contracts/src/precompiles/IJson.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant JSON_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001003; + +IJson constant JSON_CONTRACT = IJson( + JSON_PRECOMPILE_ADDRESS +); + +interface IJson { + // Queries + function extractAsBytes(bytes memory input, string memory key) external view returns (bytes memory response); + + function extractAsBytesList(bytes memory input, string memory key) external view returns (bytes[] memory response); + + function extractAsUint256(bytes memory input, string memory key) external view returns (uint256 response); +} diff --git a/contracts/src/precompiles/IWasmd.sol b/contracts/src/precompiles/IWasmd.sol new file mode 100644 index 0000000000..c174867a6d --- /dev/null +++ b/contracts/src/precompiles/IWasmd.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant WASMD_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001002; + +IWasmd constant WASMD_CONTRACT = IWasmd( + WASMD_PRECOMPILE_ADDRESS +); + +interface IWasmd { + // Transactions + function instantiate( + uint64 codeID, + string memory admin, + bytes memory payload, + string memory label, + bytes memory coins + ) external returns (string memory contractAddr, bytes memory data); + + function execute( + string memory contractAddress, + bytes memory payload, + bytes memory coins + ) external returns (bytes memory response); + + // Queries + function query(string memory contractAddress, bytes memory req) external view returns (bytes memory response); +} diff --git a/contracts/test/CW20ERC20PointerTest.js b/contracts/test/CW20ERC20PointerTest.js new file mode 100644 index 0000000000..ca1c360c88 --- /dev/null +++ b/contracts/test/CW20ERC20PointerTest.js @@ -0,0 +1,401 @@ +const { expect } = require("chai"); +const {isBigNumber} = require("hardhat/common"); +const { exec } = require("child_process"); // Importing exec from child_process +const { cons } = require("fp-ts/lib/NonEmptyArray2v"); + +// Run instructions +// Should be run on a local chain using: `npx hardhat test --network seilocal test/CW20ERC20PointerTest.js` + +async function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +async function delay() { + await sleep(3000) +} + +function debug(msg) { + //console.log(msg) +} + +const CW20_BASE_WASM_LOCATION = "wasm/cw20_base.wasm"; +const secondAnvilAddrETH = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"; +const secondAnvilAddrSEI = "sei1cjzphr67dug28rw9ueewrqllmxlqe5f0awulvy"; +const thirdAnvilAddrETH = "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"; +const thirdAnvilAddrSEI = "sei183zvmhdk4yq0526cthffncpaztay9yauk6y0ue" +const secondAnvilPk = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"; // Replace with the spender's private key +const secondAnvilWallet = new ethers.Wallet(secondAnvilPk); +const secondAnvilSigner = secondAnvilWallet.connect(ethers.provider); + +describe("CW20ERC20PointerTest", function () { + let adminAddrSei; + let contractAddress; + let deployerAddrETH; + let deployerAddrSEI; + let cW20ERC20Pointer; + + before(async function () { + // fund addresses with SEI + console.log("funding addresses with SEI...") + await fundwithSei(deployerAddrETH); + await fundwithSei(secondAnvilAddrETH); + await fundwithSei(thirdAnvilAddrETH); + + let signers = await hre.ethers.getSigners(); + const deployer = signers[0]; + deployerAddrETH = await deployer.getAddress(); + deployerAddrSEI = await getSeiAddr(deployerAddrETH); + console.log("deployer address ETH = ", deployerAddrETH); + console.log("deployer address SEI = ", deployerAddrSEI); + + console.log("deploying wasm...") + let codeId = await deployWasm(); + console.log(`codeId: ${codeId}`); + console.log("getting admin addr...") + adminAddrSei = await getAdmin(); + console.log(`seid admin address: ${adminAddrSei}`); + console.log("instantiating wasm...") + contractAddress = await instantiateWasm(codeId, deployerAddrSEI); + console.log(`CW20 Sei contract address: ${contractAddress}`) + console.log( + "Deploying contracts with the account:", + deployerAddrETH + ); + + await delay(); + const CW20ERC20Pointer = await ethers.getContractFactory("CW20ERC20Pointer"); + await delay(); + console.log("deploying cw20 erc20 pointer...") + cW20ERC20Pointer = await CW20ERC20Pointer.deploy(contractAddress, "BTOK", "TOK"); + await cW20ERC20Pointer.waitForDeployment(); + console.log("CW20ERC20Pointer address = ", cW20ERC20Pointer.target) + }); + + describe("name", function () { + it("name should work", async function () { + const name = await cW20ERC20Pointer.name(); + console.log(`Name: ${name}`); + expect(name).to.equal("BTOK"); + }); + }); + + describe("symbol", function () { + it("symbol should work", async function () { + const symbol = await cW20ERC20Pointer.symbol(); + console.log(`Symbol: ${symbol}`); + expect(symbol).to.equal("TOK"); // Replace "TOK" with the expected symbol + }); + }); + + describe("decimals", function () { + it("decimals should work", async function () { + const decimals = await cW20ERC20Pointer.decimals(); + console.log(`Decimals: ${decimals}`); + expect(Number(decimals)).to.be.greaterThan(0); + }); + }); + + describe("balanceOf", function () { + it("balanceOf should work", async function () { + let addressToCheck = secondAnvilAddrETH; + console.log(`addressToCheck: ${addressToCheck}`); + let secondAnvilAddrBalance = await cW20ERC20Pointer.balanceOf(addressToCheck); + console.log(`Balance of ${addressToCheck}: ${secondAnvilAddrBalance}`); // without this line the test fails more frequently + expect(Number(secondAnvilAddrBalance)).to.be.greaterThan(0); + }); + }); + + describe("totalSupply", function () { + it("totalSupply should work", async function () { + let totalSupply = await cW20ERC20Pointer.totalSupply(); + console.log(`Total supply: ${totalSupply}`); + // expect total supply to be great than 0 + expect(Number(totalSupply)).to.be.greaterThan(0); + }); + }); + + describe("allowance", function () { + it("increase allowance should work", async function () { + let owner = deployerAddrETH; // Replace with the owner's address + let spender = deployerAddrETH; // Replace with the spender's address + let allowance = await cW20ERC20Pointer.allowance(owner, spender); + console.log(`Allowance for ${spender} from ${owner}: ${allowance}`); + expect(Number(allowance)).to.equal(0); // Replace with the expected allowance + }); + }); + + describe("approve", function () { + it("increasing approval should work", async function () { + let spender = secondAnvilAddrETH; + let amount = 1000000; // Replace with the amount to approve + const tx = await cW20ERC20Pointer.approve(spender, amount); + await tx.wait(); + const allowance = await cW20ERC20Pointer.allowance(deployerAddrETH, spender); + console.log(`Allowance for ${spender} from ${deployerAddrETH}: ${allowance}`); + expect(Number(allowance)).to.equal(amount); + }); + + it("decreasing approval should work", async function () { + let spender = secondAnvilAddrETH; + let amount = 10; // Replace with the amount to approve + + // check that current allowance is greater than amount + const currentAllowance = await cW20ERC20Pointer.allowance(deployerAddrETH, spender); + expect(Number(currentAllowance)).to.be.greaterThan(amount); + + // decrease allowance + const tx = await cW20ERC20Pointer.approve(spender, amount); + await tx.wait(); + const allowance = await cW20ERC20Pointer.allowance(deployerAddrETH, spender); + console.log(`Allowance for ${spender} from ${deployerAddrETH}: ${allowance}`); + expect(Number(allowance)).to.equal(amount); + }); + }); + + describe("transfer", function () { + it("transfer should work", async function () { + let recipient = secondAnvilAddrETH; + let amount = 8; // Replace with the amount to transfer + + // check that balanceOf sender address has enough ERC20s to send + let balanceOfDeployer = await cW20ERC20Pointer.balanceOf(deployerAddrETH); + expect(Number(balanceOfDeployer)).to.be.greaterThan(amount); + console.log("transfer: deployerAddr balance = ", balanceOfDeployer); + + // capture recipient balance before the transfer + let balanceOfRecipientBefore = await cW20ERC20Pointer.balanceOf(recipient); + console.log("transfer: recipient balance before = ", balanceOfRecipientBefore); + + // do the transfer + const tx = await cW20ERC20Pointer.transfer(recipient, amount); + await tx.wait(); + + // compare recipient balance before and after the transfer + let balanceOfRecipientAfter = await cW20ERC20Pointer.balanceOf(recipient); + let diff = balanceOfRecipientAfter - balanceOfRecipientBefore; + expect(diff).to.equal(amount); + }); + + it("transfer should fail if sender has insufficient balance", async function () { + const balanceOfDeployer = await cW20ERC20Pointer.balanceOf(deployerAddrETH); + + const recipient = secondAnvilAddrETH; + const amount = balanceOfDeployer + BigInt(1); // This should be more than the sender's balance + + await expect(cW20ERC20Pointer.transfer(recipient, amount)).to.be.revertedWith("CosmWasm execute failed"); + }); + }); + + describe("transferFrom", function () { + it("transferFrom should work", async function () { + const amountToTransfer = 10; + const spender = secondAnvilAddrETH; + const recipient = thirdAnvilAddrETH; + // check balanceOf deployer + console.log("transferFrom: checking balanceOf deployer...") + const balanceOfDeployer = await cW20ERC20Pointer.balanceOf(deployerAddrETH); + expect(Number(balanceOfDeployer)).to.be.greaterThanOrEqual(amountToTransfer); + + // give allowance of deployer to spender (third party) + console.log("transferFrom: doing approve...") + const tx = await cW20ERC20Pointer.approve(spender, amountToTransfer); + await tx.wait(); + + // check allownce of deployer to spender + console.log("transferFrom: checking allowance...") + const allowanceBefore = await cW20ERC20Pointer.allowance(deployerAddrETH, spender); + expect(Number(allowanceBefore)).to.be.greaterThanOrEqual(amountToTransfer); + + // check that spender has gas + console.log("transferFrom: checking spender has gas...") + const spenderGas = await ethers.provider.getBalance(spender); + expect(Number(spenderGas)).to.be.greaterThan(0); + console.log("transferFrom: spender gas = ", spenderGas) + + // capture recipient balance before transfer + console.log("transferFrom: checking balanceOf recipient before transfer...") + const balanceOfRecipientBefore = await cW20ERC20Pointer.balanceOf(recipient); + + // check balanceOf sender (deployerAddr) to ensure it went down + const balanceOfSenderBefore = await cW20ERC20Pointer.balanceOf(deployerAddrETH); + + // have deployer transferFrom spender to recipient + console.log("transferFrom: doing actual transferFrom...") + const tfTx = await cW20ERC20Pointer.connect(secondAnvilSigner).transferFrom(deployerAddrETH, recipient, amountToTransfer); + await tfTx.wait(); + + // check balance diff to ensure transfer went through + console.log("transferFrom: checking balanceOf recipient after transfer...") + const balanceOfRecipientAfter = await cW20ERC20Pointer.balanceOf(recipient); + const diff = balanceOfRecipientAfter - balanceOfRecipientBefore; + expect(diff).to.equal(amountToTransfer); + + // check balanceOf sender (deployerAddr) to ensure it went down + const balanceOfSenderAfter = await cW20ERC20Pointer.balanceOf(deployerAddrETH); + const diff2 = balanceOfSenderBefore - balanceOfSenderAfter; + expect(diff2).to.equal(amountToTransfer); + + // check that allowance has gone down by amountToTransfer + const allowanceAfter = await cW20ERC20Pointer.allowance(deployerAddrETH, spender); + expect(Number(allowanceBefore) - Number(allowanceAfter)).to.equal(amountToTransfer); + }); + + it("transferFrom should fail if sender has insufficient balance", async function() { + const fromAddrBalance = await cW20ERC20Pointer.balanceOf(deployerAddrETH); + const spender = secondAnvilAddrETH; + const recipient = thirdAnvilAddrETH; + + // try to transfer more than the balance + const amountToTransfer = fromAddrBalance + BigInt(1); + + const tx = await cW20ERC20Pointer.approve(spender, amountToTransfer); + await tx.wait(); + + await expect(cW20ERC20Pointer.connect(secondAnvilSigner).transferFrom(deployerAddrETH, recipient, amountToTransfer)) + .to.be.revertedWith("CosmWasm execute failed"); + }); + + it("transferFrom should fail if proper allowance not given", async function () { + const fromAddrBalance = await cW20ERC20Pointer.balanceOf(deployerAddrETH); + const spender = secondAnvilAddrETH; + const recipient = thirdAnvilAddrETH; + + const amountToTransfer = 1 + + // set approval to 0 + const tx = await cW20ERC20Pointer.approve(spender, 0); + await tx.wait(); + + await expect(cW20ERC20Pointer.connect(secondAnvilSigner).transferFrom(deployerAddrETH, recipient, amountToTransfer)) + .to.be.revertedWith("CosmWasm execute failed"); + }); + + }); +}); + +async function getSeiAddr(ethAddr) { + let seiAddr = await new Promise((resolve, reject) => { + exec(`seid q evm sei-addr ${ethAddr}`, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + reject(new Error(stderr)); + return; + } + debug(`stdout: ${stdout}`) + resolve(stdout.trim()); + }); + }); + return seiAddr.replace("sei_address: ", "");; +} + +async function fundwithSei(deployerAddress) { + // Wrap the exec function in a Promise + await new Promise((resolve, reject) => { + exec(`seid tx evm send ${deployerAddress} 10000000000000000000 --from admin`, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + reject(new Error(stderr)); + return; + } + debug(`stdout: ${stdout}`) + resolve(); + }); + }); +} + +async function deployWasm() { + // Wrap the exec function in a Promise + let codeId = await new Promise((resolve, reject) => { + exec(`seid tx wasm store ${CW20_BASE_WASM_LOCATION} --from admin --gas=5000000 --fees=1000000usei -y --broadcast-mode block`, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + reject(new Error(stderr)); + return; + } + debug(`stdout: ${stdout}`) + + // Regular expression to find the 'code_id' value + const regex = /key: code_id\s+value: "(\d+)"/; + + // Searching for the pattern in the string + const match = stdout.match(regex); + + let cId = null; + if (match && match[1]) { + // The captured group is the code_id value + cId = match[1]; + } + + console.log(`cId: ${cId}`); + resolve(cId); + }); + }); + + return codeId; +} + +async function getAdmin() { + // Wrap the exec function in a Promise + let adminAddr = await new Promise((resolve, reject) => { + exec(`seid keys show admin -a`, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + reject(new Error(stderr)); + return; + } + debug(`stdout: ${stdout}`) + resolve(stdout.trim()); + }); + }); + return adminAddr; +} + +async function instantiateWasm(codeId, adminAddr) { + // Wrap the exec function in a Promise + console.log("instantiateWasm: will fund admin addr = ", adminAddr); + console.log("instantiateWasm: will fund secondAnvilAddr = ", secondAnvilAddrSEI); + let contractAddress = await new Promise((resolve, reject) => { + const cmd = `seid tx wasm instantiate ${codeId} '{ "name": "BTOK", "symbol": "BTOK", "decimals": 6, "initial_balances": [ { "address": "${adminAddr}", "amount": "1000000" }, { "address": "${secondAnvilAddrSEI}", "amount": "1000000"} ], "mint": { "minter": "${adminAddr}", "cap": "99900000000" } }' --label cw20-test --admin ${adminAddr} --from admin --gas=5000000 --fees=1000000usei -y --broadcast-mode block`; + exec(cmd, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`); + reject(error); + return; + } + if (stderr) { + console.log(`stderr: ${stderr}`); + reject(new Error(stderr)); + return; + } + debug(`stdout: ${stdout}`) + const regex = /_contract_address\s*value:\s*(\w+)/; + const match = stdout.match(regex); + if (match && match[1]) { + resolve(match[1]); + } else { + reject(new Error('Contract address not found')); + } + }); + }); + return contractAddress; +} diff --git a/contracts/test/CW721ERC721PointerTest.t.sol b/contracts/test/CW721ERC721PointerTest.t.sol new file mode 100644 index 0000000000..9c4602e7cd --- /dev/null +++ b/contracts/test/CW721ERC721PointerTest.t.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; + +import {Test, console2} from "forge-std/Test.sol"; +import {CW721ERC721Pointer} from "../src/CW721ERC721Pointer.sol"; +import {IWasmd} from "../src/precompiles/IWasmd.sol"; +import {IJson} from "../src/precompiles/IJson.sol"; +import {IAddr} from "../src/precompiles/IAddr.sol"; + +address constant WASMD_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001002; +address constant JSON_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001003; +address constant ADDR_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001004; + +address constant MockCallerEVMAddr = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; +address constant MockOperatorEVMAddr = 0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267; +string constant MockCallerSeiAddr = "sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw"; +string constant MockOperatorSeiAddr = "sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe"; +string constant MockCWContractAddress = "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m"; + +contract MockWasmd is IWasmd { + + // Transactions + function instantiate( + uint64, + string memory, + bytes memory, + string memory, + bytes memory + ) external pure returns (string memory, bytes memory) { + return (MockCWContractAddress, bytes("")); + } + + function execute( + string memory contractAddress, + bytes memory, + bytes memory + ) external pure returns (bytes memory) { + require(keccak256(abi.encodePacked(contractAddress)) == keccak256(abi.encodePacked(MockCWContractAddress)), "wrong CW contract address"); + return bytes(""); + } + + // Queries + function query(string memory, bytes memory) external pure returns (bytes memory) { + return bytes(""); + } +} + +contract MockJson is IJson { + function extractAsBytes(bytes memory, string memory) external pure returns (bytes memory) { + return bytes("extracted bytes"); + } + + function extractAsBytesList(bytes memory, string memory) external pure returns (bytes[] memory) { + return new bytes[](0); + } + + function extractAsUint256(bytes memory input, string memory key) external view returns (uint256 response) { + return 0; + } +} + +contract MockAddr is IAddr { + function getSeiAddr(address addr) external pure returns (string memory) { + if (addr == MockCallerEVMAddr) { + return MockCallerSeiAddr; + } + return MockOperatorSeiAddr; + } + + function getEvmAddr(string memory addr) external pure returns (address) { + if (keccak256(abi.encodePacked(addr)) == keccak256(abi.encodePacked(MockCallerSeiAddr))) { + return MockCallerEVMAddr; + } + return MockOperatorEVMAddr; + } +} + +contract CW721ERC721PointerTest is Test { + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + CW721ERC721Pointer pointer; + MockWasmd mockWasmd; + MockJson mockJson; + MockAddr mockAddr; + + function setUp() public { + pointer = new CW721ERC721Pointer(MockCWContractAddress, "name", "symbol"); + mockWasmd = new MockWasmd(); + mockJson = new MockJson(); + mockAddr = new MockAddr(); + vm.etch(WASMD_PRECOMPILE_ADDRESS, address(mockWasmd).code); + vm.etch(JSON_PRECOMPILE_ADDRESS, address(mockJson).code); + vm.etch(ADDR_PRECOMPILE_ADDRESS, address(mockAddr).code); + } + + function testName() public { + assertEq(pointer.name(), "name"); + } + + function testSymbol() public { + assertEq(pointer.symbol(), "symbol"); + } + + function testBalanceOf() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"tokens\":{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}}")), + abi.encode("{\"tokens\":[\"a\",\"b\"]}") + ); + bytes[] memory response = new bytes[](2); + response[0] = bytes("a"); + response[1] = bytes("b"); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytesList(bytes,string)", bytes("{\"tokens\":[\"a\",\"b\"]}"), "tokens"), + abi.encode(response) + ); + assertEq(pointer.balanceOf(MockCallerEVMAddr), 2); + } + + function testOwnerOf() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"owner_of\":{\"token_id\":\"1\"}}")), + abi.encode("{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}") + ); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytes(bytes,string)", bytes("{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}"), "owner"), + abi.encode(bytes("sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw")) + ); + assertEq(pointer.ownerOf(1), 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + } + + function testGetApproved() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"approvals\":{\"token_id\":\"1\"}}")), + abi.encode("{\"approvals\":[{\"spender\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}]}") + ); + bytes[] memory response = new bytes[](1); + response[0] = bytes("{\"spender\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}"); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytesList(bytes,string)", bytes("{\"approvals\":[{\"spender\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}]}"), "approvals"), + abi.encode(response) + ); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytes(bytes,string)", bytes("{\"spender\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}}"), "spender"), + abi.encode(bytes("sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe")) + ); + vm.startPrank(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(pointer.getApproved(1), 0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267); + vm.stopPrank(); + } + + function testIsApprovedForAll() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"all_operators\":{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}}")), + abi.encode("{\"operators\":[{\"spender\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}]}") + ); + bytes[] memory response = new bytes[](1); + response[0] = bytes("{\"spender\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}"); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytesList(bytes,string)", bytes("{\"operators\":[{\"spender\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}]}"), "operators"), + abi.encode(response) + ); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytes(bytes,string)", bytes("{\"spender\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}}"), "spender"), + abi.encode(bytes("sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe")) + ); + assertEq(pointer.isApprovedForAll(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267), true); + } + + function testTransferFrom() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"owner_of\":{\"token_id\":\"1\"}}")), + abi.encode("{\"owner\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}") + ); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytes(bytes,string)", bytes("{\"owner\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}"), "owner"), + abi.encode(bytes("sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe")) + ); + vm.mockCall( + ADDR_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("getEvmAddr(string)", "sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe"), + abi.encode(address(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)) + ); + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("execute(string,bytes,bytes)", MockCWContractAddress, bytes("{\"transfer_nft\":{\"recipient\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\",\"token_id\":\"1\"}}"), bytes("[]")), + abi.encode(bytes("")) + ); + vm.startPrank(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + vm.expectEmit(); + emit Transfer(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267, 1); + pointer.transferFrom(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267, 1); + vm.stopPrank(); + } + + function testApprove() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("execute(string,bytes,bytes)", MockCWContractAddress, bytes("{\"approve\":{\"spender\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\",\"token_id\":\"1\"}}"), bytes("[]")), + abi.encode(bytes("")) + ); + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("query(string,bytes)", MockCWContractAddress, bytes("{\"owner_of\":{\"token_id\":\"1\"}}")), + abi.encode("{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}") + ); + vm.mockCall( + JSON_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("extractAsBytes(bytes,string)", bytes("{\"owner\":\"sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw\"}"), "owner"), + abi.encode(bytes("sei19zhelek4q5lt4zam8mcarmgv92vzgqd3ux32jw")) + ); + vm.startPrank(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + vm.expectEmit(); + emit Approval(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267, 1); + pointer.approve(0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267, 1); + vm.stopPrank(); + } + + function testSetApprovalForAll() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("execute(string,bytes,bytes)", MockCWContractAddress, bytes("{\"approval_all\":{\"operator\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}}"), bytes("[]")), + abi.encode(bytes("")) + ); + vm.startPrank(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + vm.expectEmit(); + emit ApprovalForAll(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267, true); + pointer.setApprovalForAll(0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267, true); + vm.stopPrank(); + } + + function testSetRevokeForAll() public { + vm.mockCall( + WASMD_PRECOMPILE_ADDRESS, + abi.encodeWithSignature("execute(string,bytes,bytes)", MockCWContractAddress, bytes("{\"revoke_all\":{\"operator\":\"sei1vldxw5dy5k68hqr4d744rpg9w8cqs54x4asdqe\"}}"), bytes("[]")), + abi.encode(bytes("")) + ); + vm.startPrank(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + vm.expectEmit(); + emit ApprovalForAll(0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267, false); + pointer.setApprovalForAll(0xF39fD6e51Aad88F6f4CE6AB8827279CFffb92267, false); + vm.stopPrank(); + } +} \ No newline at end of file diff --git a/contracts/test/ERC721Test.js b/contracts/test/ERC721Test.js new file mode 100644 index 0000000000..32347e757b --- /dev/null +++ b/contracts/test/ERC721Test.js @@ -0,0 +1,38 @@ +const { ethers, upgrades } = require('hardhat'); + +describe("ERC721 test", function () { + + describe("ERC721 Throughput", function () { + let erc721; + let owner; + let receiver; + + // This function deploys a new instance of the contract before each test + beforeEach(async function () { + let signers = await ethers.getSigners(); + owner = signers[0]; + receiver = signers[1]; + const ERC721 = await ethers.getContractFactory("MyNFT") + erc721 = await ERC721.deploy(); + + await Promise.all([erc721.waitForDeployment()]) + }); + + it("should send 10000", async function(){ + this.timeout(100000); // Increase timeout for this test + + let nonce = await ethers.provider.getTransactionCount(owner.address); + const sends = [] + + const count = 10000 + // start of all the rpc calls + for(let i=0; i setTimeout(resolve, ms)); +} + +async function delay() { + // await sleep(3000) +} + +function debug(msg) { + // leaving commented out to make output readable (unless debugging) + // console.log(msg) +} + +async function sendTransactionAndCheckGas(sender, recipient, amount) { + // Get the balance of the sender before the transaction + const balanceBefore = await ethers.provider.getBalance(sender.address); + + // Send the transaction + const tx = await sender.sendTransaction({ + to: recipient.address, + value: amount + }); + + // Wait for the transaction to be mined and get the receipt + const receipt = await tx.wait(); + + // Get the balance of the sender after the transaction + const balanceAfter = await ethers.provider.getBalance(sender.address); + + // Calculate the total cost of the transaction (amount + gas fees) + const gasPrice = receipt.gasPrice; + const gasUsed = receipt.gasUsed; + const totalCost = gasPrice * gasUsed + BigInt(amount); + + // Check that the sender's balance decreased by the total cost + return balanceBefore - balanceAfter === totalCost +} + +function generateWallet() { + const wallet = ethers.Wallet.createRandom(); + return wallet.connect(ethers.provider); +} + +async function sendTx(sender, txn, responses) { + const txResponse = await sender.sendTransaction(txn); + responses.push({nonce: txn.nonce, response: txResponse}) +} + + +describe("EVM Test", function () { + + describe("EVMCompatibilityTester", function () { + let evmTester; + let testToken; + let owner; + let evmAddr; + + // The first contract address deployed from 0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 + // should always be 0xbD5d765B226CaEA8507EE030565618dAFFD806e2 when sent with nonce=0 + const firstContractAddress = "0xbD5d765B226CaEA8507EE030565618dAFFD806e2"; + + // This function deploys a new instance of the contract before each test + beforeEach(async function () { + if(evmTester && testToken) { + return + } + let signers = await ethers.getSigners(); + owner = signers[0]; + debug(`OWNER = ${owner.address}`) + + const TestToken = await ethers.getContractFactory("TestToken") + testToken = await TestToken.deploy("TestToken", "TTK"); + + const EVMCompatibilityTester = await ethers.getContractFactory("EVMCompatibilityTester"); + evmTester = await EVMCompatibilityTester.deploy(); + + await Promise.all([evmTester.waitForDeployment(), testToken.waitForDeployment()]) + + let tokenAddr = await testToken.getAddress() + evmAddr = await evmTester.getAddress() + + debug(`Token: ${tokenAddr}, EvmAddr: ${evmAddr}`); + }); + + describe("Deployment", function () { + it("Should deploy successfully", async function () { + expect(await evmTester.getAddress()).to.be.properAddress; + expect(await testToken.getAddress()).to.be.properAddress; + expect(await evmTester.getAddress()).to.not.equal(await testToken.getAddress()); + + // The first contract address deployed from 0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 + // should always be 0xbD5d765B226CaEA8507EE030565618dAFFD806e2 when sent with nonce=0 + expect(await testToken.getAddress()).to.equal(firstContractAddress); + }); + + it("Should estimate gas for a contract deployment", async function () { + const callData = evmTester.interface.encodeFunctionData("createToken", ["TestToken", "TTK"]); + const estimatedGas = await ethers.provider.estimateGas({ + to: await evmTester.getAddress(), + data: callData + }); + expect(estimatedGas).to.greaterThan(0); + }); + }); + + describe("Contract Factory", function() { + it("should deploy a second contract from createToken", async function () { + const txResponse = await evmTester.createToken("TestToken", "TTK"); + const testerAddress = await evmTester.getAddress(); + const receipt = await txResponse.wait(); + const newTokenAddress = receipt.logs[0].address; + expect(newTokenAddress).to.not.equal(testerAddress); + const TestToken = await ethers.getContractFactory("TestToken") + const tokenInstance = await TestToken.attach(newTokenAddress); + const bal = await tokenInstance.balanceOf(await owner.getAddress()); + expect(bal).to.equal(100); + }); + }) + + describe("Call Another Contract", function(){ + it("should set balance and then retrieve it via callAnotherContract", async function () { + const setAmount = ethers.parseUnits("1000", 18); + + await delay() + // Set balance + await testToken.setBalance(owner.address, setAmount); + + // Prepare call data for balanceOf function of MyToken + const balanceOfData = testToken.interface.encodeFunctionData("balanceOf", [owner.address]); + + const tokenAddress = await testToken.getAddress() + + await delay() + // Call balanceOf using callAnotherContract from EVMCompatibilityTester + await evmTester.callAnotherContract(tokenAddress, balanceOfData); + + await delay() + // Verify the balance using MyToken contract directly + const balance = await testToken.balanceOf(owner.address); + expect(balance).to.equal(setAmount); + }); + }) + + describe("Msg Properties", function() { + it("Should store and retrieve msg properties correctly", async function() { + // Store msg properties + const txResponse = await evmTester.storeMsgProperties({ value: 1 }); + await txResponse.wait(); + + // Retrieve stored msg properties + const msgDetails = await evmTester.lastMsgDetails(); + + debug(msgDetails) + + // Assertions + expect(msgDetails.sender).to.equal(owner.address); + expect(msgDetails.value).to.equal(1); + // `data` is the encoded function call, which is difficult to predict and assert + // `gas` is the remaining gas after the transaction, which is also difficult to predict and assert + }); + }); + + + describe("Block Properties", function () { + it("Should have consistent block properties for a block", async function () { + const currentBlockNumber = await ethers.provider.getBlockNumber(); + const iface = new ethers.Interface(["function getBlockProperties() view returns (bytes32 blockHash, address coinbase, uint256 prevrandao, uint256 gaslimit, uint256 number, uint256 timestamp)"]); + const addr = await evmTester.getAddress() + const tx = { + to: addr, + data: iface.encodeFunctionData("getBlockProperties", []), + blockTag: currentBlockNumber-2 + }; + const result = await ethers.provider.call(tx); + + // wait for block to change + while(true){ + const bn = await ethers.provider.getBlockNumber(); + if(bn !== currentBlockNumber){ + break + } + await sleep(100) + } + const result2 = await ethers.provider.call(tx); + expect(result).to.equal(result2) + }); + }); + + describe("Variable Types", function () { + it("Should set the address correctly and emit an event", async function () { + // Call setAddress + await delay() + const txResponse = await evmTester.setAddressVar(); + await txResponse.wait(); // Wait for the transaction to be mined + await expect(txResponse) + .to.emit(evmTester, 'AddressSet') + .withArgs(owner.address); + }); + + it("Should set the bool correctly and emit an event", async function () { + // Call setBoolVar + await delay() + const txResponse = await evmTester.setBoolVar(true); + await txResponse.wait(); // Wait for the transaction to be mined + + debug(JSON.stringify(txResponse)) + + await expect(txResponse) + .to.emit(evmTester, 'BoolSet') + .withArgs(owner.address, true); + + // Verify that addr is set correctly + expect(await evmTester.boolVar()).to.equal(true); + }); + + it("Should set the uint256 correctly and emit an event", async function () { + // Call setBoolVar + await delay() + const txResponse = await evmTester.setUint256Var(12345); + await txResponse.wait(); // Wait for the transaction to be mined + + debug(JSON.stringify(txResponse)) + + await expect(txResponse) + .to.emit(evmTester, 'Uint256Set') + .withArgs(owner.address, 12345); + + // Verify that addr is set correctly + expect(await evmTester.uint256Var()).to.equal(12345); + }); + + // this uses a newer version of ethers to attempt a blob transaction (different signer wallet) + it("should return an error for blobs", async function(){ + const key = "0x57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e" + const signer = new ethers.Wallet(key, ethers.provider); + const blobData = "BLOB"; + const blobDataBytes = ethers.toUtf8Bytes(blobData); + const blobHash = ethers.keccak256(blobDataBytes); + + const tx = { + type: 3, + to: owner.address, + value: ethers.parseEther("0.1"), + data: '0x', + maxFeePerGas: ethers.parseUnits('100', 'gwei'), + maxPriorityFeePerGas: ethers.parseUnits('1', 'gwei'), + gasLimit: 100000, + maxFeePerBlobGas: ethers.parseUnits('10', 'gwei'), + blobVersionedHashes: [blobHash], + } + + await expect(signer.sendTransaction(tx)).to.be.rejectedWith("unsupported transaction type"); + }) + + it("Should trace a call with timestamp", async function () { + await delay() + const txResponse = await evmTester.setTimestamp(); + const receipt = await txResponse.wait(); // Wait for the transaction to be mined + + // get the timestamp that was saved off during setTimestamp() + const lastTimestamp = await evmTester.lastTimestamp(); + + // perform two trace calls with a small delay in between + const trace1 = await hre.network.provider.request({ + method: "debug_traceTransaction", + params: [receipt.hash], + }); + await sleep(500) + const trace2 = await hre.network.provider.request({ + method: "debug_traceTransaction", + params: [receipt.hash], + }); + + // expect consistency in the trace calls (timestamp should be fixed to block) + expect(JSON.stringify(trace1)).to.equal(JSON.stringify(trace2)) + + // expect timestamp in the actual trace to match the timestamp seen at the time of invocation + let found = false + for(let log of trace1.structLogs) { + if(log.op === "SSTORE" && log.stack.length >= 3) { + const ts = log.stack[2] + expect(ts).to.equal(lastTimestamp) + found = true + break; + } + } + expect(found).to.be.true; + }); + + + it("Should set the string correctly and emit an event", async function () { + // Call setBoolVar + await delay() + const txResponse = await evmTester.setStringVar("test"); + await txResponse.wait(); // Wait for the transaction to be mined + await expect(txResponse) + .to.emit(evmTester, 'StringSet') + .withArgs(owner.address, "test"); + + // Verify that addr is set correctly + expect(await evmTester.stringVar()).to.equal("test"); + }); + + it("Should correctly set and retrieve balances in the mapping", async function () { + const testAmount = 1000; + + await delay() + // Send the transaction and wait for it to be confirmed + const txResponse = await evmTester.setBalance(owner.address, testAmount); + await txResponse.wait(); + await delay() + // Now check the balance + const balance = await evmTester.balances(owner.address); + expect(balance).to.equal(testAmount); + }); + + it("Should store and retrieve a private var correctly", async function () { + const testAmount = 12345; + await delay() + const txResponse = await evmTester.storeData(testAmount); + await txResponse.wait(); // Wait for the transaction to be mined + await delay() + const retrievedAmount = await evmTester.retrieveData(); + expect(retrievedAmount).to.equal(BigInt(testAmount)); + }); + }); + + describe("Require Logic", function(){ + it("Should revert when false is passed to revertIfFalse", async function () { + await expect(evmTester.revertIfFalse(false)).to.be.reverted; + }); + + it("Should not revert when true is passed to revertIfFalse", async function () { + await evmTester.revertIfFalse(true) + }); + }) + + + describe("Assembly", function(){ + it("Should add numbers correctly", async function () { + expect(await evmTester.addNumbers(10, 20)).to.equal(30); + }); + + it("Should return the current balance of the contract", async function () { + const balance = await evmTester.getContractBalance(); + const address = await evmTester.getAddress() + await delay() + expect(balance).to.equal(await ethers.provider.getBalance(address)); + }); + + it("Should return correct value from readFromStorage(index)", async function () { + const testAmount = 12345; + await delay() + const txResponse = await evmTester.storeData(testAmount); + await delay() + await txResponse.wait(); // Wait for the transaction to be mined + + const retrievedAmount = await evmTester.readFromStorage(0); + expect(retrievedAmount).to.equal(BigInt(testAmount)); + }); + }) + + describe("Historical query test", function() { + it("Should be able to get historical block data", async function() { + const feeData = await ethers.provider.getFeeData(); + const gasPrice = Number(feeData.gasPrice); + const zero = ethers.parseUnits('0', 'ether') + const txResponse = await owner.sendTransaction({ + to: owner.address, + gasPrice: gasPrice, + value: zero, + type: 1, + }); + const receipt = await txResponse.wait(); + const bn = receipt.blockNumber; + + // Check historical balance + const balance1 = await ethers.provider.getBalance(owner, bn-1); + const balance2 = await ethers.provider.getBalance(owner, bn); + expect(balance1 - balance2).to.equal(21000 * Number(gasPrice)) + + // Check historical nonce + const nonce1 = await ethers.provider.getTransactionCount(owner, bn-1); + const nonce2 = await ethers.provider.getTransactionCount(owner, bn); + expect(nonce1 + 1).to.equal(nonce2) + }); + }); + + describe("Gas tests", function() { + it("Should deduct correct amount of gas on transfer", async function () { + const balanceBefore = await ethers.provider.getBalance(owner); + + const feeData = await ethers.provider.getFeeData(); + const gasPrice = Number(feeData.gasPrice); + + const zero = ethers.parseUnits('0', 'ether') + const txResponse = await owner.sendTransaction({ + to: owner.address, + gasPrice: gasPrice, + value: zero, + type: 1, + }); + await txResponse.wait(); + + const balanceAfter = await ethers.provider.getBalance(owner); + + const diff = balanceBefore - balanceAfter; + expect(diff).to.equal(21000 * gasPrice); + + const success = await sendTransactionAndCheckGas(owner, owner, 0) + expect(success).to.be.true + }); + + it("Should fail if insufficient gas is provided", async function () { + const feeData = await ethers.provider.getFeeData(); + const gasPrice = Number(feeData.gasPrice); + const zero = ethers.parseUnits('0', 'ether') + expect(owner.sendTransaction({ + to: owner.address, + gasPrice: gasPrice - 1, + value: zero, + type: 1, + })).to.be.reverted; + }); + + it("Should deduct correct amount even if higher gas price is used", async function () { + const balanceBefore = await ethers.provider.getBalance(owner); + + 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({ + to: owner.address, + value: zero, + gasPrice: higherGasPrice, + type: 1, + }); + const receipt = await txResponse.wait(); + + const balanceAfter = await ethers.provider.getBalance(owner); + + const diff = balanceBefore - balanceAfter; + expect(diff).to.equal(21000 * higherGasPrice); + + const success = await sendTransactionAndCheckGas(owner, owner, 0) + expect(success).to.be.true + }); + + describe("EIP-1559", async function() { + const zero = ethers.parseUnits('0', 'ether') + const twoGwei = ethers.parseUnits("2", "gwei"); + const oneGwei = ethers.parseUnits("1", "gwei"); + + const testCases = [ + ["No truncation from max priority fee", oneGwei, oneGwei], + ["With truncation from max priority fee", oneGwei, twoGwei], + ["With complete truncation from max priority fee", zero, twoGwei] + ]; + + it("Should be able to send many EIP-1559 txs", async function () { + const oneGwei = ethers.parseUnits("1", "gwei"); + const zero = ethers.parseUnits('0', 'ether') + for (let i = 0; i < 10; i++) { + const txResponse = await owner.sendTransaction({ + to: owner.address, + value: zero, + maxPriorityFeePerGas: oneGwei, + maxFeePerGas: oneGwei, + type: 2 + }); + await txResponse.wait(); + } + }); + + 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({ + to: owner.address, + value: zero, + maxPriorityFeePerGas: maxPriorityFeePerGas, + maxFeePerGas: maxFeePerGas, + type: 2 + }); + const receipt = await txResponse.wait(); + 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); + + const tip = Math.min( + 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); + }); + } + }); + }); + }); + + describe("JSON-RPC", function() { + it("Should retrieve a transaction by its hash", async function () { + // Send a transaction to get its hash + const txResponse = await evmTester.setBoolVar(true); + await txResponse.wait(); + + // Retrieve the transaction by its hash + const tx = await ethers.provider.getTransaction(txResponse.hash); + expect(tx).to.not.be.null; + expect(tx.hash).to.equal(txResponse.hash); + }); + + it("Should retrieve a block by its number", async function () { + // Get the current block number + const currentBlockNumber = await ethers.provider.getBlockNumber(); + + // Retrieve the block by its number + const block = await ethers.provider.getBlock(currentBlockNumber); + expect(block).to.not.be.null; + expect(block.number).to.equal(currentBlockNumber); + }); + + it("Should retrieve the latest block", async function () { + // Retrieve the latest block + const block = await ethers.provider.getBlock("latest"); + expect(block).to.not.be.null; + }); + + it("Should get the balance of an account", async function () { + // Get the balance of an account (e.g., the owner) + const balance = await ethers.provider.getBalance(owner.address); + + // The balance should be a BigNumber; we can't predict its exact value + expect(isBigNumber(balance)).to.be.true; + }); + + it("Should get the code at a specific address", async function () { + // Get the code at the address of a deployed contract (e.g., evmTester) + const code = await ethers.provider.getCode(await evmTester.getAddress()); + + // The code should start with '0x' and be longer than just '0x' for a deployed contract + expect(code.startsWith("0x")).to.be.true; + expect(code.length).to.be.greaterThan(2); + debug(code) + }); + + + it("Should retrieve a block by its hash", async function () { + const blockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(blockNumber); + const fetchedBlock = await ethers.provider.getBlock(block.hash); + expect(fetchedBlock).to.not.be.null; + expect(fetchedBlock.hash).to.equal(block.hash); + }); + + it("Should fetch the number of transactions in a block", async function () { + const block = await ethers.provider.getBlock("latest"); + expect(block.transactions).to.be.an('array'); + }); + + it("Should retrieve a transaction receipt", async function () { + const txResponse = await evmTester.setBoolVar(false, { + type: 2, // force it to be EIP-1559 + maxPriorityFeePerGas: ethers.parseUnits('100', 'gwei'), // set gas high just to get it included + maxFeePerGas: ethers.parseUnits('100', 'gwei') + }); + await txResponse.wait(); + const receipt = await ethers.provider.getTransactionReceipt(txResponse.hash); + expect(receipt).to.not.be.undefined; + expect(receipt.hash).to.equal(txResponse.hash); + expect(receipt.blockHash).to.not.be.undefined; + expect(receipt.blockNumber).to.not.be.undefined; + expect(receipt.logsBloom).to.not.be.undefined; + expect(receipt.gasUsed).to.be.greaterThan(0); + expect(receipt.gasPrice).to.be.greaterThan(0); + expect(receipt.type).to.equal(2); // sei is failing this + expect(receipt.status).to.equal(1); + expect(receipt.to).to.equal(await evmTester.getAddress()); + expect(receipt.from).to.equal(owner.address); + expect(receipt.cumulativeGasUsed).to.be.greaterThanOrEqual(0); // on seilocal, this is 0 + + // undefined / null on anvil and goerli + // expect(receipt.contractAddress).to.be.equal(null); // seeing this be null (sei devnet) and not null (anvil, goerli) + expect(receipt.effectiveGasPrice).to.be.undefined; + expect(receipt.transactionHash).to.be.undefined; + expect(receipt.transactionIndex).to.be.undefined; + const logs = receipt.logs + for (let i = 0; i < logs.length; i++) { + const log = logs[i]; + expect(log).to.not.be.undefined; + expect(log.address).to.equal(receipt.to); + expect(log.topics).to.be.an('array'); + expect(log.data).to.be.a('string'); + expect(log.data.startsWith('0x')).to.be.true; + expect(log.data.length).to.be.greaterThan(3); + expect(log.blockNumber).to.equal(receipt.blockNumber); + expect(log.transactionHash).to.not.be.undefined; // somehow log.transactionHash exists but receipt.transactionHash does not + expect(log.transactionHash).to.not.be.undefined; + expect(log.transactionIndex).to.be.greaterThanOrEqual(0); + expect(log.blockHash).to.equal(receipt.blockHash); + + // undefined / null on anvil and goerli + expect(log.logIndex).to.be.undefined; + expect(log.removed).to.be.undefined; + } + }); + + it("Should fetch the current gas price", async function () { + const feeData = await ethers.provider.getFeeData() + expect(isBigNumber(feeData.gasPrice)).to.be.true; + }); + + it("Should estimate gas for a transaction", async function () { + const estimatedGas = await ethers.provider.estimateGas({ + to: await evmTester.getAddress(), + data: evmTester.interface.encodeFunctionData("setBoolVar", [true]) + }); + expect(isBigNumber(estimatedGas)).to.be.true; + }); + + it("Should check the network status", async function () { + const network = await ethers.provider.getNetwork(); + expect(network).to.have.property('name'); + expect(network).to.have.property('chainId'); + }); + + it("Should fetch the nonce for an account", async function () { + const nonce = await ethers.provider.getTransactionCount(owner.address); + expect(nonce).to.be.a('number'); + }); + + it("Should set log index correctly", async function () { + const blockNumber = await ethers.provider.getBlockNumber(); + const numberOfEvents = 5; + + // check receipt + const txResponse = await evmTester.emitMultipleLogs(numberOfEvents); + const receipt = await txResponse.wait(); + expect(receipt.logs.length).to.equal(numberOfEvents) + for(let i=0; i { + expect(log).to.not.be.null; + ethers.provider.removeListener(filter, listener); + }; + ethers.provider.on(filter, listener); + + // Trigger the event + const txResponse = await evmTester.setBoolVar(false); + await txResponse.wait(); + }); + + it("Should get the current block number", async function () { + const blockNumber = await ethers.provider.getBlockNumber(); + expect(blockNumber).to.be.a('number'); + }); + + it("Should fetch a block with full transactions", async function () { + const blockNumber = await ethers.provider.getBlockNumber(); + const blockWithTransactions = await ethers.provider.getBlock(blockNumber, true); + expect(blockWithTransactions).to.not.be.null; + expect(blockWithTransactions.transactions).to.be.an('array'); + }); + + it("Should get the chain ID", async function () { + const { chainId } = await ethers.provider.getNetwork() + expect(chainId).to.be.greaterThan(0) + }); + + it("Should fetch past logs", async function () { + const contractAddress = await evmTester.getAddress() + const filter = { + fromBlock: 0, + toBlock: 'latest', + address: contractAddress + }; + const logs = await ethers.provider.getLogs(filter); + expect(logs).to.be.an('array'); + expect(logs).length.to.be.greaterThan(0) + }); + + it("Should check account's transaction count", async function () { + const nonce = await ethers.provider.getTransactionCount(owner.address, "latest"); + expect(nonce).to.be.a('number'); + }); + + it("Should check if an address is a contract", async function () { + const code = await ethers.provider.getCode(await evmTester.getAddress()); + const isContract = code !== '0x'; + expect(isContract).to.be.true; + }); + + it("advanced log topic filtering", async function() { + describe("log topic filtering", async function() { + let blockStart; + let blockEnd; + let numTxs = 5; + before(async function() { + await sleep(5000); // wait for a block to pass so we get a fresh block number + blockStart = await ethers.provider.getBlockNumber(); + + // Emit an event by making a transaction + for (let i = 0; i < numTxs; i++) { + const txResponse = await evmTester.emitDummyEvent("test", i); + await txResponse.wait(); + } + blockEnd = await ethers.provider.getBlockNumber(); + console.log("blockStart = ", blockStart) + console.log("blockEnd = ", blockEnd) + }); + + it("Block range filter", async function () { + const filter = { + fromBlock: blockStart, + toBlock: blockEnd, + }; + + const logs = await ethers.provider.getLogs(filter); + expect(logs).to.be.an('array'); + expect(logs.length).to.equal(numTxs); + }); + + it("Single topic filter", async function() { + const filter = { + fromBlock: blockStart, + toBlock: blockEnd, + topics: [ethers.id("DummyEvent(string,bool,address,uint256,bytes)")] + }; + + const logs = await ethers.provider.getLogs(filter); + expect(logs).to.be.an('array'); + expect(logs.length).to.equal(numTxs); + }); + + it("Blockhash filter", async function() { + // first get a log + const filter = { + fromBlock: blockStart, + toBlock: blockEnd, + topics: [ethers.id("DummyEvent(string,bool,address,uint256,bytes)")] + }; + + const logs = await ethers.provider.getLogs(filter); + const blockHash = logs[0].blockHash; + + // now get logs by blockhash + const blockHashFilter = { + blockHash: blockHash, + }; + + const blockHashLogs = await ethers.provider.getLogs(blockHashFilter); + expect(blockHashLogs).to.be.an('array'); + for (let i = 0; i < blockHashLogs.length; i++) { + expect(blockHashLogs[i].blockHash).to.equal(blockHash); + } + }); + + it("Multiple topic filter", async function() { + // Topic A and B represented as [A, B] + const paddedOwnerAddr = "0x" + owner.address.slice(2).padStart(64, '0'); + const filter1 = { + fromBlock: blockStart, + toBlock: blockEnd, + topics: [ + ethers.id("DummyEvent(string,bool,address,uint256,bytes)"), + ethers.id("test"), + paddedOwnerAddr, + ] + }; + + const logs = await ethers.provider.getLogs(filter1); + + expect(logs).to.be.an('array'); + expect(logs.length).to.equal(numTxs); + + // Topic A and B represented as [A, [B]] + const filter2 = { + fromBlock: blockStart, + toBlock: blockEnd, + topics: [ + ethers.id("DummyEvent(string,bool,address,uint256,bytes)"), + [ethers.id("test")], + [paddedOwnerAddr], + ] + }; + + const logs2 = await ethers.provider.getLogs(filter1); + + expect(logs2).to.be.an('array'); + expect(logs2.length).to.equal(numTxs); + }); + + it("Wildcard topic filter", async function() { + const filter1 = { + fromBlock: blockStart, + toBlock: blockEnd, + topics: [ + ethers.id("DummyEvent(string,bool,address,uint256,bytes)"), + ethers.id("test"), + null, + "0x0000000000000000000000000000000000000000000000000000000000000003", + ] + }; + + const logs1 = await ethers.provider.getLogs(filter1); + expect(logs1).to.be.an('array'); + expect(logs1.length).to.equal(1); + + // filter for topic A and (B or C) = [A, [B, C]] + const filter2 = { + fromBlock: blockStart, + toBlock: blockEnd, + topics: [ + ethers.id("DummyEvent(string,bool,address,uint256,bytes)"), + ethers.id("test"), + null, + [ + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000000000000000000000000000003", + ] + ] + } + const logs2 = await ethers.provider.getLogs(filter2); + expect(logs2).to.be.an('array'); + expect(logs2.length).to.equal(2); + }); + + it("Address and topics combination filter", async function() { + const filter = { + fromBlock: blockStart, + toBlock: blockEnd, + address: await evmTester.getAddress(), + topics: [ + ethers.id("DummyEvent(string,bool,address,uint256,bytes)"), + ] + } + const logs = await ethers.provider.getLogs(filter); + expect(logs).to.be.an('array'); + expect(logs.length).to.equal(numTxs); + }); + + it("Empty result filter", async function() { + const filter = { + fromBlock: blockStart, + toBlock: blockEnd, + topics: [ + ethers.id("DummyEvent(string,bool,address,uint256,bytes)"), + ethers.id("nonexistent event string"), + ] + }; + + const logs = await ethers.provider.getLogs(filter); + expect(logs).to.be.an('array'); + expect(logs.length).to.equal(0); + }); + + it("Overlapping criteria filter", async function() { + // [ (topic[0] = A) OR (topic[0] = B) ] AND [ (topic[1] = C) OR (topic[1] = D) ] + const filter = { + fromBlock: blockStart, + toBlock: blockEnd, + topics: [ + ethers.id("DummyEvent(string,bool,address,uint256,bytes)"), + [ethers.id("test"), ethers.id("nonexistent event string")], + null, + [ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000000000000000000000000000003", + ] + ] + } + + const logs = await ethers.provider.getLogs(filter); + expect(logs).to.be.an('array'); + expect(logs.length).to.equal(3); + }); + }); + }); + }); + + describe("Contract Upgradeability", function() { + it("Should allow for contract upgrades", async 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) + + // make sure you can retrieve the value + const retrievedValue = await box.retrieve(); + expect(retrievedValue).to.equal(val); + + // increment value + console.log("Incrementing value...") + const resp = await box.boxIncr(); + await resp.wait(); + + // make sure value is incremented + const retrievedValue1 = await box.retrieve(); + expect(retrievedValue1).to.equal(val+1); + + // upgrade to BoxV2 + const BoxV2 = await ethers.getContractFactory('BoxV2'); + console.log('Upgrading Box...'); + const box2 = await upgrades.upgradeProxy(boxAddr, BoxV2, [val+1], { initializer: 'store' }); + await box2.deployTransaction.wait(); + console.log('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); + const boxV2 = await BoxV2.attach(boxV2Addr); + + // check that value is still the same + console.log("Calling boxV2 retrieve()...") + const retrievedValue2 = await boxV2.retrieve(); + console.log("retrievedValue2 = ", retrievedValue2) + expect(retrievedValue2).to.equal(val+1); + + // use new function in boxV2 and increment value + console.log("Calling boxV2 boxV2Incr()...") + const txResponse = await boxV2.boxV2Incr(); + await txResponse.wait(); + + // make sure value is incremented + expect(await boxV2.retrieve()).to.equal(val+2); + + // store something in value2 and check it(check value2) + const store2Resp = await boxV2.store2(10); + await store2Resp.wait(); + expect(await boxV2.retrieve2()).to.equal(10); + + // ensure value is still the same in boxV2 (checking for any storage corruption) + expect(await boxV2.retrieve()).to.equal(val+2); + }); + }); + + describe("Usei/Wei testing", function() { + it("Send 1 usei to contract", async function() { + const usei = ethers.parseUnits("1", 12); + const wei = ethers.parseUnits("1", 0); + const twoWei = ethers.parseUnits("2", 0); + + // Check that the contract has no ETH + const initialBalance = await ethers.provider.getBalance(evmAddr); + + const txResponse = await evmTester.depositEther({ + value: usei, + }); + await txResponse.wait(); // Wait for the transaction to be mined + + // Check that the contract received the ETH + const contractBalance = await ethers.provider.getBalance(evmAddr); + expect(contractBalance - initialBalance).to.equal(usei); + + // send 1 wei out of contract + const txResponse2 = await evmTester.sendEther(owner.address, wei); + await txResponse2.wait(); // Wait for the transaction to be mined + + const contractBalance2 = await ethers.provider.getBalance(evmAddr); + expect(contractBalance2 - contractBalance).to.equal(-wei); + + // send 2 wei to contract + const txResponse3 = await evmTester.depositEther({ + value: twoWei, + }); + await txResponse3.wait(); // Wait for the transaction to be mined + + const contractBalance3 = await ethers.provider.getBalance(evmAddr); + expect(contractBalance3 - contractBalance2).to.equal(twoWei); + }); + }); + }); +}); + +describe("EVM throughput", function(){ + + 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 txCount = 100; + + const nonce = await ethers.provider.getTransactionCount(address); + const responses = [] + + let txs = [] + let maxNonce = 0 + for(let i=0; i { + return sendTx(sender, txn, responses) + }); + await Promise.all(promises) + + // wait for last nonce to mine (means all prior mined) + for(let r of responses){ + if(r.nonce === maxNonce) { + await r.response.wait() + break; + } + } + + // get represented block numbers + let blockNumbers = [] + for(let response of responses){ + const receipt = await response.response.wait() + const blockNumber = receipt.blockNumber + blockNumbers.push(blockNumber) + } + + blockNumbers = uniq(blockNumbers).sort((a,b)=>{return a-b}) + const minedNonceOrder = [] + for(const blockNumber of blockNumbers){ + const block = await ethers.provider.getBlock(parseInt(blockNumber,10)); + // get receipt for transaction hash in block + for(const txHash of block.transactions){ + const tx = await ethers.provider.getTransaction(txHash) + minedNonceOrder.push(tx.nonce) + } + } + + expect(minedNonceOrder.length).to.equal(txCount); + for (let i = 0; i < minedNonceOrder.length; i++) { + expect(minedNonceOrder[i]).to.equal(i+nonce) + } + }) +}) diff --git a/contracts/test/EVMPrecompileTester.js b/contracts/test/EVMPrecompileTester.js new file mode 100644 index 0000000000..c094334f8f --- /dev/null +++ b/contracts/test/EVMPrecompileTester.js @@ -0,0 +1,378 @@ +const { execSync } = require('child_process'); +const { expect } = require("chai"); +const fs = require('fs'); +const path = require('path'); + +const { expectRevert } = require('@openzeppelin/test-helpers'); + +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); + + await expectRevert.unspecified(erc20AsOwner2.transferFrom(owner, receiver, 100)); + }); + + 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); + }); + + it("Balance of function", async function() { + const balance = await erc20.balanceOf(owner); + expect(balance).to.be.greaterThan(Number(0)); + }); + + it("Name function", async function () { + const name = await erc20.name() + expect(name).to.equal('UATOM'); + }); + + it("Symbol function", async function () { + const symbol = await erc20.symbol() + // expect symbol to be 'UATOM' + expect(symbol).to.equal('UATOM'); + }); + }); + + // 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 + }); + }); + + // 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 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 + }); + }); + + 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; + + const [signer, _] = await ethers.getSigners(); + owner = await signer.getAddress(); + + const contractABIPath = path.join(__dirname, '../../precompiles/oracle/abi.json'); + const contractABI = require(contractABIPath); + // Get a contract instance + oracle = new ethers.Contract(OraclePrecompileContract, contractABI, signer); + }); + + 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); + + 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); + } + }); + }); + + 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')); + + const [signer, _] = await ethers.getSigners(); + owner = await signer.getAddress(); + + 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("Wasm Precompile Instantiate", async function () { + encoder = new TextEncoder(); + + queryCountMsg = {get_count: {}}; + queryStr = JSON.stringify(queryCountMsg); + queryBz = encoder.encode(queryStr); + + instantiateMsg = {count: 2}; + instantiateStr = JSON.stringify(instantiateMsg); + instantiateBz = encoder.encode(instantiateStr); + + coins = []; + coinsStr = JSON.stringify(coins); + coinsBz = encoder.encode(coinsStr); + + 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? + }); + + it("Wasm Precompile 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); + + execute = await wasmd.execute(wasmContractAddress, incrementBz, coinsBz); + const receipt = await execute.wait(); + expect(receipt.status).to.equal(1); + + finalCountBz = await wasmd.query(wasmContractAddress, queryBz); + finalCount = parseHexToJSON(finalCountBz) + expect(finalCount.count).to.equal(initialCount.count + 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); + }); + + }); + + }); +}); + +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 + hexStr = hexStr.slice(2); + // Convert to bytes + const bytes = Buffer.from(hexStr, 'hex'); + // Convert to JSON + return JSON.parse(bytes.toString()); +} \ No newline at end of file diff --git a/contracts/test/NativeSeiTokensERC20Test.t.sol b/contracts/test/NativeSeiTokensERC20Test.t.sol new file mode 100644 index 0000000000..0e02267fa3 --- /dev/null +++ b/contracts/test/NativeSeiTokensERC20Test.t.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import {Test, console2} from "forge-std/Test.sol"; +import {NativeSeiTokensERC20} from "../src/NativeSeiTokensERC20.sol"; +import {IBank} from "../src/precompiles/IBank.sol"; + +address constant BANK_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001001; + +contract MockBank { + mapping(address => uint256) balances; + + // mocking functions + function setBalances(address[] memory addressesToFund) public { + for (uint256 i = 0; i < addressesToFund.length; i++) { + balances[addressesToFund[i]] = 1000; + } + } + + // subset of IBank functions + function balance(address account, string memory denom) public view returns (uint256) { + require(keccak256(abi.encodePacked(denom)) == keccak256(abi.encodePacked("usei")), "MockBank: denom not supported"); + return balances[account]; + } + + function send( + address fromAddress, + address toAddress, + string memory denom, + uint256 amount + ) external returns (bool success) { + require(keccak256(abi.encodePacked(denom)) == keccak256(abi.encodePacked("usei")), "MockBank: denom not supported"); + balances[fromAddress] -= amount; + balances[toAddress] += amount; + return true; + } +} + +contract NativeSeiTokensERC20Test is Test { + + event Transfer(address indexed from, address indexed to, uint256 value); + event Approval(address indexed owner, address indexed spender, uint256 value); + + NativeSeiTokensERC20 seiERC20; + address alice; + address bob; + + function setUp() public { + alice = makeAddr("alice"); + bob = makeAddr("bob"); + seiERC20 = new NativeSeiTokensERC20("usei", "SEI", "SEISYMBOL", 6); + + MockBank mockBank = new MockBank(); + vm.etch(BANK_PRECOMPILE_ADDRESS, address(mockBank).code); + address[] memory addressesToFund = new address[](2); + addressesToFund[0] = alice; + addressesToFund[1] = bob; + MockBank(BANK_PRECOMPILE_ADDRESS).setBalances(addressesToFund); + } + + function testName() public { + assertEq(seiERC20.name(), "SEI"); + } + + function testSymbol() public { + assertEq(seiERC20.symbol(), "SEISYMBOL"); + } + + function testBalanceOf() public { + vm.mockCall(BANK_PRECOMPILE_ADDRESS, abi.encodeWithSelector(IBank.balance.selector, address(this), "usei"), abi.encode(123)); + assertEq(seiERC20.balanceOf(address(this)), 123); + } + + function testDecimals() public { + assertEq(seiERC20.decimals(), 6); + } + + function testTotalSupply() public { + vm.mockCall(BANK_PRECOMPILE_ADDRESS, abi.encodeWithSelector(IBank.supply.selector, "usei"), abi.encode(123)); + assertEq(seiERC20.totalSupply(), 123); + } + + function testTransfer() public { + vm.expectEmit(); + emit Transfer(alice, bob, 123); + + vm.startPrank(alice); + bool success = seiERC20.transfer(bob, 123); + vm.stopPrank(); + + assertEq(success, true); + assertEq(seiERC20.balanceOf(alice), 1000 - 123); + assertEq(seiERC20.balanceOf(bob), 1000 + 123); + } + + function testApprovals() public { + // Alice approves Bob to spend 200 tokens on her behalf + vm.expectEmit(); + emit Approval(alice, bob, 200); + + vm.startPrank(alice); + bool approvalSuccess = seiERC20.approve(bob, 200); + vm.stopPrank(); + + assertEq(approvalSuccess, true); + assertEq(seiERC20.allowance(alice, bob), 200); + } + + function testTransferFrom() public { + // expect fail because no approval was given + vm.startPrank(bob); + vm.expectRevert(); + seiERC20.transferFrom(alice, bob, 150); + vm.stopPrank(); + + // alice to approve bob to spend tokens on her behalf + vm.startPrank(alice); + seiERC20.approve(bob, 200); + vm.stopPrank(); + + vm.startPrank(bob); + vm.expectEmit(); + emit Transfer(alice, bob, 150); + bool transferFromSuccess = seiERC20.transferFrom(alice, bob, 150); + vm.stopPrank(); + + assertEq(transferFromSuccess, true); + assertEq(seiERC20.balanceOf(alice), 1000 - 150); + assertEq(seiERC20.balanceOf(bob), 1000 + 150); + assertEq(seiERC20.allowance(alice, bob), 50); // Remaining allowance after the transfer + } +} \ No newline at end of file diff --git a/contracts/test/deploy_atom_erc20.sh b/contracts/test/deploy_atom_erc20.sh new file mode 100644 index 0000000000..f5408f3139 --- /dev/null +++ b/contracts/test/deploy_atom_erc20.sh @@ -0,0 +1,27 @@ +#!/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 new file mode 100644 index 0000000000..b35df1703f --- /dev/null +++ b/contracts/test/deploy_wasm_contract.sh @@ -0,0 +1,26 @@ +#!/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 new file mode 100644 index 0000000000..e8c7049811 --- /dev/null +++ b/contracts/test/get_validator_address.sh @@ -0,0 +1,12 @@ +#!/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/param_change_proposal.json b/contracts/test/param_change_proposal.json new file mode 100644 index 0000000000..9e8891872f --- /dev/null +++ b/contracts/test/param_change_proposal.json @@ -0,0 +1,14 @@ +{ + "title": "Gov Param Change", + "description": "Update quorum to 0.45", + "changes": [ + { + "subspace": "gov", + "key": "tallyparams", + "value": { + "quorum":"0.45" + } + } + ], + "is_expedited": false +} diff --git a/contracts/test/query_oracle_data.sh b/contracts/test/query_oracle_data.sh new file mode 100644 index 0000000000..7531f6fe46 --- /dev/null +++ b/contracts/test/query_oracle_data.sh @@ -0,0 +1,5 @@ +#!/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 new file mode 100644 index 0000000000..27641fc897 --- /dev/null +++ b/contracts/test/send_gov_proposal.sh @@ -0,0 +1,12 @@ +#!/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/wasm/cw20_base.wasm b/contracts/wasm/cw20_base.wasm new file mode 100755 index 0000000000..b750812a2b Binary files /dev/null and b/contracts/wasm/cw20_base.wasm differ diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 98e287e059..0a58689d08 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -8,6 +8,7 @@ services: ports: - "26656-26658:26656-26658" - "9090-9091:9090-9091" + - "8545-8546:8545-8546" environment: - ID=0 - CLUSTER_SIZE=4 @@ -20,6 +21,7 @@ services: - "${PROJECT_HOME}/../sei-tendermint:/sei-protocol/sei-tendermint:Z" - "${PROJECT_HOME}/../sei-cosmos:/sei-protocol/sei-cosmos:Z" - "${PROJECT_HOME}/../sei-db:/sei-protocol/sei-db:Z" + - "${PROJECT_HOME}/../go-ethereum:/sei-protocol/go-ethereum:Z" - "${GO_PKG_PATH}/mod:/root/go/pkg/mod:Z" networks: localnet: @@ -44,6 +46,7 @@ services: - "${PROJECT_HOME}/../sei-tendermint:/sei-protocol/sei-tendermint:Z" - "${PROJECT_HOME}/../sei-cosmos:/sei-protocol/sei-cosmos:Z" - "${PROJECT_HOME}/../sei-db:/sei-protocol/sei-db:Z" + - "${PROJECT_HOME}/../go-ethereum:/sei-protocol/go-ethereum:Z" - "${GO_PKG_PATH}/mod:/root/go/pkg/mod:Z" networks: localnet: @@ -68,6 +71,7 @@ services: - "${PROJECT_HOME}/../sei-tendermint:/sei-protocol/sei-tendermint:Z" - "${PROJECT_HOME}/../sei-cosmos:/sei-protocol/sei-cosmos:Z" - "${PROJECT_HOME}/../sei-db:/sei-protocol/sei-db:Z" + - "${PROJECT_HOME}/../go-ethereum:/sei-protocol/go-ethereum:Z" - "${GO_PKG_PATH}/mod:/root/go/pkg/mod:Z" networks: localnet: @@ -92,6 +96,7 @@ services: - "${PROJECT_HOME}/../sei-tendermint:/sei-protocol/sei-tendermint:Z" - "${PROJECT_HOME}/../sei-cosmos:/sei-protocol/sei-cosmos:Z" - "${PROJECT_HOME}/../sei-db:/sei-protocol/sei-db:Z" + - "${PROJECT_HOME}/../go-ethereum:/sei-protocol/go-ethereum:Z" - "${GO_PKG_PATH}/mod:/root/go/pkg/mod:Z" networks: localnet: diff --git a/docker/localnode/Dockerfile b/docker/localnode/Dockerfile index 85799b7d85..49283c86d3 100644 --- a/docker/localnode/Dockerfile +++ b/docker/localnode/Dockerfile @@ -2,9 +2,15 @@ FROM ubuntu:latest RUN apt-get update && \ apt-get install -y make git wget build-essential jq python3 curl vim uuid-runtime RUN rm -rf build/generated -RUN wget https://go.dev/dl/go1.20.6.linux-amd64.tar.gz -RUN tar -xvf go1.20.6.linux-amd64.tar.gz +RUN wget https://go.dev/dl/go1.21.4.linux-amd64.tar.gz +RUN tar -xvf go1.21.4.linux-amd64.tar.gz RUN mv go /usr/local/ +RUN curl -L https://foundry.paradigm.xyz | bash +RUN /root/.foundry/bin/foundryup +RUN curl -sL https://deb.nodesource.com/setup_16.x | bash +RUN apt-get install -y nodejs +RUN mkdir -p /root/.config && \ + chmod -R 777 /root/.config SHELL ["/bin/bash", "-c"] diff --git a/docker/localnode/scripts/deploy.sh b/docker/localnode/scripts/deploy.sh index 4b971a39a3..9591f24636 100755 --- a/docker/localnode/scripts/deploy.sh +++ b/docker/localnode/scripts/deploy.sh @@ -11,7 +11,7 @@ export BUILD_PATH=/sei-protocol/sei-chain/build export PATH=$GOBIN:$PATH:/usr/local/go/bin:$BUILD_PATH echo "export GOPATH=$HOME/go" >> /root/.bashrc echo "GOBIN=$GOPATH/bin" >> /root/.bashrc -echo "export PATH=$GOBIN:$PATH:/usr/local/go/bin:$BUILD_PATH" >> /root/.bashrc +echo "export PATH=$GOBIN:$PATH:/usr/local/go/bin:$BUILD_PATH:/root/.foundry/bin" >> /root/.bashrc /bin/bash -c "source /root/.bashrc" mkdir -p $GOBIN # Step 0: Build on node 0 @@ -70,4 +70,4 @@ echo "All $CLUSTER_SIZE Nodes started successfully, starting oracle price feeder /usr/bin/start_price_feeder.sh echo "Oracle price feeder is started" -tail -f /dev/null \ No newline at end of file +tail -f /dev/null diff --git a/docker/localnode/scripts/step1_configure_init.sh b/docker/localnode/scripts/step1_configure_init.sh index b006d3060a..6cbf4fb85b 100755 --- a/docker/localnode/scripts/step1_configure_init.sh +++ b/docker/localnode/scripts/step1_configure_init.sh @@ -46,7 +46,7 @@ GENESIS_ACCOUNT_ADDRESS=$(printf "12345678\n" | seid keys show "$ACCOUNT_NAME" - echo "$GENESIS_ACCOUNT_ADDRESS" >> build/generated/genesis_accounts.txt # Add funds to genesis account -seid add-genesis-account "$GENESIS_ACCOUNT_ADDRESS" 10000000usei +seid add-genesis-account "$GENESIS_ACCOUNT_ADDRESS" 10000000usei,10000000uusdc,10000000uatom # Create gentx printf "12345678\n" | seid gentx "$ACCOUNT_NAME" 10000000usei --chain-id sei diff --git a/docker/localnode/scripts/step2_genesis.sh b/docker/localnode/scripts/step2_genesis.sh index 9ba50a98a3..0db68437e7 100755 --- a/docker/localnode/scripts/step2_genesis.sh +++ b/docker/localnode/scripts/step2_genesis.sh @@ -33,11 +33,12 @@ override_genesis ".app_state[\"mint\"][\"params\"][\"token_release_schedule\"]=[ override_genesis '.app_state["auth"]["accounts"]=[]' override_genesis '.app_state["bank"]["balances"]=[]' override_genesis '.app_state["genutil"]["gen_txs"]=[]' +override_genesis '.app_state["bank"]["denom_metadata"]=[{"denom_units":[{"denom":"UATOM","exponent":6,"aliases":["UATOM"]}],"base":"uatom","display":"uatom","name":"UATOM","symbol":"UATOM"}]' # gov parameters override_genesis '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="usei"' override_genesis '.app_state["gov"]["deposit_params"]["min_expedited_deposit"][0]["denom"]="usei"' -override_genesis '.app_state["gov"]["deposit_params"]["max_deposit_period"]="30s"' +override_genesis '.app_state["gov"]["deposit_params"]["max_deposit_period"]="100s"' override_genesis '.app_state["gov"]["voting_params"]["voting_period"]="30s"' override_genesis '.app_state["gov"]["voting_params"]["expedited_voting_period"]="15s"' override_genesis '.app_state["gov"]["tally_params"]["quorum"]="0.5"' @@ -48,11 +49,11 @@ override_genesis '.app_state["gov"]["tally_params"]["expedited_threshold"]="0.9" # add genesis accounts for each node while read account; do echo "Adding: $account" - seid add-genesis-account "$account" 1000000000000000000000usei + seid add-genesis-account "$account" 1000000000000000000000usei,1000000000000000000000uusdc,1000000000000000000000uatom done 0 { + filter := make([][]byte, len(addresses)) + for i, address := range addresses { + filter[i] = address.Bytes() + } + filters = append(filters, filter) + } + for _, topicList := range topics { + filter := make([][]byte, len(topicList)) + for i, topic := range topicList { + filter[i] = topic.Bytes() + } + filters = append(filters, filter) + } + for _, filter := range filters { + // Gather the bit indexes of the filter rule, special casing the nil filter + if len(filter) == 0 { + continue + } + bloomBits := make([]bloomIndexes, len(filter)) + for i, clause := range filter { + if clause == nil { + bloomBits = nil + break + } + bloomBits[i] = calcBloomIndexes(clause) + } + // Accumulate the filter rules if no nil rule was within + if bloomBits != nil { + res = append(res, bloomBits) + } + } + return +} + +// TODO: parallelize if filters too large +func MatchFilters(bloom ethtypes.Bloom, filters [][]bloomIndexes) bool { + for _, filter := range filters { + if !matchFilter(bloom, filter) { + return false + } + } + return true +} + +func matchFilter(bloom ethtypes.Bloom, filter []bloomIndexes) bool { + for _, possibility := range filter { + if matchBloomIndexes(bloom, possibility) { + return true + } + } + return false +} + +func matchBloomIndexes(bloom ethtypes.Bloom, idx bloomIndexes) bool { + for _, bit := range idx { + // big endian + whichByte := bloom[ethtypes.BloomByteLength-1-bit/8] + mask := BitMasks[bit%8] + if whichByte&mask == 0 { + return false + } + } + return true +} diff --git a/evmrpc/bloom_test.go b/evmrpc/bloom_test.go new file mode 100644 index 0000000000..9e6834ce2e --- /dev/null +++ b/evmrpc/bloom_test.go @@ -0,0 +1,52 @@ +package evmrpc_test + +import ( + "encoding/hex" + "testing" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/stretchr/testify/require" +) + +func TestMatchBloom(t *testing.T) { + log := ethtypes.Log{ + Address: common.HexToAddress("0x797C2dBE5736D0096914Cd1f9A7330403c71d301"), + Topics: []common.Hash{common.HexToHash("0x036285defb58e7bdfda894dd4f86e1c7c826522ae0755f0017a2155b4c58022e")}, + } + bloom := ethtypes.CreateBloom(ethtypes.Receipts{ðtypes.Receipt{Logs: []*ethtypes.Log{&log}}}) + require.Equal(t, + "00000000001000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000400000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + hex.EncodeToString(bloom[:]), + ) + filters := evmrpc.EncodeFilters( + []common.Address{common.HexToAddress("0x797C2dBE5736D0096914Cd1f9A7330403c71d301")}, + [][]common.Hash{{common.HexToHash("0x036285defb58e7bdfda894dd4f86e1c7c826522ae0755f0017a2155b4c58022e")}}, + ) + require.True(t, evmrpc.MatchFilters(bloom, filters)) + + filters = evmrpc.EncodeFilters( + []common.Address{common.HexToAddress("0x797C2dBE5736D0096914Cd1f9A7330403c71d301")}, + [][]common.Hash{}, + ) + require.True(t, evmrpc.MatchFilters(bloom, filters)) + + filters = evmrpc.EncodeFilters( + []common.Address{}, + [][]common.Hash{{common.HexToHash("0x036285defb58e7bdfda894dd4f86e1c7c826522ae0755f0017a2155b4c58022e")}}, + ) + require.True(t, evmrpc.MatchFilters(bloom, filters)) + + filters = evmrpc.EncodeFilters( + []common.Address{common.HexToAddress("0x797C2dBE5736D0096914Cd1f9A7330403c71d302")}, + [][]common.Hash{}, + ) + require.False(t, evmrpc.MatchFilters(bloom, filters)) + + filters = evmrpc.EncodeFilters( + []common.Address{}, + [][]common.Hash{{common.HexToHash("0x036285defb58e7bdfda894dd4f86e1c7c826522ae0755f0017a2155b4c58022f")}}, + ) + require.False(t, evmrpc.MatchFilters(bloom, filters)) +} diff --git a/evmrpc/config.go b/evmrpc/config.go new file mode 100644 index 0000000000..69f428dfff --- /dev/null +++ b/evmrpc/config.go @@ -0,0 +1,207 @@ +package evmrpc + +import ( + "time" + + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/ethereum/go-ethereum/rpc" + "github.com/spf13/cast" +) + +// EVMRPC Config defines configurations for EVM RPC server on this node +type Config struct { + // controls whether an HTTP EVM server is enabled + HTTPEnabled bool `mapstructure:"http_enabled"` + HTTPPort int `mapstructure:"http_port"` + + // controls whether a websocket server is enabled + WSEnabled bool `mapstructure:"ws_enabled"` + WSPort int `mapstructure:"ws_port"` + + // ReadTimeout is the maximum duration for reading the entire + // request, including the body. + // + // Because ReadTimeout does not let Handlers make per-request + // decisions on each request body's acceptable deadline or + // upload rate, most users will prefer to use + // ReadHeaderTimeout. It is valid to use them both. + ReadTimeout time.Duration `mapstructure:"read_timeout"` + + // ReadHeaderTimeout is the amount of time allowed to read + // request headers. The connection's read deadline is reset + // after reading the headers and the Handler can decide what + // is considered too slow for the body. If ReadHeaderTimeout + // is zero, the value of ReadTimeout is used. If both are + // zero, there is no timeout. + ReadHeaderTimeout time.Duration `mapstructure:"read_header_timeout"` + + // WriteTimeout is the maximum duration before timing out + // writes of the response. It is reset whenever a new + // request's header is read. Like ReadTimeout, it does not + // let Handlers make decisions on a per-request basis. + WriteTimeout time.Duration `mapstructure:"write_timeout"` + + // IdleTimeout is the maximum amount of time to wait for the + // next request when keep-alives are enabled. If IdleTimeout + // is zero, the value of ReadTimeout is used. If both are + // zero, ReadHeaderTimeout is used. + IdleTimeout time.Duration `mapstructure:"idle_timeout"` + + // Maximum gas limit for simulation + SimulationGasLimit uint64 `mapstructure:"simulation_gas_limit"` + + // Timeout for EVM call in simulation + SimulationEVMTimeout time.Duration `mapstructure:"simulation_evm_timeout"` + + // list of CORS allowed origins, separated by comma + CORSOrigins string `mapstructure:"cors_origins"` + + // list of WS origins, separated by comma + WSOrigins string `mapstructure:"ws_origins"` + + // timeout for filters + FilterTimeout time.Duration `mapstructure:"filter_timeout"` + + // checkTx timeout for sig verify + CheckTxTimeout time.Duration `mapstructure:"checktx_timeout"` + + // max number of txs to pull from mempool + MaxTxPoolTxs uint64 `mapstructure:"max_tx_pool_txs"` + + // controls whether to have txns go through one by one + Slow bool `mapstructure:"slow"` + + // Deny list defines list of methods that EVM RPC should fail fast + DenyList []string `mapstructure:"deny_list"` +} + +var DefaultConfig = Config{ + HTTPEnabled: true, + HTTPPort: 8545, + WSEnabled: true, + WSPort: 8546, + ReadTimeout: rpc.DefaultHTTPTimeouts.ReadTimeout, + ReadHeaderTimeout: rpc.DefaultHTTPTimeouts.ReadHeaderTimeout, + WriteTimeout: rpc.DefaultHTTPTimeouts.WriteTimeout, + IdleTimeout: rpc.DefaultHTTPTimeouts.IdleTimeout, + SimulationGasLimit: 10_000_000, // 10M + SimulationEVMTimeout: 60 * time.Second, + CORSOrigins: "*", + WSOrigins: "*", + FilterTimeout: 120 * time.Second, + CheckTxTimeout: 5 * time.Second, + MaxTxPoolTxs: 1000, + Slow: false, + DenyList: make([]string, 0), +} + +const ( + flagHTTPEnabled = "evm.http_enabled" + flagHTTPPort = "evm.http_port" + flagWSEnabled = "evm.ws_enabled" + flagWSPort = "evm.ws_port" + flagReadTimeout = "evm.read_timeout" + flagReadHeaderTimeout = "evm.read_header_timeout" + flagWriteTimeout = "evm.write_timeout" + flagIdleTimeout = "evm.idle_timeout" + flagSimulationGasLimit = "evm.simulation_gas_limit" + flagSimulationEVMTimeout = "evm.simulation_evm_timeout" + flagCORSOrigins = "evm.cors_origins" + flagWSOrigins = "evm.ws_origins" + flagFilterTimeout = "evm.filter_timeout" + flagMaxTxPoolTxs = "evm.max_tx_pool_txs" + flagCheckTxTimeout = "evm.checktx_timeout" + flagSlow = "evm.slow" + flagDenyList = "evm.deny_list" +) + +func ReadConfig(opts servertypes.AppOptions) (Config, error) { + cfg := DefaultConfig // copy + var err error + if v := opts.Get(flagHTTPEnabled); v != nil { + if cfg.HTTPEnabled, err = cast.ToBoolE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagHTTPPort); v != nil { + if cfg.HTTPPort, err = cast.ToIntE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagWSEnabled); v != nil { + if cfg.WSEnabled, err = cast.ToBoolE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagWSPort); v != nil { + if cfg.WSPort, err = cast.ToIntE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagReadTimeout); v != nil { + if cfg.ReadTimeout, err = cast.ToDurationE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagReadHeaderTimeout); v != nil { + if cfg.ReadHeaderTimeout, err = cast.ToDurationE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagWriteTimeout); v != nil { + if cfg.WriteTimeout, err = cast.ToDurationE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagIdleTimeout); v != nil { + if cfg.IdleTimeout, err = cast.ToDurationE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagSimulationGasLimit); v != nil { + if cfg.SimulationGasLimit, err = cast.ToUint64E(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagSimulationEVMTimeout); v != nil { + if cfg.SimulationEVMTimeout, err = cast.ToDurationE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagCORSOrigins); v != nil { + if cfg.CORSOrigins, err = cast.ToStringE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagWSOrigins); v != nil { + if cfg.WSOrigins, err = cast.ToStringE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagFilterTimeout); v != nil { + if cfg.FilterTimeout, err = cast.ToDurationE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagCheckTxTimeout); v != nil { + if cfg.CheckTxTimeout, err = cast.ToDurationE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagMaxTxPoolTxs); v != nil { + if cfg.MaxTxPoolTxs, err = cast.ToUint64E(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagSlow); v != nil { + if cfg.Slow, err = cast.ToBoolE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagDenyList); v != nil { + if cfg.DenyList, err = cast.ToStringSliceE(v); err != nil { + return cfg, err + } + } + return cfg, nil +} diff --git a/evmrpc/config_test.go b/evmrpc/config_test.go new file mode 100644 index 0000000000..5dbcefe7de --- /dev/null +++ b/evmrpc/config_test.go @@ -0,0 +1,176 @@ +package evmrpc_test + +import ( + "testing" + "time" + + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/stretchr/testify/require" +) + +type opts struct { + httpEnabled interface{} + httpPort interface{} + wsEnabled interface{} + wsPort interface{} + readTimeout interface{} + readHeaderTimeout interface{} + writeTimeout interface{} + idleTimeout interface{} + simulationGasLimit interface{} + simulationEVMTimeout interface{} + corsOrigins interface{} + wsOrigins interface{} + filterTimeout interface{} + checkTxTimeout interface{} + maxTxPoolTxs interface{} + slow interface{} + denyList interface{} +} + +func (o *opts) Get(k string) interface{} { + if k == "evm.http_enabled" { + return o.httpEnabled + } + if k == "evm.http_port" { + return o.httpPort + } + if k == "evm.ws_enabled" { + return o.wsEnabled + } + if k == "evm.ws_port" { + return o.wsPort + } + if k == "evm.read_timeout" { + return o.readTimeout + } + if k == "evm.read_header_timeout" { + return o.readHeaderTimeout + } + if k == "evm.write_timeout" { + return o.writeTimeout + } + if k == "evm.idle_timeout" { + return o.idleTimeout + } + if k == "evm.simulation_gas_limit" { + return o.simulationGasLimit + } + if k == "evm.simulation_evm_timeout" { + return o.simulationEVMTimeout + } + if k == "evm.cors_origins" { + return o.corsOrigins + } + if k == "evm.ws_origins" { + return o.wsOrigins + } + if k == "evm.filter_timeout" { + return o.filterTimeout + } + if k == "evm.checktx_timeout" { + return o.checkTxTimeout + } + if k == "evm.max_tx_pool_txs" { + return o.maxTxPoolTxs + } + if k == "evm.slow" { + return o.slow + } + if k == "evm.deny_list" { + return o.denyList + } + panic("unknown key") +} + +func TestReadConfig(t *testing.T) { + goodOpts := opts{ + true, + 1, + true, + 2, + time.Duration(5), + time.Duration(5), + time.Duration(5), + time.Duration(5), + uint64(10), + time.Duration(60), + "", + "", + time.Duration(5), + time.Duration(5), + 1000, + false, + make([]string, 0), + } + _, err := evmrpc.ReadConfig(&goodOpts) + require.Nil(t, err) + badOpts := goodOpts + badOpts.httpEnabled = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.httpPort = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.wsEnabled = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.wsPort = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.readTimeout = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.readHeaderTimeout = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.writeTimeout = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.idleTimeout = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.filterTimeout = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.simulationGasLimit = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.simulationEVMTimeout = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.corsOrigins = map[string]interface{}{} + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.wsOrigins = map[string]interface{}{} + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.checkTxTimeout = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.maxTxPoolTxs = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.slow = "bad" + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) + badOpts = goodOpts + badOpts.denyList = map[string]interface{}{} + _, err = evmrpc.ReadConfig(&badOpts) + require.NotNil(t, err) +} diff --git a/evmrpc/echo.go b/evmrpc/echo.go new file mode 100644 index 0000000000..e6a8a6e133 --- /dev/null +++ b/evmrpc/echo.go @@ -0,0 +1,11 @@ +package evmrpc + +type EchoAPI struct{} + +func NewEchoAPI() *EchoAPI { + return &EchoAPI{} +} + +func (a *EchoAPI) Echo(data string) string { + return data +} diff --git a/evmrpc/endpoints.go b/evmrpc/endpoints.go new file mode 100644 index 0000000000..b7414ac45b --- /dev/null +++ b/evmrpc/endpoints.go @@ -0,0 +1,96 @@ +// Copyright 2020 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package evmrpc + +import ( + "fmt" + "net" + "net/http" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" +) + +// StartHTTPEndpoint starts the HTTP RPC endpoint. +func StartHTTPEndpoint(endpoint string, timeouts rpc.HTTPTimeouts, handler http.Handler) (*http.Server, net.Addr, error) { + // start the HTTP listener + var ( + listener net.Listener + err error + ) + if listener, err = net.Listen("tcp", endpoint); err != nil { + return nil, nil, err + } + // make sure timeout values are meaningful + CheckTimeouts(&timeouts) + // Bundle and start the HTTP server + httpSrv := &http.Server{ + Handler: handler, + ReadTimeout: timeouts.ReadTimeout, + ReadHeaderTimeout: timeouts.ReadHeaderTimeout, + WriteTimeout: timeouts.WriteTimeout, + IdleTimeout: timeouts.IdleTimeout, + } + go func() { + if err := httpSrv.Serve(listener); err != nil { + fmt.Printf("server exiting due to %s\n", err) + } + }() + return httpSrv, listener.Addr(), err +} + +// checkModuleAvailability checks that all names given in modules are actually +// available API services. It assumes that the MetadataApi module ("rpc") is always available; +// the registration of this "rpc" module happens in NewServer() and is thus common to all endpoints. +func checkModuleAvailability(modules []string, apis []rpc.API) (bad, available []string) { + availableSet := make(map[string]struct{}) + for _, api := range apis { + if _, ok := availableSet[api.Namespace]; !ok { + availableSet[api.Namespace] = struct{}{} + available = append(available, api.Namespace) + } + } + for _, name := range modules { + if _, ok := availableSet[name]; !ok { + if name != rpc.MetadataApi && name != rpc.EngineApi { + bad = append(bad, name) + } + } + } + return bad, available +} + +// CheckTimeouts ensures that timeout values are meaningful +func CheckTimeouts(timeouts *rpc.HTTPTimeouts) { + if timeouts.ReadTimeout < time.Second { + log.Warn("Sanitizing invalid HTTP read timeout", "provided", timeouts.ReadTimeout, "updated", rpc.DefaultHTTPTimeouts.ReadTimeout) + timeouts.ReadTimeout = rpc.DefaultHTTPTimeouts.ReadTimeout + } + if timeouts.ReadHeaderTimeout < time.Second { + log.Warn("Sanitizing invalid HTTP read header timeout", "provided", timeouts.ReadHeaderTimeout, "updated", rpc.DefaultHTTPTimeouts.ReadHeaderTimeout) + timeouts.ReadHeaderTimeout = rpc.DefaultHTTPTimeouts.ReadHeaderTimeout + } + if timeouts.WriteTimeout < time.Second { + log.Warn("Sanitizing invalid HTTP write timeout", "provided", timeouts.WriteTimeout, "updated", rpc.DefaultHTTPTimeouts.WriteTimeout) + timeouts.WriteTimeout = rpc.DefaultHTTPTimeouts.WriteTimeout + } + if timeouts.IdleTimeout < time.Second { + log.Warn("Sanitizing invalid HTTP idle timeout", "provided", timeouts.IdleTimeout, "updated", rpc.DefaultHTTPTimeouts.IdleTimeout) + timeouts.IdleTimeout = rpc.DefaultHTTPTimeouts.IdleTimeout + } +} diff --git a/evmrpc/filter.go b/evmrpc/filter.go new file mode 100644 index 0000000000..41d246b98f --- /dev/null +++ b/evmrpc/filter.go @@ -0,0 +1,380 @@ +package evmrpc + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "sync" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/filters" + ethrpc "github.com/ethereum/go-ethereum/rpc" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + rpcclient "github.com/tendermint/tendermint/rpc/client" + "github.com/tendermint/tendermint/rpc/coretypes" + tmtypes "github.com/tendermint/tendermint/types" +) + +const TxSearchPerPage = 10 + +type FilterType byte + +const ( + UnknownSubscription FilterType = iota + LogsSubscription + BlocksSubscription +) + +type filter struct { + typ FilterType + fc filters.FilterCriteria + deadline *time.Timer + + // BlocksSubscription + blockCursor string + + // LogsSubscription + lastToHeight int64 +} + +type FilterAPI struct { + tmClient rpcclient.Client + filtersMu sync.Mutex + filters map[ethrpc.ID]filter + filterConfig *FilterConfig + logFetcher *LogFetcher +} + +type FilterConfig struct { + timeout time.Duration +} + +type EventItemDataWrapper struct { + Type string `json:"type"` + Value json.RawMessage `json:"value"` +} + +func NewFilterAPI(tmClient rpcclient.Client, logFetcher *LogFetcher, filterConfig *FilterConfig) *FilterAPI { + filters := make(map[ethrpc.ID]filter) + api := &FilterAPI{ + tmClient: tmClient, + filtersMu: sync.Mutex{}, + filters: filters, + filterConfig: filterConfig, + logFetcher: logFetcher, + } + + go api.timeoutLoop(filterConfig.timeout) + + return api +} + +func (a *FilterAPI) timeoutLoop(timeout time.Duration) { + ticker := time.NewTicker(timeout) + defer ticker.Stop() + for { + <-ticker.C + a.filtersMu.Lock() + for id, filter := range a.filters { + select { + case <-filter.deadline.C: + delete(a.filters, id) + default: + continue + } + } + a.filtersMu.Unlock() + } +} + +func (a *FilterAPI) NewFilter( + _ context.Context, + crit filters.FilterCriteria, +) (ethrpc.ID, error) { + a.filtersMu.Lock() + defer a.filtersMu.Unlock() + curFilterID := ethrpc.NewID() + a.filters[curFilterID] = filter{ + typ: LogsSubscription, + fc: crit, + deadline: time.NewTimer(a.filterConfig.timeout), + lastToHeight: 0, + } + return curFilterID, nil +} + +func (a *FilterAPI) NewBlockFilter( + _ context.Context, +) (ethrpc.ID, error) { + a.filtersMu.Lock() + defer a.filtersMu.Unlock() + curFilterID := ethrpc.NewID() + a.filters[curFilterID] = filter{ + typ: BlocksSubscription, + deadline: time.NewTimer(a.filterConfig.timeout), + blockCursor: "", + } + return curFilterID, nil +} + +func (a *FilterAPI) GetFilterChanges( + ctx context.Context, + filterID ethrpc.ID, +) (interface{}, error) { + a.filtersMu.Lock() + defer a.filtersMu.Unlock() + filter, ok := a.filters[filterID] + if !ok { + return nil, errors.New("filter does not exist") + } + + if !filter.deadline.Stop() { + // timer expired but filter is not yet removed in timeout loop + // receive timer value and reset timer + <-filter.deadline.C + } + filter.deadline.Reset(a.filterConfig.timeout) + + switch filter.typ { + case BlocksSubscription: + hashes, cursor, err := a.getBlockHeadersAfter(ctx, filter.blockCursor) + if err != nil { + return nil, err + } + updatedFilter := a.filters[filterID] + updatedFilter.blockCursor = cursor + a.filters[filterID] = updatedFilter + return hashes, nil + case LogsSubscription: + // filter by hash would have no updates if it has previously queried for this crit + if filter.fc.BlockHash != nil && filter.lastToHeight > 0 { + return nil, nil + } + // filter with a ToBlock would have no updates if it has previously queried for this crit + if filter.fc.ToBlock != nil && filter.lastToHeight >= filter.fc.ToBlock.Int64() { + return nil, nil + } + logs, lastToHeight, err := a.logFetcher.GetLogsByFilters(ctx, filter.fc, filter.lastToHeight) + if err != nil { + return nil, err + } + updatedFilter := a.filters[filterID] + updatedFilter.lastToHeight = lastToHeight + 1 + a.filters[filterID] = updatedFilter + return logs, nil + default: + return nil, errors.New("unknown filter type") + } +} + +func (a *FilterAPI) GetFilterLogs( + ctx context.Context, + filterID ethrpc.ID, +) ([]*ethtypes.Log, error) { + a.filtersMu.Lock() + defer a.filtersMu.Unlock() + filter, ok := a.filters[filterID] + if !ok { + return nil, errors.New("filter does not exist") + } + + if !filter.deadline.Stop() { + // timer expired but filter is not yet removed in timeout loop + // receive timer value and reset timer + <-filter.deadline.C + } + filter.deadline.Reset(a.filterConfig.timeout) + + logs, lastToHeight, err := a.logFetcher.GetLogsByFilters(ctx, filter.fc, 0) + if err != nil { + return nil, err + } + updatedFilter := a.filters[filterID] + updatedFilter.lastToHeight = lastToHeight + a.filters[filterID] = updatedFilter + return logs, nil +} + +func (a *FilterAPI) GetLogs( + ctx context.Context, + crit filters.FilterCriteria, +) ([]*ethtypes.Log, error) { + logs, _, err := a.logFetcher.GetLogsByFilters(ctx, crit, 0) + return logs, err +} + +// get block headers after a certain cursor. Can use an empty string cursor +// to get the latest block header. +func (a *FilterAPI) getBlockHeadersAfter( + ctx context.Context, + cursor string, +) ([]common.Hash, string, error) { + q := NewBlockQueryBuilder() + builtQuery := q.Build() + hasMore := true + headers := []common.Hash{} + for hasMore { + res, err := a.tmClient.Events(ctx, &coretypes.RequestEvents{ + Filter: &coretypes.EventFilter{Query: builtQuery}, + After: cursor, + }) + if err != nil { + return nil, "", err + } + hasMore = res.More + cursor = res.Newest + + for _, item := range res.Items { + wrapper := EventItemDataWrapper{} + err := json.Unmarshal(item.Data, &wrapper) + if err != nil { + return nil, "", err + } + block := tmtypes.EventDataNewBlock{} + err = json.Unmarshal(wrapper.Value, &block) + if err != nil { + return nil, "", err + } + headers = append(headers, common.BytesToHash(block.Block.Hash())) + } + } + return headers, cursor, nil +} + +func (a *FilterAPI) UninstallFilter( + _ context.Context, + filterID ethrpc.ID, +) bool { + a.filtersMu.Lock() + defer a.filtersMu.Unlock() + _, found := a.filters[filterID] + if !found { + return false + } + delete(a.filters, filterID) + return true +} + +type LogFetcher struct { + tmClient rpcclient.Client + k *keeper.Keeper + ctxProvider func(int64) sdk.Context +} + +func (f *LogFetcher) GetLogsByFilters(ctx context.Context, crit filters.FilterCriteria, lastToHeight int64) ([]*ethtypes.Log, int64, error) { + bloomIndexes := EncodeFilters(crit.Addresses, crit.Topics) + if crit.BlockHash != nil { + block, err := blockByHashWithRetry(ctx, f.tmClient, crit.BlockHash[:], 1) + if err != nil { + return nil, 0, err + } + return f.GetLogsForBlock(ctx, block, crit, bloomIndexes), block.Block.Height, nil + } + latest := f.ctxProvider(LatestCtxHeight).BlockHeight() + begin, end := latest, latest + if crit.FromBlock != nil { + begin = getHeightFromBigIntBlockNumber(latest, crit.FromBlock) + } + if crit.ToBlock != nil { + end = getHeightFromBigIntBlockNumber(latest, crit.ToBlock) + // only if fromBlock is not specified, default it to end block + if crit.FromBlock == nil && begin > end { + begin = end + } + } + if lastToHeight > begin { + begin = lastToHeight + } + // begin should always be <= end block at this point + if begin > end { + return nil, 0, fmt.Errorf("fromBlock %d is after toBlock %d", begin, end) + } + blockHeights := f.FindBlockesByBloom(begin, end, bloomIndexes) + res := []*ethtypes.Log{} + for _, height := range blockHeights { + h := height + block, err := blockByNumberWithRetry(ctx, f.tmClient, &h, 1) + if err != nil { + return nil, 0, err + } + res = append(res, f.GetLogsForBlock(ctx, block, crit, bloomIndexes)...) + } + + return res, end, nil +} + +func (f *LogFetcher) GetLogsForBlock(ctx context.Context, block *coretypes.ResultBlock, crit filters.FilterCriteria, filters [][]bloomIndexes) []*ethtypes.Log { + possibleLogs := f.FindLogsByBloom(block.Block.Height, filters) + matchedLogs := utils.Filter(possibleLogs, func(l *ethtypes.Log) bool { return f.IsLogExactMatch(l, crit) }) + for _, l := range matchedLogs { + l.BlockHash = common.Hash(block.BlockID.Hash) + } + return matchedLogs +} + +func (f *LogFetcher) FindBlockesByBloom(begin, end int64, filters [][]bloomIndexes) (res []int64) { + //TODO: parallelize + ctx := f.ctxProvider(LatestCtxHeight) + for height := begin; height <= end; height++ { + blockBloom := f.k.GetBlockBloom(ctx, height) + if MatchFilters(blockBloom, filters) { + res = append(res, height) + } + } + return +} + +func (f *LogFetcher) FindLogsByBloom(height int64, filters [][]bloomIndexes) (res []*ethtypes.Log) { + ctx := f.ctxProvider(LatestCtxHeight) + txHashes := f.k.GetTxHashesOnHeight(ctx, height) + for _, hash := range txHashes { + receipt, err := f.k.GetReceipt(ctx, hash) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("FindLogsByBloom: unable to find receipt for hash %s", hash.Hex())) + continue + } + if len(receipt.LogsBloom) > 0 && MatchFilters(ethtypes.Bloom(receipt.LogsBloom), filters) { + res = append(res, keeper.GetLogsForTx(receipt)...) + } + } + return +} + +func (f *LogFetcher) IsLogExactMatch(log *ethtypes.Log, crit filters.FilterCriteria) bool { + addrMatch := len(crit.Addresses) == 0 + for _, addrFilter := range crit.Addresses { + if log.Address == addrFilter { + addrMatch = true + break + } + } + return addrMatch && matchTopics(crit.Topics, log.Topics) +} + +func matchTopics(topics [][]common.Hash, eventTopics []common.Hash) bool { + for i, topicList := range topics { + if len(topicList) == 0 { + // anything matches for this position + continue + } + if i >= len(eventTopics) { + return false + } + matched := false + for _, topic := range topicList { + if topic == eventTopics[i] { + matched = true + break + } + } + if !matched { + return false + } + } + return true +} diff --git a/evmrpc/filter_test.go b/evmrpc/filter_test.go new file mode 100644 index 0000000000..9480400b4d --- /dev/null +++ b/evmrpc/filter_test.go @@ -0,0 +1,356 @@ +package evmrpc_test + +import ( + "fmt" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestFilterNew(t *testing.T) { + t.Parallel() + tests := []struct { + name string + fromBlock string + toBlock string + blockHash common.Hash + addrs []common.Address + topics [][]common.Hash + wantErr bool + }{ + { + name: "happy path", + fromBlock: "0x1", + toBlock: "0x2", + addrs: []common.Address{common.HexToAddress("0x123")}, + topics: [][]common.Hash{{common.HexToHash("0x456")}}, + wantErr: false, + }, + { + name: "error: block hash and block range both given", + fromBlock: "0x1", + toBlock: "0x2", + blockHash: common.HexToHash("0xabc"), + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + filterCriteria := map[string]interface{}{ + "fromBlock": tt.fromBlock, + "toBlock": tt.toBlock, + "address": tt.addrs, + "topics": tt.topics, + } + if tt.blockHash != (common.Hash{}) { + filterCriteria["blockHash"] = tt.blockHash.Hex() + } + if len(tt.fromBlock) > 0 || len(tt.toBlock) > 0 { + filterCriteria["fromBlock"] = tt.fromBlock + filterCriteria["toBlock"] = tt.toBlock + } + resObj := sendRequestGood(t, "newFilter", filterCriteria) + _, errExists := resObj["error"] + + if tt.wantErr { + require.True(t, errExists) + } else { + require.False(t, errExists, "error should not exist") + got := resObj["result"].(string) + // make sure next filter id is not equal to this one + resObj := sendRequestGood(t, "newFilter", filterCriteria) + got2 := resObj["result"].(string) + require.NotEqual(t, got, got2) + } + }) + } +} + +func TestFilterUninstall(t *testing.T) { + t.Parallel() + // uninstall existing filter + filterCriteria := map[string]interface{}{ + "fromBlock": "0x1", + "toBlock": "0xa", + } + resObj := sendRequestGood(t, "newFilter", filterCriteria) + filterId := resObj["result"].(string) + require.NotEmpty(t, filterId) + + resObj = sendRequest(t, TestPort, "uninstallFilter", filterId) + uninstallSuccess := resObj["result"].(bool) + require.True(t, uninstallSuccess) + + // uninstall non-existing filter + nonExistingFilterId := "100" + resObj = sendRequest(t, TestPort, "uninstallFilter", nonExistingFilterId) + uninstallSuccess = resObj["result"].(bool) + require.False(t, uninstallSuccess) +} + +func TestFilterGetLogs(t *testing.T) { + tests := []struct { + name string + blockHash *common.Hash + fromBlock string + toBlock string + addrs []common.Address + topics [][]common.Hash + wantErr bool + wantLen int + check func(t *testing.T, log map[string]interface{}) + }{ + { + name: "filter by single address", + fromBlock: "0x2", + toBlock: "0x2", + addrs: []common.Address{common.HexToAddress("0x1111111111111111111111111111111111111112")}, + wantErr: false, + check: func(t *testing.T, log map[string]interface{}) { + require.Equal(t, "0x1111111111111111111111111111111111111112", log["address"].(string)) + }, + wantLen: 2, + }, + { + name: "filter by single topic", + fromBlock: "0x2", + toBlock: "0x2", + topics: [][]common.Hash{{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123")}}, + wantErr: false, + check: func(t *testing.T, log map[string]interface{}) { + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000123", log["topics"].([]interface{})[0].(string)) + }, + wantLen: 4, + }, + { + name: "filter by single topic with default range", + topics: [][]common.Hash{{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123")}}, + wantErr: false, + check: func(t *testing.T, log map[string]interface{}) { + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000123", log["topics"].([]interface{})[0].(string)) + }, + wantLen: 1, + }, + { + name: "error with from block ahead of to block", + fromBlock: "0x3", + toBlock: "0x2", + topics: [][]common.Hash{{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123")}}, + wantErr: true, + }, + { + name: "multiple addresses, multiple topics", + fromBlock: "0x2", + toBlock: "0x2", + addrs: []common.Address{ + common.HexToAddress("0x1111111111111111111111111111111111111112"), + common.HexToAddress("0x1111111111111111111111111111111111111113"), + }, + topics: [][]common.Hash{ + {common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123")}, + {common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456")}, + }, + wantErr: false, + check: func(t *testing.T, log map[string]interface{}) { + if log["address"].(string) != "0x1111111111111111111111111111111111111112" && log["address"].(string) != "0x1111111111111111111111111111111111111113" { + t.Fatalf("address %s not in expected list", log["address"].(string)) + } + firstTopic := log["topics"].([]interface{})[0].(string) + secondTopic := log["topics"].([]interface{})[1].(string) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000123", firstTopic) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000456", secondTopic) + }, + wantLen: 2, + }, + { + name: "wildcard first topic", + fromBlock: "0x2", + toBlock: "0x2", + topics: [][]common.Hash{ + {}, + {common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456")}, + }, + wantErr: false, + check: func(t *testing.T, log map[string]interface{}) { + secondTopic := log["topics"].([]interface{})[1].(string) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000456", secondTopic) + }, + wantLen: 3, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fmt.Println(tt.name) + filterCriteria := map[string]interface{}{ + "address": tt.addrs, + "topics": tt.topics, + } + if tt.blockHash != nil { + filterCriteria["blockHash"] = tt.blockHash.Hex() + } + if len(tt.fromBlock) > 0 || len(tt.toBlock) > 0 { + filterCriteria["fromBlock"] = tt.fromBlock + filterCriteria["toBlock"] = tt.toBlock + } + resObj := sendRequestGood(t, "getLogs", filterCriteria) + if tt.wantErr { + _, ok := resObj["error"] + require.True(t, ok) + } else { + got := resObj["result"].([]interface{}) + for _, log := range got { + logObj := log.(map[string]interface{}) + tt.check(t, logObj) + } + require.Equal(t, tt.wantLen, len(got)) + } + }) + } +} + +func TestFilterGetFilterLogs(t *testing.T) { + filterCriteria := map[string]interface{}{ + "fromBlock": "0x2", + "toBlock": "0x2", + } + resObj := sendRequestGood(t, "newFilter", filterCriteria) + filterId := resObj["result"].(string) + + resObj = sendRequest(t, TestPort, "getFilterLogs", filterId) + logs := resObj["result"].([]interface{}) + require.Equal(t, 4, len(logs)) + for _, log := range logs { + logObj := log.(map[string]interface{}) + require.Equal(t, "0x2", logObj["blockNumber"].(string)) + } + + // error: filter id does not exist + nonexistentFilterId := 1000 + resObj = sendRequest(t, TestPort, "getFilterLogs", nonexistentFilterId) + _, ok := resObj["error"] + require.True(t, ok) +} + +func TestFilterGetFilterChanges(t *testing.T) { + filterCriteria := map[string]interface{}{ + "fromBlock": "0x2", + } + resObj := sendRequest(t, TestPort, "newFilter", filterCriteria) + filterId := resObj["result"].(string) + + resObj = sendRequest(t, TestPort, "getFilterChanges", filterId) + logs := resObj["result"].([]interface{}) + require.Equal(t, 5, len(logs)) + logObj := logs[0].(map[string]interface{}) + require.Equal(t, "0x2", logObj["blockNumber"].(string)) + + // another query + bloom := ethtypes.CreateBloom(ethtypes.Receipts{ðtypes.Receipt{Logs: []*ethtypes.Log{{ + Address: common.HexToAddress("0x1111111111111111111111111111111111111112"), + Topics: []common.Hash{}, + }}}}) + EVMKeeper.SetReceipt(Ctx, common.HexToHash("0x123456789012345678902345678901234567890123456789012345678900005"), &types.Receipt{ + BlockNumber: 9, + LogsBloom: bloom[:], + Logs: []*types.Log{{ + Address: "0x1111111111111111111111111111111111111114", + }}, + }) + EVMKeeper.SetTxHashesOnHeight(Ctx, 9, []common.Hash{ + common.HexToHash("0x123456789012345678902345678901234567890123456789012345678900005"), + }) + EVMKeeper.SetBlockBloom(Ctx, 9, []ethtypes.Bloom{bloom}) + Ctx = Ctx.WithBlockHeight(9) + resObj = sendRequest(t, TestPort, "getFilterChanges", filterId) + Ctx = Ctx.WithBlockHeight(8) + logs = resObj["result"].([]interface{}) + require.Equal(t, 1, len(logs)) + logObj = logs[0].(map[string]interface{}) + require.Equal(t, "0x9", logObj["blockNumber"].(string)) + + // error: filter id does not exist + nonExistingFilterId := 1000 + resObj = sendRequest(t, TestPort, "getFilterChanges", nonExistingFilterId) + _, ok := resObj["error"] + require.True(t, ok) +} + +func TestFilterBlockFilter(t *testing.T) { + t.Parallel() + resObj := sendRequestGood(t, "newBlockFilter") + blockFilterId := resObj["result"].(string) + resObj = sendRequestGood(t, "getFilterChanges", blockFilterId) + hashesInterface := resObj["result"].([]interface{}) + for _, hashInterface := range hashesInterface { + hash := hashInterface.(string) + require.Equal(t, 66, len(hash)) + require.Equal(t, "0x", hash[:2]) + } + // query again to make sure cursor is updated + resObj = sendRequestGood(t, "getFilterChanges", blockFilterId) + hashesInterface = resObj["result"].([]interface{}) + for _, hashInterface := range hashesInterface { + hash := hashInterface.(string) + require.Equal(t, 66, len(hash)) + require.Equal(t, "0x", hash[:2]) + } +} + +func TestFilterExpiration(t *testing.T) { + t.Parallel() + filterCriteria := map[string]interface{}{ + "fromBlock": "0x1", + "toBlock": "0xa", + } + resObj := sendRequestGood(t, "newFilter", filterCriteria) + filterId := resObj["result"].(string) + + // wait for filter to expire + time.Sleep(2 * filterTimeoutDuration) + + resObj = sendRequest(t, TestPort, "getFilterLogs", filterId) + _, ok := resObj["error"] + require.True(t, ok) +} + +func TestFilterGetFilterLogsKeepsFilterAlive(t *testing.T) { + t.Parallel() + filterCriteria := map[string]interface{}{ + "fromBlock": "0x1", + "toBlock": "0xa", + } + resObj := sendRequestGood(t, "newFilter", filterCriteria) + filterId := resObj["result"].(string) + + for i := 0; i < 5; i++ { + // should keep filter alive + resObj = sendRequestGood(t, "getFilterLogs", filterId) + _, ok := resObj["error"] + require.False(t, ok) + time.Sleep(filterTimeoutDuration / 2) + } +} + +func TestFilterGetFilterChangesKeepsFilterAlive(t *testing.T) { + t.Parallel() + filterCriteria := map[string]interface{}{ + "fromBlock": "0x1", + "toBlock": "0xa", + } + resObj := sendRequestGood(t, "newFilter", filterCriteria) + filterId := resObj["result"].(string) + + for i := 0; i < 5; i++ { + // should keep filter alive + resObj = sendRequestGood(t, "getFilterChanges", filterId) + _, ok := resObj["error"] + require.False(t, ok) + time.Sleep(filterTimeoutDuration / 2) + } +} diff --git a/evmrpc/info.go b/evmrpc/info.go new file mode 100644 index 0000000000..e165cc3cf4 --- /dev/null +++ b/evmrpc/info.go @@ -0,0 +1,219 @@ +package evmrpc + +import ( + "context" + "errors" + "math/big" + "slices" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/rpc" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + rpcclient "github.com/tendermint/tendermint/rpc/client" + "github.com/tendermint/tendermint/rpc/coretypes" +) + +type InfoAPI struct { + tmClient rpcclient.Client + keeper *keeper.Keeper + ctxProvider func(int64) sdk.Context + txDecoder sdk.TxDecoder + homeDir string +} + +func NewInfoAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txDecoder sdk.TxDecoder, homeDir string) *InfoAPI { + return &InfoAPI{tmClient: tmClient, keeper: k, ctxProvider: ctxProvider, txDecoder: txDecoder, homeDir: homeDir} +} + +type FeeHistoryResult struct { + OldestBlock *hexutil.Big `json:"oldestBlock"` + Reward [][]*hexutil.Big `json:"reward,omitempty"` + BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"` + GasUsedRatio []float64 `json:"gasUsedRatio"` +} + +func (i *InfoAPI) BlockNumber() hexutil.Uint64 { + startTime := time.Now() + defer recordMetrics("eth_BlockNumber", startTime, true) + return hexutil.Uint64(i.ctxProvider(LatestCtxHeight).BlockHeight()) +} + +//nolint:revive +func (i *InfoAPI) ChainId() *hexutil.Big { + startTime := time.Now() + defer recordMetrics("eth_ChainId", startTime, true) + return (*hexutil.Big)(i.keeper.ChainID(i.ctxProvider(LatestCtxHeight))) +} + +func (i *InfoAPI) Coinbase() (common.Address, error) { + startTime := time.Now() + defer recordMetrics("eth_Coinbase", startTime, true) + return i.keeper.GetFeeCollectorAddress(i.ctxProvider(LatestCtxHeight)) +} + +func (i *InfoAPI) Accounts() (result []common.Address, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_Accounts", startTime, returnErr == nil) + kb, err := getTestKeyring(i.homeDir) + if err != nil { + return []common.Address{}, err + } + for addr := range getAddressPrivKeyMap(kb) { + result = append(result, common.HexToAddress(addr)) + } + return result, nil +} + +func (i *InfoAPI) GasPrice(ctx context.Context) (result *hexutil.Big, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_GasPrice", startTime, returnErr == nil) + // get fee history of the most recent block with 50% reward percentile + feeHist, err := i.FeeHistory(ctx, 1, rpc.LatestBlockNumber, []float64{0.5}) + if err != nil { + return nil, err + } + if len(feeHist.Reward) == 0 || len(feeHist.Reward[0]) == 0 { + // if there is no EVM tx in the most recent block, return the minimum fee param + return (*hexutil.Big)(i.keeper.GetMinimumFeePerGas(i.ctxProvider(LatestCtxHeight)).TruncateInt().BigInt()), nil + } + return (*hexutil.Big)(new(big.Int).Add( + feeHist.Reward[0][0].ToInt(), + i.keeper.GetBaseFeePerGas(i.ctxProvider(LatestCtxHeight)).TruncateInt().BigInt(), + )), nil +} + +// lastBlock is inclusive +func (i *InfoAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (result *FeeHistoryResult, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_feeHistory", startTime, returnErr == nil) + result = &FeeHistoryResult{} + + // validate reward percentiles + for i, p := range rewardPercentiles { + 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") + } + } + + lastBlockNumber := lastBlock.Int64() + genesis, err := i.tmClient.Genesis(ctx) + if err != nil { + return nil, err + } + genesisHeight := genesis.Genesis.InitialHeight + currentHeight := i.ctxProvider(LatestCtxHeight).BlockHeight() + switch lastBlock { + case rpc.SafeBlockNumber, rpc.FinalizedBlockNumber, rpc.LatestBlockNumber, rpc.PendingBlockNumber: + lastBlockNumber = currentHeight + case rpc.EarliestBlockNumber: + lastBlockNumber = genesisHeight + default: + if lastBlockNumber > currentHeight { + lastBlockNumber = currentHeight + } + } + + if lastBlockNumber < genesisHeight { + return nil, errors.New("requested last block is before genesis height") + } + + if uint64(lastBlockNumber-genesisHeight) < uint64(blockCount) { + result.OldestBlock = (*hexutil.Big)(big.NewInt(genesisHeight)) + } else { + result.OldestBlock = (*hexutil.Big)(big.NewInt(lastBlockNumber - int64(blockCount) + 1)) + } + + result.Reward = [][]*hexutil.Big{} + // Potentially parallelize the following logic + for blockNum := result.OldestBlock.ToInt().Int64(); blockNum <= lastBlockNumber; blockNum++ { + sdkCtx := i.ctxProvider(blockNum) + if CheckVersion(sdkCtx, i.keeper) != nil { + // either height is pruned or before EVM is introduced. Skipping + continue + } + result.GasUsedRatio = append(result.GasUsedRatio, GasUsedRatio) + baseFee := i.safeGetBaseFee(blockNum) + if baseFee == nil { + // the block has been pruned + continue + } + result.BaseFee = append(result.BaseFee, (*hexutil.Big)(baseFee)) + height := blockNum + block, err := blockByNumber(ctx, i.tmClient, &height) + if err != nil { + // block pruned from tendermint store. Skipping + continue + } + rewards, err := i.getRewards(block, baseFee, rewardPercentiles) + if err != nil { + return nil, err + } + result.Reward = append(result.Reward, rewards) + } + return result, nil +} + +func (i *InfoAPI) safeGetBaseFee(targetHeight int64) (res *big.Int) { + defer func() { + if err := recover(); err != nil { + res = nil + } + }() + res = i.keeper.GetBaseFeePerGas(i.ctxProvider(targetHeight)).BigInt() + return +} + +type GasAndReward struct { + GasUsed uint64 + Reward *big.Int +} + +func (i *InfoAPI) getRewards(block *coretypes.ResultBlock, baseFee *big.Int, rewardPercentiles []float64) ([]*hexutil.Big, error) { + GasAndRewards := []GasAndReward{} + totalEVMGasUsed := uint64(0) + for _, txbz := range block.Block.Txs { + ethtx := getEthTxForTxBz(txbz, i.txDecoder) + if ethtx == nil { + // not evm tx + continue + } + // okay to get from latest since receipt is immutable + receipt, err := i.keeper.GetReceipt(i.ctxProvider(LatestCtxHeight), ethtx.Hash()) + if err != nil { + return nil, err + } + reward := new(big.Int).Sub(new(big.Int).SetUint64(receipt.EffectiveGasPrice), baseFee) + GasAndRewards = append(GasAndRewards, GasAndReward{GasUsed: receipt.GasUsed, Reward: reward}) + totalEVMGasUsed += receipt.GasUsed + } + return CalculatePercentiles(rewardPercentiles, GasAndRewards, totalEVMGasUsed), nil +} + +// Following go-ethereum implementation +// Specifically, the reward value at a percentile of p% will be the reward value of the +// lowest-rewarded transaction such that the sum of its gasUsed value and gasUsed values +// of all lower-rewarded transactions is no less than (total gasUsed * p%). +func CalculatePercentiles(rewardPercentiles []float64, GasAndRewards []GasAndReward, totalEVMGasUsed uint64) []*hexutil.Big { + slices.SortStableFunc(GasAndRewards, func(a, b GasAndReward) int { + return a.Reward.Cmp(b.Reward) + }) + res := []*hexutil.Big{} + if len(GasAndRewards) == 0 { + return res + } + var txIndex int + sumGasUsed := GasAndRewards[0].GasUsed + for _, p := range rewardPercentiles { + thresholdGasUsed := uint64(float64(totalEVMGasUsed) * p / 100) + for sumGasUsed < thresholdGasUsed && txIndex < len(GasAndRewards)-1 { + txIndex++ + sumGasUsed += GasAndRewards[txIndex].GasUsed + } + res = append(res, (*hexutil.Big)(GasAndRewards[txIndex].Reward)) + } + return res +} diff --git a/evmrpc/info_test.go b/evmrpc/info_test.go new file mode 100644 index 0000000000..33fb2fe3af --- /dev/null +++ b/evmrpc/info_test.go @@ -0,0 +1,141 @@ +package evmrpc_test + +import ( + "math/big" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/config" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/go-bip39" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/stretchr/testify/require" +) + +func TestBlockNumber(t *testing.T) { + resObj := sendRequestGood(t, "blockNumber") + result := resObj["result"].(string) + require.Equal(t, "0x8", result) +} + +func TestChainID(t *testing.T) { + resObj := sendRequestGood(t, "chainId") + result := resObj["result"].(string) + require.Equal(t, "0xae3f3", result) +} + +func TestAccounts(t *testing.T) { + homeDir := t.TempDir() + api := evmrpc.NewInfoAPI(nil, nil, nil, nil, homeDir) + clientCtx := client.Context{}.WithViper("").WithHomeDir(homeDir) + clientCtx, err := config.ReadFromClientConfig(clientCtx) + require.Nil(t, err) + kb, err := client.NewKeyringFromBackend(clientCtx, keyring.BackendTest) + require.Nil(t, err) + entropySeed, err := bip39.NewEntropy(256) + require.Nil(t, err) + mnemonic, err := bip39.NewMnemonic(entropySeed) + require.Nil(t, err) + algos, _ := kb.SupportedAlgorithms() + algo, err := keyring.NewSigningAlgoFromString(string(hd.Secp256k1Type), algos) + require.Nil(t, err) + _, err = kb.NewAccount("test", mnemonic, "", hd.CreateHDPath(sdk.GetConfig().GetCoinType(), 0, 0).String(), algo) + require.Nil(t, err) + accounts, _ := api.Accounts() + require.Equal(t, 1, len(accounts)) +} + +func TestCoinbase(t *testing.T) { + Ctx = Ctx.WithBlockHeight(1) + resObj := sendRequestGood(t, "coinbase") + Ctx = Ctx.WithBlockHeight(8) + result := resObj["result"].(string) + require.Equal(t, "0x27f7b8b8b5a4e71e8e9aa671f4e4031e3773303f", result) +} + +func TestGasPrice(t *testing.T) { + Ctx = Ctx.WithBlockHeight(1) + resObj := sendRequestGood(t, "gasPrice") + Ctx = Ctx.WithBlockHeight(8) + result := resObj["result"].(string) + require.Equal(t, "0xa", result) +} + +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)) + } + + // 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(8) +} + +func TestCalculatePercentiles(t *testing.T) { + // all empty + result := evmrpc.CalculatePercentiles([]float64{}, []evmrpc.GasAndReward{}, 0) + require.Equal(t, 0, len(result)) + + // empty GasAndRewards + result = evmrpc.CalculatePercentiles([]float64{1}, []evmrpc.GasAndReward{}, 0) + require.Equal(t, 0, len(result)) + + // empty percentiles + result = evmrpc.CalculatePercentiles([]float64{}, []evmrpc.GasAndReward{{Reward: big.NewInt(10), GasUsed: 1}}, 1) + require.Equal(t, 0, len(result)) + + // 0 percentile + result = evmrpc.CalculatePercentiles([]float64{0}, []evmrpc.GasAndReward{{Reward: big.NewInt(10), GasUsed: 1}}, 1) + require.Equal(t, 1, len(result)) + // see comments above CalculatePercentiles to understand why it should return 10 here + require.Equal(t, big.NewInt(10), result[0].ToInt()) + + // 100 percentile + result = evmrpc.CalculatePercentiles([]float64{100}, []evmrpc.GasAndReward{{Reward: big.NewInt(10), GasUsed: 1}}, 1) + require.Equal(t, 1, len(result)) + require.Equal(t, big.NewInt(10), result[0].ToInt()) + + // 0 percentile and 100 percentile with just one transaction + result = evmrpc.CalculatePercentiles([]float64{0, 100}, []evmrpc.GasAndReward{{Reward: big.NewInt(10), GasUsed: 1}}, 1) + require.Equal(t, 2, len(result)) + require.Equal(t, big.NewInt(10), result[0].ToInt()) + require.Equal(t, big.NewInt(10), result[1].ToInt()) + + // more transactions than percentiles + result = evmrpc.CalculatePercentiles([]float64{0, 50, 100}, []evmrpc.GasAndReward{{Reward: big.NewInt(10), GasUsed: 1}, {Reward: big.NewInt(5), GasUsed: 2}, {Reward: big.NewInt(3), GasUsed: 3}}, 6) + require.Equal(t, 3, len(result)) + require.Equal(t, big.NewInt(3), result[0].ToInt()) + require.Equal(t, big.NewInt(3), result[1].ToInt()) + require.Equal(t, big.NewInt(10), result[2].ToInt()) +} diff --git a/evmrpc/jwt_handler.go b/evmrpc/jwt_handler.go new file mode 100644 index 0000000000..8603d922aa --- /dev/null +++ b/evmrpc/jwt_handler.go @@ -0,0 +1,80 @@ +// Copyright 2022 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package evmrpc + +import ( + "net/http" + "strings" + "time" + + "github.com/golang-jwt/jwt/v4" +) + +const JwtExpiryTimeout = 60 * time.Second + +type jwtHandler struct { + keyFunc func(token *jwt.Token) (interface{}, error) + next http.Handler +} + +// newJWTHandler creates a http.Handler with jwt authentication support. +func newJWTHandler(secret []byte, next http.Handler) http.Handler { + return &jwtHandler{ + keyFunc: func(token *jwt.Token) (interface{}, error) { + return secret, nil + }, + next: next, + } +} + +// ServeHTTP implements http.Handler +func (handler *jwtHandler) ServeHTTP(out http.ResponseWriter, r *http.Request) { + var ( + strToken string + claims jwt.RegisteredClaims + ) + if auth := r.Header.Get("Authorization"); strings.HasPrefix(auth, "Bearer ") { + strToken = strings.TrimPrefix(auth, "Bearer ") + } + if len(strToken) == 0 { + http.Error(out, "missing token", http.StatusUnauthorized) + return + } + // We explicitly set only HS256 allowed, and also disables the + // claim-check: the RegisteredClaims internally requires 'iat' to + // be no later than 'now', but we allow for a bit of drift. + token, err := jwt.ParseWithClaims(strToken, &claims, handler.keyFunc, + jwt.WithValidMethods([]string{"HS256"}), + jwt.WithoutClaimsValidation()) + + switch { + case err != nil: + http.Error(out, err.Error(), http.StatusUnauthorized) + case !token.Valid: + http.Error(out, "invalid token", http.StatusUnauthorized) + case !claims.VerifyExpiresAt(time.Now(), false): // optional + http.Error(out, "token is expired", http.StatusUnauthorized) + case claims.IssuedAt == nil: + http.Error(out, "missing issued-at", http.StatusUnauthorized) + case time.Since(claims.IssuedAt.Time) > JwtExpiryTimeout: + http.Error(out, "stale token", http.StatusUnauthorized) + case time.Until(claims.IssuedAt.Time) > JwtExpiryTimeout: + http.Error(out, "future token", http.StatusUnauthorized) + default: + handler.next.ServeHTTP(out, r) + } +} diff --git a/evmrpc/net.go b/evmrpc/net.go new file mode 100644 index 0000000000..9bc603cc84 --- /dev/null +++ b/evmrpc/net.go @@ -0,0 +1,27 @@ +package evmrpc + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/tendermint/tendermint/libs/time" + rpcclient "github.com/tendermint/tendermint/rpc/client" +) + +type NetAPI struct { + tmClient rpcclient.Client + keeper *keeper.Keeper + ctxProvider func(int64) sdk.Context + txDecoder sdk.TxDecoder +} + +func NewNetAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txDecoder sdk.TxDecoder) *NetAPI { + return &NetAPI{tmClient: tmClient, keeper: k, ctxProvider: ctxProvider, txDecoder: txDecoder} +} + +func (i *NetAPI) Version() string { + startTime := time.Now() + defer recordMetrics("net_version", startTime, true) + return fmt.Sprintf("%d", i.keeper.ChainID(i.ctxProvider(LatestCtxHeight)).Uint64()) +} diff --git a/evmrpc/query_builder.go b/evmrpc/query_builder.go new file mode 100644 index 0000000000..0a85a1f895 --- /dev/null +++ b/evmrpc/query_builder.go @@ -0,0 +1,29 @@ +package evmrpc + +import ( + "strings" +) + +type QueryBuilder struct { + conditions []string +} + +func NewHeadQueryBuilder() *QueryBuilder { + return &QueryBuilder{ + conditions: []string{ + "tm.event = 'NewBlockHeader'", + }, + } +} + +func NewBlockQueryBuilder() *QueryBuilder { + return &QueryBuilder{ + conditions: []string{ + "tm.event = 'NewBlock'", + }, + } +} + +func (q *QueryBuilder) Build() string { + return strings.Join(q.conditions, " AND ") +} diff --git a/evmrpc/rpcstack.go b/evmrpc/rpcstack.go new file mode 100644 index 0000000000..847495aacb --- /dev/null +++ b/evmrpc/rpcstack.go @@ -0,0 +1,594 @@ +// Copyright 2020 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package evmrpc + +import ( + "compress/gzip" + "context" + "fmt" + "io" + "net" + "net/http" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/rpc" + "github.com/rs/cors" + "github.com/tendermint/tendermint/libs/log" +) + +// HTTPConfig is the JSON-RPC/HTTP configuration. +type HTTPConfig struct { + Modules []string + CorsAllowedOrigins []string + Vhosts []string + DenyList []string + prefix string // path prefix on which to mount http handler + RPCEndpointConfig +} + +// WsConfig is the JSON-RPC/Websocket configuration +type WsConfig struct { + Origins []string + Modules []string + prefix string // path prefix on which to mount ws handler + RPCEndpointConfig +} + +type RPCEndpointConfig struct { + JwtSecret []byte // optional JWT secret + batchItemLimit int + batchResponseSizeLimit int +} + +type rpcHandler struct { + http.Handler + server *rpc.Server +} + +type HTTPServer struct { + log log.Logger + timeouts rpc.HTTPTimeouts + mux http.ServeMux // registered handlers go here + + mu sync.Mutex + server *http.Server + listener net.Listener // non-nil when server is running + + // HTTP RPC handler things. + + HTTPConfig HTTPConfig + httpHandler atomic.Value // *rpcHandler + + // WebSocket handler things. + WsConfig WsConfig + wsHandler atomic.Value // *rpcHandler + + // These are set by SetListenAddr. + endpoint string + host string + port int + + handlerNames map[string]string +} + +const ( + shutdownTimeout = 5 * time.Second +) + +func NewHTTPServer(log log.Logger, timeouts rpc.HTTPTimeouts) *HTTPServer { + h := &HTTPServer{log: log, timeouts: timeouts, handlerNames: make(map[string]string)} + + h.httpHandler.Store((*rpcHandler)(nil)) + h.wsHandler.Store((*rpcHandler)(nil)) + return h +} + +// SetListenAddr configures the listening address of the server. +// The address can only be set while the server isn't running. +func (h *HTTPServer) SetListenAddr(host string, port int) error { + h.mu.Lock() + defer h.mu.Unlock() + + if h.listener != nil && (host != h.host || port != h.port) { + return fmt.Errorf("HTTP server already running on %s", h.endpoint) + } + + h.host, h.port = host, port + h.endpoint = net.JoinHostPort(host, fmt.Sprintf("%d", port)) + return nil +} + +// listenAddr returns the listening address of the server. +func (h *HTTPServer) ListenAddr() string { + h.mu.Lock() + defer h.mu.Unlock() + + if h.listener != nil { + return h.listener.Addr().String() + } + return h.endpoint +} + +// start starts the HTTP server if it is enabled and not already running. +func (h *HTTPServer) Start() error { + h.mu.Lock() + defer h.mu.Unlock() + + if h.endpoint == "" || h.listener != nil { + return nil // already running or not configured + } + + // Initialize the server. + CheckTimeouts(&h.timeouts) + h.server = &http.Server{ + Handler: h, + ReadTimeout: h.timeouts.ReadTimeout, + ReadHeaderTimeout: h.timeouts.ReadHeaderTimeout, + WriteTimeout: h.timeouts.WriteTimeout, + IdleTimeout: h.timeouts.IdleTimeout, + } + + // Start the server. + listener, err := net.Listen("tcp", h.endpoint) + if err != nil { + // If the server fails to start, we need to clear out the RPC and WS + // configuration so they can be configured another time. + h.disableRPC() + h.disableWS() + return err + } + h.listener = listener + go func() { + if err := h.server.Serve(listener); err != nil { + h.log.Error(fmt.Sprintf("server exiting due to %s\n", err)) + } + }() + + if h.wsAllowed() { + url := fmt.Sprintf("ws://%v", listener.Addr()) + if h.WsConfig.prefix != "" { + url += h.WsConfig.prefix + } + h.log.Info("WebSocket enabled", "url", url) + } + // if server is websocket only, return after logging + if !h.rpcAllowed() { + return nil + } + // Log http endpoint. + h.log.Info("HTTP server started", + "endpoint", listener.Addr(), "auth", (h.HTTPConfig.JwtSecret != nil), + "prefix", h.HTTPConfig.prefix, + "cors", strings.Join(h.HTTPConfig.CorsAllowedOrigins, ","), + "vhosts", strings.Join(h.HTTPConfig.Vhosts, ","), + ) + + // Log all handlers mounted on server. + paths := make([]string, len(h.handlerNames)) + for path := range h.handlerNames { + paths = append(paths, path) + } + sort.Strings(paths) + logged := make(map[string]bool, len(paths)) + for _, path := range paths { + name := h.handlerNames[path] + if !logged[name] { + h.log.Info(name+" enabled", "url", "http://"+listener.Addr().String()+path) + logged[name] = true + } + } + return nil +} + +func (h *HTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // check if ws request and serve if ws enabled + ws := h.wsHandler.Load().(*rpcHandler) + if ws != nil && IsWebsocket(r) { + if CheckPath(r, h.WsConfig.prefix) { + ws.ServeHTTP(w, r) + } + return + } + + // if http-rpc is enabled, try to serve request + rpc := h.httpHandler.Load().(*rpcHandler) + if rpc != nil { + // First try to route in the mux. + // Requests to a path below root are handled by the mux, + // which has all the handlers registered via Node.RegisterHandler. + // These are made available when RPC is enabled. + muxHandler, pattern := h.mux.Handler(r) + if pattern != "" { + muxHandler.ServeHTTP(w, r) + return + } + + if CheckPath(r, h.HTTPConfig.prefix) { + rpc.ServeHTTP(w, r) + return + } + } + w.WriteHeader(http.StatusNotFound) +} + +// CheckPath checks whether a given request URL matches a given path prefix. +func CheckPath(r *http.Request, path string) bool { + // if no prefix has been specified, request URL must be on root + if path == "" { + return r.URL.Path == "/" + } + // otherwise, check to make sure prefix matches + return len(r.URL.Path) >= len(path) && r.URL.Path[:len(path)] == path +} + +// stop shuts down the HTTP server. +func (h *HTTPServer) Stop() { + h.mu.Lock() + defer h.mu.Unlock() + h.log.Info("Stopping EVM HTTP Server") + h.doStop() + h.log.Info("EVM HTTP Server stopped") +} + +func (h *HTTPServer) doStop() { + if h.listener == nil { + return // not running + } + + // Shut down the server. + httpHandler := h.httpHandler.Load().(*rpcHandler) + wsHandler := h.wsHandler.Load().(*rpcHandler) + if httpHandler != nil { + h.httpHandler.Store((*rpcHandler)(nil)) + httpHandler.server.Stop() + } + if wsHandler != nil { + h.wsHandler.Store((*rpcHandler)(nil)) + wsHandler.server.Stop() + } + + ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) + defer cancel() + err := h.server.Shutdown(ctx) + if err != nil && err == ctx.Err() { + h.log.Error("HTTP server graceful shutdown timed out") + h.server.Close() + } + + h.listener.Close() + h.log.Info("HTTP server stopped", "endpoint", h.listener.Addr()) + + // Clear out everything to allow re-configuring it later. + h.host, h.port, h.endpoint = "", 0, "" + h.server, h.listener = nil, nil +} + +// EnableRPC turns on JSON-RPC over HTTP on the server. +func (h *HTTPServer) EnableRPC(apis []rpc.API, config HTTPConfig) error { + h.mu.Lock() + defer h.mu.Unlock() + + if h.rpcAllowed() { + return fmt.Errorf("JSON-RPC over HTTP is already enabled") + } + + // Create RPC server and handler. + srv := rpc.NewServer() + srv.SetBatchLimits(config.batchItemLimit, config.batchResponseSizeLimit) + h.log.Info("Registering apis for evm rpc") + if err := RegisterApis(h.log, apis, config.Modules, srv); err != nil { + return err + } + for _, method := range config.DenyList { + srv.RegisterDenyList(method) + } + h.HTTPConfig = config + h.httpHandler.Store(&rpcHandler{ + Handler: NewHTTPHandlerStack(srv, config.CorsAllowedOrigins, config.Vhosts, config.JwtSecret), + server: srv, + }) + return nil +} + +// disableRPC stops the HTTP RPC handler. This is internal, the caller must hold h.mu. +func (h *HTTPServer) disableRPC() bool { + handler := h.httpHandler.Load().(*rpcHandler) + if handler != nil { + h.httpHandler.Store((*rpcHandler)(nil)) + handler.server.Stop() + } + return handler != nil +} + +// EnableWS turns on JSON-RPC over WebSocket on the server. +func (h *HTTPServer) EnableWS(apis []rpc.API, config WsConfig) error { + h.mu.Lock() + defer h.mu.Unlock() + + if h.wsAllowed() { + return fmt.Errorf("JSON-RPC over WebSocket is already enabled") + } + // Create RPC server and handler. + srv := rpc.NewServer() + srv.SetBatchLimits(config.batchItemLimit, config.batchResponseSizeLimit) + h.log.Info("Registering apis for evm websocket") + if err := RegisterApis(h.log, apis, config.Modules, srv); err != nil { + return err + } + h.WsConfig = config + h.wsHandler.Store(&rpcHandler{ + Handler: NewWSHandlerStack(srv.WebsocketHandler(config.Origins), config.JwtSecret), + server: srv, + }) + return nil +} + +// stopWS disables JSON-RPC over WebSocket and also stops the server if it only serves WebSocket. +func (h *HTTPServer) stopWS() { + h.mu.Lock() + defer h.mu.Unlock() + + if h.disableWS() { + if !h.rpcAllowed() { + h.doStop() + } + } +} + +// disableWS disables the WebSocket handler. This is internal, the caller must hold h.mu. +func (h *HTTPServer) disableWS() bool { + ws := h.wsHandler.Load().(*rpcHandler) + if ws != nil { + h.wsHandler.Store((*rpcHandler)(nil)) + ws.server.Stop() + } + return ws != nil +} + +// rpcAllowed returns true when JSON-RPC over HTTP is enabled. +func (h *HTTPServer) rpcAllowed() bool { + return h.httpHandler.Load().(*rpcHandler) != nil +} + +// wsAllowed returns true when JSON-RPC over WebSocket is enabled. +func (h *HTTPServer) wsAllowed() bool { + return h.wsHandler.Load().(*rpcHandler) != nil +} + +// IsWebsocket checks the header of an http request for a websocket upgrade request. +func IsWebsocket(r *http.Request) bool { + return strings.EqualFold(r.Header.Get("Upgrade"), "websocket") && + strings.Contains(strings.ToLower(r.Header.Get("Connection")), "upgrade") +} + +// NewHTTPHandlerStack returns wrapped http-related handlers +func NewHTTPHandlerStack(srv http.Handler, cors []string, vhosts []string, JwtSecret []byte) http.Handler { + // Wrap the CORS-handler within a host-handler + handler := newCorsHandler(srv, cors) + handler = newVHostHandler(vhosts, handler) + if len(JwtSecret) != 0 { + handler = newJWTHandler(JwtSecret, handler) + } + return NewGzipHandler(handler) +} + +// NewWSHandlerStack returns a wrapped ws-related handler. +func NewWSHandlerStack(srv http.Handler, JwtSecret []byte) http.Handler { + if len(JwtSecret) != 0 { + return newJWTHandler(JwtSecret, srv) + } + return srv +} + +func newCorsHandler(srv http.Handler, allowedOrigins []string) http.Handler { + // disable CORS support if user has not specified a custom CORS configuration + if len(allowedOrigins) == 0 { + return srv + } + c := cors.New(cors.Options{ + AllowedOrigins: allowedOrigins, + AllowedMethods: []string{http.MethodPost, http.MethodGet}, + AllowedHeaders: []string{"*"}, + MaxAge: 600, + }) + return c.Handler(srv) +} + +// virtualHostHandler is a handler which validates the Host-header of incoming requests. +// Using virtual hosts can help prevent DNS rebinding attacks, where a 'random' domain name points to +// the service ip address (but without CORS headers). By verifying the targeted virtual host, we can +// ensure that it's a destination that the node operator has defined. +type virtualHostHandler struct { + vhosts map[string]struct{} + next http.Handler +} + +func newVHostHandler(vhosts []string, next http.Handler) http.Handler { + vhostMap := make(map[string]struct{}) + for _, allowedHost := range vhosts { + vhostMap[strings.ToLower(allowedHost)] = struct{}{} + } + return &virtualHostHandler{vhostMap, next} +} + +// ServeHTTP serves JSON-RPC requests over HTTP, implements http.Handler +func (h *virtualHostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // if r.Host is not set, we can continue serving since a browser would set the Host header + if r.Host == "" { + h.next.ServeHTTP(w, r) + return + } + host, _, err := net.SplitHostPort(r.Host) + if err != nil { + // Either invalid (too many colons) or no port specified + host = r.Host + } + if ipAddr := net.ParseIP(host); ipAddr != nil { + // It's an IP address, we can serve that + h.next.ServeHTTP(w, r) + return + } + // Not an IP address, but a hostname. Need to validate + if _, exist := h.vhosts["*"]; exist { + h.next.ServeHTTP(w, r) + return + } + if _, exist := h.vhosts[host]; exist { + h.next.ServeHTTP(w, r) + return + } + http.Error(w, "invalid host specified", http.StatusForbidden) +} + +var gzPool = sync.Pool{ + New: func() interface{} { + w := gzip.NewWriter(io.Discard) + return w + }, +} + +type gzipResponseWriter struct { + resp http.ResponseWriter + + gz *gzip.Writer + contentLength uint64 // total length of the uncompressed response + written uint64 // amount of written bytes from the uncompressed response + hasLength bool // true if uncompressed response had Content-Length + inited bool // true after init was called for the first time +} + +// init runs just before response headers are written. Among other things, this function +// also decides whether compression will be applied at all. +func (w *gzipResponseWriter) init() { + if w.inited { + return + } + w.inited = true + + hdr := w.resp.Header() + length := hdr.Get("content-length") + if len(length) > 0 { + if n, err := strconv.ParseUint(length, 10, 64); err != nil { + w.hasLength = true + w.contentLength = n + } + } + + // Setting Transfer-Encoding to "identity" explicitly disables compression. net/http + // also recognizes this header value and uses it to disable "chunked" transfer + // encoding, trimming the header from the response. This means downstream handlers can + // set this without harm, even if they aren't wrapped by NewGzipHandler. + // + // In go-ethereum, we use this signal to disable compression for certain error + // responses which are flushed out close to the write deadline of the response. For + // these cases, we want to avoid chunked transfer encoding and compression because + // they require additional output that may not get written in time. + passthrough := hdr.Get("transfer-encoding") == "identity" + if !passthrough { + w.gz = gzPool.Get().(*gzip.Writer) + w.gz.Reset(w.resp) + hdr.Del("content-length") + hdr.Set("content-encoding", "gzip") + } +} + +func (w *gzipResponseWriter) Header() http.Header { + return w.resp.Header() +} + +func (w *gzipResponseWriter) WriteHeader(status int) { + w.init() + w.resp.WriteHeader(status) +} + +func (w *gzipResponseWriter) Write(b []byte) (int, error) { + w.init() + + if w.gz == nil { + // Compression is disabled. + return w.resp.Write(b) + } + + n, err := w.gz.Write(b) + w.written += uint64(n) + if w.hasLength && w.written >= w.contentLength { + // The HTTP handler has finished writing the entire uncompressed response. Close + // the gzip stream to ensure the footer will be seen by the client in case the + // response is flushed after this call to write. + err = w.gz.Close() + } + return n, err +} + +func (w *gzipResponseWriter) Flush() { + if w.gz != nil { + w.gz.Flush() + } + if f, ok := w.resp.(http.Flusher); ok { + f.Flush() + } +} + +func (w *gzipResponseWriter) close() { + if w.gz == nil { + return + } + w.gz.Close() + gzPool.Put(w.gz) + w.gz = nil +} + +func NewGzipHandler(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { + next.ServeHTTP(w, r) + return + } + + wrapper := &gzipResponseWriter{resp: w} + defer wrapper.close() + + next.ServeHTTP(wrapper, r) + }) +} + +// RegisterApis checks the given modules' availability, generates an allowlist based on the allowed modules, +// and then registers all of the APIs exposed by the services. +func RegisterApis(logger log.Logger, apis []rpc.API, modules []string, srv *rpc.Server) error { + if bad, available := checkModuleAvailability(modules, apis); len(bad) > 0 { + logger.Error("Unavailable modules in HTTP API list", "unavailable", bad, "available", available) + } + // Generate the allow list based on the allowed modules + allowList := make(map[string]bool) + for _, module := range modules { + allowList[module] = true + } + // Register all the APIs exposed by the services + for _, api := range apis { + if allowList[api.Namespace] || len(allowList) == 0 { + if err := srv.RegisterName(api.Namespace, api.Service); err != nil { + return err + } + } + } + return nil +} diff --git a/evmrpc/rpcstack_test.go b/evmrpc/rpcstack_test.go new file mode 100644 index 0000000000..b080d08d23 --- /dev/null +++ b/evmrpc/rpcstack_test.go @@ -0,0 +1,641 @@ +// Copyright 2020 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package evmrpc_test + +import ( + "bytes" + "fmt" + "io" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/rpc" + "github.com/golang-jwt/jwt/v4" + "github.com/gorilla/websocket" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/stretchr/testify/assert" + "github.com/tendermint/tendermint/libs/log" +) + +const testMethod = "rpc_modules" + +// TestCorsHandler makes sure CORS are properly handled on the http server. +func TestCorsHandler(t *testing.T) { + srv := createAndStartServer(t, &evmrpc.HTTPConfig{CorsAllowedOrigins: []string{"test", "test.com"}}, false, &evmrpc.WsConfig{}, nil) + defer srv.Stop() + url := "http://" + srv.ListenAddr() + + resp := rpcRequest(t, url, testMethod, "origin", "test.com") + assert.Equal(t, "test.com", resp.Header.Get("Access-Control-Allow-Origin")) + + resp2 := rpcRequest(t, url, testMethod, "origin", "bad") + assert.Equal(t, "", resp2.Header.Get("Access-Control-Allow-Origin")) +} + +// TestVhosts makes sure vhosts are properly handled on the http server. +func TestVhosts(t *testing.T) { + srv := createAndStartServer(t, &evmrpc.HTTPConfig{Vhosts: []string{"test"}}, false, &evmrpc.WsConfig{}, nil) + defer srv.Stop() + url := "http://" + srv.ListenAddr() + + resp := rpcRequest(t, url, testMethod, "host", "test") + assert.Equal(t, resp.StatusCode, http.StatusOK) + + resp2 := rpcRequest(t, url, testMethod, "host", "bad") + assert.Equal(t, resp2.StatusCode, http.StatusForbidden) +} + +type originTest struct { + spec string + expOk []string + expFail []string +} + +// splitAndTrim splits input separated by a comma +// and trims excessive white space from the substrings. +// Copied over from flags.go +func splitAndTrim(input string) (ret []string) { + l := strings.Split(input, ",") + for _, r := range l { + r = strings.TrimSpace(r) + if len(r) > 0 { + ret = append(ret, r) + } + } + return ret +} + +// TestWebsocketOrigins makes sure the websocket origins are properly handled on the websocket server. +func TestWebsocketOrigins(t *testing.T) { + tests := []originTest{ + { + spec: "*", // allow all + expOk: []string{"", "http://test", "https://test", "http://test:8540", "https://test:8540", + "http://test.com", "https://foo.test", "http://testa", "http://atestb:8540", "https://atestb:8540"}, + }, + { + spec: "test", + expOk: []string{"http://test", "https://test", "http://test:8540", "https://test:8540"}, + expFail: []string{"http://test.com", "https://foo.test", "http://testa", "http://atestb:8540", "https://atestb:8540"}, + }, + // scheme tests + { + spec: "https://test", + expOk: []string{"https://test", "https://test:9999"}, + expFail: []string{ + "test", // no scheme, required by spec + "http://test", // wrong scheme + "http://test.foo", "https://a.test.x", // subdomain variations + "http://testx:8540", "https://xtest:8540"}, + }, + // ip tests + { + spec: "https://12.34.56.78", + expOk: []string{"https://12.34.56.78", "https://12.34.56.78:8540"}, + expFail: []string{ + "http://12.34.56.78", // wrong scheme + "http://12.34.56.78:443", // wrong scheme + "http://1.12.34.56.78", // wrong 'domain name' + "http://12.34.56.78.a", // wrong 'domain name' + "https://87.65.43.21", "http://87.65.43.21:8540", "https://87.65.43.21:8540"}, + }, + // port tests + { + spec: "test:8540", + expOk: []string{"http://test:8540", "https://test:8540"}, + expFail: []string{ + "http://test", "https://test", // spec says port required + "http://test:8541", "https://test:8541", // wrong port + "http://bad", "https://bad", "http://bad:8540", "https://bad:8540"}, + }, + // scheme and port + { + spec: "https://test:8540", + expOk: []string{"https://test:8540"}, + expFail: []string{ + "https://test", // missing port + "http://test", // missing port, + wrong scheme + "http://test:8540", // wrong scheme + "http://test:8541", "https://test:8541", // wrong port + "http://bad", "https://bad", "http://bad:8540", "https://bad:8540"}, + }, + // several allowed origins + { + spec: "localhost,http://127.0.0.1", + expOk: []string{"localhost", "http://localhost", "https://localhost:8443", + "http://127.0.0.1", "http://127.0.0.1:8080"}, + expFail: []string{ + "https://127.0.0.1", // wrong scheme + "http://bad", "https://bad", "http://bad:8540", "https://bad:8540"}, + }, + } + for _, tc := range tests { + srv := createAndStartServer(t, &evmrpc.HTTPConfig{}, true, &evmrpc.WsConfig{Origins: splitAndTrim(tc.spec)}, nil) + url := fmt.Sprintf("ws://%v", srv.ListenAddr()) + for _, origin := range tc.expOk { + if err := wsRequest(t, url, "Origin", origin); err != nil { + t.Errorf("spec '%v', origin '%v': expected ok, got %v", tc.spec, origin, err) + } + } + for _, origin := range tc.expFail { + if err := wsRequest(t, url, "Origin", origin); err == nil { + t.Errorf("spec '%v', origin '%v': expected not to allow, got ok", tc.spec, origin) + } + } + srv.Stop() + } +} + +// Testevmrpc.IsWebsocket tests if an incoming websocket upgrade request is handled properly. +func TestIsWebsocket(t *testing.T) { + r, _ := http.NewRequest(http.MethodGet, "/", nil) + + assert.False(t, evmrpc.IsWebsocket(r)) + r.Header.Set("upgrade", "websocket") + assert.False(t, evmrpc.IsWebsocket(r)) + r.Header.Set("connection", "upgrade") + assert.True(t, evmrpc.IsWebsocket(r)) + r.Header.Set("connection", "upgrade,keep-alive") + assert.True(t, evmrpc.IsWebsocket(r)) + r.Header.Set("connection", " UPGRADE,keep-alive") + assert.True(t, evmrpc.IsWebsocket(r)) +} + +func Test_CheckPath(t *testing.T) { + tests := []struct { + req *http.Request + prefix string + expected bool + }{ + { + req: &http.Request{URL: &url.URL{Path: "/test"}}, + prefix: "/test", + expected: true, + }, + { + req: &http.Request{URL: &url.URL{Path: "/testing"}}, + prefix: "/test", + expected: true, + }, + { + req: &http.Request{URL: &url.URL{Path: "/"}}, + prefix: "/test", + expected: false, + }, + { + req: &http.Request{URL: &url.URL{Path: "/fail"}}, + prefix: "/test", + expected: false, + }, + { + req: &http.Request{URL: &url.URL{Path: "/"}}, + prefix: "", + expected: true, + }, + { + req: &http.Request{URL: &url.URL{Path: "/fail"}}, + prefix: "", + expected: false, + }, + { + req: &http.Request{URL: &url.URL{Path: "/"}}, + prefix: "/", + expected: true, + }, + { + req: &http.Request{URL: &url.URL{Path: "/testing"}}, + prefix: "/", + expected: true, + }, + } + + for i, tt := range tests { + t.Run(strconv.Itoa(i), func(t *testing.T) { + assert.Equal(t, tt.expected, evmrpc.CheckPath(tt.req, tt.prefix)) + }) + } +} + +func createAndStartServer(t *testing.T, conf *evmrpc.HTTPConfig, ws bool, wsConf *evmrpc.WsConfig, timeouts *rpc.HTTPTimeouts) *evmrpc.HTTPServer { + t.Helper() + + if timeouts == nil { + timeouts = &rpc.DefaultHTTPTimeouts + } + srv := evmrpc.NewHTTPServer(log.NewNopLogger(), *timeouts) + assert.NoError(t, srv.EnableRPC(apis(), *conf)) + if ws { + assert.NoError(t, srv.EnableWS(nil, *wsConf)) + } + assert.NoError(t, srv.SetListenAddr("localhost", 0)) + assert.NoError(t, srv.Start()) + return srv +} + +// wsRequest attempts to open a WebSocket connection to the given URL. +func wsRequest(t *testing.T, url string, extraHeaders ...string) error { + t.Helper() + //t.Logf("checking WebSocket on %s (origin %q)", url, browserOrigin) + + headers := make(http.Header) + // Apply extra headers. + if len(extraHeaders)%2 != 0 { + panic("odd extraHeaders length") + } + for i := 0; i < len(extraHeaders); i += 2 { + key, value := extraHeaders[i], extraHeaders[i+1] + headers.Set(key, value) + } + conn, _, err := websocket.DefaultDialer.Dial(url, headers) + if conn != nil { + conn.Close() + } + return err +} + +// rpcRequest performs a JSON-RPC request to the given URL. +func rpcRequest(t *testing.T, url, method string, extraHeaders ...string) *http.Response { + t.Helper() + + body := fmt.Sprintf(`{"jsonrpc":"2.0","id":1,"method":"%s","params":[]}`, method) + return baseRpcRequest(t, url, body, extraHeaders...) +} + +func batchRpcRequest(t *testing.T, url string, methods []string, extraHeaders ...string) *http.Response { + reqs := make([]string, len(methods)) + for i, m := range methods { + reqs[i] = fmt.Sprintf(`{"jsonrpc":"2.0","id":1,"method":"%s","params":[]}`, m) + } + body := fmt.Sprintf(`[%s]`, strings.Join(reqs, ",")) + return baseRpcRequest(t, url, body, extraHeaders...) +} + +func baseRpcRequest(t *testing.T, url, bodyStr string, extraHeaders ...string) *http.Response { + t.Helper() + + // Create the request. + body := bytes.NewReader([]byte(bodyStr)) + req, err := http.NewRequest(http.MethodPost, url, body) + if err != nil { + t.Fatal("could not create http request:", err) + } + req.Header.Set("content-type", "application/json") + req.Header.Set("accept-encoding", "identity") + + // Apply extra headers. + if len(extraHeaders)%2 != 0 { + panic("odd extraHeaders length") + } + for i := 0; i < len(extraHeaders); i += 2 { + key, value := extraHeaders[i], extraHeaders[i+1] + if strings.EqualFold(key, "host") { + req.Host = value + } else { + req.Header.Set(key, value) + } + } + + // Perform the request. + t.Logf("checking RPC/HTTP on %s %v", url, extraHeaders) + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { resp.Body.Close() }) + return resp +} + +type testClaim map[string]interface{} + +func (testClaim) Valid() error { + return nil +} + +func TestJWT(t *testing.T) { + var secret = []byte("secret") + issueToken := func(secret []byte, method jwt.SigningMethod, input map[string]interface{}) string { + if method == nil { + method = jwt.SigningMethodHS256 + } + ss, _ := jwt.NewWithClaims(method, testClaim(input)).SignedString(secret) + return ss + } + cfg := evmrpc.RPCEndpointConfig{JwtSecret: []byte("secret")} + httpcfg := &evmrpc.HTTPConfig{RPCEndpointConfig: cfg} + wscfg := &evmrpc.WsConfig{Origins: []string{"*"}, RPCEndpointConfig: cfg} + srv := createAndStartServer(t, httpcfg, true, wscfg, nil) + wsUrl := fmt.Sprintf("ws://%v", srv.ListenAddr()) + htUrl := fmt.Sprintf("http://%v", srv.ListenAddr()) + + expOk := []func() string{ + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + 4})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() - 4})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{ + "iat": time.Now().Unix(), + "exp": time.Now().Unix() + 2, + })) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{ + "iat": time.Now().Unix(), + "bar": "baz", + })) + }, + } + for i, tokenFn := range expOk { + token := tokenFn() + if err := wsRequest(t, wsUrl, "Authorization", token); err != nil { + t.Errorf("test %d-ws, token '%v': expected ok, got %v", i, token, err) + } + token = tokenFn() + if resp := rpcRequest(t, htUrl, testMethod, "Authorization", token); resp.StatusCode != 200 { + t.Errorf("test %d-http, token '%v': expected ok, got %v", i, token, resp.StatusCode) + } + } + + expFail := []func() string{ + // future + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() + int64(evmrpc.JwtExpiryTimeout.Seconds()) + 1})) + }, + // stale + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix() - int64(evmrpc.JwtExpiryTimeout.Seconds()) - 1})) + }, + // wrong algo + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, jwt.SigningMethodHS512, testClaim{"iat": time.Now().Unix() + 4})) + }, + // expired + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix(), "exp": time.Now().Unix()})) + }, + // missing mandatory iat + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{})) + }, + // wrong secret + func() string { + return fmt.Sprintf("Bearer %v", issueToken([]byte("wrong"), nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken([]byte{}, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(nil, nil, testClaim{"iat": time.Now().Unix()})) + }, + // Various malformed syntax + func() string { + return fmt.Sprintf("%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("bearer %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer: %v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer:%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer\t%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + func() string { + return fmt.Sprintf("Bearer \t%v", issueToken(secret, nil, testClaim{"iat": time.Now().Unix()})) + }, + } + for i, tokenFn := range expFail { + token := tokenFn() + if err := wsRequest(t, wsUrl, "Authorization", token); err == nil { + t.Errorf("tc %d-ws, token '%v': expected not to allow, got ok", i, token) + } + + token = tokenFn() + resp := rpcRequest(t, htUrl, testMethod, "Authorization", token) + if resp.StatusCode != http.StatusUnauthorized { + t.Errorf("tc %d-http, token '%v': expected not to allow, got %v", i, token, resp.StatusCode) + } + } + srv.Stop() +} + +func TestGzipHandler(t *testing.T) { + type gzipTest struct { + name string + handler http.HandlerFunc + status int + isGzip bool + header map[string]string + } + tests := []gzipTest{ + { + name: "Write", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("response")) + }, + isGzip: true, + status: 200, + }, + { + name: "WriteHeader", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("x-foo", "bar") + w.WriteHeader(205) + w.Write([]byte("response")) + }, + isGzip: true, + status: 205, + header: map[string]string{"x-foo": "bar"}, + }, + { + name: "WriteContentLength", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("content-length", "8") + w.Write([]byte("response")) + }, + isGzip: true, + status: 200, + }, + { + name: "Flush", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("res")) + w.(http.Flusher).Flush() + w.Write([]byte("ponse")) + }, + isGzip: true, + status: 200, + }, + { + name: "disable", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("transfer-encoding", "identity") + w.Header().Set("x-foo", "bar") + w.Write([]byte("response")) + }, + isGzip: false, + status: 200, + header: map[string]string{"x-foo": "bar"}, + }, + { + name: "disable-WriteHeader", + handler: func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("transfer-encoding", "identity") + w.Header().Set("x-foo", "bar") + w.WriteHeader(205) + w.Write([]byte("response")) + }, + isGzip: false, + status: 205, + header: map[string]string{"x-foo": "bar"}, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + srv := httptest.NewServer(evmrpc.NewGzipHandler(test.handler)) + defer srv.Close() + + resp, err := http.Get(srv.URL) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + + content, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + wasGzip := resp.Uncompressed + + if string(content) != "response" { + t.Fatalf("wrong response content %q", content) + } + if wasGzip != test.isGzip { + t.Fatalf("response gzipped == %t, want %t", wasGzip, test.isGzip) + } + if resp.StatusCode != test.status { + t.Fatalf("response status == %d, want %d", resp.StatusCode, test.status) + } + for name, expectedValue := range test.header { + if v := resp.Header.Get(name); v != expectedValue { + t.Fatalf("response header %s == %s, want %s", name, v, expectedValue) + } + } + }) + } +} + +func TestHTTPWriteTimeout(t *testing.T) { + const ( + timeoutRes = `{"jsonrpc":"2.0","id":1,"error":{"code":-32002,"message":"request timed out"}}` + greetRes = `{"jsonrpc":"2.0","id":1,"result":"Hello"}` + ) + // Set-up server + timeouts := rpc.DefaultHTTPTimeouts + timeouts.WriteTimeout = time.Second + srv := createAndStartServer(t, &evmrpc.HTTPConfig{Modules: []string{"test"}}, false, &evmrpc.WsConfig{}, &timeouts) + url := fmt.Sprintf("http://%v", srv.ListenAddr()) + + // Send normal request + t.Run("message", func(t *testing.T) { + resp := rpcRequest(t, url, "test_sleep") + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + if string(body) != timeoutRes { + t.Errorf("wrong response. have %s, want %s", string(body), timeoutRes) + } + }) + + // Batch request + t.Run("batch", func(t *testing.T) { + want := fmt.Sprintf("[%s,%s,%s]", greetRes, timeoutRes, timeoutRes) + resp := batchRpcRequest(t, url, []string{"test_greet", "test_sleep", "test_greet"}) + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + if string(body) != want { + t.Errorf("wrong response. have %s, want %s", string(body), want) + } + }) +} + +func apis() []rpc.API { + return []rpc.API{ + { + Namespace: "test", + Service: &testService{}, + }, + } +} + +type testService struct{} + +func (s *testService) Greet() string { + return "Hello" +} + +func (s *testService) Sleep() { + time.Sleep(1500 * time.Millisecond) +} + +func TestHttpDenyList(t *testing.T) { + const ( + expectRes = `{"jsonrpc":"2.0","id":null,"error":{"code":-32601,"message":"the method test_sleep does not exist/is not available"}}` + ) + // Set-up server + timeouts := rpc.DefaultHTTPTimeouts + timeouts.WriteTimeout = time.Second + srv := createAndStartServer(t, &evmrpc.HTTPConfig{ + DenyList: []string{"test_sleep"}, + Modules: []string{"test"}}, false, &evmrpc.WsConfig{}, &timeouts) + url := fmt.Sprintf("http://%v", srv.ListenAddr()) + // Send normal request + t.Run("message", func(t *testing.T) { + resp := rpcRequest(t, url, "test_sleep") + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + if string(body) != expectRes { + t.Errorf("wrong response. have %s, want %s", string(body), expectRes) + } + }) +} diff --git a/evmrpc/send.go b/evmrpc/send.go new file mode 100644 index 0000000000..ec388d84c4 --- /dev/null +++ b/evmrpc/send.go @@ -0,0 +1,140 @@ +package evmrpc + +import ( + "context" + "errors" + "time" + + "github.com/cosmos/cosmos-sdk/client" + 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/common/hexutil" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/lib/ethapi" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + "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" + rpcclient "github.com/tendermint/tendermint/rpc/client" +) + +type SendAPI struct { + tmClient rpcclient.Client + txConfig client.TxConfig + sendConfig *SendConfig + keeper *keeper.Keeper + ctxProvider func(int64) sdk.Context + homeDir string + backend *Backend +} + +type SendConfig struct { + slow bool +} + +func NewSendAPI(tmClient rpcclient.Client, txConfig client.TxConfig, sendConfig *SendConfig, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, homeDir string, simulateConfig *SimulateConfig) *SendAPI { + return &SendAPI{ + tmClient: tmClient, + txConfig: txConfig, + sendConfig: sendConfig, + keeper: k, + ctxProvider: ctxProvider, + homeDir: homeDir, + backend: NewBackend(ctxProvider, k, txConfig.TxDecoder(), tmClient, simulateConfig), + } +} + +func (s *SendAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (hash common.Hash, err error) { + startTime := time.Now() + defer recordMetrics("eth_sendRawTransaction", startTime, err == nil) + tx := new(ethtypes.Transaction) + if err = tx.UnmarshalBinary(input); err != nil { + return + } + hash = tx.Hash() + txData, err := ethtx.NewTxDataFromTx(tx) + if err != nil { + return + } + msg, err := types.NewMsgEVMTransaction(txData) + if err != nil { + return + } + txBuilder := s.txConfig.NewTxBuilder() + if err = txBuilder.SetMsgs(msg); err != nil { + return + } + txbz, encodeErr := s.txConfig.TxEncoder()(txBuilder.GetTx()) + if encodeErr != nil { + return hash, encodeErr + } + + if s.sendConfig.slow { + res, broadcastError := s.tmClient.BroadcastTxCommit(ctx, txbz) + if broadcastError != nil { + err = broadcastError + } else if res == nil { + err = errors.New("missing broadcast response") + } else if res.CheckTx.Code != 0 { + err = sdkerrors.ABCIError(sdkerrors.RootCodespace, res.CheckTx.Code, "") + } + } else { + res, broadcastError := s.tmClient.BroadcastTx(ctx, txbz) + if broadcastError != nil { + err = broadcastError + } else if res == nil { + err = errors.New("missing broadcast response") + } else if res.Code != 0 { + err = sdkerrors.ABCIError(sdkerrors.RootCodespace, res.Code, "") + } + } + return +} + +func (s *SendAPI) SignTransaction(_ context.Context, args apitypes.SendTxArgs, _ *string) (result *ethapi.SignTransactionResult, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_signTransaction", startTime, returnErr == nil) + var unsignedTx = args.ToTransaction() + signedTx, err := s.signTransaction(unsignedTx, args.From.Address().Hex()) + if err != nil { + return nil, err + } + data, err := signedTx.MarshalBinary() + if err != nil { + return nil, err + } + return ðapi.SignTransactionResult{Raw: data, Tx: signedTx}, nil +} + +func (s *SendAPI) SendTransaction(ctx context.Context, args ethapi.TransactionArgs) (result common.Hash, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_sendTransaction", startTime, returnErr == nil) + if err := args.SetDefaults(ctx, s.backend); err != nil { + return common.Hash{}, err + } + var unsignedTx = args.ToTransaction() + signedTx, err := s.signTransaction(unsignedTx, args.From.Hex()) + if err != nil { + return common.Hash{}, err + } + data, err := signedTx.MarshalBinary() + if err != nil { + return common.Hash{}, err + } + return s.SendRawTransaction(ctx, data) +} + +func (s *SendAPI) signTransaction(unsignedTx *ethtypes.Transaction, from string) (*ethtypes.Transaction, error) { + kb, err := getTestKeyring(s.homeDir) + if err != nil { + return nil, err + } + privKey, ok := getAddressPrivKeyMap(kb)[from] + if !ok { + return nil, errors.New("from address does not have hosted key") + } + chainId := s.keeper.ChainID(s.ctxProvider(LatestCtxHeight)) + signer := ethtypes.LatestSignerForChainID(chainId) + return ethtypes.SignTx(unsignedTx, signer, privKey) +} diff --git a/evmrpc/send_test.go b/evmrpc/send_test.go new file mode 100644 index 0000000000..2f86cc7904 --- /dev/null +++ b/evmrpc/send_test.go @@ -0,0 +1,65 @@ +package evmrpc_test + +import ( + "encoding/hex" + "math/big" + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/hd" + sdk "github.com/cosmos/cosmos-sdk/types" + "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/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestMnemonicToPrivateKey(t *testing.T) { + mnemonic := "mushroom lamp kingdom obscure sun advice puzzle ancient crystal service beef have zone true chimney act situate laundry guess vacuum razor virus wink enforce" + hdp := hd.CreateHDPath(sdk.GetConfig().GetCoinType(), 0, 0).String() + derivedPriv, _ := hd.Secp256k1.Derive()(mnemonic, "", hdp) + privKey := hd.Secp256k1.Generate()(derivedPriv) + testPrivHex := hex.EncodeToString(privKey.Bytes()) + require.Equal(t, "fcf3a38c4c63a29f60ec962f4b87ac67a182a3d546fa6e46fef3606e089072d2", testPrivHex) +} + +func TestSendRawTransaction(t *testing.T) { + // build tx + to := common.HexToAddress("010203") + txData := ethtypes.DynamicFeeTx{ + Nonce: 1, + GasFeeCap: big.NewInt(10), + Gas: 1000, + To: &to, + Value: big.NewInt(1000), + Data: []byte("abc"), + ChainID: EVMKeeper.ChainID(Ctx), + } + mnemonic := "fish mention unlock february marble dove vintage sand hub ordinary fade found inject room embark supply fabric improve spike stem give current similar glimpse" + derivedPriv, _ := hd.Secp256k1.Derive()(mnemonic, "", "") + privKey := hd.Secp256k1.Generate()(derivedPriv) + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + ethCfg := types.DefaultChainConfig().EthereumConfig(EVMKeeper.ChainID(Ctx)) + signer := ethtypes.MakeSigner(ethCfg, big.NewInt(Ctx.BlockHeight()), uint64(Ctx.BlockTime().Unix())) + tx := ethtypes.NewTx(&txData) + tx, err := ethtypes.SignTx(tx, signer, key) + require.Nil(t, err) + bz, err := tx.MarshalBinary() + require.Nil(t, err) + payload := "0x" + hex.EncodeToString(bz) + + resObj := sendRequestGood(t, "sendRawTransaction", payload) + result := resObj["result"].(string) + require.Equal(t, tx.Hash().Hex(), result) + + // bad payload + resObj = sendRequestGood(t, "sendRawTransaction", "0x1234") + errMap := resObj["error"].(map[string]interface{}) + require.Equal(t, "transaction type not supported", errMap["message"].(string)) + + // bad server + resObj = sendRequestBad(t, "sendRawTransaction", payload) + errMap = resObj["error"].(map[string]interface{}) + require.Equal(t, ": invalid sequence", errMap["message"].(string)) +} diff --git a/evmrpc/server.go b/evmrpc/server.go new file mode 100644 index 0000000000..081d5167e9 --- /dev/null +++ b/evmrpc/server.go @@ -0,0 +1,168 @@ +package evmrpc + +import ( + "strings" + + "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/rpc" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/tendermint/tendermint/libs/log" + rpcclient "github.com/tendermint/tendermint/rpc/client" +) + +const LocalAddress = "0.0.0.0" + +type EVMServer interface { + Start() error +} + +func NewEVMHTTPServer( + logger log.Logger, + config Config, + tmClient rpcclient.Client, + k *keeper.Keeper, + ctxProvider func(int64) sdk.Context, + txConfig client.TxConfig, + homeDir string, +) (EVMServer, error) { + httpServer := NewHTTPServer(logger, rpc.HTTPTimeouts{ + ReadTimeout: config.ReadTimeout, + ReadHeaderTimeout: config.ReadHeaderTimeout, + WriteTimeout: config.WriteTimeout, + IdleTimeout: config.IdleTimeout, + }) + if err := httpServer.SetListenAddr(LocalAddress, config.HTTPPort); err != nil { + return nil, err + } + simulateConfig := &SimulateConfig{GasCap: config.SimulationGasLimit, EVMTimeout: config.SimulationEVMTimeout} + sendAPI := NewSendAPI(tmClient, txConfig, &SendConfig{slow: config.Slow}, k, ctxProvider, homeDir, simulateConfig) + apis := []rpc.API{ + { + Namespace: "echo", + Service: NewEchoAPI(), + }, + { + Namespace: "eth", + Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig), + }, + { + Namespace: "eth", + Service: NewTransactionAPI(tmClient, k, ctxProvider, txConfig, homeDir), + }, + { + Namespace: "eth", + Service: NewStateAPI(tmClient, k, ctxProvider), + }, + { + Namespace: "eth", + Service: NewInfoAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), homeDir), + }, + { + Namespace: "eth", + Service: sendAPI, + }, + { + Namespace: "eth", + Service: NewSimulationAPI(ctxProvider, k, txConfig.TxDecoder(), tmClient, simulateConfig), + }, + { + Namespace: "net", + Service: NewNetAPI(tmClient, k, ctxProvider, txConfig.TxDecoder()), + }, + { + Namespace: "eth", + Service: NewFilterAPI(tmClient, &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider}, &FilterConfig{timeout: config.FilterTimeout}), + }, + { + Namespace: "sei", + Service: NewAssociationAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), sendAPI), + }, + { + Namespace: "txpool", + Service: NewTxPoolAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), &TxPoolConfig{maxNumTxs: int(config.MaxTxPoolTxs)}), + }, + { + Namespace: "web3", + Service: &Web3API{}, + }, + { + Namespace: "debug", + Service: NewDebugAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), simulateConfig), + }, + } + if err := httpServer.EnableRPC(apis, HTTPConfig{ + CorsAllowedOrigins: strings.Split(config.CORSOrigins, ","), + Vhosts: []string{"*"}, + }); err != nil { + return nil, err + } + return httpServer, nil +} + +func NewEVMWebSocketServer( + logger log.Logger, + config Config, + tmClient rpcclient.Client, + k *keeper.Keeper, + ctxProvider func(int64) sdk.Context, + txConfig client.TxConfig, + homeDir string, +) (EVMServer, error) { + httpServer := NewHTTPServer(logger, rpc.HTTPTimeouts{ + ReadTimeout: config.ReadTimeout, + ReadHeaderTimeout: config.ReadHeaderTimeout, + WriteTimeout: config.WriteTimeout, + IdleTimeout: config.IdleTimeout, + }) + if err := httpServer.SetListenAddr(LocalAddress, config.WSPort); err != nil { + return nil, err + } + simulateConfig := &SimulateConfig{GasCap: config.SimulationGasLimit, EVMTimeout: config.SimulationEVMTimeout} + apis := []rpc.API{ + { + Namespace: "echo", + Service: NewEchoAPI(), + }, + { + Namespace: "eth", + Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig), + }, + { + Namespace: "eth", + Service: NewTransactionAPI(tmClient, k, ctxProvider, txConfig, homeDir), + }, + { + Namespace: "eth", + Service: NewStateAPI(tmClient, k, ctxProvider), + }, + { + Namespace: "eth", + Service: NewInfoAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), homeDir), + }, + { + Namespace: "eth", + Service: NewSendAPI(tmClient, txConfig, &SendConfig{slow: config.Slow}, k, ctxProvider, homeDir, simulateConfig), + }, + { + Namespace: "eth", + Service: NewSimulationAPI(ctxProvider, k, txConfig.TxDecoder(), tmClient, simulateConfig), + }, + { + Namespace: "net", + Service: NewNetAPI(tmClient, k, ctxProvider, txConfig.TxDecoder()), + }, + { + Namespace: "eth", + Service: NewSubscriptionAPI(tmClient, &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider}, &SubscriptionConfig{subscriptionCapacity: 100}), + }, + { + Namespace: "web3", + Service: &Web3API{}, + }, + } + if err := httpServer.EnableWS(apis, WsConfig{Origins: strings.Split(config.WSOrigins, ",")}); err != nil { + return nil, err + } + return httpServer, nil +} diff --git a/evmrpc/setup_test.go b/evmrpc/setup_test.go new file mode 100644 index 0000000000..5df8df331d --- /dev/null +++ b/evmrpc/setup_test.go @@ -0,0 +1,870 @@ +package evmrpc_test + +import ( + "context" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "math/big" + "net" + "net/http" + "strconv" + "strings" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/hd" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/gorilla/websocket" + "github.com/sei-protocol/sei-chain/app" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + evmtypes "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" + "github.com/tendermint/tendermint/libs/bytes" + "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/rpc/client/mock" + "github.com/tendermint/tendermint/rpc/coretypes" + tmtypes "github.com/tendermint/tendermint/types" + "github.com/tendermint/tendermint/version" +) + +const TestAddr = "127.0.0.1" +const TestPort = 7777 +const TestWSPort = 7778 +const TestBadPort = 7779 + +const MockHeight = 8 +const MultiTxBlockHeight = 2 +const DebugTraceMockHeight = 101 + +var DebugTraceHashHex = "0x1234567890123456789023456789012345678901234567890123456789000004" +var DebugTraceBlockHash = "BE17E0261E539CB7E9A91E123A6D794E0163D656FCF9B8EAC07823F7ED28512B" + +var EncodingConfig = app.MakeEncodingConfig() +var TxConfig = EncodingConfig.TxConfig +var Encoder = TxConfig.TxEncoder() +var Decoder = TxConfig.TxDecoder() +var Tx1 sdk.Tx +var MultiTxBlockTx1 sdk.Tx +var MultiTxBlockTx2 sdk.Tx +var MultiTxBlockTx3 sdk.Tx +var MultiTxBlockTx4 sdk.Tx +var tx1 *ethtypes.Transaction +var multiTxBlockTx1 *ethtypes.Transaction +var multiTxBlockTx2 *ethtypes.Transaction +var multiTxBlockTx3 *ethtypes.Transaction +var multiTxBlockTx4 *ethtypes.Transaction + +var DebugTraceTx sdk.Tx +var TxNonEvm sdk.Tx +var UnconfirmedTx sdk.Tx + +var SConfig = evmrpc.SimulateConfig{GasCap: 10000000} + +var filterTimeoutDuration = 500 * time.Millisecond +var TotalTxCount int = 11 + +var MockBlockID = tmtypes.BlockID{ + Hash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000001")), +} + +type MockClient struct { + mock.Client +} + +func mustHexToBytes(h string) []byte { + bz, err := hex.DecodeString(h) + if err != nil { + panic(err) + } + return bz +} + +func mockBlockHeader(height int64) tmtypes.Header { + return tmtypes.Header{ + ChainID: "test", + Height: height, + Time: time.Unix(1696941649, 0), + DataHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000002")), + AppHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000003")), + LastResultsHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000004")), + ProposerAddress: tmtypes.Address(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000005")), + LastBlockID: tmtypes.BlockID{ + Hash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000006")), + }, + LastCommitHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000007")), + ValidatorsHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000009")), + NextValidatorsHash: bytes.HexBytes(mustHexToBytes("000000000000000000000000000000000000000000000000000000000000000A")), + ConsensusHash: bytes.HexBytes(mustHexToBytes("000000000000000000000000000000000000000000000000000000000000000B")), + EvidenceHash: bytes.HexBytes(mustHexToBytes("000000000000000000000000000000000000000000000000000000000000000E")), + } +} + +func (c *MockClient) mockBlock(height int64) *coretypes.ResultBlock { + if height == MultiTxBlockHeight { + return &coretypes.ResultBlock{ + BlockID: MockBlockID, + Block: &tmtypes.Block{ + Header: mockBlockHeader(height), + Data: tmtypes.Data{ + Txs: []tmtypes.Tx{ + func() []byte { + bz, _ := Encoder(TxNonEvm) // non evm tx + return bz + }(), + func() []byte { + bz, _ := Encoder(MultiTxBlockTx1) + return bz + }(), + func() []byte { + bz, _ := Encoder(TxNonEvm) // non evm tx + return bz + }(), + func() []byte { + bz, _ := Encoder(MultiTxBlockTx2) + return bz + }(), + func() []byte { + bz, _ := Encoder(MultiTxBlockTx3) + return bz + }(), + }, + }, + LastCommit: &tmtypes.Commit{ + Height: height, + }, + }, + } + } + res := &coretypes.ResultBlock{ + BlockID: MockBlockID, + Block: &tmtypes.Block{ + Header: mockBlockHeader(height), + Data: tmtypes.Data{ + Txs: []tmtypes.Tx{ + func() []byte { + bz, _ := Encoder(Tx1) + return bz + }(), + func() []byte { + bz, _ := Encoder(TxNonEvm) + return bz + }(), + }, + }, + LastCommit: &tmtypes.Commit{ + Height: MockHeight - 1, + }, + }, + } + if height == DebugTraceMockHeight { + res.Block.Data.Txs = []tmtypes.Tx{ + func() []byte { + bz, _ := Encoder(DebugTraceTx) + return bz + }(), + } + } + return res +} + +func (c *MockClient) mockEventDataNewBlockHeader(mockHeight uint64) *tmtypes.EventDataNewBlockHeader { + return &tmtypes.EventDataNewBlockHeader{ + Header: tmtypes.Header{ + Version: version.Consensus{ + Block: mockHeight, + App: 10, + }, + ChainID: "1", + Height: int64(mockHeight), + Time: time.Now(), + + // prev block info + LastBlockID: tmtypes.BlockID{ + Hash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000006")), + }, + + // hashes of block data + LastCommitHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000001")), + DataHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000002")), + + ValidatorsHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000009")), + NextValidatorsHash: bytes.HexBytes(mustHexToBytes("000000000000000000000000000000000000000000000000000000000000000A")), + ConsensusHash: bytes.HexBytes(mustHexToBytes("000000000000000000000000000000000000000000000000000000000000000B")), + EvidenceHash: bytes.HexBytes(mustHexToBytes("000000000000000000000000000000000000000000000000000000000000000E")), + AppHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000003")), + LastResultsHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000004")), + ProposerAddress: tmtypes.Address(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000005")), + }, + NumTxs: 5, + ResultFinalizeBlock: abci.ResponseFinalizeBlock{ + TxResults: mockTxResult(), + AppHash: bytes.HexBytes(mustHexToBytes("0000000000000000000000000000000000000000000000000000000000000006")), + }, + } +} + +func mockTxResult() []*abci.ExecTxResult { + return []*abci.ExecTxResult{ + { + Data: []byte("abc"), + Log: "log1", + GasUsed: 10, + GasWanted: 11, + }, + { + Data: []byte("def"), + Log: "log2", + GasUsed: 20, + GasWanted: 21, + }, + } +} + +func (c *MockClient) Genesis(context.Context) (*coretypes.ResultGenesis, error) { + return &coretypes.ResultGenesis{Genesis: &tmtypes.GenesisDoc{InitialHeight: 1}}, nil +} + +func (c *MockClient) Block(_ context.Context, h *int64) (*coretypes.ResultBlock, error) { + height := int64(MockHeight) + if h != nil { + height = *h + } + return c.mockBlock(height), nil +} + +func (c *MockClient) BlockByHash(_ context.Context, hash bytes.HexBytes) (*coretypes.ResultBlock, error) { + if hash.String() == DebugTraceBlockHash { + return c.mockBlock(DebugTraceMockHeight), nil + } + return c.mockBlock(MockHeight), nil +} + +func (c *MockClient) BlockResults(_ context.Context, height *int64) (*coretypes.ResultBlockResults, error) { + return &coretypes.ResultBlockResults{ + TxsResults: []*abci.ExecTxResult{ + { + Data: func() []byte { + bz, _ := Encoder(MultiTxBlockTx1) + return bz + }(), + GasWanted: 10, + GasUsed: 5, + }, + }, + }, nil +} + +func (c *MockClient) Subscribe(ctx context.Context, subscriber string, query string, outCapacity ...int) (<-chan coretypes.ResultEvent, error) { + if query == "tm.event = 'NewBlockHeader'" { + resCh := make(chan coretypes.ResultEvent, 5) + go func() { + for i := uint64(0); i < 5; i++ { + resCh <- coretypes.ResultEvent{ + SubscriptionID: subscriber, + Query: query, + Data: *c.mockEventDataNewBlockHeader(i + 1), + Events: c.mockEventDataNewBlockHeader(i + 1).ABCIEvents(), + } + time.Sleep(20 * time.Millisecond) // sleep a little to simulate real events + } + }() + return resCh, nil + // hardcoded test case for simplicity + } + return nil, errors.New("unknown query") +} + +func (c *MockClient) Unsubscribe(_ context.Context, _, _ string) error { + return nil +} + +func (c *MockClient) Events(_ context.Context, req *coretypes.RequestEvents) (*coretypes.ResultEvents, error) { + if strings.Contains(req.Filter.Query, "tm.event = 'NewBlock'") { + var cursor int + var err error + if req.After != "" { + cursor, err = strconv.Atoi(req.After) + if err != nil { + panic("invalid cursor") + } + } else { + cursor = MockHeight + } + resultBlock := c.mockBlock(int64(cursor)) + data := tmtypes.EventDataNewBlock{ + Block: resultBlock.Block, + BlockID: tmtypes.BlockID{}, + } + newCursor := strconv.FormatInt(int64(cursor)+1, 10) + return buildSingleResultEvent(data, false, newCursor, "event"), nil + } else { + panic("unknown query") + } +} + +func buildSingleResultEvent(data interface{}, more bool, cursor string, event string) *coretypes.ResultEvents { + eventData, err := json.Marshal(data) + if err != nil { + panic(err) + } + wrappedData := evmrpc.EventItemDataWrapper{ + Type: "NewBlock", + Value: eventData, + } + bz, err := json.Marshal(wrappedData) + if err != nil { + panic(err) + } + return &coretypes.ResultEvents{ + Items: []*coretypes.EventItem{ + { + Cursor: cursor, + Event: event, + Data: bz, + }, + }, + More: more, + Oldest: cursor, + Newest: cursor, + } +} + +func (c *MockClient) BroadcastTx(context.Context, tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { + return &coretypes.ResultBroadcastTx{Code: 0, Hash: []byte("0x123")}, nil +} + +func (c *MockClient) UnconfirmedTxs(ctx context.Context, page, perPage *int) (*coretypes.ResultUnconfirmedTxs, error) { + tx, _ := Encoder(UnconfirmedTx) + return &coretypes.ResultUnconfirmedTxs{ + Count: 1, + Total: 1, + TotalBytes: int64(len(tx)), + Txs: []tmtypes.Tx{tx}, + }, nil +} + +type MockBadClient struct { + MockClient +} + +func (m *MockBadClient) Block(context.Context, *int64) (*coretypes.ResultBlock, error) { + return nil, errors.New("error block") +} + +func (m *MockBadClient) BlockByHash(context.Context, bytes.HexBytes) (*coretypes.ResultBlock, error) { + return nil, errors.New("error block") +} + +func (m *MockBadClient) Genesis(context.Context) (*coretypes.ResultGenesis, error) { + return nil, errors.New("error genesis") +} + +func (m *MockBadClient) Subscribe(context.Context, string, string, ...int) (<-chan coretypes.ResultEvent, error) { + return nil, errors.New("bad subscribe") +} + +func (m *MockBadClient) BroadcastTx(context.Context, tmtypes.Tx) (*coretypes.ResultBroadcastTx, error) { + return &coretypes.ResultBroadcastTx{Code: 3, Codespace: "test", Log: "log"}, nil +} + +var EVMKeeper *keeper.Keeper +var Ctx sdk.Context + +func init() { + types.RegisterInterfaces(EncodingConfig.InterfaceRegistry) + testApp := app.Setup(false, false) + Ctx = testApp.GetContextForDeliverTx([]byte{}).WithBlockHeight(8) + EVMKeeper = &testApp.EvmKeeper + EVMKeeper.InitGenesis(Ctx, *evmtypes.DefaultGenesis()) + seiAddr, err := sdk.AccAddressFromHex(common.Bytes2Hex([]byte("seiAddr"))) + if err != nil { + panic(err) + } + err = testApp.BankKeeper.MintCoins(Ctx, "evm", sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))) + if err != nil { + panic(err) + } + err = testApp.BankKeeper.SendCoinsFromModuleToAccount(Ctx, "evm", seiAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))) + if err != nil { + panic(err) + } + testApp.Commit(context.Background()) + // Start good http server + goodConfig := evmrpc.DefaultConfig + goodConfig.HTTPPort = TestPort + goodConfig.WSPort = TestWSPort + goodConfig.FilterTimeout = 500 * time.Millisecond + infoLog, err := log.NewDefaultLogger("text", "info") + if err != nil { + panic(err) + } + HttpServer, err := evmrpc.NewEVMHTTPServer(infoLog, goodConfig, &MockClient{}, EVMKeeper, func(int64) sdk.Context { return Ctx }, TxConfig, "") + if err != nil { + panic(err) + } + if err := HttpServer.Start(); err != nil { + panic(err) + } + + // Start bad http server + badConfig := evmrpc.DefaultConfig + badConfig.HTTPPort = TestBadPort + badConfig.FilterTimeout = 500 * time.Millisecond + badHTTPServer, err := evmrpc.NewEVMHTTPServer(infoLog, badConfig, &MockBadClient{}, EVMKeeper, func(int64) sdk.Context { return Ctx }, TxConfig, "") + if err != nil { + panic(err) + } + if err := badHTTPServer.Start(); err != nil { + panic(err) + } + + // Start ws server + wsServer, err := evmrpc.NewEVMWebSocketServer(infoLog, goodConfig, &MockClient{}, EVMKeeper, func(int64) sdk.Context { return Ctx }, TxConfig, "") + if err != nil { + panic(err) + } + if err := wsServer.Start(); err != nil { + panic(err) + } + fmt.Printf("wsServer started with config = %+v\n", goodConfig) + time.Sleep(1 * time.Second) + + // Generate data + generateTxData() + + // Setup logs + setupLogs() +} + +func generateTxData() { + chainId := big.NewInt(types.DefaultChainID.Int64()) + to := common.HexToAddress("010203") + var txBuilder1, txBuilder1_5, txBuilder2, txBuilder3, txBuilder4 client.TxBuilder + txBuilder1, tx1 = buildTx(ethtypes.DynamicFeeTx{ + Nonce: 1, + GasFeeCap: big.NewInt(10), + Gas: 1000, + To: &to, + Value: big.NewInt(1000), + Data: []byte("abc"), + ChainID: chainId, + }) + txBuilder1_5, multiTxBlockTx1 = buildTx(ethtypes.DynamicFeeTx{ + Nonce: 2, + GasFeeCap: big.NewInt(10), + Gas: 1000, + To: &to, + Value: big.NewInt(1000), + Data: []byte("abc"), + ChainID: chainId, + }) + txBuilder2, multiTxBlockTx2 = buildTx(ethtypes.DynamicFeeTx{ + Nonce: 3, + GasFeeCap: big.NewInt(10), + Gas: 1000, + To: &to, + Value: big.NewInt(1000), + Data: []byte("abc"), + ChainID: chainId, + }) + txBuilder3, multiTxBlockTx3 = buildTx(ethtypes.DynamicFeeTx{ + Nonce: 4, + GasFeeCap: big.NewInt(10), + Gas: 1000, + To: &to, + Value: big.NewInt(1000), + Data: []byte("abc"), + ChainID: chainId, + }) + txBuilder4, multiTxBlockTx4 = buildTx(ethtypes.DynamicFeeTx{ + Nonce: 5, + GasFeeCap: big.NewInt(10), + Gas: 1000, + To: &to, + Value: big.NewInt(1000), + Data: []byte("abc"), + ChainID: chainId, + }) + debugTraceTxBuilder, _ := buildTx(ethtypes.DynamicFeeTx{ + Nonce: 0, + GasFeeCap: big.NewInt(10), + Gas: 22000, + To: &to, + Value: big.NewInt(1000), + Data: []byte("abc"), + ChainID: chainId, + }) + Tx1 = txBuilder1.GetTx() + MultiTxBlockTx1 = txBuilder1_5.GetTx() + MultiTxBlockTx2 = txBuilder2.GetTx() + MultiTxBlockTx3 = txBuilder3.GetTx() + MultiTxBlockTx4 = txBuilder4.GetTx() + DebugTraceTx = debugTraceTxBuilder.GetTx() + TxNonEvm = app.TestTx{} + if err := EVMKeeper.SetReceipt(Ctx, tx1.Hash(), &types.Receipt{ + From: "0x1234567890123456789012345678901234567890", + To: "0x1234567890123456789012345678901234567890", + TransactionIndex: 0, + BlockNumber: 8, + TxType: 1, + ContractAddress: "0x1234567890123456789012345678901234567890", + CumulativeGasUsed: 123, + TxHashHex: tx1.Hash().Hex(), + GasUsed: 55, + Status: 0, + EffectiveGasPrice: 10, + Logs: []*types.Log{{ + Address: "0x1111111111111111111111111111111111111111", + Topics: []string{"0x1111111111111111111111111111111111111111111111111111111111111111", "0x1111111111111111111111111111111111111111111111111111111111111112"}, + }}, + }); err != nil { + panic(err) + } + seiAddr, err := sdk.AccAddressFromHex(common.Bytes2Hex([]byte("seiAddr"))) + if err != nil { + panic(err) + } + evmAddr := common.HexToAddress(common.Bytes2Hex([]byte("evmAddr"))) + EVMKeeper.SetAddressMapping(Ctx, seiAddr, evmAddr) + unassociatedAddr := common.HexToAddress("0x1234567890123456789023456789012345678901") + debugTraceAddr := common.HexToAddress("0x5B4eba929F3811980f5AE0c5D04fa200f837DF4E") + amts := sdk.NewCoins(sdk.NewCoin(EVMKeeper.GetBaseDenom(Ctx), sdk.NewInt(1000000))) + balanceAmts := sdk.NewCoins(sdk.NewCoin(EVMKeeper.GetBaseDenom(Ctx), sdk.NewInt(1000))) + debugTraceAmts := sdk.NewCoins(sdk.NewCoin(EVMKeeper.GetBaseDenom(Ctx), sdk.NewInt(100000))) + EVMKeeper.BankKeeper().MintCoins(Ctx, types.ModuleName, amts) + EVMKeeper.BankKeeper().SendCoinsFromModuleToAccount(Ctx, types.ModuleName, sdk.AccAddress(unassociatedAddr[:]), balanceAmts) + EVMKeeper.BankKeeper().SendCoinsFromModuleToAccount(Ctx, types.ModuleName, sdk.AccAddress(debugTraceAddr[:]), debugTraceAmts) + EVMKeeper.SetCode(Ctx, common.HexToAddress("0x1234567890123456789023456789012345678901"), []byte("abc")) + EVMKeeper.SetState( + Ctx, + common.HexToAddress("0x1234567890123456789023456789012345678901"), + common.BytesToHash([]byte("key")), + common.BytesToHash([]byte("value")), + ) + EVMKeeper.SetAddressMapping( + Ctx, + sdk.MustAccAddressFromBech32("sei1mf0llhmqane5w2y8uynmghmk2w4mh0xll9seym"), + common.HexToAddress("0x1df809C639027b465B931BD63Ce71c8E5834D9d6"), + ) + EVMKeeper.SetNonce(Ctx, common.HexToAddress("0x1234567890123456789012345678901234567890"), 1) + unconfirmedTxBuilder, _ := buildTx(ethtypes.DynamicFeeTx{ + Nonce: 2, + GasFeeCap: big.NewInt(10), + Gas: 1000, + To: &to, + Value: big.NewInt(2000), + Data: []byte("abc"), + ChainID: chainId, + }) + UnconfirmedTx = unconfirmedTxBuilder.GetTx() +} + +func buildTx(txData ethtypes.DynamicFeeTx) (client.TxBuilder, *ethtypes.Transaction) { + chainId := big.NewInt(types.DefaultChainID.Int64()) + mnemonic := "fish mention unlock february marble dove vintage sand hub ordinary fade found inject room embark supply fabric improve spike stem give current similar glimpse" + derivedPriv, _ := hd.Secp256k1.Derive()(mnemonic, "", "") + privKey := hd.Secp256k1.Generate()(derivedPriv) + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + ethCfg := types.DefaultChainConfig().EthereumConfig(chainId) + signer := ethtypes.MakeSigner(ethCfg, big.NewInt(Ctx.BlockHeight()), uint64(Ctx.BlockTime().Unix())) + tx := ethtypes.NewTx(&txData) + tx, err := ethtypes.SignTx(tx, signer, key) + if err != nil { + panic(err) + } + + typedTx, err := ethtx.NewDynamicFeeTx(tx) + if err != nil { + panic(err) + } + msg, err := types.NewMsgEVMTransaction(typedTx) + if err != nil { + panic(err) + } + builder := TxConfig.NewTxBuilder() + if err := builder.SetMsgs(msg); err != nil { + panic(err) + } + return builder, tx +} + +func setupLogs() { + // block height 2 + bloom1 := ethtypes.CreateBloom(ethtypes.Receipts{ðtypes.Receipt{Logs: []*ethtypes.Log{{ + Address: common.HexToAddress("0x1111111111111111111111111111111111111112"), + Topics: []common.Hash{ + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123"), + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"), + }, + }, { + Address: common.HexToAddress("0x1111111111111111111111111111111111111112"), + Topics: []common.Hash{ + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123"), + }, + }}}}) + EVMKeeper.SetReceipt(Ctx, multiTxBlockTx1.Hash(), &types.Receipt{ + BlockNumber: MultiTxBlockHeight, + TransactionIndex: 1, // start at 1 bc 0 is the non-evm tx + TxHashHex: multiTxBlockTx1.Hash().Hex(), + LogsBloom: bloom1[:], + Logs: []*types.Log{{ + Address: "0x1111111111111111111111111111111111111112", + Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"}, + }, { + Address: "0x1111111111111111111111111111111111111112", + Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123"}, + }}, + }) + bloom2 := ethtypes.CreateBloom(ethtypes.Receipts{ðtypes.Receipt{Logs: []*ethtypes.Log{{ + Address: common.HexToAddress("0x1111111111111111111111111111111111111113"), + Topics: []common.Hash{ + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123"), + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"), + }, + }}}}) + EVMKeeper.SetReceipt(Ctx, multiTxBlockTx2.Hash(), &types.Receipt{ + BlockNumber: MultiTxBlockHeight, + TransactionIndex: 3, + TxHashHex: multiTxBlockTx2.Hash().Hex(), + LogsBloom: bloom2[:], + Logs: []*types.Log{{ + Address: "0x1111111111111111111111111111111111111113", + Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"}, + }}, + }) + bloom3 := ethtypes.CreateBloom(ethtypes.Receipts{ðtypes.Receipt{Logs: []*ethtypes.Log{{ + Address: common.HexToAddress("0x1111111111111111111111111111111111111114"), + Topics: []common.Hash{ + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123"), + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"), + }, + }}}}) + EVMKeeper.SetReceipt(Ctx, multiTxBlockTx3.Hash(), &types.Receipt{ + BlockNumber: MultiTxBlockHeight, + TransactionIndex: 4, + TxHashHex: multiTxBlockTx3.Hash().Hex(), + LogsBloom: bloom3[:], + Logs: []*types.Log{{ + Address: "0x1111111111111111111111111111111111111114", + Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"}, + }}, + }) + bloom4 := ethtypes.CreateBloom(ethtypes.Receipts{ðtypes.Receipt{Logs: []*ethtypes.Log{{ + Address: common.HexToAddress("0x1111111111111111111111111111111111111115"), + Topics: []common.Hash{ + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123"), + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"), + }, + }}}}) + EVMKeeper.SetReceipt(Ctx, multiTxBlockTx4.Hash(), &types.Receipt{ + BlockNumber: MockHeight, + TransactionIndex: 0, + TxHashHex: multiTxBlockTx4.Hash().Hex(), + LogsBloom: bloom4[:], + Logs: []*types.Log{{ + Address: "0x1111111111111111111111111111111111111115", + Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"}, + }}, + }) + EVMKeeper.SetReceipt(Ctx, common.HexToHash(DebugTraceHashHex), &types.Receipt{ + BlockNumber: DebugTraceMockHeight, + TransactionIndex: 0, + TxHashHex: DebugTraceHashHex, + }) + EVMKeeper.SetTxHashesOnHeight(Ctx, MultiTxBlockHeight, []common.Hash{ + multiTxBlockTx1.Hash(), + multiTxBlockTx2.Hash(), + multiTxBlockTx3.Hash(), + }) + EVMKeeper.SetTxHashesOnHeight(Ctx, MockHeight, []common.Hash{ + multiTxBlockTx4.Hash(), + }) + EVMKeeper.SetBlockBloom(Ctx, MultiTxBlockHeight, []ethtypes.Bloom{bloom1, bloom2, bloom3}) + EVMKeeper.SetBlockBloom(Ctx, MockHeight, []ethtypes.Bloom{bloom4}) +} + +//nolint:deadcode +func sendRequestGood(t *testing.T, method string, params ...interface{}) map[string]interface{} { + return sendRequest(t, TestPort, method, params...) +} + +//nolint:deadcode +func sendRequestBad(t *testing.T, method string, params ...interface{}) map[string]interface{} { + return sendRequest(t, TestBadPort, method, params...) +} + +// nolint:deadcode +func sendRequestGoodWithNamespace(t *testing.T, namespace string, method string, params ...interface{}) map[string]interface{} { + return sendRequestWithNamespace(t, namespace, TestPort, method, params...) +} + +func sendRequest(t *testing.T, port int, method string, params ...interface{}) map[string]interface{} { + return sendRequestWithNamespace(t, "eth", port, method, params...) +} + +func sendRequestWithNamespace(t *testing.T, namespace string, port int, method string, params ...interface{}) map[string]interface{} { + paramsFormatted := "" + if len(params) > 0 { + paramsFormatted = strings.Join(utils.Map(params, formatParam), ",") + } + body := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"%s_%s\",\"params\":[%s],\"id\":\"test\"}", namespace, method, paramsFormatted) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, port), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + defer res.Body.Close() + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + return resObj +} + +func sendWSRequestGood(t *testing.T, method string, params ...interface{}) (chan map[string]interface{}, chan struct{}) { + return sendWSRequestAndListen(t, TestWSPort, method, params...) +} + +func sendWSRequestBad(t *testing.T, method string, params ...interface{}) (chan map[string]interface{}, chan struct{}) { + return sendWSRequestAndListen(t, TestBadPort, method, params...) +} + +func sendWSRequestAndListen(t *testing.T, port int, method string, params ...interface{}) (chan map[string]interface{}, chan struct{}) { + paramsFormatted := "" + if len(params) > 0 { + paramsFormatted = strings.Join(utils.Map(params, formatParam), ",") + } + body := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"eth_%s\",\"params\":[%s],\"id\":\"test\"}", method, paramsFormatted) + + headers := make(http.Header) + headers.Set("Origin", "localhost") + headers.Set("Content-Type", "application/json") + conn, _, err := websocket.DefaultDialer.Dial(fmt.Sprintf("ws://%s:%d", TestAddr, TestWSPort), headers) + require.Nil(t, err) + + recv := make(chan map[string]interface{}) + done := make(chan struct{}) + + err = conn.WriteMessage(websocket.TextMessage, []byte(body)) + require.Nil(t, err) + + go func() { + defer close(recv) + + // Set a read deadline to prevent blocking forever + conn.SetReadDeadline(time.Now().Add(1 * time.Second)) + + for { + select { + case <-done: + return + case <-time.After(200 * time.Millisecond): + _, message, err := conn.ReadMessage() + if err != nil { + if ne, ok := err.(net.Error); ok && ne.Timeout() { + // It was a timeout error, no data was ready to be read + continue // Retry the read operation + } + recv <- map[string]interface{}{"error": err.Error()} + return + } + res := map[string]interface{}{} + err = json.Unmarshal(message, &res) + if err != nil { + recv <- map[string]interface{}{"error": err.Error()} + return + } + recv <- res + } + } + }() + + return recv, done +} + +func formatParam(p interface{}) string { + if p == nil { + return "null" + } + switch v := p.(type) { + case bool: + if v { + return "true" + } + return "false" + case int: + return fmt.Sprintf("%d", v) + case float64: + return fmt.Sprintf("%f", v) + case string: + return fmt.Sprintf("\"%s\"", v) + case common.Address: + return fmt.Sprintf("\"%s\"", v) + case []common.Address: + wrapper := func(i common.Address) string { + return formatParam(i) + } + return fmt.Sprintf("[%s]", strings.Join(utils.Map(v, wrapper), ",")) + case common.Hash: + return fmt.Sprintf("\"%s\"", v) + case []common.Hash: + wrapper := func(i common.Hash) string { + return formatParam(i) + } + return fmt.Sprintf("[%s]", strings.Join(utils.Map(v, wrapper), ",")) + case [][]common.Hash: + wrapper := func(i []common.Hash) string { + return formatParam(i) + } + return fmt.Sprintf("[%s]", strings.Join(utils.Map(v, wrapper), ",")) + case []string: + return fmt.Sprintf("[%s]", strings.Join(v, ",")) + case []interface{}: + return fmt.Sprintf("[%s]", strings.Join(utils.Map(v, formatParam), ",")) + case map[string]interface{}: + kvs := []string{} + for k, v := range v { + kvs = append(kvs, fmt.Sprintf("\"%s\":%s", k, formatParam(v))) + } + return fmt.Sprintf("{%s}", strings.Join(kvs, ",")) + default: + panic("did not match on type") + } +} + +func TestEcho(t *testing.T) { + // Test HTTP server + body := "{\"jsonrpc\": \"2.0\",\"method\": \"echo_echo\",\"params\":[\"something\"],\"id\":\"test\"}" + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + require.Equal(t, "{\"jsonrpc\":\"2.0\",\"id\":\"test\",\"result\":\"something\"}\n", string(resBody)) + + // Test WS server + headers := make(http.Header) + headers.Set("Origin", "localhost") + headers.Set("Content-Type", "application/json") + conn, _, err := websocket.DefaultDialer.Dial(fmt.Sprintf("ws://%s:%d", TestAddr, TestWSPort), headers) + require.Nil(t, err) + require.Nil(t, conn.WriteMessage(websocket.TextMessage, []byte(body))) + _, buf, err := conn.ReadMessage() + require.Nil(t, err) + require.Equal(t, "{\"jsonrpc\":\"2.0\",\"id\":\"test\",\"result\":\"something\"}\n", string(buf)) +} diff --git a/evmrpc/simulate.go b/evmrpc/simulate.go new file mode 100644 index 0000000000..8e82ef1b3c --- /dev/null +++ b/evmrpc/simulate.go @@ -0,0 +1,384 @@ +package evmrpc + +import ( + "context" + "errors" + "fmt" + "math/big" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/lib/ethapi" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + rpcclient "github.com/tendermint/tendermint/rpc/client" + "github.com/tendermint/tendermint/rpc/coretypes" +) + +type SimulationAPI struct { + backend *Backend +} + +func NewSimulationAPI( + ctxProvider func(int64) sdk.Context, + keeper *keeper.Keeper, + txDecoder sdk.TxDecoder, + tmClient rpcclient.Client, + config *SimulateConfig, +) *SimulationAPI { + return &SimulationAPI{ + backend: NewBackend(ctxProvider, keeper, txDecoder, tmClient, config), + } +} + +type AccessListResult struct { + Accesslist *ethtypes.AccessList `json:"accessList"` + Error string `json:"error,omitempty"` + GasUsed hexutil.Uint64 `json:"gasUsed"` +} + +func (s *SimulationAPI) CreateAccessList(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (result *AccessListResult, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_createAccessList", startTime, returnErr == nil) + bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) + if blockNrOrHash != nil { + bNrOrHash = *blockNrOrHash + } + acl, gasUsed, vmerr, err := ethapi.AccessList(ctx, s.backend, bNrOrHash, args) + if err != nil { + return nil, err + } + result = &AccessListResult{Accesslist: &acl, GasUsed: hexutil.Uint64(gasUsed)} + if vmerr != nil { + result.Error = vmerr.Error() + } + return result, nil +} + +func (s *SimulationAPI) EstimateGas(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *ethapi.StateOverride) (result hexutil.Uint64, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_estimateGas", startTime, returnErr == nil) + bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) + if blockNrOrHash != nil { + bNrOrHash = *blockNrOrHash + } + estimate, err := ethapi.DoEstimateGas(ctx, s.backend, args, bNrOrHash, overrides, s.backend.RPCGasCap()) + return estimate, err +} + +func (s *SimulationAPI) Call(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *ethapi.StateOverride, blockOverrides *ethapi.BlockOverrides) (result hexutil.Bytes, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_call", startTime, returnErr == nil) + if blockNrOrHash == nil { + latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) + blockNrOrHash = &latest + } + callResult, err := ethapi.DoCall(ctx, s.backend, args, *blockNrOrHash, overrides, blockOverrides, s.backend.RPCEVMTimeout(), s.backend.RPCGasCap()) + if err != nil { + return nil, err + } + // If the result contains a revert reason, try to unpack and return it. + if len(callResult.Revert()) > 0 { + return nil, NewRevertError(callResult) + } + return callResult.Return(), callResult.Err +} + +func NewRevertError(result *core.ExecutionResult) *RevertError { + reason, errUnpack := abi.UnpackRevert(result.Revert()) + err := errors.New("execution reverted") + if errUnpack == nil { + err = fmt.Errorf("execution reverted: %v", reason) + } + return &RevertError{ + error: err, + reason: hexutil.Encode(result.Revert()), + } +} + +// RevertError is an API error that encompasses an EVM revertal with JSON error +// code and a binary data blob. +type RevertError struct { + error + reason string // revert reason hex encoded +} + +// ErrorCode returns the JSON error code for a revertal. +// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal +func (e *RevertError) ErrorCode() int { + return 3 +} + +// ErrorData returns the hex encoded revert reason. +func (e *RevertError) ErrorData() interface{} { + return e.reason +} + +type SimulateConfig struct { + GasCap uint64 + EVMTimeout time.Duration +} + +var _ tracers.Backend = (*Backend)(nil) + +type Backend struct { + *eth.EthAPIBackend + ctxProvider func(int64) sdk.Context + txDecoder sdk.TxDecoder + keeper *keeper.Keeper + tmClient rpcclient.Client + config *SimulateConfig +} + +func NewBackend(ctxProvider func(int64) sdk.Context, keeper *keeper.Keeper, txDecoder sdk.TxDecoder, tmClient rpcclient.Client, config *SimulateConfig) *Backend { + return &Backend{ + ctxProvider: ctxProvider, + keeper: keeper, + txDecoder: txDecoder, + tmClient: tmClient, + config: config, + } +} + +func (b *Backend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (vm.StateDB, *ethtypes.Header, error) { + height, err := b.getBlockHeight(ctx, blockNrOrHash) + if err != nil { + return nil, nil, err + } + sdkCtx := b.ctxProvider(height) + if err := CheckVersion(sdkCtx, b.keeper); err != nil { + return nil, nil, err + } + return state.NewDBImpl(b.ctxProvider(height), b.keeper, true), b.getHeader(big.NewInt(height)), nil +} + +func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (tx *ethtypes.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, err error) { + sdkCtx := b.ctxProvider(LatestCtxHeight) + receipt, err := b.keeper.GetReceipt(sdkCtx, txHash) + if err != nil { + return nil, common.Hash{}, 0, 0, err + } + txHeight := int64(receipt.BlockNumber) + block, err := blockByNumber(ctx, b.tmClient, &txHeight) + if err != nil { + return nil, common.Hash{}, 0, 0, err + } + txIndex := hexutil.Uint(receipt.TransactionIndex) + tmTx := block.Block.Txs[int(txIndex)] + // We need to find the ethIndex + evmTxIndex, found := GetEvmTxIndex(block.Block.Txs, receipt.TransactionIndex, b.txDecoder) + if !found { + return nil, common.Hash{}, 0, 0, errors.New("failed to find transaction in block") + } + tx = getEthTxForTxBz(tmTx, b.txDecoder) + blockHash = common.BytesToHash(block.Block.Header.Hash().Bytes()) + return tx, blockHash, uint64(txHeight), uint64(evmTxIndex), nil +} + +func (b *Backend) ChainDb() ethdb.Database { + panic("implement me") +} + +func (b Backend) BlockByNumber(ctx context.Context, bn rpc.BlockNumber) (*ethtypes.Block, error) { + blockNum := bn.Int64() + tmBlock, err := blockByNumber(ctx, b.tmClient, &blockNum) + if err != nil { + return nil, err + } + blockRes, err := b.tmClient.BlockResults(ctx, &tmBlock.Block.Height) + if err != nil { + return nil, err + } + var txs []*ethtypes.Transaction + for i := range blockRes.TxsResults { + decoded, err := b.txDecoder(tmBlock.Block.Txs[i]) + if err != nil { + return nil, err + } + for _, msg := range decoded.GetMsgs() { + switch m := msg.(type) { + case *types.MsgEVMTransaction: + if m.IsAssociateTx() { + continue + } + ethtx, _ := m.AsTransaction() + txs = append(txs, ethtx) + } + } + } + header := b.getHeader(big.NewInt(bn.Int64())) + block := ðtypes.Block{ + Header_: header, + Txs: txs, + } + return block, nil +} + +func (b Backend) BlockByHash(ctx context.Context, hash common.Hash) (*ethtypes.Block, error) { + tmBlock, err := blockByHash(ctx, b.tmClient, hash.Bytes()) + if err != nil { + return nil, err + } + blockNumber := rpc.BlockNumber(tmBlock.Block.Height) + return b.BlockByNumber(ctx, blockNumber) +} + +func (b *Backend) RPCGasCap() uint64 { return b.config.GasCap } + +func (b *Backend) RPCEVMTimeout() time.Duration { return b.config.EVMTimeout } + +func (b *Backend) ChainConfig() *params.ChainConfig { + ctx := b.ctxProvider(LatestCtxHeight) + return types.DefaultChainConfig().EthereumConfig(b.keeper.ChainID(ctx)) +} + +func (b *Backend) GetPoolNonce(_ context.Context, addr common.Address) (uint64, error) { + return state.NewDBImpl(b.ctxProvider(LatestCtxHeight), b.keeper, true).GetNonce(addr), nil +} + +func (b *Backend) Engine() consensus.Engine { + return &Engine{ctxProvider: b.ctxProvider, keeper: b.keeper} +} + +func (b *Backend) HeaderByNumber(ctx context.Context, bn rpc.BlockNumber) (*ethtypes.Header, error) { + height, err := b.getBlockHeight(ctx, rpc.BlockNumberOrHashWithNumber(bn)) + if err != nil { + return nil, err + } + return b.getHeader(big.NewInt(height)), nil +} + +func (b *Backend) StateAtTransaction(ctx context.Context, block *ethtypes.Block, txIndex int, reexec uint64) (*ethtypes.Transaction, vm.BlockContext, vm.StateDB, tracers.StateReleaseFunc, error) { + emptyRelease := func() {} + // Short circuit if it's genesis block. + if block.Number().Int64() == 0 { + return nil, vm.BlockContext{}, nil, emptyRelease, errors.New("no transaction in genesis") + } + // get the parent block using block.parentHash + prevBlockHeight := block.Number().Int64() - 1 + // Get statedb of parent block from the store + statedb := state.NewDBImpl(b.ctxProvider(prevBlockHeight), b.keeper, true) + if txIndex == 0 && len(block.Transactions()) == 0 { + return nil, vm.BlockContext{}, statedb, emptyRelease, nil + } + // 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()) + txContext := core.NewEVMTxContext(msg) + blockContext, err := b.keeper.GetVMBlockContext(b.ctxProvider(prevBlockHeight), core.GasPool(b.RPCGasCap())) + if err != nil { + return nil, vm.BlockContext{}, nil, nil, err + } + // set block context time as of the block time (block time is the time of the CURRENT block) + blockContext.Time = block.Time() + + if idx == txIndex { + return tx, *blockContext, statedb, emptyRelease, nil + } + // Not yet the searched for transaction, execute on top of the current state + vmenv := vm.NewEVM(*blockContext, txContext, statedb, b.ChainConfig(), vm.Config{}) + statedb.SetTxContext(tx.Hash(), idx) + if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) + } + // Ensure any modifications are committed to the state + // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect + statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number())) + } + return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) +} + +func (b *Backend) StateAtBlock(ctx context.Context, block *ethtypes.Block, reexec uint64, base vm.StateDB, readOnly bool, preferDisk bool) (vm.StateDB, tracers.StateReleaseFunc, error) { + emptyRelease := func() {} + statedb := state.NewDBImpl(b.ctxProvider(block.Number().Int64()-1), b.keeper, true) + return statedb, emptyRelease, nil +} + +func (b *Backend) GetEVM(_ context.Context, msg *core.Message, stateDB vm.StateDB, _ *ethtypes.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { + txContext := core.NewEVMTxContext(msg) + 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 +} + +func (b *Backend) CurrentHeader() *ethtypes.Header { + return b.getHeader(big.NewInt(b.ctxProvider(LatestCtxHeight).BlockHeight())) +} + +func (b *Backend) SuggestGasTipCap(context.Context) (*big.Int, error) { + return utils.Big0, nil +} + +func (b *Backend) getBlockHeight(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (int64, error) { + var block *coretypes.ResultBlock + var err error + if blockNr, ok := blockNrOrHash.Number(); ok { + blockNumber, blockNumErr := getBlockNumber(ctx, b.tmClient, blockNr) + if blockNumErr != nil { + return 0, blockNumErr + } + if blockNumber == nil { + // we don't want to get the latest block from Tendermint's perspective, because + // Tendermint writes store in TM store before commits application state. The + // latest block in Tendermint may not have its application state committed yet. + currentHeight := b.ctxProvider(LatestCtxHeight).BlockHeight() + blockNumber = ¤tHeight + } + block, err = blockByNumber(ctx, b.tmClient, blockNumber) + } else { + block, err = blockByHash(ctx, b.tmClient, blockNrOrHash.BlockHash[:]) + } + if err != nil { + return 0, err + } + return block.Block.Height, nil +} + +func (b *Backend) getHeader(blockNumber *big.Int) *ethtypes.Header { + header := ðtypes.Header{ + Difficulty: common.Big0, + Number: blockNumber, + BaseFee: b.keeper.GetBaseFeePerGas(b.ctxProvider(LatestCtxHeight)).BigInt(), + GasLimit: b.config.GasCap, + Time: uint64(time.Now().Unix()), + } + number := blockNumber.Int64() + block, err := blockByNumber(context.Background(), b.tmClient, &number) + //TODO: what should happen if an err occurs here? + if err == nil { + header.ParentHash = common.BytesToHash(block.BlockID.Hash) + header.Time = uint64(block.Block.Header.Time.Unix()) + } + return header +} + +type Engine struct { + *ethash.Ethash + ctxProvider func(int64) sdk.Context + keeper *keeper.Keeper +} + +func (e *Engine) Author(*ethtypes.Header) (common.Address, error) { + return e.keeper.GetFeeCollectorAddress(e.ctxProvider(LatestCtxHeight)) +} diff --git a/evmrpc/simulate_test.go b/evmrpc/simulate_test.go new file mode 100644 index 0000000000..28b5a06f03 --- /dev/null +++ b/evmrpc/simulate_test.go @@ -0,0 +1,140 @@ +package evmrpc_test + +import ( + "encoding/hex" + "fmt" + "math/big" + "os" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/core" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/sei-protocol/sei-chain/example/contracts/simplestorage" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestEstimateGas(t *testing.T) { + Ctx = Ctx.WithBlockHeight(1) + // transfer + _, from := testkeeper.MockAddressPair() + _, to := testkeeper.MockAddressPair() + txArgs := map[string]interface{}{ + "from": from.Hex(), + "to": to.Hex(), + "value": "0x10", + "nonce": "0x1", + "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID(Ctx)), + } + amts := sdk.NewCoins(sdk.NewCoin(EVMKeeper.GetBaseDenom(Ctx), sdk.NewInt(20))) + EVMKeeper.BankKeeper().MintCoins(Ctx, types.ModuleName, amts) + EVMKeeper.BankKeeper().SendCoinsFromModuleToAccount(Ctx, types.ModuleName, sdk.AccAddress(from[:]), amts) + resObj := sendRequestGood(t, "estimateGas", txArgs, nil, map[string]interface{}{}) + result := resObj["result"].(string) + require.Equal(t, "0x5208", result) // 21000 + resObj = sendRequestGood(t, "estimateGas", txArgs, "latest", map[string]interface{}{}) + result = resObj["result"].(string) + require.Equal(t, "0x5208", result) // 21000 + resObj = sendRequestGood(t, "estimateGas", txArgs, "0x123456", map[string]interface{}{}) + result = resObj["result"].(string) + require.Equal(t, "0x5208", result) // 21000 + + // contract call + _, contractAddr := testkeeper.MockAddressPair() + code, err := os.ReadFile("../example/contracts/simplestorage/SimpleStorage.bin") + require.Nil(t, err) + bz, err := hex.DecodeString(string(code)) + require.Nil(t, err) + abi, err := simplestorage.SimplestorageMetaData.GetAbi() + require.Nil(t, err) + input, err := abi.Pack("set", big.NewInt(20)) + require.Nil(t, err) + EVMKeeper.SetCode(Ctx, contractAddr, bz) + txArgs = map[string]interface{}{ + "from": from.Hex(), + "to": contractAddr.Hex(), + "value": "0x0", + "nonce": "0x2", + "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID(Ctx)), + "input": fmt.Sprintf("%#x", input), + } + resObj = sendRequestGood(t, "estimateGas", txArgs, nil, map[string]interface{}{}) + result = resObj["result"].(string) + require.Equal(t, "0x53f3", result) // 21491 + + Ctx = Ctx.WithBlockHeight(8) +} + +func TestCreateAccessList(t *testing.T) { + Ctx = Ctx.WithBlockHeight(1) + + _, from := testkeeper.MockAddressPair() + _, contractAddr := testkeeper.MockAddressPair() + code, err := os.ReadFile("../example/contracts/simplestorage/SimpleStorage.bin") + require.Nil(t, err) + bz, err := hex.DecodeString(string(code)) + require.Nil(t, err) + abi, err := simplestorage.SimplestorageMetaData.GetAbi() + require.Nil(t, err) + input, err := abi.Pack("set", big.NewInt(20)) + require.Nil(t, err) + EVMKeeper.SetCode(Ctx, contractAddr, bz) + txArgs := map[string]interface{}{ + "from": from.Hex(), + "to": contractAddr.Hex(), + "value": "0x0", + "nonce": "0x1", + "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID(Ctx)), + "input": fmt.Sprintf("%#x", input), + } + amts := sdk.NewCoins(sdk.NewCoin(EVMKeeper.GetBaseDenom(Ctx), sdk.NewInt(20))) + EVMKeeper.BankKeeper().MintCoins(Ctx, types.ModuleName, amts) + EVMKeeper.BankKeeper().SendCoinsFromModuleToAccount(Ctx, types.ModuleName, sdk.AccAddress(from[:]), amts) + resObj := sendRequestGood(t, "createAccessList", txArgs, "latest") + result := resObj["result"].(map[string]interface{}) + require.Equal(t, []interface{}{}, result["accessList"]) // the code uses MSTORE which does not trace access list + + resObj = sendRequestBad(t, "createAccessList", txArgs, "latest") + result = resObj["error"].(map[string]interface{}) + require.Equal(t, "error block", result["message"]) + + Ctx = Ctx.WithBlockHeight(8) +} + +func TestCall(t *testing.T) { + Ctx = Ctx.WithBlockHeight(1) + + _, from := testkeeper.MockAddressPair() + _, contractAddr := testkeeper.MockAddressPair() + code, err := os.ReadFile("../example/contracts/simplestorage/SimpleStorage.bin") + require.Nil(t, err) + bz, err := hex.DecodeString(string(code)) + require.Nil(t, err) + abi, err := simplestorage.SimplestorageMetaData.GetAbi() + require.Nil(t, err) + input, err := abi.Pack("set", big.NewInt(20)) + require.Nil(t, err) + EVMKeeper.SetCode(Ctx, contractAddr, bz) + txArgs := map[string]interface{}{ + "from": from.Hex(), + "to": contractAddr.Hex(), + "value": "0x0", + "nonce": "0x2", + "chainId": fmt.Sprintf("%#x", EVMKeeper.ChainID(Ctx)), + "input": fmt.Sprintf("%#x", input), + } + resObj := sendRequestGood(t, "call", txArgs, nil, map[string]interface{}{}, map[string]interface{}{}) + result := resObj["result"].(string) + require.Equal(t, "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c806360fe47b1146100385780636d4ce63c14610054575b5f80fd5b610052600480360381019061004d91906100f1565b610072565b005b61005c6100b2565b604051610069919061012b565b60405180910390f35b805f819055507f0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1816040516100a7919061012b565b60405180910390a150565b5f8054905090565b5f80fd5b5f819050919050565b6100d0816100be565b81146100da575f80fd5b50565b5f813590506100eb816100c7565b92915050565b5f60208284031215610106576101056100ba565b5b5f610113848285016100dd565b91505092915050565b610125816100be565b82525050565b5f60208201905061013e5f83018461011c565b9291505056fea26469706673582212205b2eaa3bd967fbbfe4490610612964348d1d0b2a793d2b0d117fe05ccb02d1e364736f6c63430008150033", result) // 21325 + + Ctx = Ctx.WithBlockHeight(8) +} + +func TestNewRevertError(t *testing.T) { + err := evmrpc.NewRevertError(&core.ExecutionResult{}) + require.NotNil(t, err) + require.Equal(t, 3, err.ErrorCode()) + require.Equal(t, "0x", err.ErrorData()) +} diff --git a/evmrpc/state.go b/evmrpc/state.go new file mode 100644 index 0000000000..7b5a73f63b --- /dev/null +++ b/evmrpc/state.go @@ -0,0 +1,182 @@ +package evmrpc + +import ( + "context" + "encoding/hex" + "errors" + "fmt" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/store/cachekv" + iavlstore "github.com/cosmos/cosmos-sdk/store/iavl" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/proto/tendermint/crypto" + rpcclient "github.com/tendermint/tendermint/rpc/client" + "github.com/tendermint/tendermint/rpc/coretypes" +) + +type StateAPI struct { + tmClient rpcclient.Client + keeper *keeper.Keeper + ctxProvider func(int64) sdk.Context +} + +func NewStateAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context) *StateAPI { + return &StateAPI{tmClient: tmClient, keeper: k, ctxProvider: ctxProvider} +} + +func (a *StateAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (result *hexutil.Big, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getBalance", startTime, returnErr == nil) + block, err := GetBlockNumberByNrOrHash(ctx, a.tmClient, blockNrOrHash) + if err != nil { + return nil, err + } + sdkCtx := a.ctxProvider(LatestCtxHeight) + if block != nil { + sdkCtx = a.ctxProvider(*block) + if err := CheckVersion(sdkCtx, a.keeper); err != nil { + return nil, err + } + } + statedb := state.NewDBImpl(sdkCtx, a.keeper, true) + return (*hexutil.Big)(statedb.GetBalance(address)), nil +} + +func (a *StateAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (result hexutil.Bytes, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getCode", startTime, returnErr == nil) + block, err := GetBlockNumberByNrOrHash(ctx, a.tmClient, blockNrOrHash) + if err != nil { + return nil, err + } + sdkCtx := a.ctxProvider(LatestCtxHeight) + if block != nil { + sdkCtx = a.ctxProvider(*block) + if err := CheckVersion(sdkCtx, a.keeper); err != nil { + return nil, err + } + } + code := a.keeper.GetCode(sdkCtx, address) + return code, nil +} + +func (a *StateAPI) GetStorageAt(ctx context.Context, address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (result hexutil.Bytes, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getStorageAt", startTime, returnErr == nil) + block, err := GetBlockNumberByNrOrHash(ctx, a.tmClient, blockNrOrHash) + if err != nil { + return nil, err + } + sdkCtx := a.ctxProvider(LatestCtxHeight) + if block != nil { + sdkCtx = a.ctxProvider(*block) + if err := CheckVersion(sdkCtx, a.keeper); err != nil { + return nil, err + } + } + key, _, err := decodeHash(hexKey) + if err != nil { + return nil, fmt.Errorf("unable to decode storage key: %s", err) + } + state := a.keeper.GetState(sdkCtx, address, key) + return state[:], nil +} + +// Result structs for GetProof +// This differs from go-ethereum AccountResult in two ways: +// 1. Proof object is an iavl proof, not a trie proof +// 2. Per-account fields are excluded because there is no per-account root +type ProofResult struct { + Address common.Address `json:"address"` + HexValues []string `json:"hexValues"` + StorageProof []*crypto.ProofOps `json:"storageProof"` +} + +func (a *StateAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (result *ProofResult, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getProof", startTime, returnErr == nil) + var block *coretypes.ResultBlock + var err error + if blockNr, ok := blockNrOrHash.Number(); ok { + blockNumber, blockNumErr := getBlockNumber(ctx, a.tmClient, blockNr) + if blockNumErr != nil { + return nil, blockNumErr + } + block, err = blockByNumber(ctx, a.tmClient, blockNumber) + } else { + block, err = blockByHash(ctx, a.tmClient, blockNrOrHash.BlockHash[:]) + } + if err != nil { + return nil, err + } + sdkCtx := a.ctxProvider(block.Block.Height) + if err := CheckVersion(sdkCtx, a.keeper); err != nil { + return nil, err + } + var iavl *iavlstore.Store + s := sdkCtx.MultiStore().GetKVStore((a.keeper.GetStoreKey())) +OUTER: + for { + switch cast := s.(type) { + case *iavlstore.Store: + iavl = cast + break OUTER + case *cachekv.Store: + if cast.GetParent() == nil { + return nil, errors.New("cannot find EVM IAVL store") + } + s = cast.GetParent() + default: + return nil, errors.New("cannot find EVM IAVL store") + } + } + proofResult := ProofResult{Address: address} + for _, key := range storageKeys { + paddedKey := common.BytesToHash([]byte(key)) + formattedKey := append(types.StateKey(address), paddedKey[:]...) + qres := iavl.Query(abci.RequestQuery{ + Path: "/key", + Data: formattedKey, + Height: block.Block.Height, + Prove: true, + }) + proofResult.HexValues = append(proofResult.HexValues, hex.EncodeToString(qres.Value)) + proofResult.StorageProof = append(proofResult.StorageProof, qres.ProofOps) + } + + return &proofResult, nil +} + +func (a *StateAPI) GetNonce(_ context.Context, address common.Address) uint64 { + startTime := time.Now() + defer recordMetrics("eth_getNonce", startTime, true) + return a.keeper.GetNonce(a.ctxProvider(LatestCtxHeight), address) +} + +// decodeHash parses a hex-encoded 32-byte hash. The input may optionally +// be prefixed by 0x and can have a byte length up to 32. +func decodeHash(s string) (h common.Hash, inputLength int, err error) { + if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") { + s = s[2:] + } + if (len(s) & 1) > 0 { + s = "0" + s + } + b, err := hex.DecodeString(s) + if err != nil { + return common.Hash{}, 0, errors.New("hex string invalid") + } + if len(b) > 32 { + return common.Hash{}, len(b), errors.New("hex string too long, want at most 32 bytes") + } + return common.BytesToHash(b), len(b), nil +} diff --git a/evmrpc/state_test.go b/evmrpc/state_test.go new file mode 100644 index 0000000000..a6801984f8 --- /dev/null +++ b/evmrpc/state_test.go @@ -0,0 +1,251 @@ +package evmrpc_test + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rpc" + "github.com/sei-protocol/sei-chain/app" + "github.com/sei-protocol/sei-chain/evmrpc" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" +) + +func TestGetBalance(t *testing.T) { + Ctx = Ctx.WithBlockHeight(1) + tests := []struct { + name string + addr string + blockNr string + wantErr bool + wantAmount string + }{ + { + name: "latest block", + addr: "0x1234567890123456789023456789012345678901", + blockNr: "latest", + wantErr: false, + wantAmount: "0x38d7ea4c68000", + }, + { + name: "safe block", + addr: "0x1234567890123456789023456789012345678901", + blockNr: "safe", + wantErr: false, + wantAmount: "0x38d7ea4c68000", + }, + { + name: "finalized block", + addr: "0x1234567890123456789023456789012345678901", + blockNr: "finalized", + wantErr: false, + wantAmount: "0x38d7ea4c68000", + }, + { + name: "pending block", + addr: "0x1234567890123456789023456789012345678901", + blockNr: "pending", + wantErr: false, + wantAmount: "0x38d7ea4c68000", + }, + { + name: "evm address with sei address mapping", + addr: common.HexToAddress(common.Bytes2Hex([]byte("evmAddr"))).String(), + blockNr: "latest", + wantErr: false, + wantAmount: "0x9184e72a000", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + body := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"eth_getBalance\",\"params\":[\"%s\",\"%s\"],\"id\":\"test\"}", tt.addr, tt.blockNr) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + if tt.wantErr { + _, ok := resObj["error"] + require.True(t, ok) + } else { + _, ok := resObj["error"] + require.False(t, ok) + require.Equal(t, tt.wantAmount, resObj["result"]) + } + }) + } + Ctx = Ctx.WithBlockHeight(8) +} + +func TestGetCode(t *testing.T) { + Ctx = Ctx.WithBlockHeight(1) + wantKey := "0x" + hex.EncodeToString([]byte("abc")) + tests := []struct { + name string + blockNr string + wantErr bool + }{ + { + name: "latest block", + blockNr: "latest", + wantErr: false, + }, + { + name: "safe block", + blockNr: "safe", + wantErr: false, + }, + { + name: "finalized block", + blockNr: "finalized", + wantErr: false, + }, + { + name: "pending block", + blockNr: "pending", + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + body := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"eth_getCode\",\"params\":[\"0x1234567890123456789023456789012345678901\",\"%s\"],\"id\":\"test\"}", tt.blockNr) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + if tt.wantErr { + _, ok := resObj["error"] + require.True(t, ok) + } else { + _, ok := resObj["error"] + require.False(t, ok) + got := resObj["result"] + require.Equal(t, wantKey, got) + } + }) + } + Ctx = Ctx.WithBlockHeight(8) +} + +func TestGetStorageAt(t *testing.T) { + Ctx = Ctx.WithBlockHeight(1) + hexValue := common.BytesToHash([]byte("value")) + wantValue := "0x" + hex.EncodeToString(hexValue[:]) + tests := []struct { + name string + blockNr string + wantErr bool + }{ + { + name: "latest block", + blockNr: "latest", + wantErr: false, + }, + { + name: "safe block", + blockNr: "safe", + wantErr: false, + }, + { + name: "finalized block", + blockNr: "finalized", + wantErr: false, + }, + { + name: "pending block", + blockNr: "pending", + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + hexKey := common.BytesToHash([]byte("key")) + body := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"eth_getStorageAt\",\"params\":[\"0x1234567890123456789023456789012345678901\",\"%s\",\"%s\"],\"id\":\"test\"}", hexKey, tt.blockNr) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + if tt.wantErr { + _, ok := resObj["error"] + require.True(t, ok) + } else { + _, ok := resObj["error"] + require.False(t, ok) + got := resObj["result"] + require.Equal(t, wantValue, got) + } + }) + } + Ctx = Ctx.WithBlockHeight(8) +} + +func TestGetProof(t *testing.T) { + testApp := app.Setup(false, false) + _, evmAddr := testkeeper.MockAddressPair() + key, val := []byte("test"), []byte("abc") + testApp.EvmKeeper.SetState(testApp.GetContextForDeliverTx([]byte{}), evmAddr, common.BytesToHash(key), common.BytesToHash(val)) + for i := 0; i < MockHeight; i++ { + testApp.FinalizeBlock(context.Background(), &abci.RequestFinalizeBlock{Height: int64(i + 1)}) + testApp.SetDeliverStateToCommit() + _, err := testApp.Commit(context.Background()) + require.Nil(t, err) + } + stateAPI := evmrpc.NewStateAPI(&MockClient{}, &testApp.EvmKeeper, func(int64) sdk.Context { return testApp.GetCheckCtx() }) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000616263", testApp.EvmKeeper.GetState(testApp.GetCheckCtx(), evmAddr, common.BytesToHash(key)).Hex()) + tests := []struct { + key string + blockNr rpc.BlockNumber + expectedVal []byte + }{ + { + key: string(key), + blockNr: rpc.BlockNumber(-2), + expectedVal: val, + }, + { + key: string(key), + blockNr: rpc.BlockNumber(8), + expectedVal: val, + }, + { + key: "non existent", + blockNr: rpc.BlockNumber(-2), + expectedVal: []byte{}, + }, + } + for _, test := range tests { + bptr := &rpc.BlockNumberOrHash{BlockNumber: &test.blockNr} + res, err := stateAPI.GetProof(context.Background(), evmAddr, []string{test.key}, *bptr) + require.Nil(t, err) + vals := res.HexValues + require.Equal(t, common.BytesToHash(test.expectedVal), common.HexToHash(vals[0])) + proofs := res.StorageProof + require.Equal(t, "ics23:iavl", proofs[0].Ops[0].Type) + } +} diff --git a/evmrpc/subscribe.go b/evmrpc/subscribe.go new file mode 100644 index 0000000000..bdb073f98d --- /dev/null +++ b/evmrpc/subscribe.go @@ -0,0 +1,224 @@ +package evmrpc + +import ( + "context" + "fmt" + "math/big" + "sync" + "time" + + "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/eth/filters" + "github.com/ethereum/go-ethereum/rpc" + "github.com/sei-protocol/sei-chain/utils" + rpcclient "github.com/tendermint/tendermint/rpc/client" + "github.com/tendermint/tendermint/rpc/coretypes" + tmtypes "github.com/tendermint/tendermint/types" +) + +const SleepInterval = 5 * time.Second + +type SubscriptionAPI struct { + tmClient rpcclient.Client + subscriptionManager *SubscriptionManager + subscriptonConfig *SubscriptionConfig + + logFetcher *LogFetcher +} + +type SubscriptionConfig struct { + subscriptionCapacity int +} + +func NewSubscriptionAPI(tmClient rpcclient.Client, logFetcher *LogFetcher, subscriptionConfig *SubscriptionConfig) *SubscriptionAPI { + return &SubscriptionAPI{ + tmClient: tmClient, + subscriptionManager: NewSubscriptionManager(tmClient), + subscriptonConfig: subscriptionConfig, + logFetcher: logFetcher, + } +} + +func (a *SubscriptionAPI) NewHeads(ctx context.Context) (*rpc.Subscription, error) { + notifier, supported := rpc.NotifierFromContext(ctx) + if !supported { + return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported + } + + rpcSub := notifier.CreateSubscription() + subscriberID, subCh, err := a.subscriptionManager.Subscribe(context.Background(), NewHeadQueryBuilder(), a.subscriptonConfig.subscriptionCapacity) + if err != nil { + return nil, err + } + + go func() { + defer func() { + _ = a.subscriptionManager.Unsubscribe(context.Background(), subscriberID) + }() + for { + select { + case res := <-subCh: + ethHeader, err := encodeTmHeader(res.Data.(tmtypes.EventDataNewBlockHeader)) + if err != nil { + return + } + err = notifier.Notify(rpcSub.ID, ethHeader) + if err != nil { + return + } + case <-rpcSub.Err(): + return + case <-notifier.Closed(): + return + } + } + }() + return rpcSub, nil +} + +func (a *SubscriptionAPI) Logs(ctx context.Context, filter *filters.FilterCriteria) (*rpc.Subscription, error) { + notifier, supported := rpc.NotifierFromContext(ctx) + if !supported { + return &rpc.Subscription{}, rpc.ErrNotificationsUnsupported + } + + rpcSub := notifier.CreateSubscription() + + if filter.BlockHash != nil { + go func() { + logs, _, err := a.logFetcher.GetLogsByFilters(ctx, *filter, 0) + if err != nil { + _ = notifier.Notify(rpcSub.ID, err) + return + } + for _, log := range logs { + if err := notifier.Notify(rpcSub.ID, log); err != nil { + return + } + } + }() + return rpcSub, nil + } + + go func() { + begin := int64(0) + for { + logs, lastToHeight, err := a.logFetcher.GetLogsByFilters(ctx, *filter, begin) + if err != nil { + _ = notifier.Notify(rpcSub.ID, err) + return + } + for _, log := range logs { + if err := notifier.Notify(rpcSub.ID, log); err != nil { + return + } + } + if filter.ToBlock != nil && lastToHeight >= filter.ToBlock.Int64() { + return + } + begin = lastToHeight + + time.Sleep(SleepInterval) + } + }() + + return rpcSub, nil +} + +const SubscriberPrefix = "evm.rpc." + +type SubscriberID uint64 + +type SubInfo struct { + Query string + SubscriptionCh <-chan coretypes.ResultEvent +} + +type SubscriptionManager struct { + subMu sync.Mutex + NextID SubscriberID + SubscriptionInfo map[SubscriberID]SubInfo + tmClient rpcclient.Client +} + +func NewSubscriptionManager(tmClient rpcclient.Client) *SubscriptionManager { + return &SubscriptionManager{ + subMu: sync.Mutex{}, + NextID: 1, + SubscriptionInfo: make(map[SubscriberID]SubInfo), + tmClient: tmClient, + } +} + +func (s *SubscriptionManager) Subscribe(ctx context.Context, q *QueryBuilder, limit int) (SubscriberID, <-chan coretypes.ResultEvent, error) { + query := q.Build() + s.subMu.Lock() + defer s.subMu.Unlock() + id := s.NextID + // ignore deprecation here since the new endpoint does not support polling + //nolint:staticcheck + res, err := s.tmClient.Subscribe(ctx, fmt.Sprintf("%s%d", SubscriberPrefix, id), query, limit) + if err != nil { + return 0, nil, err + } + s.SubscriptionInfo[id] = SubInfo{Query: query, SubscriptionCh: res} + s.NextID++ + return id, res, nil +} + +func (s *SubscriptionManager) Unsubscribe(ctx context.Context, id SubscriberID) error { + s.subMu.Lock() + defer s.subMu.Unlock() + // ignore deprecation here since the new endpoint does not support polling + //nolint:staticcheck + err := s.tmClient.Unsubscribe(ctx, SubscriberPrefix, s.SubscriptionInfo[id].Query) + if err != nil { + return err + } + delete(s.SubscriptionInfo, id) + return nil +} + +func encodeTmHeader( + header tmtypes.EventDataNewBlockHeader, +) (map[string]interface{}, error) { + blockHash := common.HexToHash(header.Header.Hash().String()) + number := big.NewInt(header.Header.Height) + miner := common.HexToAddress(header.Header.ProposerAddress.String()) + gasLimit, gasWanted := int64(0), int64(0) + lastHash := common.HexToHash(header.Header.LastBlockID.Hash.String()) + resultHash := common.HexToHash(header.Header.LastResultsHash.String()) + appHash := common.HexToHash(header.Header.AppHash.String()) + txHash := common.HexToHash(header.Header.DataHash.String()) + for _, txRes := range header.ResultFinalizeBlock.TxResults { + gasLimit += txRes.GasWanted + gasWanted += txRes.GasUsed + } + result := map[string]interface{}{ + "difficulty": (*hexutil.Big)(utils.Big0), // inapplicable to Sei + "extraData": hexutil.Bytes{}, // inapplicable to Sei + "gasLimit": hexutil.Uint64(gasLimit), + "gasUsed": hexutil.Uint64(gasWanted), + "logsBloom": ethtypes.Bloom{}, // inapplicable to Sei + "miner": miner, + "nonce": ethtypes.BlockNonce{}, // inapplicable to Sei + "number": (*hexutil.Big)(number), + "parentHash": lastHash, + "receiptsRoot": resultHash, + "sha3Uncles": common.Hash{}, // inapplicable to Sei + "stateRoot": appHash, + "timestamp": hexutil.Uint64(header.Header.Time.Unix()), + "transactionsRoot": txHash, + "mixHash": common.Hash{}, // inapplicable to Sei + "excessBlobGas": hexutil.Uint64(0), // inapplicable to Sei + "parentBeaconBlockRoot": common.Hash{}, // inapplicable to Sei + "hash": blockHash, + "withdrawlsRoot": common.Hash{}, // inapplicable to Sei + "baseFeePerGas": hexutil.Uint64(0), // inapplicable to Sei + "withdrawalsRoot": common.Hash{}, // inapplicable to Sei + "blobGasUsed": hexutil.Uint64(0), // inapplicable to Sei + } + return result, nil +} diff --git a/evmrpc/subscribe_test.go b/evmrpc/subscribe_test.go new file mode 100644 index 0000000000..d999482599 --- /dev/null +++ b/evmrpc/subscribe_test.go @@ -0,0 +1,164 @@ +package evmrpc_test + +import ( + "context" + "fmt" + "regexp" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/stretchr/testify/require" +) + +func TestSubscribeNewHeads(t *testing.T) { + t.Parallel() + recvCh, done := sendWSRequestGood(t, "subscribe", "newHeads") + defer func() { done <- struct{}{} }() + + receivedSubMsg := false + receivedEvents := false + timer := time.NewTimer(1 * time.Second) + + expectedKeys := []string{ + "parentHash", "sha3Uncles", "miner", "stateRoot", "transactionsRoot", + "receiptsRoot", "logsBloom", "difficulty", "number", "gasLimit", + "gasUsed", "timestamp", "extraData", "mixHash", "nonce", + "baseFeePerGas", "withdrawalsRoot", "blobGasUsed", "excessBlobGas", + "parentBeaconBlockRoot", "hash", + } + inapplicableKeys := make(map[string]struct{}) + for _, key := range []string{ + "difficulty", "extraData", "logsBloom", "nonce", "sha3Uncles", "mixHash", + "excessBlobGas", "parentBeaconBlockRoot", "withdrawlsRoot", "baseFeePerGas", + "withdrawalsRoot", "blobGasUsed", + } { + inapplicableKeys[key] = struct{}{} + } + var subscriptionId string + + for { + select { + case resObj := <-recvCh: + _, ok := resObj["error"] + if ok { + t.Fatal("Received error:", resObj["error"]) + } + if !receivedSubMsg { + // get subscriptionId from first message + subscriptionId = resObj["result"].(string) + receivedSubMsg = true + continue + } + receivedEvents = true + method := resObj["method"].(string) + if method != "eth_subscription" { + t.Fatal("Method is not eth_subscription") + } + paramMap := resObj["params"].(map[string]interface{}) + if paramMap["subscription"] != subscriptionId { + t.Fatal("Subscription ID does not match") + } + resultMap := paramMap["result"].(map[string]interface{}) + // check all fields + for _, key := range expectedKeys { + if _, ok := resultMap[key]; !ok { + t.Fatalf("%s is nil", key) + } + // check that applicable keys aren't all 0's + if _, inapplicable := inapplicableKeys[key]; !inapplicable { + if matched, err := regexp.MatchString("^0+$", fmt.Sprintf("%v", resultMap[key])); err != nil || matched { + t.Fatalf("%s was unable to parse or expected non-zero value", key) + } + } + } + case <-timer.C: + if !receivedSubMsg || !receivedEvents { + t.Fatal("No message received within 5 seconds") + } + return + } + } +} + +func TestSubscribeNewLogs(t *testing.T) { + t.Parallel() + data := map[string]interface{}{ + "fromBlock": "0x0", + "toBlock": "latest", + "address": []common.Address{ + common.HexToAddress("0x1111111111111111111111111111111111111112"), + common.HexToAddress("0xc0ffee254729296a45a3885639AC7E10F9d54979"), + }, + "topics": [][]common.Hash{ + { + common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123"), + }, + }, + } + recvCh, done := sendWSRequestGood(t, "subscribe", "logs", data) + defer func() { done <- struct{}{} }() + + receivedSubMsg := false + receivedEvents := false + timer := time.NewTimer(2 * time.Second) + + var subscriptionId string + + for { + select { + case resObj := <-recvCh: + _, ok := resObj["error"] + if ok { + t.Fatal("Received error:", resObj["error"]) + } + if !receivedSubMsg { + // get subscriptionId from first message + subscriptionId = resObj["result"].(string) + receivedSubMsg = true + continue + } + receivedEvents = true + method := resObj["method"].(string) + if method != "eth_subscription" { + t.Fatal("Method is not eth_subscription") + } + paramMap := resObj["params"].(map[string]interface{}) + if paramMap["subscription"] != subscriptionId { + t.Fatal("Subscription ID does not match") + } + resultMap := paramMap["result"].(map[string]interface{}) + if resultMap["address"] != "0x1111111111111111111111111111111111111112" && resultMap["address"] != "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" { + t.Fatalf("Unexpected address, got %v", resultMap["address"]) + } + firstTopic := resultMap["topics"].([]interface{})[0].(string) + if firstTopic != "0x0000000000000000000000000000000000000000000000000000000000000123" { + t.Fatalf("Unexpected topic, got %v", firstTopic) + } + case <-timer.C: + if !receivedSubMsg || !receivedEvents { + t.Fatal("No message received within 5 seconds") + } + return + } + } +} + +func TestSubscriptionManager(t *testing.T) { + manager := evmrpc.NewSubscriptionManager(&MockClient{}) + res, subCh, err := manager.Subscribe(context.Background(), evmrpc.NewHeadQueryBuilder(), 10) + require.Nil(t, err) + require.NotNil(t, subCh) + require.Equal(t, 1, int(res)) + + res, subCh, err = manager.Subscribe(context.Background(), evmrpc.NewHeadQueryBuilder(), 10) + require.Nil(t, err) + require.NotNil(t, subCh) + require.Equal(t, 2, int(res)) + + badManager := evmrpc.NewSubscriptionManager(&MockBadClient{}) + _, subCh, err = badManager.Subscribe(context.Background(), evmrpc.NewHeadQueryBuilder(), 10) + require.NotNil(t, err) + require.Nil(t, subCh) +} diff --git a/evmrpc/tracers.go b/evmrpc/tracers.go new file mode 100644 index 0000000000..303f41d824 --- /dev/null +++ b/evmrpc/tracers.go @@ -0,0 +1,46 @@ +package evmrpc + +import ( + "context" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/eth/tracers" + _ "github.com/ethereum/go-ethereum/eth/tracers/native" // run init()s to register native tracers + "github.com/ethereum/go-ethereum/rpc" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + rpcclient "github.com/tendermint/tendermint/rpc/client" +) + +type DebugAPI struct { + tracersAPI *tracers.API + tmClient rpcclient.Client + keeper *keeper.Keeper + ctxProvider func(int64) sdk.Context + txDecoder sdk.TxDecoder +} + +func NewDebugAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txDecoder sdk.TxDecoder, config *SimulateConfig) *DebugAPI { + backend := NewBackend(ctxProvider, k, txDecoder, tmClient, config) + tracersAPI := tracers.NewAPI(backend) + return &DebugAPI{tracersAPI: tracersAPI, tmClient: tmClient, keeper: k, ctxProvider: ctxProvider, txDecoder: txDecoder} +} + +func (api *DebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, config *tracers.TraceConfig) (interface{}, error) { + startTime := time.Now() + defer recordMetrics("debug_traceTransaction", startTime, true) + return api.tracersAPI.TraceTransaction(ctx, hash, config) +} + +func (api *DebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *tracers.TraceConfig) (interface{}, error) { + startTime := time.Now() + defer recordMetrics("debug_traceBlockByNumber", startTime, true) + return api.tracersAPI.TraceBlockByNumber(ctx, number, config) +} + +func (api *DebugAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, config *tracers.TraceConfig) (interface{}, error) { + startTime := time.Now() + defer recordMetrics("debug_traceBlockByHash", startTime, true) + return api.tracersAPI.TraceBlockByHash(ctx, hash, config) +} diff --git a/evmrpc/tracers_test.go b/evmrpc/tracers_test.go new file mode 100644 index 0000000000..d3f2584605 --- /dev/null +++ b/evmrpc/tracers_test.go @@ -0,0 +1,71 @@ +package evmrpc_test + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestTraceTransaction(t *testing.T) { + args := map[string]interface{}{} + + // test callTracer + args["tracer"] = "callTracer" + resObj := sendRequestGoodWithNamespace(t, "debug", "traceTransaction", DebugTraceHashHex, args) + result := resObj["result"].(map[string]interface{}) + require.Equal(t, "0x5b4eba929f3811980f5ae0c5d04fa200f837df4e", result["from"]) + require.Equal(t, "0x55f0", result["gas"]) + require.Equal(t, "0x616263", result["input"]) + require.Equal(t, "0x0000000000000000000000000000000000010203", result["to"]) + require.Equal(t, "CALL", result["type"]) + require.Equal(t, "0x3e8", result["value"]) + + // test prestateTracer + args["tracer"] = "prestateTracer" + resObj = sendRequestGoodWithNamespace(t, "debug", "traceTransaction", DebugTraceHashHex, args) + result = resObj["result"].(map[string]interface{}) + for _, v := range result { + require.Contains(t, v, "balance") + balanceMap := v.(map[string]interface{}) + balance := balanceMap["balance"].(string) + require.Greater(t, len(balance), 2) + } +} + +func TestTraceBlockByNumber(t *testing.T) { + args := map[string]interface{}{} + // test callTracer + args["tracer"] = "callTracer" + resObj := sendRequestGoodWithNamespace(t, "debug", "traceBlockByNumber", "0x65", args) + result := resObj["result"].([]interface{})[0].(map[string]interface{})["result"].(map[string]interface{}) + require.Equal(t, "0x5b4eba929f3811980f5ae0c5d04fa200f837df4e", result["from"]) + require.Equal(t, "0x55f0", result["gas"]) + require.Equal(t, "0x616263", result["input"]) + require.Equal(t, "0x0000000000000000000000000000000000010203", result["to"]) + require.Equal(t, "CALL", result["type"]) + require.Equal(t, "0x3e8", result["value"]) + args["tracer"] = "prestateTracer" + resObj = sendRequestGoodWithNamespace(t, "debug", "traceBlockByNumber", "0x65", args) + result = resObj["result"].([]interface{})[0].(map[string]interface{})["result"].(map[string]interface{}) + require.Equal(t, 3, len(result)) +} + +func TestTraceBlockByHash(t *testing.T) { + args := map[string]interface{}{} + // test callTracer + args["tracer"] = "callTracer" + resObj := sendRequestGoodWithNamespace(t, "debug", "traceBlockByHash", "0xBE17E0261E539CB7E9A91E123A6D794E0163D656FCF9B8EAC07823F7ED28512B", args) + result := resObj["result"].([]interface{})[0].(map[string]interface{})["result"].(map[string]interface{}) + require.Equal(t, "0x5b4eba929f3811980f5ae0c5d04fa200f837df4e", result["from"]) + require.Equal(t, "0x55f0", result["gas"]) + require.Equal(t, "0x616263", result["input"]) + require.Equal(t, "0x0000000000000000000000000000000000010203", result["to"]) + require.Equal(t, "CALL", result["type"]) + require.Equal(t, "0x3e8", result["value"]) + + // test prestateTracer + args["tracer"] = "prestateTracer" + resObj = sendRequestGoodWithNamespace(t, "debug", "traceBlockByHash", "0xBE17E0261E539CB7E9A91E123A6D794E0163D656FCF9B8EAC07823F7ED28512B", args) + result = resObj["result"].([]interface{})[0].(map[string]interface{})["result"].(map[string]interface{}) + require.Equal(t, 3, len(result)) +} diff --git a/evmrpc/tx.go b/evmrpc/tx.go new file mode 100644 index 0000000000..3863506be7 --- /dev/null +++ b/evmrpc/tx.go @@ -0,0 +1,292 @@ +package evmrpc + +import ( + "context" + "errors" + "math/big" + "strings" + "time" + + "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts" + "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/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + rpcclient "github.com/tendermint/tendermint/rpc/client" + "github.com/tendermint/tendermint/rpc/coretypes" + tmtypes "github.com/tendermint/tendermint/types" +) + +const UnconfirmedTxQueryMaxPage = 20 +const UnconfirmedTxQueryPerPage = 30 + +type TransactionAPI struct { + tmClient rpcclient.Client + keeper *keeper.Keeper + ctxProvider func(int64) sdk.Context + txConfig client.TxConfig + homeDir string +} + +func NewTransactionAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txConfig client.TxConfig, homeDir string) *TransactionAPI { + return &TransactionAPI{tmClient: tmClient, keeper: k, ctxProvider: ctxProvider, txConfig: txConfig, homeDir: homeDir} +} + +func (t *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (result map[string]interface{}, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getTransactionReceipt", startTime, returnErr == nil) + receipt, err := t.keeper.GetReceipt(t.ctxProvider(LatestCtxHeight), hash) + if err != nil { + if strings.Contains(err.Error(), "not found") { + // When the transaction doesn't exist, the RPC method should return JSON null + // as per specification. + return nil, nil + } + return nil, err + } + height := int64(receipt.BlockNumber) + block, err := blockByNumberWithRetry(ctx, t.tmClient, &height, 1) + if err != nil { + return nil, err + } + return encodeReceipt(receipt, t.txConfig.TxDecoder(), block) +} + +func (t *TransactionAPI) GetVMError(hash common.Hash) (result string, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getVMError", startTime, true) + receipt, err := t.keeper.GetReceipt(t.ctxProvider(LatestCtxHeight), hash) + if err != nil { + return "", err + } + return receipt.VmError, nil +} + +func (t *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (result *RPCTransaction, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getTransactionByBlockNumberAndIndex", startTime, returnErr == nil) + blockNumber, err := getBlockNumber(ctx, t.tmClient, blockNr) + if err != nil { + return nil, err + } + block, err := blockByNumberWithRetry(ctx, t.tmClient, blockNumber, 1) + if err != nil { + return nil, err + } + return t.getTransactionWithBlock(block, index) +} + +func (t *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (result *RPCTransaction, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getTransactionByBlockHashAndIndex", startTime, returnErr == nil) + block, err := blockByHash(ctx, t.tmClient, blockHash[:]) + if err != nil { + return nil, err + } + return t.getTransactionWithBlock(block, index) +} + +func (t *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (result *RPCTransaction, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getTransactionByHash", startTime, returnErr == nil) + sdkCtx := t.ctxProvider(LatestCtxHeight) + // first try get from mempool + for page := 1; page <= UnconfirmedTxQueryMaxPage; page++ { + res, err := t.tmClient.UnconfirmedTxs(ctx, &page, nil) + if err != nil || len(res.Txs) == 0 { + break + } + for _, tx := range res.Txs { + etx := getEthTxForTxBz(tx, t.txConfig.TxDecoder()) + if etx != nil && etx.Hash() == hash { + signer := ethtypes.MakeSigner( + types.DefaultChainConfig().EthereumConfig(t.keeper.ChainID(sdkCtx)), + big.NewInt(sdkCtx.BlockHeight()), + uint64(sdkCtx.BlockTime().Unix()), + ) + from, _ := ethtypes.Sender(signer, etx) + v, r, s := etx.RawSignatureValues() + res := RPCTransaction{ + Type: hexutil.Uint64(etx.Type()), + From: from, + Gas: hexutil.Uint64(etx.Gas()), + GasPrice: (*hexutil.Big)(etx.GasPrice()), + Hash: etx.Hash(), + Input: hexutil.Bytes(etx.Data()), + Nonce: hexutil.Uint64(etx.Nonce()), + To: etx.To(), + Value: (*hexutil.Big)(etx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), + } + return &res, nil + } + } + } + + // then try get from committed + receipt, err := t.keeper.GetReceipt(t.ctxProvider(LatestCtxHeight), hash) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return nil, nil + } + return nil, err + } + return t.GetTransactionByBlockNumberAndIndex(ctx, rpc.BlockNumber(receipt.BlockNumber), hexutil.Uint(receipt.TransactionIndex)) +} + +func (t *TransactionAPI) GetTransactionErrorByHash(_ context.Context, hash common.Hash) (result string, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getTransactionErrorByHash", startTime, returnErr == nil) + receipt, err := t.keeper.GetReceipt(t.ctxProvider(LatestCtxHeight), hash) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return "", nil + } + return "", err + } + return receipt.VmError, nil +} + +func (t *TransactionAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (result *hexutil.Uint64, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_getTransactionCount", startTime, returnErr == nil) + sdkCtx := t.ctxProvider(LatestCtxHeight) + + var pending bool + if blockNrOrHash.BlockHash == nil && *blockNrOrHash.BlockNumber == rpc.PendingBlockNumber { + pending = true + } + + blkNr, err := GetBlockNumberByNrOrHash(ctx, t.tmClient, blockNrOrHash) + if err != nil { + return nil, err + } + + if blkNr != nil { + sdkCtx = t.ctxProvider(*blkNr) + if err := CheckVersion(sdkCtx, t.keeper); err != nil { + return nil, err + } + } + + nonce := t.keeper.CalculateNextNonce(sdkCtx, address, pending) + return (*hexutil.Uint64)(&nonce), nil +} + +func (t *TransactionAPI) getTransactionWithBlock(block *coretypes.ResultBlock, index hexutil.Uint) (*RPCTransaction, error) { + if int(index) >= len(block.Block.Txs) { + return nil, nil + } + ethtx := getEthTxForTxBz(block.Block.Txs[int(index)], t.txConfig.TxDecoder()) + if ethtx == nil { + return nil, nil + } + receipt, err := t.keeper.GetReceipt(t.ctxProvider(LatestCtxHeight), ethtx.Hash()) + if err != nil { + return nil, err + } + res := hydrateTransaction(ethtx, big.NewInt(block.Block.Height), common.HexToHash(block.BlockID.Hash.String()), receipt) + return &res, nil +} + +func (t *TransactionAPI) Sign(addr common.Address, data hexutil.Bytes) (result hexutil.Bytes, returnErr error) { + startTime := time.Now() + defer recordMetrics("eth_sign", startTime, returnErr == nil) + kb, err := getTestKeyring(t.homeDir) + if err != nil { + return nil, err + } + for taddr, privKey := range getAddressPrivKeyMap(kb) { + if taddr != addr.Hex() { + continue + } + dataHash := accounts.TextHash(data) + return crypto.Sign(dataHash, privKey) + } + return nil, errors.New("address does not have hosted key") +} + +func getEthTxForTxBz(tx tmtypes.Tx, decoder sdk.TxDecoder) *ethtypes.Transaction { + decoded, err := decoder(tx) + if err != nil { + return nil + } + if len(decoded.GetMsgs()) != 1 { + // not EVM tx since EVM tx will have exactly one msg + return nil + } + evmTx, ok := decoded.GetMsgs()[0].(*types.MsgEVMTransaction) + if !ok || evmTx.IsAssociateTx() { + return nil + } + ethtx, _ := evmTx.AsTransaction() + return ethtx +} + +// Gets the EVM tx index based on the tx index (typically from receipt.TransactionIndex +// Essentially loops through and calculates the index if we ignore cosmos txs +func GetEvmTxIndex(txs tmtypes.Txs, txIndex uint32, decoder sdk.TxDecoder) (index int, found bool) { + evmTxIndex := 0 + foundTx := false + for i, tx := range txs { + etx := getEthTxForTxBz(tx, decoder) + if etx == nil { // cosmos tx, skip + continue + } + if i == int(txIndex) { + foundTx = true + break + } + evmTxIndex++ + } + if !foundTx { + return -1, false + } else { + return evmTxIndex, true + + } +} + +func encodeReceipt(receipt *types.Receipt, decoder sdk.TxDecoder, block *coretypes.ResultBlock) (map[string]interface{}, error) { + blockHash := block.BlockID.Hash + bh := common.HexToHash(blockHash.String()) + logs := keeper.GetLogsForTx(receipt) + for _, log := range logs { + log.BlockHash = bh + } + evmTxIndex, foundTx := GetEvmTxIndex(block.Block.Txs, receipt.TransactionIndex, decoder) + // convert tx index including cosmos txs to tx index excluding cosmos txs + if !foundTx { + return nil, errors.New("failed to find transaction in block") + } + bloom := ethtypes.Bloom{} + bloom.SetBytes(receipt.LogsBloom) + fields := map[string]interface{}{ + "blockHash": bh, + "blockNumber": hexutil.Uint64(receipt.BlockNumber), + "transactionHash": common.HexToHash(receipt.TxHashHex), + "transactionIndex": hexutil.Uint64(evmTxIndex), + "from": common.HexToAddress(receipt.From), + "to": common.HexToAddress(receipt.To), + "gasUsed": hexutil.Uint64(receipt.GasUsed), + "cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed), + "logs": logs, + "logsBloom": bloom, + "type": hexutil.Uint(receipt.TxType), + "effectiveGasPrice": (*hexutil.Big)(big.NewInt(int64(receipt.EffectiveGasPrice))), + "status": hexutil.Uint(receipt.Status), + } + if receipt.ContractAddress != "" { + fields["contractAddress"] = common.HexToAddress(receipt.ContractAddress) + } else { + fields["contractAddress"] = nil + } + return fields, nil +} diff --git a/evmrpc/tx_test.go b/evmrpc/tx_test.go new file mode 100644 index 0000000000..e458633413 --- /dev/null +++ b/evmrpc/tx_test.go @@ -0,0 +1,249 @@ +package evmrpc_test + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/config" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/go-bip39" + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestGetTxReceipt(t *testing.T) { + body := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionReceipt\",\"params\":[\"0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e\"],\"id\":\"test\"}" + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + resObj = resObj["result"].(map[string]interface{}) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", resObj["blockHash"].(string)) + require.Equal(t, "0x8", resObj["blockNumber"].(string)) + require.Equal(t, "0x7b", resObj["cumulativeGasUsed"].(string)) + require.Equal(t, "0xa", resObj["effectiveGasPrice"].(string)) + require.Equal(t, "0x1234567890123456789012345678901234567890", resObj["from"].(string)) + require.Equal(t, "0x37", resObj["gasUsed"].(string)) + logs := resObj["logs"].([]interface{}) + require.Equal(t, 1, len(logs)) + log := logs[0].(map[string]interface{}) + require.Equal(t, "0x1111111111111111111111111111111111111111", log["address"].(string)) + topics := log["topics"].([]interface{}) + require.Equal(t, 2, len(topics)) + require.Equal(t, "0x1111111111111111111111111111111111111111111111111111111111111111", topics[0].(string)) + require.Equal(t, "0x1111111111111111111111111111111111111111111111111111111111111112", topics[1].(string)) + require.Equal(t, "0x8", log["blockNumber"].(string)) + require.Equal(t, "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e", log["transactionHash"].(string)) + require.Equal(t, "0x0", log["transactionIndex"].(string)) + require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", log["blockHash"].(string)) + require.Equal(t, "0x0", log["logIndex"].(string)) + require.False(t, log["removed"].(bool)) + require.Equal(t, "0x0", resObj["status"].(string)) + require.Equal(t, "0x1234567890123456789012345678901234567890", resObj["to"].(string)) + require.Equal(t, "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e", resObj["transactionHash"].(string)) + require.Equal(t, "0x0", resObj["transactionIndex"].(string)) + require.Equal(t, "0x1", resObj["type"].(string)) + require.Equal(t, "0x1234567890123456789012345678901234567890", resObj["contractAddress"].(string)) + + receipt, err := EVMKeeper.GetReceipt(Ctx, common.HexToHash("0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e")) + require.Nil(t, err) + receipt.ContractAddress = "" + EVMKeeper.SetReceipt(Ctx, common.HexToHash("0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e"), receipt) + body = "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionReceipt\",\"params\":[\"0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e\"],\"id\":\"test\"}" + req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err = http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err = io.ReadAll(res.Body) + require.Nil(t, err) + resObj = map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + resObj = resObj["result"].(map[string]interface{}) + require.Nil(t, resObj["contractAddress"]) + + req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestBadPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err = http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err = io.ReadAll(res.Body) + require.Nil(t, err) + resObj = map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + resObj = resObj["error"].(map[string]interface{}) + require.Equal(t, float64(-32000), resObj["code"].(float64)) + require.Equal(t, "error block", resObj["message"].(string)) + + resObj = sendRequestGood(t, "getTransactionReceipt", common.HexToHash("0x3030303030303030303030303030303030303030303030303030303030303031")) + require.Nil(t, resObj["result"]) +} + +func TestGetTransaction(t *testing.T) { + bodyByBlockNumberAndIndex := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionByBlockNumberAndIndex\",\"params\":[\"0x8\",\"0x0\"],\"id\":\"test\"}" + bodyByBlockHashAndIndex := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionByBlockHashAndIndex\",\"params\":[\"0x0000000000000000000000000000000000000000000000000000000000000001\",\"0x0\"],\"id\":\"test\"}" + bodyByHash := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionByHash\",\"params\":[\"0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e\"],\"id\":\"test\"}" + for _, body := range []string{bodyByBlockNumberAndIndex, bodyByBlockHashAndIndex, bodyByHash} { + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + 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, "0x3e8", resObj["gas"].(string)) + require.Equal(t, "0xa", resObj["gasPrice"].(string)) + require.Equal(t, "0xa", resObj["maxFeePerGas"].(string)) + require.Equal(t, "0x0", resObj["maxPriorityFeePerGas"].(string)) + require.Equal(t, "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e", resObj["hash"].(string)) + require.Equal(t, "0x616263", resObj["input"].(string)) + require.Equal(t, "0x1", resObj["nonce"].(string)) + require.Equal(t, "0x0000000000000000000000000000000000010203", resObj["to"].(string)) + require.Equal(t, "0x0", resObj["transactionIndex"].(string)) + require.Equal(t, "0x3e8", resObj["value"].(string)) + require.Equal(t, "0x2", resObj["type"].(string)) + require.Equal(t, 0, len(resObj["accessList"].([]interface{}))) + require.Equal(t, "0xae3f3", resObj["chainId"].(string)) + require.Equal(t, "0x0", resObj["v"].(string)) + require.Equal(t, "0xa1ac0e5b8202742e54ae7af350ed855313cc4f9861c2d75a0e541b4aff7c981e", resObj["r"].(string)) + require.Equal(t, "0x288b16881aed9640cd360403b9db1ce3961b29af0b00158311856d1446670996", resObj["s"].(string)) + require.Equal(t, "0x0", resObj["yParity"].(string)) + } + + for _, body := range []string{bodyByBlockNumberAndIndex, bodyByBlockHashAndIndex, bodyByHash} { + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestBadPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + require.Nil(t, resObj["result"]) + } +} + +func TestGetPendingTransactionByHash(t *testing.T) { + resObj := sendRequestGood(t, "getTransactionByHash", "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e") + result := resObj["result"].(map[string]interface{}) + require.Equal(t, "0x1", result["nonce"]) + require.Equal(t, "0x2", result["type"].(string)) +} + +func TestGetTransactionCount(t *testing.T) { + Ctx = Ctx.WithBlockHeight(1) + // happy path + bodyByNumber := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionCount\",\"params\":[\"0x1234567890123456789012345678901234567890\",\"0x8\"],\"id\":\"test\"}" + bodyByHash := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionCount\",\"params\":[\"0x1234567890123456789012345678901234567890\",\"0x3030303030303030303030303030303030303030303030303030303030303031\"],\"id\":\"test\"}" + + for _, body := range []string{bodyByNumber, bodyByHash} { + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + count := resObj["result"].(string) + require.Equal(t, "0x1", count) + } + + // address that doesn't have tx + strangerBody := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionCount\",\"params\":[\"0x0123456789012345678902345678901234567891\",\"0x8\"],\"id\":\"test\"}" + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(strangerBody)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + count := resObj["result"].(string) + require.Equal(t, "0x0", count) // no tx + + // error cases + earliestBodyToBadPort := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionCount\",\"params\":[\"0x1234567890123456789012345678901234567890\",\"earliest\"],\"id\":\"test\"}" + for body, errStr := range map[string]string{ + earliestBodyToBadPort: "error genesis", + } { + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestBadPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + errMap := resObj["error"].(map[string]interface{}) + errMsg := errMap["message"].(string) + require.Equal(t, errStr, errMsg) + } + Ctx = Ctx.WithBlockHeight(8) +} + +func TestGetTransactionError(t *testing.T) { + h := common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") + EVMKeeper.SetReceipt(Ctx, h, &types.Receipt{VmError: "test error"}) + resObj := sendRequestGood(t, "getTransactionErrorByHash", "0x1111111111111111111111111111111111111111111111111111111111111111") + require.Equal(t, "test error", resObj["result"]) + + resObj = sendRequestBad(t, "getTransactionReceipt", "0x1111111111111111111111111111111111111111111111111111111111111111") + require.Equal(t, "error block", resObj["error"].(map[string]interface{})["message"]) +} + +func TestSign(t *testing.T) { + homeDir := t.TempDir() + txApi := evmrpc.NewTransactionAPI(nil, nil, nil, nil, homeDir) + infoApi := evmrpc.NewInfoAPI(nil, nil, nil, nil, homeDir) + clientCtx := client.Context{}.WithViper("").WithHomeDir(homeDir) + clientCtx, err := config.ReadFromClientConfig(clientCtx) + require.Nil(t, err) + kb, err := client.NewKeyringFromBackend(clientCtx, keyring.BackendTest) + require.Nil(t, err) + entropySeed, err := bip39.NewEntropy(256) + require.Nil(t, err) + mnemonic, err := bip39.NewMnemonic(entropySeed) + require.Nil(t, err) + algos, _ := kb.SupportedAlgorithms() + algo, err := keyring.NewSigningAlgoFromString(string(hd.Secp256k1Type), algos) + require.Nil(t, err) + _, err = kb.NewAccount("test", mnemonic, "", hd.CreateHDPath(sdk.GetConfig().GetCoinType(), 0, 0).String(), algo) + require.Nil(t, err) + accounts, _ := infoApi.Accounts() + account := accounts[0] + signed, err := txApi.Sign(account, []byte("data")) + require.Nil(t, err) + require.NotEmpty(t, signed) +} + +func TestGetVMError(t *testing.T) { + resObj := sendRequestGood(t, "getVMError", "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e") + require.Equal(t, "", resObj["result"].(string)) + resObj = sendRequestGood(t, "getVMError", "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872f") + require.Equal(t, "not found", resObj["error"].(map[string]interface{})["message"]) +} diff --git a/evmrpc/txpool.go b/evmrpc/txpool.go new file mode 100644 index 0000000000..48f8f8f160 --- /dev/null +++ b/evmrpc/txpool.go @@ -0,0 +1,76 @@ +package evmrpc + +import ( + "context" + "math/big" + "strconv" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "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" +) + +type TxPoolAPI struct { + tmClient rpcclient.Client + keeper *keeper.Keeper + ctxProvider func(int64) sdk.Context + txDecoder sdk.TxDecoder + txPoolConfig *TxPoolConfig +} + +type TxPoolConfig struct { + maxNumTxs int +} + +func NewTxPoolAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txDecoder sdk.TxDecoder, txPoolConfig *TxPoolConfig) *TxPoolAPI { + return &TxPoolAPI{tmClient: tmClient, keeper: k, ctxProvider: ctxProvider, txDecoder: txDecoder, txPoolConfig: txPoolConfig} +} + +// 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) { + startTime := time.Now() + defer recordMetrics("sei_content", 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), + } + + total := t.txPoolConfig.maxNumTxs + resUnconfirmedTxs, err := t.tmClient.UnconfirmedTxs(ctx, nil, &total) + if err != nil { + return nil, err + } + + sdkCtx := t.ctxProvider(LatestCtxHeight) + signer := ethtypes.MakeSigner( + types.DefaultChainConfig().EthereumConfig(t.keeper.ChainID(sdkCtx)), + big.NewInt(sdkCtx.BlockHeight()), + uint64(sdkCtx.BlockTime().Unix()), + ) + + for _, tx := range resUnconfirmedTxs.Txs { + ethTx := getEthTxForTxBz(tx, t.txDecoder) + if ethTx == nil { // not an evm tx + continue + } + fromAddr, err := ethtypes.Sender(signer, ethTx) + if err != nil { + return nil, err + } + + nonce := ethTx.Nonce() + res := hydratePendingTransaction(ethTx) + nonceStr := strconv.FormatUint(nonce, 10) + if content["pending"][fromAddr.String()] == nil { + content["pending"][fromAddr.String()] = map[string]*RPCTransaction{ + nonceStr: &res, + } + } else { + content["pending"][fromAddr.String()][nonceStr] = &res + } + } + return content, nil +} diff --git a/evmrpc/txpool_test.go b/evmrpc/txpool_test.go new file mode 100644 index 0000000000..5d87fcecb3 --- /dev/null +++ b/evmrpc/txpool_test.go @@ -0,0 +1,78 @@ +package evmrpc_test + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestTxPoolContent(t *testing.T) { + body := "{\"jsonrpc\": \"2.0\",\"method\": \"txpool_content\",\"params\":[],\"id\":\"test\"}" + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s:%d", TestAddr, TestPort), strings.NewReader(body)) + require.Nil(t, err) + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + require.Nil(t, err) + resBody, err := io.ReadAll(res.Body) + require.Nil(t, err) + + // check pending has 1 txn in it + resObj := map[string]interface{}{} + require.Nil(t, json.Unmarshal(resBody, &resObj)) + resObj = resObj["result"].(map[string]interface{}) + pendingMap := resObj["pending"].(map[string]interface{}) + require.Equal(t, 1, len(pendingMap)) + + // check that txn + for fromAddr, txns := range pendingMap { + for nonce, txn := range txns.(map[string]interface{}) { + require.NotZero(t, nonce) + tx := txn.(map[string]interface{}) + require.Nil(t, tx["blockNumber"]) + require.Nil(t, tx["blockHash"]) + require.Equal(t, strings.ToLower(tx["from"].(string)), strings.ToLower(fromAddr)) + requireNotZeroHex(t, tx["gas"].(string)) + requireNotZeroHex(t, tx["gasPrice"].(string)) + // maxFeePerGas + requireNotZeroHex(t, tx["maxFeePerGas"].(string)) + // maxPriorityFeePerGas + // hash + requireNotZeroHex(t, tx["hash"].(string)) + // input + requireNotZeroHex(t, tx["input"].(string)) + // nonce -- can be 0 + // to + requireNotZeroHex(t, tx["to"].(string)) + // transactionIndex -- not set yet for pending + // value + requireNotZeroHex(t, tx["value"].(string)) + // type -- can be 0 + // acccesslist-- can be any array value + require.Equal(t, tx["chainId"], "0xae3f3") // 713715 + requireNotZeroHex(t, tx["v"].(string)) + requireNotZeroHex(t, tx["r"].(string)) + requireNotZeroHex(t, tx["s"].(string)) + } + } + + // check queued has nothing in it + queuedMap := resObj["queued"].(map[string]interface{}) + require.Equal(t, 0, len(queuedMap)) +} + +func requireNotZeroHex(t *testing.T, hexStr string) { + if strings.HasPrefix(hexStr, "0x") { + hexStr = hexStr[2:] + } + for i := 0; i < len(hexStr); i++ { + if hexStr[i] != '0' { + return // not all zeros + } + } + t.Errorf("requireNotZeroHex: %s is all zeros", hexStr) +} diff --git a/evmrpc/utils.go b/evmrpc/utils.go new file mode 100644 index 0000000000..0e7a974129 --- /dev/null +++ b/evmrpc/utils.go @@ -0,0 +1,296 @@ +package evmrpc + +import ( + "context" + "crypto/ecdsa" + "encoding/hex" + "fmt" + "math/big" + "time" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/config" + "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" +) + +const LatestCtxHeight int64 = -1 + +// Since we use a static base fee, we want GasUsedRatio returned in RPC queries +// to reflect the fact that base fee would never change, which is only true if +// 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[:]) + if err != nil { + return nil, err + } + return &res.Block.Height, nil + } + return getBlockNumber(ctx, tmClient, *blockNrOrHash.BlockNumber) +} + +func getBlockNumber(ctx context.Context, tmClient rpcclient.Client, number rpc.BlockNumber) (*int64, error) { + var numberPtr *int64 + switch number { + case rpc.SafeBlockNumber, rpc.FinalizedBlockNumber, rpc.LatestBlockNumber, rpc.PendingBlockNumber: + numberPtr = nil // requesting Block with nil means the latest block + case rpc.EarliestBlockNumber: + genesisRes, err := tmClient.Genesis(ctx) + if err != nil { + return nil, err + } + numberPtr = &genesisRes.Genesis.InitialHeight + default: + numberI64 := number.Int64() + numberPtr = &numberI64 + } + return numberPtr, nil +} + +func getHeightFromBigIntBlockNumber(latest int64, blockNumber *big.Int) int64 { + switch blockNumber.Int64() { + case rpc.FinalizedBlockNumber.Int64(), rpc.LatestBlockNumber.Int64(), rpc.SafeBlockNumber.Int64(), rpc.PendingBlockNumber.Int64(): + return latest + default: + return blockNumber.Int64() + } +} + +func getTestKeyring(homeDir string) (keyring.Keyring, error) { + clientCtx := client.Context{}.WithViper("").WithHomeDir(homeDir) + clientCtx, err := config.ReadFromClientConfig(clientCtx) + if err != nil { + return nil, err + } + return client.NewKeyringFromBackend(clientCtx, keyring.BackendTest) +} + +func getAddressPrivKeyMap(kb keyring.Keyring) map[string]*ecdsa.PrivateKey { + res := map[string]*ecdsa.PrivateKey{} + keys, err := kb.List() + if err != nil { + return res + } + for _, key := range keys { + localInfo, ok := key.(keyring.LocalInfo) + if !ok { + // will only show local key + continue + } + priv, err := legacy.PrivKeyFromBytes([]byte(localInfo.PrivKeyArmor)) + if err != nil { + continue + } + privHex := hex.EncodeToString(priv.Bytes()) + privKey, err := crypto.HexToECDSA(privHex) + if err != nil { + continue + } + address := crypto.PubkeyToAddress(privKey.PublicKey) + res[address.Hex()] = privKey + } + return res +} + +func blockResultsWithRetry(ctx context.Context, client rpcclient.Client, height *int64) (*coretypes.ResultBlockResults, error) { + blockRes, err := client.BlockResults(ctx, height) + if err != nil { + // retry once, since application DB and block DB are not committed atomically so it's possible for + // receipt to exist while block results aren't committed yet + time.Sleep(1 * time.Second) + blockRes, err = client.BlockResults(ctx, height) + if err != nil { + return nil, err + } + } + return blockRes, err +} + +func blockByNumber(ctx context.Context, client rpcclient.Client, height *int64) (*coretypes.ResultBlock, error) { + return blockByNumberWithRetry(ctx, client, height, 0) +} + +func blockByNumberWithRetry(ctx context.Context, client rpcclient.Client, height *int64, maxRetries int) (*coretypes.ResultBlock, error) { + blockRes, err := client.Block(ctx, height) + var retryCount = 0 + for err != nil && retryCount < maxRetries { + // retry once, since application DB and block DB are not committed atomically so it's possible for + // receipt to exist while block results aren't committed yet + time.Sleep(1 * time.Second) + blockRes, err = client.Block(ctx, height) + retryCount++ + } + if err != nil { + return nil, err + } + if blockRes.Block == nil { + return nil, fmt.Errorf("could not find block for height %d", height) + } + return blockRes, err +} + +func blockByHash(ctx context.Context, client rpcclient.Client, hash bytes.HexBytes) (*coretypes.ResultBlock, error) { + return blockByHashWithRetry(ctx, client, hash, 0) +} + +func blockByHashWithRetry(ctx context.Context, client rpcclient.Client, hash bytes.HexBytes, maxRetries int) (*coretypes.ResultBlock, error) { + blockRes, err := client.BlockByHash(ctx, hash) + var retryCount = 0 + for err != nil && retryCount < maxRetries { + // retry once, since application DB and block DB are not committed atomically so it's possible for + // receipt to exist while block results aren't committed yet + time.Sleep(1 * time.Second) + blockRes, err = client.BlockByHash(ctx, hash) + retryCount++ + } + if err != nil { + return nil, err + } + if blockRes.Block == nil { + return nil, fmt.Errorf("could not find block for hash %s", hash.String()) + } + return blockRes, err +} + +func recordMetrics(apiMethod string, startTime time.Time, success bool) { + metrics.IncrementRpcRequestCounter(apiMethod, success) + metrics.MeasureRpcRequestLatency(apiMethod, startTime) +} + +func CheckVersion(ctx sdk.Context, k *keeper.Keeper) error { + if !evmExists(ctx, k) { + return fmt.Errorf("evm module does not exist on height %d", ctx.BlockHeight()) + } + if !bankExists(ctx, k) { + return fmt.Errorf("bank module does not exist on height %d", ctx.BlockHeight()) + } + return nil +} + +func bankExists(ctx sdk.Context, k *keeper.Keeper) bool { + return ctx.KVStore(k.BankKeeper().GetStoreKey()).VersionExists(ctx.BlockHeight()) +} + +func evmExists(ctx sdk.Context, k *keeper.Keeper) bool { + return ctx.KVStore(k.GetStoreKey()).VersionExists(ctx.BlockHeight()) +} diff --git a/evmrpc/utils_test.go b/evmrpc/utils_test.go new file mode 100644 index 0000000000..0fbacf4bdf --- /dev/null +++ b/evmrpc/utils_test.go @@ -0,0 +1,20 @@ +package evmrpc_test + +import ( + "context" + "testing" + + "github.com/sei-protocol/sei-chain/app" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/stretchr/testify/require" +) + +func TestCheckVersion(t *testing.T) { + testApp := app.Setup(false, false) + k := &testApp.EvmKeeper + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockHeight(1) + testApp.Commit(context.Background()) // bump store version to 1 + require.Nil(t, evmrpc.CheckVersion(ctx, k)) + ctx = ctx.WithBlockHeight(2) + require.NotNil(t, evmrpc.CheckVersion(ctx, k)) +} diff --git a/evmrpc/web3.go b/evmrpc/web3.go new file mode 100644 index 0000000000..65ba27c13b --- /dev/null +++ b/evmrpc/web3.go @@ -0,0 +1,12 @@ +package evmrpc + +import "runtime" + +type Web3API struct{} + +func (w *Web3API) ClientVersion() string { + name := "Geth" // Sei EVM is backed by go-ethereum + name += "/" + runtime.GOOS + "-" + runtime.GOARCH + name += "/" + runtime.Version() + return name +} diff --git a/evmrpc/web3_test.go b/evmrpc/web3_test.go new file mode 100644 index 0000000000..23559eea48 --- /dev/null +++ b/evmrpc/web3_test.go @@ -0,0 +1,13 @@ +package evmrpc_test + +import ( + "testing" + + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/stretchr/testify/require" +) + +func TestClientVersion(t *testing.T) { + w := evmrpc.Web3API{} + require.NotEmpty(t, w.ClientVersion()) +} diff --git a/example/contracts/README b/example/contracts/README new file mode 100644 index 0000000000..520262542a --- /dev/null +++ b/example/contracts/README @@ -0,0 +1,18 @@ +# Install solc (on Mac) +brew update +brew tap ethereum/ethereum +brew install solidity + +# Install abigen +go get -u github.com/ethereum/go-ethereum +cd $GOPATH/src/github.com/ethereum/go-ethereum/ +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 + +# 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 diff --git a/example/contracts/echo/Echo.abi b/example/contracts/echo/Echo.abi new file mode 100644 index 0000000000..e7b153e957 --- /dev/null +++ b/example/contracts/echo/Echo.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"echo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"setTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"timestamps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/example/contracts/echo/Echo.bin b/example/contracts/echo/Echo.bin new file mode 100644 index 0000000000..bdafd06b66 --- /dev/null +++ b/example/contracts/echo/Echo.bin @@ -0,0 +1 @@ +608060405234801561000f575f80fd5b506101b48061001d5f395ff3fe608060405234801561000f575f80fd5b506004361061003f575f3560e01c80633beb26c4146100435780636279e43c1461005f5780638bc33af31461008f575b5f80fd5b61005d6004803603810190610058919061012b565b6100bf565b005b6100796004803603810190610074919061012b565b6100d7565b6040516100869190610165565b60405180910390f35b6100a960048036038101906100a4919061012b565b6100e0565b6040516100b69190610165565b60405180910390f35b425f808381526020019081526020015f208190555050565b5f819050919050565b5f602052805f5260405f205f915090505481565b5f80fd5b5f819050919050565b61010a816100f8565b8114610114575f80fd5b50565b5f8135905061012581610101565b92915050565b5f602082840312156101405761013f6100f4565b5b5f61014d84828501610117565b91505092915050565b61015f816100f8565b82525050565b5f6020820190506101785f830184610156565b9291505056fea26469706673582212203f73337c81097ea841db133f6d9757618539072044b2e0c6131ebd352e66354964736f6c63430008150033 \ No newline at end of file diff --git a/example/contracts/echo/Echo.go b/example/contracts/echo/Echo.go new file mode 100644 index 0000000000..f709305b8c --- /dev/null +++ b/example/contracts/echo/Echo.go @@ -0,0 +1,264 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package echo + +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 +) + +// EchoMetaData contains all meta data concerning the Echo contract. +var EchoMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"echo\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"epoch\",\"type\":\"uint256\"}],\"name\":\"setTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"timestamps\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +} + +// EchoABI is the input ABI used to generate the binding from. +// Deprecated: Use EchoMetaData.ABI instead. +var EchoABI = EchoMetaData.ABI + +// Echo is an auto generated Go binding around an Ethereum contract. +type Echo struct { + EchoCaller // Read-only binding to the contract + EchoTransactor // Write-only binding to the contract + EchoFilterer // Log filterer for contract events +} + +// EchoCaller is an auto generated read-only Go binding around an Ethereum contract. +type EchoCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EchoTransactor is an auto generated write-only Go binding around an Ethereum contract. +type EchoTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EchoFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type EchoFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// EchoSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type EchoSession struct { + Contract *Echo // 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 +} + +// EchoCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type EchoCallerSession struct { + Contract *EchoCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// EchoTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type EchoTransactorSession struct { + Contract *EchoTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// EchoRaw is an auto generated low-level Go binding around an Ethereum contract. +type EchoRaw struct { + Contract *Echo // Generic contract binding to access the raw methods on +} + +// EchoCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type EchoCallerRaw struct { + Contract *EchoCaller // Generic read-only contract binding to access the raw methods on +} + +// EchoTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type EchoTransactorRaw struct { + Contract *EchoTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewEcho creates a new instance of Echo, bound to a specific deployed contract. +func NewEcho(address common.Address, backend bind.ContractBackend) (*Echo, error) { + contract, err := bindEcho(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Echo{EchoCaller: EchoCaller{contract: contract}, EchoTransactor: EchoTransactor{contract: contract}, EchoFilterer: EchoFilterer{contract: contract}}, nil +} + +// NewEchoCaller creates a new read-only instance of Echo, bound to a specific deployed contract. +func NewEchoCaller(address common.Address, caller bind.ContractCaller) (*EchoCaller, error) { + contract, err := bindEcho(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &EchoCaller{contract: contract}, nil +} + +// NewEchoTransactor creates a new write-only instance of Echo, bound to a specific deployed contract. +func NewEchoTransactor(address common.Address, transactor bind.ContractTransactor) (*EchoTransactor, error) { + contract, err := bindEcho(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &EchoTransactor{contract: contract}, nil +} + +// NewEchoFilterer creates a new log filterer instance of Echo, bound to a specific deployed contract. +func NewEchoFilterer(address common.Address, filterer bind.ContractFilterer) (*EchoFilterer, error) { + contract, err := bindEcho(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &EchoFilterer{contract: contract}, nil +} + +// bindEcho binds a generic wrapper to an already deployed contract. +func bindEcho(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := EchoMetaData.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 (_Echo *EchoRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Echo.Contract.EchoCaller.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 (_Echo *EchoRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Echo.Contract.EchoTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Echo *EchoRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Echo.Contract.EchoTransactor.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 (_Echo *EchoCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Echo.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 (_Echo *EchoTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Echo.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Echo *EchoTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Echo.Contract.contract.Transact(opts, method, params...) +} + +// Echo is a free data retrieval call binding the contract method 0x6279e43c. +// +// Solidity: function echo(uint256 value) pure returns(uint256) +func (_Echo *EchoCaller) Echo(opts *bind.CallOpts, value *big.Int) (*big.Int, error) { + var out []interface{} + err := _Echo.contract.Call(opts, &out, "echo", value) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Echo is a free data retrieval call binding the contract method 0x6279e43c. +// +// Solidity: function echo(uint256 value) pure returns(uint256) +func (_Echo *EchoSession) Echo(value *big.Int) (*big.Int, error) { + return _Echo.Contract.Echo(&_Echo.CallOpts, value) +} + +// Echo is a free data retrieval call binding the contract method 0x6279e43c. +// +// Solidity: function echo(uint256 value) pure returns(uint256) +func (_Echo *EchoCallerSession) Echo(value *big.Int) (*big.Int, error) { + return _Echo.Contract.Echo(&_Echo.CallOpts, value) +} + +// Timestamps is a free data retrieval call binding the contract method 0x8bc33af3. +// +// Solidity: function timestamps(uint256 ) view returns(uint256) +func (_Echo *EchoCaller) Timestamps(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { + var out []interface{} + err := _Echo.contract.Call(opts, &out, "timestamps", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Timestamps is a free data retrieval call binding the contract method 0x8bc33af3. +// +// Solidity: function timestamps(uint256 ) view returns(uint256) +func (_Echo *EchoSession) Timestamps(arg0 *big.Int) (*big.Int, error) { + return _Echo.Contract.Timestamps(&_Echo.CallOpts, arg0) +} + +// Timestamps is a free data retrieval call binding the contract method 0x8bc33af3. +// +// Solidity: function timestamps(uint256 ) view returns(uint256) +func (_Echo *EchoCallerSession) Timestamps(arg0 *big.Int) (*big.Int, error) { + return _Echo.Contract.Timestamps(&_Echo.CallOpts, arg0) +} + +// SetTime is a paid mutator transaction binding the contract method 0x3beb26c4. +// +// Solidity: function setTime(uint256 epoch) returns() +func (_Echo *EchoTransactor) SetTime(opts *bind.TransactOpts, epoch *big.Int) (*types.Transaction, error) { + return _Echo.contract.Transact(opts, "setTime", epoch) +} + +// SetTime is a paid mutator transaction binding the contract method 0x3beb26c4. +// +// Solidity: function setTime(uint256 epoch) returns() +func (_Echo *EchoSession) SetTime(epoch *big.Int) (*types.Transaction, error) { + return _Echo.Contract.SetTime(&_Echo.TransactOpts, epoch) +} + +// SetTime is a paid mutator transaction binding the contract method 0x3beb26c4. +// +// Solidity: function setTime(uint256 epoch) returns() +func (_Echo *EchoTransactorSession) SetTime(epoch *big.Int) (*types.Transaction, error) { + return _Echo.Contract.SetTime(&_Echo.TransactOpts, epoch) +} diff --git a/example/contracts/echo/Echo.sol b/example/contracts/echo/Echo.sol new file mode 100644 index 0000000000..22c59f20a0 --- /dev/null +++ b/example/contracts/echo/Echo.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract Echo { + mapping(uint256 => uint) public timestamps; + + function echo(uint256 value) public pure returns (uint256) { + return value; + } + + function setTime(uint256 epoch) public { + timestamps[epoch] = block.timestamp; + } +} \ No newline at end of file diff --git a/example/contracts/sendall/IBank.abi b/example/contracts/sendall/IBank.abi new file mode 100644 index 0000000000..1863297d79 --- /dev/null +++ b/example/contracts/sendall/IBank.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"acc","type":"address"},{"internalType":"string","name":"denom","type":"string"}],"name":"balance","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"decimals","outputs":[{"internalType":"uint8","name":"response","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"name","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromAddress","type":"address"},{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"string","name":"denom","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"send","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"toNativeAddress","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sendNative","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"supply","outputs":[{"internalType":"uint256","name":"response","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"symbol","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/example/contracts/sendall/IBank.bin b/example/contracts/sendall/IBank.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/example/contracts/sendall/SendAll.abi b/example/contracts/sendall/SendAll.abi new file mode 100644 index 0000000000..f80fccffb4 --- /dev/null +++ b/example/contracts/sendall/SendAll.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"fromAddress","type":"address"},{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"string","name":"denom","type":"string"}],"name":"sendAll","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/example/contracts/sendall/SendAll.bin b/example/contracts/sendall/SendAll.bin new file mode 100644 index 0000000000..25c595be4b --- /dev/null +++ b/example/contracts/sendall/SendAll.bin @@ -0,0 +1 @@ +608060405234801561001057600080fd5b506105a0806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806389e5af5f14610030575b600080fd5b61004a60048036038101906100459190610311565b61004c565b005b600061100173ffffffffffffffffffffffffffffffffffffffff166316cadeab85846040518363ffffffff1660e01b815260040161008b929190610417565b602060405180830381865afa1580156100a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100cc919061047d565b905061100173ffffffffffffffffffffffffffffffffffffffff16635c05961b858585856040518563ffffffff1660e01b815260040161010f94939291906104b9565b6020604051808303816000875af115801561012e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610152919061053d565b5050505050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101988261016d565b9050919050565b6101a88161018d565b81146101b357600080fd5b50565b6000813590506101c58161019f565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61021e826101d5565b810181811067ffffffffffffffff8211171561023d5761023c6101e6565b5b80604052505050565b6000610250610159565b905061025c8282610215565b919050565b600067ffffffffffffffff82111561027c5761027b6101e6565b5b610285826101d5565b9050602081019050919050565b82818337600083830152505050565b60006102b46102af84610261565b610246565b9050828152602081018484840111156102d0576102cf6101d0565b5b6102db848285610292565b509392505050565b600082601f8301126102f8576102f76101cb565b5b81356103088482602086016102a1565b91505092915050565b60008060006060848603121561032a57610329610163565b5b6000610338868287016101b6565b9350506020610349868287016101b6565b925050604084013567ffffffffffffffff81111561036a57610369610168565b5b610376868287016102e3565b9150509250925092565b6103898161018d565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b838110156103c95780820151818401526020810190506103ae565b838111156103d8576000848401525b50505050565b60006103e98261038f565b6103f3818561039a565b93506104038185602086016103ab565b61040c816101d5565b840191505092915050565b600060408201905061042c6000830185610380565b818103602083015261043e81846103de565b90509392505050565b6000819050919050565b61045a81610447565b811461046557600080fd5b50565b60008151905061047781610451565b92915050565b60006020828403121561049357610492610163565b5b60006104a184828501610468565b91505092915050565b6104b381610447565b82525050565b60006080820190506104ce6000830187610380565b6104db6020830186610380565b81810360408301526104ed81856103de565b90506104fc60608301846104aa565b95945050505050565b60008115159050919050565b61051a81610505565b811461052557600080fd5b50565b60008151905061053781610511565b92915050565b60006020828403121561055357610552610163565b5b600061056184828501610528565b9150509291505056fea2646970667358221220f6c0c71d594167ca567d2a0cf0ee035f318f7bb60f183e6ae1673bbb602a715064736f6c634300080b0033 \ No newline at end of file diff --git a/example/contracts/sendall/SendAll.go b/example/contracts/sendall/SendAll.go new file mode 100644 index 0000000000..c4097f71de --- /dev/null +++ b/example/contracts/sendall/SendAll.go @@ -0,0 +1,202 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package sendall + +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 +) + +// SendallMetaData contains all meta data concerning the Sendall contract. +var SendallMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"fromAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"toAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"denom\",\"type\":\"string\"}],\"name\":\"sendAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// SendallABI is the input ABI used to generate the binding from. +// Deprecated: Use SendallMetaData.ABI instead. +var SendallABI = SendallMetaData.ABI + +// Sendall is an auto generated Go binding around an Ethereum contract. +type Sendall struct { + SendallCaller // Read-only binding to the contract + SendallTransactor // Write-only binding to the contract + SendallFilterer // Log filterer for contract events +} + +// SendallCaller is an auto generated read-only Go binding around an Ethereum contract. +type SendallCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SendallTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SendallTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SendallFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SendallFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SendallSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SendallSession struct { + Contract *Sendall // 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 +} + +// SendallCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SendallCallerSession struct { + Contract *SendallCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SendallTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SendallTransactorSession struct { + Contract *SendallTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SendallRaw is an auto generated low-level Go binding around an Ethereum contract. +type SendallRaw struct { + Contract *Sendall // Generic contract binding to access the raw methods on +} + +// SendallCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SendallCallerRaw struct { + Contract *SendallCaller // Generic read-only contract binding to access the raw methods on +} + +// SendallTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SendallTransactorRaw struct { + Contract *SendallTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSendall creates a new instance of Sendall, bound to a specific deployed contract. +func NewSendall(address common.Address, backend bind.ContractBackend) (*Sendall, error) { + contract, err := bindSendall(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Sendall{SendallCaller: SendallCaller{contract: contract}, SendallTransactor: SendallTransactor{contract: contract}, SendallFilterer: SendallFilterer{contract: contract}}, nil +} + +// NewSendallCaller creates a new read-only instance of Sendall, bound to a specific deployed contract. +func NewSendallCaller(address common.Address, caller bind.ContractCaller) (*SendallCaller, error) { + contract, err := bindSendall(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SendallCaller{contract: contract}, nil +} + +// NewSendallTransactor creates a new write-only instance of Sendall, bound to a specific deployed contract. +func NewSendallTransactor(address common.Address, transactor bind.ContractTransactor) (*SendallTransactor, error) { + contract, err := bindSendall(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SendallTransactor{contract: contract}, nil +} + +// NewSendallFilterer creates a new log filterer instance of Sendall, bound to a specific deployed contract. +func NewSendallFilterer(address common.Address, filterer bind.ContractFilterer) (*SendallFilterer, error) { + contract, err := bindSendall(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SendallFilterer{contract: contract}, nil +} + +// bindSendall binds a generic wrapper to an already deployed contract. +func bindSendall(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SendallMetaData.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 (_Sendall *SendallRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Sendall.Contract.SendallCaller.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 (_Sendall *SendallRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Sendall.Contract.SendallTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Sendall *SendallRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Sendall.Contract.SendallTransactor.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 (_Sendall *SendallCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Sendall.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 (_Sendall *SendallTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Sendall.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Sendall *SendallTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Sendall.Contract.contract.Transact(opts, method, params...) +} + +// SendAll is a paid mutator transaction binding the contract method 0x89e5af5f. +// +// Solidity: function sendAll(address fromAddress, address toAddress, string denom) returns() +func (_Sendall *SendallTransactor) SendAll(opts *bind.TransactOpts, fromAddress common.Address, toAddress common.Address, denom string) (*types.Transaction, error) { + return _Sendall.contract.Transact(opts, "sendAll", fromAddress, toAddress, denom) +} + +// SendAll is a paid mutator transaction binding the contract method 0x89e5af5f. +// +// Solidity: function sendAll(address fromAddress, address toAddress, string denom) returns() +func (_Sendall *SendallSession) SendAll(fromAddress common.Address, toAddress common.Address, denom string) (*types.Transaction, error) { + return _Sendall.Contract.SendAll(&_Sendall.TransactOpts, fromAddress, toAddress, denom) +} + +// SendAll is a paid mutator transaction binding the contract method 0x89e5af5f. +// +// Solidity: function sendAll(address fromAddress, address toAddress, string denom) returns() +func (_Sendall *SendallTransactorSession) SendAll(fromAddress common.Address, toAddress common.Address, denom string) (*types.Transaction, error) { + return _Sendall.Contract.SendAll(&_Sendall.TransactOpts, fromAddress, toAddress, denom) +} diff --git a/example/contracts/sendall/SendAll.sol b/example/contracts/sendall/SendAll.sol new file mode 100644 index 0000000000..5e3bc1fd85 --- /dev/null +++ b/example/contracts/sendall/SendAll.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../../../precompiles/bank/Bank.sol"; + +contract SendAll { + function sendAll( + address fromAddress, + address toAddress, + string memory denom + ) public { + uint256 amount = BANK_CONTRACT.balance(fromAddress, denom); + BANK_CONTRACT.send(fromAddress, toAddress, denom, amount); + } +} \ No newline at end of file diff --git a/example/contracts/simplestorage/SimpleStorage.abi b/example/contracts/simplestorage/SimpleStorage.abi new file mode 100644 index 0000000000..3c5944797a --- /dev/null +++ b/example/contracts/simplestorage/SimpleStorage.abi @@ -0,0 +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 diff --git a/example/contracts/simplestorage/SimpleStorage.bin b/example/contracts/simplestorage/SimpleStorage.bin new file mode 100644 index 0000000000..bb903ae71d --- /dev/null +++ b/example/contracts/simplestorage/SimpleStorage.bin @@ -0,0 +1 @@ +608060405234801561000f575f80fd5b5061017a8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c806360fe47b1146100385780636d4ce63c14610054575b5f80fd5b610052600480360381019061004d91906100f1565b610072565b005b61005c6100b2565b604051610069919061012b565b60405180910390f35b805f819055507f0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1816040516100a7919061012b565b60405180910390a150565b5f8054905090565b5f80fd5b5f819050919050565b6100d0816100be565b81146100da575f80fd5b50565b5f813590506100eb816100c7565b92915050565b5f60208284031215610106576101056100ba565b5b5f610113848285016100dd565b91505092915050565b610125816100be565b82525050565b5f60208201905061013e5f83018461011c565b9291505056fea26469706673582212205b2eaa3bd967fbbfe4490610612964348d1d0b2a793d2b0d117fe05ccb02d1e364736f6c63430008150033 \ No newline at end of file diff --git a/example/contracts/simplestorage/SimpleStorage.go b/example/contracts/simplestorage/SimpleStorage.go new file mode 100644 index 0000000000..c3d451e291 --- /dev/null +++ b/example/contracts/simplestorage/SimpleStorage.go @@ -0,0 +1,367 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package simplestorage + +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 +) + +// 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\"}]", +} + +// SimplestorageABI is the input ABI used to generate the binding from. +// Deprecated: Use SimplestorageMetaData.ABI instead. +var SimplestorageABI = SimplestorageMetaData.ABI + +// Simplestorage is an auto generated Go binding around an Ethereum contract. +type Simplestorage struct { + SimplestorageCaller // Read-only binding to the contract + SimplestorageTransactor // Write-only binding to the contract + SimplestorageFilterer // Log filterer for contract events +} + +// SimplestorageCaller is an auto generated read-only Go binding around an Ethereum contract. +type SimplestorageCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SimplestorageTransactor is an auto generated write-only Go binding around an Ethereum contract. +type SimplestorageTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SimplestorageFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type SimplestorageFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// SimplestorageSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type SimplestorageSession struct { + Contract *Simplestorage // 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 +} + +// SimplestorageCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type SimplestorageCallerSession struct { + Contract *SimplestorageCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// SimplestorageTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type SimplestorageTransactorSession struct { + Contract *SimplestorageTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// SimplestorageRaw is an auto generated low-level Go binding around an Ethereum contract. +type SimplestorageRaw struct { + Contract *Simplestorage // Generic contract binding to access the raw methods on +} + +// SimplestorageCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type SimplestorageCallerRaw struct { + Contract *SimplestorageCaller // Generic read-only contract binding to access the raw methods on +} + +// SimplestorageTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type SimplestorageTransactorRaw struct { + Contract *SimplestorageTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewSimplestorage creates a new instance of Simplestorage, bound to a specific deployed contract. +func NewSimplestorage(address common.Address, backend bind.ContractBackend) (*Simplestorage, error) { + contract, err := bindSimplestorage(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Simplestorage{SimplestorageCaller: SimplestorageCaller{contract: contract}, SimplestorageTransactor: SimplestorageTransactor{contract: contract}, SimplestorageFilterer: SimplestorageFilterer{contract: contract}}, nil +} + +// NewSimplestorageCaller creates a new read-only instance of Simplestorage, bound to a specific deployed contract. +func NewSimplestorageCaller(address common.Address, caller bind.ContractCaller) (*SimplestorageCaller, error) { + contract, err := bindSimplestorage(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &SimplestorageCaller{contract: contract}, nil +} + +// NewSimplestorageTransactor creates a new write-only instance of Simplestorage, bound to a specific deployed contract. +func NewSimplestorageTransactor(address common.Address, transactor bind.ContractTransactor) (*SimplestorageTransactor, error) { + contract, err := bindSimplestorage(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &SimplestorageTransactor{contract: contract}, nil +} + +// NewSimplestorageFilterer creates a new log filterer instance of Simplestorage, bound to a specific deployed contract. +func NewSimplestorageFilterer(address common.Address, filterer bind.ContractFilterer) (*SimplestorageFilterer, error) { + contract, err := bindSimplestorage(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &SimplestorageFilterer{contract: contract}, nil +} + +// bindSimplestorage binds a generic wrapper to an already deployed contract. +func bindSimplestorage(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := SimplestorageMetaData.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 (_Simplestorage *SimplestorageRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Simplestorage.Contract.SimplestorageCaller.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 (_Simplestorage *SimplestorageRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Simplestorage.Contract.SimplestorageTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Simplestorage *SimplestorageRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Simplestorage.Contract.SimplestorageTransactor.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 (_Simplestorage *SimplestorageCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Simplestorage.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 (_Simplestorage *SimplestorageTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Simplestorage.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Simplestorage *SimplestorageTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Simplestorage.Contract.contract.Transact(opts, method, params...) +} + +// Get is a free data retrieval call binding the contract method 0x6d4ce63c. +// +// Solidity: function get() view returns(uint256) +func (_Simplestorage *SimplestorageCaller) Get(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Simplestorage.contract.Call(opts, &out, "get") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Get is a free data retrieval call binding the contract method 0x6d4ce63c. +// +// Solidity: function get() view returns(uint256) +func (_Simplestorage *SimplestorageSession) Get() (*big.Int, error) { + return _Simplestorage.Contract.Get(&_Simplestorage.CallOpts) +} + +// Get is a free data retrieval call binding the contract method 0x6d4ce63c. +// +// Solidity: function get() view returns(uint256) +func (_Simplestorage *SimplestorageCallerSession) Get() (*big.Int, error) { + return _Simplestorage.Contract.Get(&_Simplestorage.CallOpts) +} + +// Set is a paid mutator transaction binding the contract method 0x60fe47b1. +// +// Solidity: function set(uint256 value) returns() +func (_Simplestorage *SimplestorageTransactor) Set(opts *bind.TransactOpts, value *big.Int) (*types.Transaction, error) { + return _Simplestorage.contract.Transact(opts, "set", value) +} + +// Set is a paid mutator transaction binding the contract method 0x60fe47b1. +// +// Solidity: function set(uint256 value) returns() +func (_Simplestorage *SimplestorageSession) Set(value *big.Int) (*types.Transaction, error) { + return _Simplestorage.Contract.Set(&_Simplestorage.TransactOpts, value) +} + +// Set is a paid mutator transaction binding the contract method 0x60fe47b1. +// +// Solidity: function set(uint256 value) returns() +func (_Simplestorage *SimplestorageTransactorSession) Set(value *big.Int) (*types.Transaction, error) { + return _Simplestorage.Contract.Set(&_Simplestorage.TransactOpts, value) +} + +// SimplestorageSetEventIterator is returned from FilterSetEvent and is used to iterate over the raw logs and unpacked data for SetEvent events raised by the Simplestorage contract. +type SimplestorageSetEventIterator struct { + Event *SimplestorageSetEvent // 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 *SimplestorageSetEventIterator) 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(SimplestorageSetEvent) + 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(SimplestorageSetEvent) + 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 *SimplestorageSetEventIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *SimplestorageSetEventIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// SimplestorageSetEvent represents a SetEvent event raised by the Simplestorage contract. +type SimplestorageSetEvent struct { + Value *big.Int + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSetEvent is a free log retrieval operation binding the contract event 0x0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1. +// +// Solidity: event SetEvent(uint256 value) +func (_Simplestorage *SimplestorageFilterer) FilterSetEvent(opts *bind.FilterOpts) (*SimplestorageSetEventIterator, error) { + + logs, sub, err := _Simplestorage.contract.FilterLogs(opts, "SetEvent") + if err != nil { + return nil, err + } + return &SimplestorageSetEventIterator{contract: _Simplestorage.contract, event: "SetEvent", logs: logs, sub: sub}, nil +} + +// WatchSetEvent is a free log subscription operation binding the contract event 0x0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1. +// +// Solidity: event SetEvent(uint256 value) +func (_Simplestorage *SimplestorageFilterer) WatchSetEvent(opts *bind.WatchOpts, sink chan<- *SimplestorageSetEvent) (event.Subscription, error) { + + logs, sub, err := _Simplestorage.contract.WatchLogs(opts, "SetEvent") + 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(SimplestorageSetEvent) + if err := _Simplestorage.contract.UnpackLog(event, "SetEvent", 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 +} + +// ParseSetEvent is a log parse operation binding the contract event 0x0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1. +// +// Solidity: event SetEvent(uint256 value) +func (_Simplestorage *SimplestorageFilterer) ParseSetEvent(log types.Log) (*SimplestorageSetEvent, error) { + event := new(SimplestorageSetEvent) + if err := _Simplestorage.contract.UnpackLog(event, "SetEvent", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/example/contracts/simplestorage/SimpleStorage.sol b/example/contracts/simplestorage/SimpleStorage.sol new file mode 100644 index 0000000000..b8688e2b9e --- /dev/null +++ b/example/contracts/simplestorage/SimpleStorage.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract SimpleStorage { + uint256 private storedData; + + event SetEvent(uint256 value); + + function set(uint256 value) public { + storedData = value; + emit SetEvent(value); + } + + function get() public view returns (uint256) { + return storedData; + } +} \ No newline at end of file diff --git a/example/cosmwasm/cw20/Cargo.lock b/example/cosmwasm/cw20/Cargo.lock new file mode 100644 index 0000000000..882c7d0f70 --- /dev/null +++ b/example/cosmwasm/cw20/Cargo.lock @@ -0,0 +1,750 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bnum" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab9008b6bb9fc80b5277f2fe481c09e828743d9151203e804583eb4c9e15b31d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cosmwasm-crypto" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bb3c77c3b7ce472056968c745eb501c440fbc07be5004eba02782c35bfbbe3" +dependencies = [ + "digest 0.10.7", + "ecdsa", + "ed25519-zebra", + "k256", + "rand_core 0.6.4", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea73e9162e6efde00018d55ed0061e93a108b5d6ec4548b4f8ce3c706249687" +dependencies = [ + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-schema" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df41ea55f2946b6b43579659eec048cc2f66e8c8e2e3652fc5e5e476f673856" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43609e92ce1b9368aa951b334dd354a2d0dd4d484931a5f83ae10e12a26c8ba9" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-std" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d6864742e3a7662d024b51a94ea81c9af21db6faea2f9a6d2232bb97c6e53e" +dependencies = [ + "base64", + "bech32", + "bnum", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "sha2 0.10.8", + "static_assertions", + "thiserror", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cw-storage-plus" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5ff29294ee99373e2cd5fd21786a3c0ced99a52fec2ca347d565489c61b723c" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-utils" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c4a657e5caacc3a0d00ee96ca8618745d050b8f757c709babafb81208d4239c" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "cw2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c120b24fbbf5c3bedebb97f2cc85fbfa1c3287e09223428e7e597b5293c1fa" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "cw20" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "526e39bb20534e25a1cd0386727f0038f4da294e5e535729ba3ef54055246abd" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils", + "schemars", + "serde", +] + +[[package]] +name = "cwerc20" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "cw-utils", + "cw20", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek", + "hashbrown", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "k256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.8", + "signature", +] + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "proc-macro2" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" + +[[package]] +name = "serde" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/example/cosmwasm/cw20/Cargo.toml b/example/cosmwasm/cw20/Cargo.toml new file mode 100644 index 0000000000..8dfb67f496 --- /dev/null +++ b/example/cosmwasm/cw20/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "cwerc20" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] +doctest = false +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[dependencies] +cosmwasm-schema = "1.5.0" +cosmwasm-std = { version = "1.3.1", features = ["staking", "stargate"] } +cw-storage-plus = "1.2.0" +cw-utils = "1.0.3" +cw20 = "1.1.2" +schemars = "0.8.16" +serde = "1.0.195" +thiserror = "1.0.56" diff --git a/example/cosmwasm/cw20/artifacts/checksums.txt b/example/cosmwasm/cw20/artifacts/checksums.txt new file mode 100644 index 0000000000..c6f576df57 --- /dev/null +++ b/example/cosmwasm/cw20/artifacts/checksums.txt @@ -0,0 +1 @@ +a25d78d7acd2ee47cc39c224e162fe79b53e6bbe6ed2a56e8c0a86593ebe6102 cwerc20.wasm diff --git a/example/cosmwasm/cw20/artifacts/checksums_intermediate.txt b/example/cosmwasm/cw20/artifacts/checksums_intermediate.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/example/cosmwasm/cw20/artifacts/cwerc20.wasm b/example/cosmwasm/cw20/artifacts/cwerc20.wasm new file mode 100644 index 0000000000..aac641633a Binary files /dev/null and b/example/cosmwasm/cw20/artifacts/cwerc20.wasm differ diff --git a/example/cosmwasm/cw20/src/contract.rs b/example/cosmwasm/cw20/src/contract.rs new file mode 100644 index 0000000000..b5b2a09a15 --- /dev/null +++ b/example/cosmwasm/cw20/src/contract.rs @@ -0,0 +1,292 @@ +#[cfg(not(feature = "library"))] +use cosmwasm_std::entry_point; +use cosmwasm_std::{ + DepsMut, Env, MessageInfo, Response, Uint128, Binary, Deps, StdResult, to_json_binary, +}; +use cw20::{Cw20ReceiveMsg, AllowanceResponse}; +use cw_utils::Expiration; +use crate::msg::{cw20receive_into_cosmos_msg, EvmMsg, EvmQueryWrapper, ExecuteMsg, QueryMsg, InstantiateMsg}; +use crate::querier::EvmQuerier; +use crate::error::ContractError; +use crate::state::ERC20_ADDRESS; + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + ERC20_ADDRESS.save(deps.storage, &msg.erc20_address)?; + Ok(Response::default()) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result, ContractError> { + match msg { + ExecuteMsg::Transfer { recipient, amount } => { + execute_transfer(deps, env, info, recipient, amount) + }, + ExecuteMsg::Send { contract, amount, msg } => { + execute_send(deps, env, info, contract, amount, msg) + }, + ExecuteMsg::TransferFrom { owner, recipient, amount } => { + execute_transfer_from(deps, env, info, owner, recipient, amount) + }, + ExecuteMsg::SendFrom { owner, contract, amount, msg} => { + execute_send_from(deps, env, info, owner, contract, amount, msg) + } + ExecuteMsg::IncreaseAllowance { spender, amount, expires: _ } => { + execute_increase_allowance(deps, env, info, spender, amount) + }, + ExecuteMsg::DecreaseAllowance { spender, amount, expires: _ } => { + execute_decrease_allowance(deps, env, info, spender, amount) + } + _ => Err(ContractError::NotSupported {}) + } +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result { + match msg { + QueryMsg::Balance { address } => Ok(query_balance(deps, address)?), + QueryMsg::TokenInfo {} => Ok(query_token_info(deps, env)?), + QueryMsg::Minter {} => Err(ContractError::NotSupported {}), + QueryMsg::Allowance { owner, spender } => { + Ok(query_allowance(deps, owner, spender)?) + }, + QueryMsg::AllAllowances { + owner: _, + start_after: _ , + limit: _, + } => Err(ContractError::NotSupported {}), + QueryMsg::AllAccounts { start_after: _, limit: _, } => Err(ContractError::NotSupported {}), + QueryMsg::MarketingInfo {} => Err(ContractError::NotSupported {}), + QueryMsg::DownloadLogo {} => Err(ContractError::NotSupported {}), + } +} + +pub fn execute_transfer( + deps: DepsMut, + _env: Env, + info: MessageInfo, + recipient: String, + amount: Uint128, +) -> Result, ContractError> { + let mut res = transfer(deps, _env, info, recipient, amount)?; + res = res.add_attribute("action", "transfer"); + Ok(res) +} + +pub fn execute_send( + deps: DepsMut, + _env: Env, + info: MessageInfo, + contract: String, + amount: Uint128, + msg: Binary, +) -> Result, ContractError> { + let mut res = transfer(deps, _env, info.clone(), contract.clone(), amount)?; + let send = Cw20ReceiveMsg { + sender: info.sender.to_string(), + amount: amount.clone(), + msg, + }; + + res = res + .add_message(cw20receive_into_cosmos_msg(contract.clone(), send)?) + .add_attribute("action", "send"); + Ok(res) +} + +// Increase the allowance of spender by amount. +// Expiration does not work here since it is not supported by ERC20. +pub fn execute_increase_allowance( + deps: DepsMut, + _env: Env, + info: MessageInfo, + spender: String, + amount: Uint128, +) -> Result, ContractError> { + deps.api.addr_validate(&spender)?; + + let erc_addr = ERC20_ADDRESS.load(deps.storage)?; + + let querier = EvmQuerier::new(&deps.querier); + + // Query the current allowance for this user + let current_allowance = querier.erc20_allowance(erc_addr.clone(), info.sender.clone().into_string(), spender.clone())?.allowance; + + // Set the new allowance as the sum of the current allowance and amount specified + let new_allowance = current_allowance + amount; + + // Send the message to approve the new amount + let payload = querier.erc20_approve_payload(spender.clone(), new_allowance)?; + let msg = EvmMsg::DelegateCallEvm { to: erc_addr, data: payload.encoded_payload }; + + let res = Response::new() + .add_attribute("action", "increase_allowance") + .add_attribute("spender", spender) + .add_attribute("amount", amount) + .add_attribute("new_allowance", new_allowance) + .add_attribute("by", info.sender) + .add_message(msg); + + Ok(res) +} + +// Decrease the allowance of spender by amount. +// Expiration does not work here since it is not supported by ERC20. +pub fn execute_decrease_allowance( + deps: DepsMut, + _env: Env, + info: MessageInfo, + spender: String, + amount: Uint128, +) -> Result, ContractError> { + deps.api.addr_validate(&spender)?; + + let erc_addr = ERC20_ADDRESS.load(deps.storage)?; + + // Query the current allowance for this spender + let querier = EvmQuerier::new(&deps.querier); + let current_allowance = querier.erc20_allowance(erc_addr.clone(), info.sender.clone().into_string(), spender.clone())?.allowance; + + // If the new allowance after deduction is negative, set allowance to 0. + let new_allowance = match current_allowance.checked_sub(amount) + { + Ok(new_amount) => new_amount, + Err(_) => Uint128::MIN, + }; + + // Send the message to approve the new amount. + let payload = querier.erc20_approve_payload(spender.clone(), new_allowance)?; + let msg = EvmMsg::DelegateCallEvm { to: erc_addr, data: payload.encoded_payload }; + + let res = Response::new() + .add_attribute("action", "decrease_allowance") + .add_attribute("spender", spender) + .add_attribute("amount", amount) + .add_attribute("new_allowance", new_allowance) + .add_attribute("by", info.sender) + .add_message(msg); + + Ok(res) +} + +pub fn execute_transfer_from( + deps: DepsMut, + env: Env, + info: MessageInfo, + owner: String, + recipient: String, + amount: Uint128, +) -> Result, ContractError> { + let mut res = transfer_from(deps, env, info, owner, recipient, amount)?; + res = res.add_attribute("action", "transfer_from"); + + Ok(res) +} + +pub fn execute_send_from( + deps: DepsMut, + env: Env, + info: MessageInfo, + owner: String, + contract: String, + amount: Uint128, + msg: Binary, +) -> Result, ContractError> { + let mut res = transfer_from(deps, env, info.clone(), owner, contract.clone(), amount)?; + let send = Cw20ReceiveMsg { + sender: info.sender.to_string(), + amount: amount.clone(), + msg, + }; + + res = res + .add_message(cw20receive_into_cosmos_msg(contract.clone(), send)?) + .add_attribute("action", "send_from"); + Ok(res) +} + +fn transfer( + deps: DepsMut, + _env: Env, + info: MessageInfo, + recipient: String, + amount: Uint128, +) -> Result, ContractError> { + deps.api.addr_validate(&recipient)?; + + let erc_addr = ERC20_ADDRESS.load(deps.storage)?; + + let querier = EvmQuerier::new(&deps.querier); + let payload = querier.erc20_transfer_payload(recipient.clone(), amount)?; + 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("amount", amount) + .add_message(msg); + + Ok(res) +} + +pub fn transfer_from( + deps: DepsMut, + _env: Env, + info: MessageInfo, + owner: String, + recipient: String, + amount: Uint128, +) -> Result, ContractError> { + deps.api.addr_validate(&owner)?; + deps.api.addr_validate(&recipient)?; + + let erc_addr = ERC20_ADDRESS.load(deps.storage)?; + + let querier = EvmQuerier::new(&deps.querier); + let payload = querier.erc20_transfer_from_payload(owner.clone(), recipient.clone(), amount)?; + let msg = EvmMsg::DelegateCallEvm { to: erc_addr, data: payload.encoded_payload }; + let res = Response::new() + .add_attribute("from", owner) + .add_attribute("to", recipient) + .add_attribute("by", info.sender) + .add_attribute("amount", amount) + .add_message(msg); + + Ok(res) +} + +pub fn query_allowance(deps: Deps, owner: String, spender: String) -> StdResult { + deps.api.addr_validate(&owner)?; + deps.api.addr_validate(&spender)?; + + let erc_addr = ERC20_ADDRESS.load(deps.storage)?; + + let querier = EvmQuerier::new(&deps.querier); + let allowance = querier.erc20_allowance(erc_addr, owner, spender)?; + to_json_binary(&AllowanceResponse{allowance: allowance.allowance, expires: Expiration::Never{}}) +} + +pub fn query_token_info(deps: Deps, env: Env) -> StdResult { + let erc_addr = ERC20_ADDRESS.load(deps.storage)?; + + let querier = EvmQuerier::new(&deps.querier); + let token_info = querier.erc20_token_info(erc_addr, env.clone().contract.address.into_string())?; + to_json_binary(&token_info) +} + +pub fn query_balance(deps: Deps, account: String) -> StdResult { + let erc_addr = ERC20_ADDRESS.load(deps.storage)?; + + let querier = EvmQuerier::new(&deps.querier); + let balance = querier.erc20_balance(erc_addr, account.clone())?; + to_json_binary(&balance) +} diff --git a/example/cosmwasm/cw20/src/error.rs b/example/cosmwasm/cw20/src/error.rs new file mode 100644 index 0000000000..1691f2f2c1 --- /dev/null +++ b/example/cosmwasm/cw20/src/error.rs @@ -0,0 +1,11 @@ +use cosmwasm_std::StdError; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("ERC20 does not support the requested functionality in it's base spec")] + NotSupported {}, +} \ No newline at end of file diff --git a/example/cosmwasm/cw20/src/lib.rs b/example/cosmwasm/cw20/src/lib.rs new file mode 100644 index 0000000000..454b5bc860 --- /dev/null +++ b/example/cosmwasm/cw20/src/lib.rs @@ -0,0 +1,5 @@ +pub mod contract; +pub mod error; +pub mod msg; +pub mod querier; +pub mod state; diff --git a/example/cosmwasm/cw20/src/msg.rs b/example/cosmwasm/cw20/src/msg.rs new file mode 100644 index 0000000000..1e63b8f55a --- /dev/null +++ b/example/cosmwasm/cw20/src/msg.rs @@ -0,0 +1,106 @@ +use cosmwasm_std::{CosmosMsg, CustomMsg, CustomQuery, StdResult, Uint128, WasmMsg}; +use cw20::Cw20ReceiveMsg; +use schemars::JsonSchema; +use cosmwasm_schema::cw_serde; +use serde::{Deserialize, Serialize}; + +pub use cw20::{Cw20ExecuteMsg as ExecuteMsg, Cw20QueryMsg as QueryMsg}; + +#[cw_serde] +pub struct InstantiateMsg { + pub erc20_address: String, +} + +/// SeiRoute is enum type to represent sei query route path +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum Route { + Evm, +} + +/// EvmQueryWrapper is an override of QueryRequest::Custom to access EVM +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct EvmQueryWrapper { + pub route: Route, + pub query_data: EvmQuery, +} + +// implement custom query +impl CustomQuery for EvmQueryWrapper {} + +/// EvmQuery is defines available query datas +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum EvmQuery { + Erc20TransferPayload { + recipient: String, + amount: Uint128, + }, + Erc20TransferFromPayload { + owner: String, + recipient: String, + amount: Uint128, + }, + Erc20ApprovePayload { + spender: String, + amount: Uint128, + }, + Erc20Allowance { + contract_address: String, + owner: String, + spender: String, + }, + Erc20TokenInfo { + contract_address: String, + caller: String, + }, + Erc20Balance { + contract_address: String, + account: String, + }, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct ErcPayloadResponse { + pub encoded_payload: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Erc20AllowanceResponse { + pub allowance: Uint128, +} + +// implement custom query +impl CustomMsg for EvmMsg {} + +// this is a helper to be able to return these as CosmosMsg easier +impl From for CosmosMsg { + fn from(original: EvmMsg) -> Self { + CosmosMsg::Custom(original) + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum EvmMsg { + DelegateCallEvm { + to: String, + data: String, // base64 encoded + }, +} + +/// Helper to convert a Cw20ReceiveMsg into an EvmMsg +pub fn cw20receive_into_cosmos_msg, C>(contract_addr: T, message: Cw20ReceiveMsg) -> StdResult> +where + C: Clone + std::fmt::Debug + PartialEq + JsonSchema, +{ + let msg = message.into_binary()?; + let execute = WasmMsg::Execute { + contract_addr: contract_addr.into(), + msg, + funds: vec![], + }; + + Ok(execute.into()) +} \ No newline at end of file diff --git a/example/cosmwasm/cw20/src/querier.rs b/example/cosmwasm/cw20/src/querier.rs new file mode 100644 index 0000000000..7465ccc25b --- /dev/null +++ b/example/cosmwasm/cw20/src/querier.rs @@ -0,0 +1,89 @@ +use cosmwasm_std::{QuerierWrapper, StdResult, Uint128}; +use cw20::{TokenInfoResponse, BalanceResponse}; + +use crate::msg::{Erc20AllowanceResponse, ErcPayloadResponse, EvmQuery, EvmQueryWrapper, Route}; + +pub struct EvmQuerier<'a> { + querier: &'a QuerierWrapper<'a, EvmQueryWrapper>, +} + +impl<'a> EvmQuerier<'a> { + pub fn new(querier: &'a QuerierWrapper) -> Self { + EvmQuerier { querier } + } + + // returns base64-encoded bytes + pub fn erc20_transfer_payload(&self, recipient: String, amount: Uint128) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc20TransferPayload { + recipient, amount, + }, + } + .into(); + + self.querier.query(&request) + } + + // returns base64-encoded bytes + pub fn erc20_transfer_from_payload(&self, owner: String, recipient: String, amount: Uint128) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc20TransferFromPayload { + owner, recipient, amount, + }, + } + .into(); + + self.querier.query(&request) + } + + // returns base64-encoded bytes + pub fn erc20_approve_payload(&self, spender: String, amount: Uint128) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc20ApprovePayload { + spender, amount, + }, + } + .into(); + + self.querier.query(&request) + } + + pub fn erc20_allowance(&self, contract_address: String, owner: String, spender: String) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc20Allowance { + contract_address, owner, spender, + }, + } + .into(); + + self.querier.query(&request) + } + + pub fn erc20_token_info(&self, contract_address: String, caller: String) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc20TokenInfo { + contract_address, caller, + }, + } + .into(); + + self.querier.query(&request) + } + + pub fn erc20_balance(&self, contract_address: String, account: String) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc20Balance { + contract_address, account, + }, + } + .into(); + + self.querier.query(&request) + } +} \ No newline at end of file diff --git a/example/cosmwasm/cw20/src/state.rs b/example/cosmwasm/cw20/src/state.rs new file mode 100644 index 0000000000..fbd8406cce --- /dev/null +++ b/example/cosmwasm/cw20/src/state.rs @@ -0,0 +1,3 @@ +use cw_storage_plus::Item; + +pub const ERC20_ADDRESS: Item = Item::new("erc20_address"); \ No newline at end of file diff --git a/example/cosmwasm/cw721/Cargo.lock b/example/cosmwasm/cw721/Cargo.lock new file mode 100644 index 0000000000..b9691cd18e --- /dev/null +++ b/example/cosmwasm/cw721/Cargo.lock @@ -0,0 +1,749 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bnum" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab9008b6bb9fc80b5277f2fe481c09e828743d9151203e804583eb4c9e15b31d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cosmwasm-crypto" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6aa9f904de106fa16443ad14ec2abe75e94ba003bb61c681c0e43d4c58d2a" +dependencies = [ + "digest 0.10.7", + "ecdsa", + "ed25519-zebra", + "k256", + "rand_core 0.6.4", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40abec852f3d4abec6d44ead9a58b78325021a1ead1e7229c3471414e57b2e49" +dependencies = [ + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-schema" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b166215fbfe93dc5575bae062aa57ae7bb41121cffe53bac33b033257949d2a9" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf12f8e20bb29d1db66b7ca590bc2f670b548d21e9be92499bc0f9022a994a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-std" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad011ae7447188e26e4a7dbca2fcd0fc186aa21ae5c86df0503ea44c78f9e469" +dependencies = [ + "base64", + "bech32", + "bnum", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "sha2 0.10.8", + "static_assertions", + "thiserror", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cw-storage-plus" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5ff29294ee99373e2cd5fd21786a3c0ced99a52fec2ca347d565489c61b723c" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-utils" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c4a657e5caacc3a0d00ee96ca8618745d050b8f757c709babafb81208d4239c" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "cw2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c120b24fbbf5c3bedebb97f2cc85fbfa1c3287e09223428e7e597b5293c1fa" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "cw721" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c4d286625ccadc957fe480dd3bdc54ada19e0e6b5b9325379db3130569e914" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-utils", + "schemars", + "serde", +] + +[[package]] +name = "cwerc721" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "cw721", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek", + "hashbrown", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.8", + "signature", +] + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" + +[[package]] +name = "serde" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/example/cosmwasm/cw721/Cargo.toml b/example/cosmwasm/cw721/Cargo.toml new file mode 100644 index 0000000000..5c06474a95 --- /dev/null +++ b/example/cosmwasm/cw721/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "cwerc721" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] +doctest = false +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[dependencies] +cosmwasm-schema = "1.5.0" +cosmwasm-std = { version = "1.3.1", features = ["staking", "stargate"] } +cw-storage-plus = "1.2.0" +cw721 = "0.18.0" +schemars = "0.8.16" +serde = "1.0.195" +thiserror = "1.0.56" diff --git a/example/cosmwasm/cw721/artifacts/checksums.txt b/example/cosmwasm/cw721/artifacts/checksums.txt new file mode 100644 index 0000000000..a31da2c613 --- /dev/null +++ b/example/cosmwasm/cw721/artifacts/checksums.txt @@ -0,0 +1 @@ +94cdd9c3e85c26f7cec43c23bfb4b3b2b2d71a0a8d85c58df12ffec0741febc8 cwerc721.wasm diff --git a/example/cosmwasm/cw721/artifacts/cwerc721.wasm b/example/cosmwasm/cw721/artifacts/cwerc721.wasm new file mode 100644 index 0000000000..318ada77bc Binary files /dev/null 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 new file mode 100644 index 0000000000..690bb262d4 --- /dev/null +++ b/example/cosmwasm/cw721/src/contract.rs @@ -0,0 +1,223 @@ +#[cfg(not(feature = "library"))] +use cosmwasm_std::entry_point; +use cosmwasm_std::{ + DepsMut, Deps, Env, MessageInfo, Response, Binary, StdResult, to_json_binary, +}; +use cw721::{Cw721ReceiveMsg, OwnerOfResponse, Approval, ApprovalResponse, ApprovalsResponse, OperatorResponse, ContractInfoResponse, NftInfoResponse, AllNftInfoResponse}; +use crate::msg::{EvmQueryWrapper, EvmMsg, InstantiateMsg, ExecuteMsg, QueryMsg}; +use crate::querier::EvmQuerier; +use crate::error::ContractError; +use crate::state::ERC721_ADDRESS; + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + ERC721_ADDRESS.save(deps.storage, &msg.erc721_address)?; + Ok(Response::default()) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result, ContractError> { + match msg { + ExecuteMsg::TransferNft { recipient, token_id } => { + execute_transfer_nft(deps, info, recipient, token_id) + }, + ExecuteMsg::SendNft { contract, token_id , msg} => { + execute_send_nft(deps, info, contract, token_id, msg) + }, + ExecuteMsg::Approve { spender, token_id, expires: _ } => { + execute_approve(deps, spender, token_id) + }, + ExecuteMsg::Revoke { spender: _, token_id } => { + execute_approve(deps, "".to_string(), token_id) + }, + ExecuteMsg::ApproveAll { operator, expires: _ } => { + execute_approve_all(deps, operator, true) + }, + ExecuteMsg::RevokeAll { operator } => { + execute_approve_all(deps, operator, false) + }, + ExecuteMsg::Burn { token_id: _ } => { execute_burn() } + } +} + +pub fn execute_transfer_nft( + deps: DepsMut, + info: MessageInfo, + recipient: String, + token_id: String, +) -> Result, ContractError> { + let mut res = transfer_nft(deps, info, recipient, token_id)?; + res = res.add_attribute("action", "transfer_nft"); + Ok(res) +} + +pub fn execute_send_nft( + deps: DepsMut, + info: MessageInfo, + recipient: String, + token_id: String, + msg: Binary, +) -> Result, ContractError> { + let mut res = transfer_nft(deps, info.clone(), recipient.clone(), token_id.clone())?; + let send = Cw721ReceiveMsg { + sender: info.sender.to_string(), + token_id: token_id.clone(), + msg, + }; + res = res + .add_message(send.into_cosmos_msg(recipient.clone())?) + .add_attribute("action", "send_nft"); + Ok(res) +} + +pub fn execute_approve( + deps: DepsMut, + spender: String, + token_id: String, +) -> 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 msg = EvmMsg::DelegateCallEvm { to: erc_addr, data: payload.encoded_payload }; + let res = Response::new() + .add_attribute("action", "approve") + .add_attribute("token_id", token_id) + .add_message(msg); + + Ok(res) +} + +pub fn execute_approve_all( + deps: DepsMut, + to: String, + approved: bool, +) -> Result, ContractError> { + let erc_addr = ERC721_ADDRESS.load(deps.storage)?; + + 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 res = Response::new() + .add_attribute("action", "approve_all") + .add_attribute("to", to) + .add_attribute("approved", format!("{}", approved)) + .add_message(msg); + + Ok(res) +} + +pub fn execute_burn() -> Result, ContractError> { + Err(ContractError::NotSupported {}) +} + +fn transfer_nft( + deps: DepsMut, + info: MessageInfo, + recipient: String, + token_id: String, +) -> Result, ContractError> { + 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 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); + + Ok(res) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +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::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 { }), + } +} + +pub fn query_owner_of(deps: Deps, env: Env, token_id: String) -> StdResult { + let erc_addr = ERC721_ADDRESS.load(deps.storage)?; + let querier = EvmQuerier::new(&deps.querier); + let owner = querier.erc721_owner(env.clone().contract.address.into_string(), erc_addr.clone(), token_id.clone())?.owner; + let approved = querier.erc721_approved(env.clone().contract.address.into_string(), erc_addr.clone(), token_id.clone())?.approved; + let mut approvals: Vec = vec![]; + if !approved.is_empty() { + approvals.push(Approval{spender:approved, expires: cw721::Expiration::Never {}}); + } + Ok(OwnerOfResponse{owner, approvals}) +} + +pub fn query_approval(deps: Deps, env: Env, token_id: String, spender: String) -> StdResult { + let erc_addr = ERC721_ADDRESS.load(deps.storage)?; + let querier = EvmQuerier::new(&deps.querier); + let approved = querier.erc721_approved(env.clone().contract.address.into_string(), erc_addr.clone(), token_id.clone())?.approved; + if !approved.is_empty() && approved == spender { + return to_json_binary(&ApprovalResponse{approval: Approval{spender, expires: cw721::Expiration::Never {}}}); + } + Err(cosmwasm_std::StdError::NotFound { kind: "not approved".to_string() }) +} + +pub fn query_approvals(deps: Deps, env: Env, token_id: String) -> StdResult { + let erc_addr = ERC721_ADDRESS.load(deps.storage)?; + let querier = EvmQuerier::new(&deps.querier); + let approved = querier.erc721_approved(env.clone().contract.address.into_string(), erc_addr.clone(), token_id.clone())?.approved; + if !approved.is_empty() { + return to_json_binary(&ApprovalsResponse{approvals: vec![Approval{spender: approved, expires: cw721::Expiration::Never {}}]}); + } + to_json_binary(&ApprovalsResponse{approvals: vec![]}) +} + +pub fn query_operator(deps: Deps, env: Env, owner: String, operator: String) -> StdResult { + let erc_addr = ERC721_ADDRESS.load(deps.storage)?; + let querier = EvmQuerier::new(&deps.querier); + let is_approved = querier.erc721_is_approved_for_all(env.clone().contract.address.into_string(), erc_addr.clone(), owner.clone(), operator.clone())?.is_approved; + if is_approved { + return to_json_binary(&OperatorResponse{approval: Approval{spender: operator.clone(), expires: cw721::Expiration::Never {}}}); + } + Err(cosmwasm_std::StdError::NotFound { kind: "not approved".to_string() }) +} + +pub fn query_contract_info(deps: Deps, env: Env) -> StdResult { + let erc_addr = ERC721_ADDRESS.load(deps.storage)?; + let querier = EvmQuerier::new(&deps.querier); + let res = querier.erc721_name_symbol(env.clone().contract.address.into_string(), erc_addr.clone())?; + to_json_binary(&ContractInfoResponse{name: res.name, symbol: res.symbol}) +} + +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())?; + to_json_binary(&NftInfoResponse{token_uri: Some(res.uri), extension: ""}) +} + +pub fn query_all_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 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 diff --git a/example/cosmwasm/cw721/src/error.rs b/example/cosmwasm/cw721/src/error.rs new file mode 100644 index 0000000000..4758f75d26 --- /dev/null +++ b/example/cosmwasm/cw721/src/error.rs @@ -0,0 +1,11 @@ +use cosmwasm_std::StdError; +use thiserror::Error; + +#[derive(Error, Debug, PartialEq)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("ERC721 does not have the requested functionality in specification")] + NotSupported {}, +} \ No newline at end of file diff --git a/example/cosmwasm/cw721/src/lib.rs b/example/cosmwasm/cw721/src/lib.rs new file mode 100644 index 0000000000..454b5bc860 --- /dev/null +++ b/example/cosmwasm/cw721/src/lib.rs @@ -0,0 +1,5 @@ +pub mod contract; +pub mod error; +pub mod msg; +pub mod querier; +pub mod state; diff --git a/example/cosmwasm/cw721/src/msg.rs b/example/cosmwasm/cw721/src/msg.rs new file mode 100644 index 0000000000..55ccb153b1 --- /dev/null +++ b/example/cosmwasm/cw721/src/msg.rs @@ -0,0 +1,123 @@ +use cosmwasm_std::{CosmosMsg, CustomMsg, CustomQuery}; +use schemars::JsonSchema; +use cosmwasm_schema::cw_serde; +use serde::{Deserialize, Serialize}; + +pub use cw721::{Cw721ExecuteMsg as ExecuteMsg, Cw721QueryMsg as QueryMsg}; + +#[cw_serde] +pub struct InstantiateMsg { + pub erc721_address: String, +} + +/// SeiRoute is enum type to represent sei query route path +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum Route { + Evm, +} + +/// EvmQueryWrapper is an override of QueryRequest::Custom to access EVM +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct EvmQueryWrapper { + pub route: Route, + pub query_data: EvmQuery, +} + +// implement custom query +impl CustomQuery for EvmQueryWrapper {} + +/// EvmQuery is defines available query datas +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum EvmQuery { + Erc721TransferPayload { + from: String, + recipient: String, + token_id: String, + }, + Erc721ApprovePayload { + spender: String, + token_id: String, + }, + Erc721Owner { + caller: String, + contract_address: String, + token_id: String, + }, + Erc721Approved { + caller: String, + contract_address: String, + token_id: String, + }, + Erc721IsApprovedForAll { + caller: String, + contract_address: String, + owner: String, + operator: String, + }, + Erc721SetApprovalAllPayload { + to: String, + approved: bool, + }, + Erc721NameSymbol { + caller: String, + contract_address: String, + }, + Erc721Uri { + caller: String, + contract_address: String, + token_id: String, + }, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct ErcPayloadResponse { + pub encoded_payload: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Erc721OwnerResponse { + pub owner: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Erc721ApprovedResponse { + pub approved: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Erc721IsApprovedForAllResponse { + pub is_approved: bool, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Erc721NameSymbolResponse { + pub name: String, + pub symbol: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Erc721UriResponse { + pub uri: String, +} + +// implement custom query +impl CustomMsg for EvmMsg {} + +// this is a helper to be able to return these as CosmosMsg easier +impl From for CosmosMsg { + fn from(original: EvmMsg) -> Self { + CosmosMsg::Custom(original) + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum EvmMsg { + DelegateCallEvm { + to: String, + data: String, // base64 encoded + }, +} \ No newline at end of file diff --git a/example/cosmwasm/cw721/src/querier.rs b/example/cosmwasm/cw721/src/querier.rs new file mode 100644 index 0000000000..542c63f8a9 --- /dev/null +++ b/example/cosmwasm/cw721/src/querier.rs @@ -0,0 +1,100 @@ +use cosmwasm_std::{QuerierWrapper, StdResult}; + +use crate::msg::{Route, EvmQuery, EvmQueryWrapper, ErcPayloadResponse, Erc721OwnerResponse, Erc721ApprovedResponse, Erc721IsApprovedForAllResponse, Erc721NameSymbolResponse, Erc721UriResponse}; + +pub struct EvmQuerier<'a> { + querier: &'a QuerierWrapper<'a, EvmQueryWrapper>, +} + +impl<'a> EvmQuerier<'a> { + pub fn new(querier: &'a QuerierWrapper) -> Self { + EvmQuerier { querier } + } + + pub fn erc721_owner(&self, caller: String, contract_address: String, token_id: String) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721Owner { caller, contract_address, token_id }, + } + .into(); + + self.querier.query(&request) + } + + pub fn erc721_approved(&self, caller: String, contract_address: String, token_id: String) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721Approved { caller, contract_address, token_id }, + } + .into(); + + self.querier.query(&request) + } + + pub fn erc721_is_approved_for_all(&self, caller: String, contract_address: String, owner: String, operator: String) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721IsApprovedForAll { caller, contract_address, owner, operator }, + } + .into(); + + self.querier.query(&request) + } + + pub fn erc721_name_symbol(&self, caller: String, contract_address: String) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721NameSymbol { caller, contract_address }, + } + .into(); + + self.querier.query(&request) + } + + pub fn erc721_uri(&self, caller: String, contract_address: String, token_id: String,) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721Uri { caller, contract_address, token_id }, + } + .into(); + + self.querier.query(&request) + } + + // returns base64-encoded bytes + pub fn erc721_transfer_payload(&self, from: String, recipient: String, token_id: String) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721TransferPayload { + from, recipient, token_id, + }, + } + .into(); + + self.querier.query(&request) + } + + // returns base64-encoded bytes + pub fn erc721_approve_payload(&self, spender: String, token_id: String) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721ApprovePayload { + spender, token_id, + }, + } + .into(); + + self.querier.query(&request) + } + + // returns base64-encoded bytes + pub fn erc721_set_approval_all_payload(&self, to: String, approved: bool) -> StdResult { + let request = EvmQueryWrapper { + route: Route::Evm, + query_data: EvmQuery::Erc721SetApprovalAllPayload { to, approved, }, + } + .into(); + + self.querier.query(&request) + } +} \ No newline at end of file diff --git a/example/cosmwasm/cw721/src/state.rs b/example/cosmwasm/cw721/src/state.rs new file mode 100644 index 0000000000..d91df9b371 --- /dev/null +++ b/example/cosmwasm/cw721/src/state.rs @@ -0,0 +1,3 @@ +use cw_storage_plus::Item; + +pub const ERC721_ADDRESS: Item = Item::new("erc721_address"); \ No newline at end of file diff --git a/example/cosmwasm/echo/Cargo.lock b/example/cosmwasm/echo/Cargo.lock new file mode 100644 index 0000000000..0f6301e5ca --- /dev/null +++ b/example/cosmwasm/echo/Cargo.lock @@ -0,0 +1,736 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bnum" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128a44527fc0d6abf05f9eda748b9027536e12dff93f5acc8449f51583309350" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + +[[package]] +name = "cosmwasm-crypto" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bb3c77c3b7ce472056968c745eb501c440fbc07be5004eba02782c35bfbbe3" +dependencies = [ + "digest 0.10.7", + "ecdsa", + "ed25519-zebra", + "k256", + "rand_core 0.6.4", + "thiserror", +] + +[[package]] +name = "cosmwasm-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea73e9162e6efde00018d55ed0061e93a108b5d6ec4548b4f8ce3c706249687" +dependencies = [ + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-schema" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df41ea55f2946b6b43579659eec048cc2f66e8c8e2e3652fc5e5e476f673856" +dependencies = [ + "cosmwasm-schema-derive", + "schemars", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43609e92ce1b9368aa951b334dd354a2d0dd4d484931a5f83ae10e12a26c8ba9" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cosmwasm-std" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d6864742e3a7662d024b51a94ea81c9af21db6faea2f9a6d2232bb97c6e53e" +dependencies = [ + "base64", + "bech32", + "bnum", + "cosmwasm-crypto", + "cosmwasm-derive", + "derivative", + "forward_ref", + "hex", + "schemars", + "serde", + "serde-json-wasm", + "sha2 0.10.8", + "static_assertions", + "thiserror", +] + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "cw-storage-plus" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f0e92a069d62067f3472c62e30adedb4cab1754725c0f2a682b3128d2bf3c79" +dependencies = [ + "cosmwasm-std", + "schemars", + "serde", +] + +[[package]] +name = "cw-utils" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9f351a4e4d81ef7c890e44d903f8c0bdcdc00f094fd3a181eaf70c0eec7a3a" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw2", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "cw2" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9431d14f64f49e41c6ef5561ed11a5391c417d0cb16455dea8cdcb9037a8d197" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "schemars", + "serde", + "thiserror", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "echo" +version = "0.1.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "cw-utils", + "schemars", + "semver", + "serde", + "thiserror", +] + +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek", + "hashbrown", + "hex", + "rand_core 0.6.4", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "forward_ref" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.8", + "signature", +] + +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "schemars" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f7b0ce13155372a76ee2e1c5ffba1fe61ede73fbea5630d61eee6fac4929c0c" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-json-wasm" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16a62a1fad1e1828b24acac8f2b468971dade7b8c3c2e672bcadefefb1f8c137" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.192" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/example/cosmwasm/echo/Cargo.toml b/example/cosmwasm/echo/Cargo.toml new file mode 100644 index 0000000000..42fbe535f5 --- /dev/null +++ b/example/cosmwasm/echo/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "echo" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] +doctest = false + +[features] +backtraces = ["cosmwasm-std/backtraces"] +# use library feature to disable all instantiate/execute/query exports +library = [] + +[dependencies] +cosmwasm-schema = { version = "1.3.1" } +cw-utils = "1.0.1" +cw-storage-plus = "1.0.1" +cosmwasm-std = { version = "1.3.1", features = ["staking", "stargate"] } +schemars = "0.8.1" +serde = { version = "1.0.103", default-features = false, features = ["derive"] } +thiserror = { version = "1.0.23" } +semver = "1" diff --git a/example/cosmwasm/echo/artifacts/checksums.txt b/example/cosmwasm/echo/artifacts/checksums.txt new file mode 100644 index 0000000000..11051d09a5 --- /dev/null +++ b/example/cosmwasm/echo/artifacts/checksums.txt @@ -0,0 +1 @@ +96442088387551ac7656847625a7507acba32716336fc9e961e284e7cd2f89c8 echo.wasm diff --git a/example/cosmwasm/echo/artifacts/checksums_intermediate.txt b/example/cosmwasm/echo/artifacts/checksums_intermediate.txt new file mode 100644 index 0000000000..2ab62526af --- /dev/null +++ b/example/cosmwasm/echo/artifacts/checksums_intermediate.txt @@ -0,0 +1 @@ +81aee154f416ddc87abe87352e55ecafbe8e53b9d175fae6eda637a592d3669e /target/wasm32-unknown-unknown/release/echo.wasm diff --git a/example/cosmwasm/echo/artifacts/echo.wasm b/example/cosmwasm/echo/artifacts/echo.wasm new file mode 100644 index 0000000000..59659cf92b Binary files /dev/null and b/example/cosmwasm/echo/artifacts/echo.wasm differ diff --git a/example/cosmwasm/echo/src/contract.rs b/example/cosmwasm/echo/src/contract.rs new file mode 100644 index 0000000000..4f22ef038c --- /dev/null +++ b/example/cosmwasm/echo/src/contract.rs @@ -0,0 +1,45 @@ +#[cfg(not(feature = "library"))] +use cosmwasm_std::entry_point; +use cosmwasm_std::{ + Deps, DepsMut, Env, MessageInfo, Response, StdError, to_json_binary, StdResult, Binary, +}; +use crate::msg::{ + ExecuteMsg, InstantiateMsg, QueryMsg, InfoResponse, +}; + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + _deps: DepsMut, + _env: Env, + _info: MessageInfo, + _msg: InstantiateMsg, +) -> Result { + Ok(Response::default()) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + _deps: DepsMut, + _env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + ExecuteMsg::Echo { message } => { + let mut data = format!("received {} from {} with", message, info.sender); + for coin in info.funds { + data = format!("{} {}", data, coin); + } + Ok(Response::new().set_data(data.as_bytes())) + } + } +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::Info {} => to_json_binary(&InfoResponse{ + message: "query test".to_string(), + }), + } +} diff --git a/example/cosmwasm/echo/src/lib.rs b/example/cosmwasm/echo/src/lib.rs new file mode 100644 index 0000000000..112ecadc84 --- /dev/null +++ b/example/cosmwasm/echo/src/lib.rs @@ -0,0 +1,2 @@ +pub mod contract; +pub mod msg; diff --git a/example/cosmwasm/echo/src/msg.rs b/example/cosmwasm/echo/src/msg.rs new file mode 100644 index 0000000000..cdd4dde67c --- /dev/null +++ b/example/cosmwasm/echo/src/msg.rs @@ -0,0 +1,23 @@ +use cosmwasm_schema::{QueryResponses, cw_serde}; + +#[cw_serde] +pub struct InstantiateMsg {} + +#[cw_serde] +pub enum ExecuteMsg { + Echo { + message: String, + }, +} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + #[returns(InfoResponse)] + Info {}, +} + +#[cw_serde] +pub struct InfoResponse { + pub message: String, +} \ No newline at end of file diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 0000000000..9c42ff1654 --- /dev/null +++ b/foundry.toml @@ -0,0 +1,7 @@ +[profile.default] +src = "contracts/src" +out = "contracts/out" +test = "contracts/test" +libs = ["contracts/lib"] + +# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options diff --git a/go.mod b/go.mod index 3a6c3bdc81..8682af6c6f 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/CosmWasm/wasmd v0.27.0 github.com/CosmWasm/wasmvm v1.5.2 github.com/armon/go-metrics v0.4.1 + github.com/btcsuite/btcd v0.22.1 github.com/cosmos/cosmos-sdk v0.45.10 github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/iavl v0.21.0-alpha.1.0.20230904092046-df3db2d96583 @@ -14,11 +15,13 @@ require ( github.com/ethereum/go-ethereum v1.13.2 github.com/go-playground/validator/v10 v10.4.1 github.com/gogo/protobuf v1.3.3 - github.com/golang/protobuf v1.5.3 + github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang/protobuf v1.5.4 github.com/golangci/golangci-lint v1.46.0 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 + github.com/holiman/uint256 v1.2.4 github.com/justinas/alice v1.2.0 github.com/k0kubun/pp/v3 v3.2.0 github.com/mitchellh/mapstructure v1.5.0 @@ -26,7 +29,7 @@ require ( github.com/rs/cors v1.8.2 github.com/rs/zerolog v1.30.0 github.com/sei-protocol/goutils v0.0.2 - github.com/sei-protocol/sei-db v0.0.23 + github.com/sei-protocol/sei-db v0.0.27-0.20240123064153-d6dfa112e760 github.com/sirkon/goproxy v1.4.8 github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.6.1 @@ -40,9 +43,9 @@ require ( golang.org/x/sync v0.5.0 golang.org/x/text v0.14.0 golang.org/x/time v0.3.0 - google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13 - google.golang.org/grpc v1.58.3 - google.golang.org/protobuf v1.31.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe + google.golang.org/grpc v1.61.0 + google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -62,6 +65,7 @@ require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/OpenPeeDeeP/depguard v1.1.0 // indirect github.com/StackExchange/wmi v1.2.1 // indirect + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect github.com/alitto/pond v1.8.3 // indirect github.com/ashanbrown/forbidigo v1.3.0 // indirect @@ -74,7 +78,6 @@ require ( github.com/bombsimon/wsl/v3 v3.3.0 // indirect github.com/breml/bidichk v0.2.3 // indirect github.com/breml/errchkjson v0.3.0 // indirect - github.com/btcsuite/btcd v0.22.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/butuzov/ireturn v0.1.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect @@ -94,6 +97,8 @@ require ( github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/gorocksdb v1.2.0 // indirect github.com/cosmos/ledger-cosmos-go v0.12.4 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect github.com/daixiang0/gci v0.3.3 // indirect @@ -115,8 +120,11 @@ require ( github.com/fatih/structtag v1.2.0 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect github.com/firefart/nonamedreturns v1.0.1 // indirect + github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fzipp/gocyclo v0.5.1 // indirect + github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect + github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/go-critic/go-critic v0.6.3 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect @@ -152,7 +160,7 @@ require ( github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/flatbuffers v1.12.1 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/uuid v1.3.0 // indirect @@ -166,6 +174,7 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-bexpr v0.1.10 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-version v1.6.0 // indirect @@ -174,9 +183,12 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect - github.com/holiman/uint256 v1.2.4 // indirect + github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 // indirect + github.com/holiman/bloomfilter/v2 v2.0.3 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/improbable-eng/grpc-web v0.14.1 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jgautheron/goconst v1.5.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect @@ -210,6 +222,7 @@ require ( github.com/mbilski/exhaustivestruct v1.2.0 // indirect github.com/mgechev/revive v1.2.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/moricho/tparallel v0.2.1 // indirect github.com/mtibben/percent v0.2.1 // indirect @@ -242,6 +255,7 @@ require ( github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/rs/xid v1.5.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryancurrah/gomodguard v1.2.3 // indirect github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect @@ -261,6 +275,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.13.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect + github.com/status-im/keycard-go v0.2.0 // indirect github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.4.1 // indirect @@ -281,9 +296,12 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/tomarrell/wrapcheck/v2 v2.6.1 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.0 // indirect + github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/ultraware/funlen v0.0.3 // indirect github.com/ultraware/whitespace v0.0.5 // indirect + github.com/urfave/cli/v2 v2.25.7 // indirect github.com/uudashr/gocognit v1.0.5 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.2.0 // indirect github.com/yourbasic/graph v0.0.0-20210606180040-8ecfec1c2869 // indirect @@ -295,16 +313,17 @@ 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.15.0 // indirect + golang.org/x/crypto v0.18.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.18.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/term 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 - google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a // 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 + gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect honnef.co/go/tools v0.3.1 // indirect lukechampine.com/uint128 v1.2.0 // indirect modernc.org/cc/v3 v3.40.0 // indirect @@ -325,17 +344,17 @@ require ( ) replace ( - github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.1.0 + github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.0.10-0.20240415230844-461d7d3b8890 // TODO: Update once sei-wasmd PR merged github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 - github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.2.79 + github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.2.81-seiv2.0.20240418134744-d2fa1374ec62 // TODO: Update once sei-cosmos PR merged 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-8 + github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-13 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.33 + github.com/sei-protocol/sei-db => github.com/sei-protocol/sei-db v0.0.35 // 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.2.40 + github.com/tendermint/tendermint => github.com/sei-protocol/sei-tendermint v0.2.41-seiv2 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 e6ec52301b..3967c0086f 100644 --- a/go.sum +++ b/go.sum @@ -153,6 +153,7 @@ github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pO github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alitto/pond v1.8.3 h1:ydIqygCLVPqIX/USe5EaV/aSRXTRXDEI9JwuDdu+/xs= github.com/alitto/pond v1.8.3/go.mod h1:CmvIIGd5jKLasGI3D87qDkQxjzChdKMmnXMg3fG6M6Q= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -321,7 +322,6 @@ github.com/cosmos/interchain-accounts v0.1.0 h1:QmuwNsf1Hxl3P5GSGt7Z+JeuHPiZw4Z3 github.com/cosmos/interchain-accounts v0.1.0/go.mod h1:Fv6LXDs+0ng4mIDVWwEJMXbAIMxY4kiq+A7Bw1Fb9AY= github.com/cosmos/ledger-cosmos-go v0.12.4 h1:drvWt+GJP7Aiw550yeb3ON/zsrgW0jgh5saFCr7pDnw= github.com/cosmos/ledger-cosmos-go v0.12.4/go.mod h1:fjfVWRf++Xkygt9wzCsjEBdjcf7wiiY35fv3ctT+k4M= -github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -561,7 +561,6 @@ github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= -github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= @@ -606,8 +605,9 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -663,8 +663,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -1316,7 +1317,6 @@ github.com/rs/zerolog v1.12.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK github.com/rs/zerolog v1.14.3/go.mod h1:3WXPzbXEEliJ+a6UFE4vhIxV8qR1EML6ngzP9ug4eYg= github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -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-8 h1:z6rUvSgLXtXQBdF1dOe8A1iDFORz0+ObH2H1qM5FQKE= -github.com/sei-protocol/go-ethereum v1.13.5-sei-8/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= +github.com/sei-protocol/go-ethereum v1.13.5-sei-13 h1:ied1MMoqJyTEPvT7AtJeVTn3bEuwksInfvyXxp2siLw= +github.com/sei-protocol/go-ethereum v1.13.5-sei-13/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA= github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= -github.com/sei-protocol/sei-cosmos v0.2.79 h1:7dhNRzytkadDXLTifvlNOVFqwRQFulSRqScKMQiKs5E= -github.com/sei-protocol/sei-cosmos v0.2.79/go.mod h1:BNRPUvKOpyLNqUzwZ7e2JEES+qOcTwuiCvPk++WJtgs= -github.com/sei-protocol/sei-db v0.0.33 h1:TspNkw/lW7fubR0TsOpmJdzWiLecMDOS5DAxFNQXQ6M= -github.com/sei-protocol/sei-db v0.0.33/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= +github.com/sei-protocol/sei-cosmos v0.2.81-seiv2.0.20240418134744-d2fa1374ec62 h1:neYsC5M5MHRywoD5AhRHIClw4X7WQiwDvgD0L1o3FOk= +github.com/sei-protocol/sei-cosmos v0.2.81-seiv2.0.20240418134744-d2fa1374ec62/go.mod h1:ib/gp0gCxN7FXUZ40j5+x8BeyoI7AcX+rTvf53JoDsY= +github.com/sei-protocol/sei-db v0.0.35 h1:BNHv0gtKE4J5kq1Mhxt9dpop3lI4W2I5WurgWYIYa4E= +github.com/sei-protocol/sei-db v0.0.35/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.2.40 h1:uG7QsUhG/PLRnKoCVHnFaeQoRf1wlY3aFQJiOEpGtyA= -github.com/sei-protocol/sei-tendermint v0.2.40/go.mod h1:4LSlJdhl3nf3OmohliwRNUFLOB1XWlrmSodrIP7fLh4= +github.com/sei-protocol/sei-tendermint v0.2.41-seiv2 h1:X6CGPY0zWNevTyvZafIw0dZG7Qw34N0dVmcki+hFtik= +github.com/sei-protocol/sei-tendermint v0.2.41-seiv2/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.0 h1:YCJ8SzJYMUR6hYOtgfjETFmSX1qx6cfLCmRAav2KMIs= -github.com/sei-protocol/sei-wasmd v0.1.0/go.mod h1:CNF8PPkDFU0I/Lzw2+DbaNQhyxQj309ljOq7Waxj3fk= +github.com/sei-protocol/sei-wasmd v0.0.10-0.20240415230844-461d7d3b8890 h1:naxcs9dWzNysEKuFiU5lYk3zW1w3F2qOKH8TP2yO0PI= +github.com/sei-protocol/sei-wasmd v0.0.10-0.20240415230844-461d7d3b8890/go.mod h1:CNF8PPkDFU0I/Lzw2+DbaNQhyxQj309ljOq7Waxj3fk= 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= @@ -1519,7 +1519,6 @@ github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lP github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI= github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.24.1/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= @@ -1647,8 +1646,9 @@ golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45 golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= 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 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= 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/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= @@ -1786,8 +1786,9 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 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 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= 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/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= @@ -1952,8 +1953,9 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= 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/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= @@ -1965,8 +1967,9 @@ golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= 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 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= 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/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= @@ -2246,12 +2249,12 @@ google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2 google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 h1:SeZZZx0cP0fqUyA+oRzP9k7cSwJlvDFiROO72uwD6i0= -google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= -google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13 h1:U7+wNaVuSTaUqNvK2+osJ9ejEZxbjHHk8F2b6Hpx0AE= -google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a h1:a2MQQVoTo96JC9PMGtGBymLp7+/RzpFc2yX/9WfFg1c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= +google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= +google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe h1:bQnxqljG/wqi4NTXu2+DJ3n7APcEA882QZ1JvhQAq9o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= @@ -2269,8 +2272,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/integration_test/evm_module/hardhat_test.yaml b/integration_test/evm_module/hardhat_test.yaml new file mode 100644 index 0000000000..14e7c153eb --- /dev/null +++ b/integration_test/evm_module/hardhat_test.yaml @@ -0,0 +1,17 @@ +- 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/gov_module/gov_proposal_test.yaml b/integration_test/gov_module/gov_proposal_test.yaml index 0e0d09378d..4023c88754 100644 --- a/integration_test/gov_module/gov_proposal_test.yaml +++ b/integration_test/gov_module/gov_proposal_test.yaml @@ -75,7 +75,7 @@ - name: Test making a proposal which got rejected should burn tokens inputs: # Get the current tally params - - cmd: seid q bank total --output json | jq -r .supply[0].amount + - cmd: seid q bank total --denom usei --output json | jq -r .amount env: TOTAL_SUPPLY_BEFORE_BURN # Make a new expedited proposal - cmd: printf "12345678\n" | seid tx gov submit-proposal param-change ./integration_test/gov_module/proposal/expedited_proposal.json @@ -97,7 +97,7 @@ - cmd: seid q gov params --output json | jq -r .tally_params.expedited_quorum env: NEW_PARAM # Get the current tally params - - cmd: seid q bank total --output json | jq -r .supply[0].amount + - cmd: seid q bank total --denom usei --output json | jq -r .amount env: TOTAL_SUPPLY_AFTER_BURN verifiers: # Check if the total supply is reduced or not to verify token burns diff --git a/integration_test/scripts/runner.py b/integration_test/scripts/runner.py index ca5bb82938..0e3c159200 100644 --- a/integration_test/scripts/runner.py +++ b/integration_test/scripts/runner.py @@ -72,7 +72,7 @@ def run_bash_command(self, command, docker=False, container="", env_map=None, ve if env_map: for key in env_map: envs += f'-e {key}=\'{env_map[key]}\' ' - full_cmd = f'docker exec {envs} {container} /bin/bash -c \'export PATH=$PATH:/root/go/bin && {command}\'' + full_cmd = f'docker exec {envs} {container} /bin/bash -c \'export PATH=$PATH:/root/go/bin:/root/.foundry/bin && {command}\'' else: full_cmd = command if verbose: diff --git a/integration_test/seidb/state_store_test.yaml b/integration_test/seidb/state_store_test.yaml index 3c96f1064a..829d79587e 100644 --- a/integration_test/seidb/state_store_test.yaml +++ b/integration_test/seidb/state_store_test.yaml @@ -39,19 +39,19 @@ verifiers: # Verify number of wasm codes at each height - type: eval - expr: BEGINNING_LIST_CODE_LENGTH == 0 + expr: BEGINNING_LIST_CODE_LENGTH == 2 - type: eval - expr: FIRST_SET_LIST_CODE_LENGTH == 10 + expr: FIRST_SET_LIST_CODE_LENGTH == 12 - type: eval - expr: FIRST_SET_LIST_CODE_LENGTH_REVERSE == 10 + expr: FIRST_SET_LIST_CODE_LENGTH_REVERSE == 12 - type: eval - expr: SECOND_SET_LIST_CODE_LENGTH == 20 + expr: SECOND_SET_LIST_CODE_LENGTH == 22 - type: eval - expr: SECOND_SET_LIST_CODE_LENGTH_REVERSE == 20 + expr: SECOND_SET_LIST_CODE_LENGTH_REVERSE == 22 - type: eval - expr: THIRD_SET_LIST_CODE_LENGTH == 30 + expr: THIRD_SET_LIST_CODE_LENGTH == 32 - type: eval - expr: THIRD_SET_LIST_CODE_LENGTH_REVERSE == 30 + expr: THIRD_SET_LIST_CODE_LENGTH_REVERSE == 32 - name: Test state store historical data checking specific wasm codes inputs: @@ -59,19 +59,19 @@ - cmd: tail -1 integration_test/contracts/wasm_first_set_block_height.txt env: FIRST_SET_BLOCK_HEIGHT # Get code id from first contract returned at first set height in forward order (0) - - cmd: seid q wasm list-code --count-total --limit 400 --height $FIRST_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[0].code_id" + - cmd: seid q wasm list-code --count-total --limit 400 --height $FIRST_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[3].code_id" env: FIRST_ID_FIRST_SET # Get creator from first contract returned at first set height in forward order - - cmd: seid q wasm list-code --count-total --limit 400 --height $FIRST_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[0].creator" + - cmd: seid q wasm list-code --count-total --limit 400 --height $FIRST_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[3].creator" env: FIRST_CREATOR_FIRST_SET # Get height from second set - cmd: tail -1 integration_test/contracts/wasm_second_set_block_height.txt env: SECOND_SET_BLOCK_HEIGHT # Get code id from first contract returned at second set height in reverse order (200) - - cmd: seid q wasm list-code --reverse --count-total --limit 400 --height $SECOND_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[0].code_id" + - cmd: seid q wasm list-code --reverse --count-total --limit 400 --height $SECOND_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[3].code_id" env: SECOND_ID_FIRST_SET # Get creator from second contract returned at second set height in reverse order - - cmd: seid q wasm list-code --reverse --count-total --limit 400 --height $SECOND_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[0].creator" + - cmd: seid q wasm list-code --reverse --count-total --limit 400 --height $SECOND_SET_BLOCK_HEIGHT --output json | jq -r ".code_infos[3].creator" env: FIRST_CREATOR_SECOND_SET # Get creator id - cmd: tail -1 integration_test/contracts/wasm_creator_id.txt @@ -85,9 +85,9 @@ # Verify correct code ids # NOTE: Since chain is continually running / stateful, may have remove - type: eval - expr: FIRST_ID_FIRST_SET == 1 + expr: FIRST_ID_FIRST_SET == 4 - type: eval - expr: SECOND_ID_FIRST_SET == 20 + expr: SECOND_ID_FIRST_SET == 19 - name: Test state store iteration through tokenfactory denoms inputs: diff --git a/loadtest/config.json b/loadtest/config.json index 2ef222f662..8456cad1b3 100644 --- a/loadtest/config.json +++ b/loadtest/config.json @@ -18,6 +18,10 @@ "max": "21", "number_of_distinct_values": 20 }, + "post_tx_evm_queries": { + "block_by_number": 0, + "receipt": 0 + }, "message_configs": { "default": { "gas": 3000000, @@ -54,7 +58,9 @@ "wasm_instantiate", "wasm_occ_iterator_write", "wasm_occ_iterator_range", - "wasm_occ_parallel_write" + "wasm_occ_parallel_write", + "evm", + "univ2" ], "run_oracle": false, "metrics_port": 9695, @@ -113,5 +119,6 @@ "contract_address": "sei1nwp0ynjv84wxysf2f5ctvysl6dpm8ngm70hss6jeqt8q7e7u345s8zru6u", "percentage": "0.1" } - ] + ], + "ticks": 0 } diff --git a/loadtest/contracts/deploy_erc20.sh b/loadtest/contracts/deploy_erc20.sh index ba436b2c07..4cf45ff515 100755 --- a/loadtest/contracts/deploy_erc20.sh +++ b/loadtest/contracts/deploy_erc20.sh @@ -5,10 +5,18 @@ evm_endpoint=$1 +# first fund account if necessary +THRESHOLD=100000000000000000000 # 100 Eth +ACCOUNT="0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52" +BALANCE=$(cast balance $ACCOUNT --rpc-url "$evm_endpoint") +if (( $(echo "$BALANCE < $THRESHOLD" | bc -l) )); then + printf "12345678\n" | ~/go/bin/seid tx evm send $ACCOUNT 100000000000000000000 --from admin --evm-rpc "$evm_endpoint" + sleep 3 +fi cd loadtest/contracts/evm || exit 1 -./setup.sh +./setup.sh > /dev/null -git submodule update --init --recursive +git submodule update --init --recursive > /dev/null /root/.foundry/bin/forge create -r "$evm_endpoint" --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e src/NoopToken.sol:NoopToken --json --constructor-args "NoopToken" "NT" | jq -r '.deployedTo' diff --git a/loadtest/contracts/deploy_erc721.sh b/loadtest/contracts/deploy_erc721.sh new file mode 100755 index 0000000000..0e5613b458 --- /dev/null +++ b/loadtest/contracts/deploy_erc721.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# This script is used to deploy the NoopToken contract to the target network +# This avoids trying to predict what address it might be deployed to + +evm_endpoint=$1 + +# first fund account if necessary +THRESHOLD=100000000000000000000 # 100 Eth +ACCOUNT="0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52" +BALANCE=$(cast balance $ACCOUNT --rpc-url "$evm_endpoint") +if (( $(echo "$BALANCE < $THRESHOLD" | bc -l) )); then + printf "12345678\n" | ~/go/bin/seid tx evm send $ACCOUNT 100000000000000000000 --from admin --evm-rpc "$evm_endpoint" + sleep 3 +fi + +cd loadtest/contracts/evm || exit 1 + +./setup.sh > /dev/null + +git submodule update --init --recursive > /dev/null + +/root/.foundry/bin/forge create -r "$evm_endpoint" --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e src/ERC721.sol:MyNFT --json | jq -r '.deployedTo' diff --git a/loadtest/contracts/deploy_univ2.sh b/loadtest/contracts/deploy_univ2.sh new file mode 100755 index 0000000000..24a4a850d5 --- /dev/null +++ b/loadtest/contracts/deploy_univ2.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# This script is used to deploy the UniV2 contract to the target network +# This avoids trying to predict what address it might be deployed to +set -e + +evm_endpoint=$1 + +echo "Deploying UniswapV2 contracts to $evm_endpoint" + +cd loadtest/contracts/evm || exit 1 + +echo "Installing forge libaries..." +forge install + +bigNumber=100000000000000000000000000000000 # 10^32 +feeCollector=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 # first anvil address, just need a random address for fees +wallet=0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 + +walletBalance=$(cast balance $wallet --rpc-url "$evm_endpoint") +if [[ $walletBalance == 0 ]]; then + echo "Please fund the wallet $wallet to continue." + exit 1 +fi + +echo "Deploying factory contract..." +factoryAddress=$(forge create -r "$evm_endpoint" --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e src/univ2/UniswapV2Factory.sol:UniswapV2Factory --json --legacy --constructor-args $feeCollector | jq -r '.deployedTo') +echo "factoryAddress=$factoryAddress" + +echo "Deploying router contract..." +routerAddress=$(forge create -r "$evm_endpoint" --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e src/univ2/UniswapV2Router.sol:UniswapV2Router --json --legacy --constructor-args $factoryAddress $feeCollector | jq -r '.deployedTo') +echo "routerAddress=$routerAddress" + +echo "Deploying token1 contract..." +token1Address=$(forge create -r "$evm_endpoint" --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e src/ERC20Token.sol:ERC20Token --json --legacy --constructor-args "Token1" "T1" | jq -r '.deployedTo') +echo "token1Address=$token1Address" + +echo "Deploying token2 contract..." +token2Address=$(forge create -r "$evm_endpoint" --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e src/ERC20Token.sol:ERC20Token --json --legacy --constructor-args "Token2" "T2" | jq -r '.deployedTo') +echo "token2Address=$token2Address" + +echo "Deploying UniV2Swapper contract..." +uniV2SwapperAddress=$(forge create -r "$evm_endpoint" --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e src/UniV2Swapper.sol:UniV2Swapper --json --legacy --constructor-args $token1Address $token2Address $routerAddress | jq -r '.deployedTo') +echo "uniV2SwapperAddress=$uniV2SwapperAddress" + +echo "Minting tokens..." +cast send -r "$evm_endpoint" $token1Address --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e "mint(address,uint256)" $wallet $bigNumber --legacy --json +cast send -r "$evm_endpoint" $token2Address --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e "mint(address,uint256)" $wallet $bigNumber --legacy --json + +echo "Creating a pool..." +cast send -r "$evm_endpoint" $factoryAddress --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e "createPair(address,address)" $token1Address $token2Address --legacy --json + +# get the pair address +pairAddress=$(cast call -r "$evm_endpoint" $factoryAddress "getAllPairsIndex(uint256)" 0) + +echo "Approving router to spend tokens..." +cast send -r "$evm_endpoint" $token1Address --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e "approve(address,uint256)" $routerAddress $bigNumber --legacy --json +cast send -r "$evm_endpoint" $token2Address --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e "approve(address,uint256)" $routerAddress $bigNumber --legacy --json + +echo "Adding liquidity to the pool..." +cast send -r "$evm_endpoint" $routerAddress --private-key 57acb95d82739866a5c29e40b0aa2590742ae50425b7dd5b5d279a986370189e "addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)" $token1Address $token2Address $bigNumber $bigNumber 0 0 $wallet 1000000000000000000 --legacy --json + +# print addresses out for use in other scripts +echo "UniswapV2Factory Address: \"$factoryAddress\"" +echo "UniswapV2Router Address: \"$routerAddress\"" +echo "Token1 Address: \"$token1Address\"" +echo "Token2 Address: \"$token2Address\"" +echo "Pair Address: \"$pairAddress\"" +echo "Swapper Address: \"$uniV2SwapperAddress\"" diff --git a/loadtest/contracts/evm/bindings/erc20/abi.json b/loadtest/contracts/evm/bindings/erc20/abi.json index 7beb03aba4..3433ca801f 100644 --- a/loadtest/contracts/evm/bindings/erc20/abi.json +++ b/loadtest/contracts/evm/bindings/erc20/abi.json @@ -1,339 +1,354 @@ [ { - "inputs": [ - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" + "type":"constructor", + "inputs":[ + { + "name":"name", + "type":"string", + "internalType":"string" + }, + { + "name":"symbol", + "type":"string", + "internalType":"string" + } + ], + "stateMutability":"nonpayable" }, { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "allowance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "ERC20InsufficientAllowance", - "type": "error" + "type":"function", + "name":"allowance", + "inputs":[ + { + "name":"owner", + "type":"address", + "internalType":"address" + }, + { + "name":"spender", + "type":"address", + "internalType":"address" + } + ], + "outputs":[ + { + "name":"", + "type":"uint256", + "internalType":"uint256" + } + ], + "stateMutability":"view" }, { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "balance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "ERC20InsufficientBalance", - "type": "error" + "type":"function", + "name":"approve", + "inputs":[ + { + "name":"spender", + "type":"address", + "internalType":"address" + }, + { + "name":"value", + "type":"uint256", + "internalType":"uint256" + } + ], + "outputs":[ + { + "name":"", + "type":"bool", + "internalType":"bool" + } + ], + "stateMutability":"nonpayable" }, { - "inputs": [ - { - "internalType": "address", - "name": "approver", - "type": "address" - } - ], - "name": "ERC20InvalidApprover", - "type": "error" + "type":"function", + "name":"balanceOf", + "inputs":[ + { + "name":"account", + "type":"address", + "internalType":"address" + } + ], + "outputs":[ + { + "name":"", + "type":"uint256", + "internalType":"uint256" + } + ], + "stateMutability":"view" }, { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "ERC20InvalidReceiver", - "type": "error" + "type":"function", + "name":"decimals", + "inputs":[ + + ], + "outputs":[ + { + "name":"", + "type":"uint8", + "internalType":"uint8" + } + ], + "stateMutability":"view" }, { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "ERC20InvalidSender", - "type": "error" + "type":"function", + "name":"mint", + "inputs":[ + { + "name":"to", + "type":"address", + "internalType":"address" + }, + { + "name":"amount", + "type":"uint256", + "internalType":"uint256" + } + ], + "outputs":[ + + ], + "stateMutability":"nonpayable" }, { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "ERC20InvalidSpender", - "type": "error" + "type":"function", + "name":"name", + "inputs":[ + + ], + "outputs":[ + { + "name":"", + "type":"string", + "internalType":"string" + } + ], + "stateMutability":"view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" + "type":"function", + "name":"symbol", + "inputs":[ + + ], + "outputs":[ + { + "name":"", + "type":"string", + "internalType":"string" + } + ], + "stateMutability":"view" }, { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" + "type":"function", + "name":"totalSupply", + "inputs":[ + + ], + "outputs":[ + { + "name":"", + "type":"uint256", + "internalType":"uint256" + } + ], + "stateMutability":"view" }, { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" + "type":"function", + "name":"transfer", + "inputs":[ + { + "name":"to", + "type":"address", + "internalType":"address" + }, + { + "name":"value", + "type":"uint256", + "internalType":"uint256" + } + ], + "outputs":[ + { + "name":"", + "type":"bool", + "internalType":"bool" + } + ], + "stateMutability":"nonpayable" }, { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" + "type":"function", + "name":"transferFrom", + "inputs":[ + { + "name":"from", + "type":"address", + "internalType":"address" + }, + { + "name":"to", + "type":"address", + "internalType":"address" + }, + { + "name":"value", + "type":"uint256", + "internalType":"uint256" + } + ], + "outputs":[ + { + "name":"", + "type":"bool", + "internalType":"bool" + } + ], + "stateMutability":"nonpayable" }, { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" + "type":"event", + "name":"Approval", + "inputs":[ + { + "name":"owner", + "type":"address", + "indexed":true, + "internalType":"address" + }, + { + "name":"spender", + "type":"address", + "indexed":true, + "internalType":"address" + }, + { + "name":"value", + "type":"uint256", + "indexed":false, + "internalType":"uint256" + } + ], + "anonymous":false }, { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" + "type":"event", + "name":"Transfer", + "inputs":[ + { + "name":"from", + "type":"address", + "indexed":true, + "internalType":"address" + }, + { + "name":"to", + "type":"address", + "indexed":true, + "internalType":"address" + }, + { + "name":"value", + "type":"uint256", + "indexed":false, + "internalType":"uint256" + } + ], + "anonymous":false }, { - "inputs": [], - "name": "lastValue", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" + "type":"error", + "name":"ERC20InsufficientAllowance", + "inputs":[ + { + "name":"spender", + "type":"address", + "internalType":"address" + }, + { + "name":"allowance", + "type":"uint256", + "internalType":"uint256" + }, + { + "name":"needed", + "type":"uint256", + "internalType":"uint256" + } + ] }, { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" + "type":"error", + "name":"ERC20InsufficientBalance", + "inputs":[ + { + "name":"sender", + "type":"address", + "internalType":"address" + }, + { + "name":"balance", + "type":"uint256", + "internalType":"uint256" + }, + { + "name":"needed", + "type":"uint256", + "internalType":"uint256" + } + ] }, { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" + "type":"error", + "name":"ERC20InvalidApprover", + "inputs":[ + { + "name":"approver", + "type":"address", + "internalType":"address" + } + ] }, { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" + "type":"error", + "name":"ERC20InvalidReceiver", + "inputs":[ + { + "name":"receiver", + "type":"address", + "internalType":"address" + } + ] }, { - "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" + "type":"error", + "name":"ERC20InvalidSender", + "inputs":[ + { + "name":"sender", + "type":"address", + "internalType":"address" + } + ] }, { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" + "type":"error", + "name":"ERC20InvalidSpender", + "inputs":[ + { + "name":"spender", + "type":"address", + "internalType":"address" + } + ] } ] \ No newline at end of file diff --git a/loadtest/contracts/evm/bindings/erc20/erc20.go b/loadtest/contracts/evm/bindings/erc20/erc20.go index e5dbf6c4ec..5f225c93f2 100644 --- a/loadtest/contracts/evm/bindings/erc20/erc20.go +++ b/loadtest/contracts/evm/bindings/erc20/erc20.go @@ -31,7 +31,7 @@ var ( // Erc20MetaData contains all meta data concerning the Erc20 contract. var Erc20MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastValue\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"name\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"symbol\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"allowance\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"decimals\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"mint\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"totalSupply\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transfer\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"spender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"value\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"ERC20InsufficientAllowance\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"allowance\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"needed\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC20InsufficientBalance\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"balance\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"needed\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC20InvalidApprover\",\"inputs\":[{\"name\":\"approver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC20InvalidReceiver\",\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC20InvalidSender\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC20InvalidSpender\",\"inputs\":[{\"name\":\"spender\",\"type\":\"address\",\"internalType\":\"address\"}]}]", } // Erc20ABI is the input ABI used to generate the binding from. @@ -182,10 +182,10 @@ func (_Erc20 *Erc20TransactorRaw) Transact(opts *bind.TransactOpts, method strin // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. // -// Solidity: function allowance(address , address ) view returns(uint256) -func (_Erc20 *Erc20Caller) Allowance(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address) (*big.Int, error) { +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Erc20 *Erc20Caller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { var out []interface{} - err := _Erc20.contract.Call(opts, &out, "allowance", arg0, arg1) + err := _Erc20.contract.Call(opts, &out, "allowance", owner, spender) if err != nil { return *new(*big.Int), err @@ -199,24 +199,24 @@ func (_Erc20 *Erc20Caller) Allowance(opts *bind.CallOpts, arg0 common.Address, a // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. // -// Solidity: function allowance(address , address ) view returns(uint256) -func (_Erc20 *Erc20Session) Allowance(arg0 common.Address, arg1 common.Address) (*big.Int, error) { - return _Erc20.Contract.Allowance(&_Erc20.CallOpts, arg0, arg1) +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Erc20 *Erc20Session) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Erc20.Contract.Allowance(&_Erc20.CallOpts, owner, spender) } // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. // -// Solidity: function allowance(address , address ) view returns(uint256) -func (_Erc20 *Erc20CallerSession) Allowance(arg0 common.Address, arg1 common.Address) (*big.Int, error) { - return _Erc20.Contract.Allowance(&_Erc20.CallOpts, arg0, arg1) +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Erc20 *Erc20CallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Erc20.Contract.Allowance(&_Erc20.CallOpts, owner, spender) } // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(address ) view returns(uint256) -func (_Erc20 *Erc20Caller) BalanceOf(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Erc20 *Erc20Caller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { var out []interface{} - err := _Erc20.contract.Call(opts, &out, "balanceOf", arg0) + err := _Erc20.contract.Call(opts, &out, "balanceOf", account) if err != nil { return *new(*big.Int), err @@ -230,16 +230,16 @@ func (_Erc20 *Erc20Caller) BalanceOf(opts *bind.CallOpts, arg0 common.Address) ( // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(address ) view returns(uint256) -func (_Erc20 *Erc20Session) BalanceOf(arg0 common.Address) (*big.Int, error) { - return _Erc20.Contract.BalanceOf(&_Erc20.CallOpts, arg0) +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Erc20 *Erc20Session) BalanceOf(account common.Address) (*big.Int, error) { + return _Erc20.Contract.BalanceOf(&_Erc20.CallOpts, account) } // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. // -// Solidity: function balanceOf(address ) view returns(uint256) -func (_Erc20 *Erc20CallerSession) BalanceOf(arg0 common.Address) (*big.Int, error) { - return _Erc20.Contract.BalanceOf(&_Erc20.CallOpts, arg0) +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Erc20 *Erc20CallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Erc20.Contract.BalanceOf(&_Erc20.CallOpts, account) } // Decimals is a free data retrieval call binding the contract method 0x313ce567. @@ -273,37 +273,6 @@ func (_Erc20 *Erc20CallerSession) Decimals() (uint8, error) { return _Erc20.Contract.Decimals(&_Erc20.CallOpts) } -// LastValue is a free data retrieval call binding the contract method 0x43183834. -// -// Solidity: function lastValue() view returns(uint256) -func (_Erc20 *Erc20Caller) LastValue(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _Erc20.contract.Call(opts, &out, "lastValue") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// LastValue is a free data retrieval call binding the contract method 0x43183834. -// -// Solidity: function lastValue() view returns(uint256) -func (_Erc20 *Erc20Session) LastValue() (*big.Int, error) { - return _Erc20.Contract.LastValue(&_Erc20.CallOpts) -} - -// LastValue is a free data retrieval call binding the contract method 0x43183834. -// -// Solidity: function lastValue() view returns(uint256) -func (_Erc20 *Erc20CallerSession) LastValue() (*big.Int, error) { - return _Erc20.Contract.LastValue(&_Erc20.CallOpts) -} - // Name is a free data retrieval call binding the contract method 0x06fdde03. // // Solidity: function name() view returns(string) @@ -399,65 +368,86 @@ func (_Erc20 *Erc20CallerSession) TotalSupply() (*big.Int, error) { // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address spender, uint256 amount) returns(bool) -func (_Erc20 *Erc20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) { - return _Erc20.contract.Transact(opts, "approve", spender, amount) +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_Erc20 *Erc20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "approve", spender, value) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address spender, uint256 amount) returns(bool) -func (_Erc20 *Erc20Session) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { - return _Erc20.Contract.Approve(&_Erc20.TransactOpts, spender, amount) +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_Erc20 *Erc20Session) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Approve(&_Erc20.TransactOpts, spender, value) } // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. // -// Solidity: function approve(address spender, uint256 amount) returns(bool) -func (_Erc20 *Erc20TransactorSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { - return _Erc20.Contract.Approve(&_Erc20.TransactOpts, spender, amount) +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_Erc20 *Erc20TransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Approve(&_Erc20.TransactOpts, spender, value) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address to, uint256 amount) returns() +func (_Erc20 *Erc20Transactor) Mint(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "mint", to, amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address to, uint256 amount) returns() +func (_Erc20 *Erc20Session) Mint(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Mint(&_Erc20.TransactOpts, to, amount) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address to, uint256 amount) returns() +func (_Erc20 *Erc20TransactorSession) Mint(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Mint(&_Erc20.TransactOpts, to, amount) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(address recipient, uint256 amount) returns(bool) -func (_Erc20 *Erc20Transactor) Transfer(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _Erc20.contract.Transact(opts, "transfer", recipient, amount) +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_Erc20 *Erc20Transactor) Transfer(opts *bind.TransactOpts, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "transfer", to, value) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(address recipient, uint256 amount) returns(bool) -func (_Erc20 *Erc20Session) Transfer(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _Erc20.Contract.Transfer(&_Erc20.TransactOpts, recipient, amount) +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_Erc20 *Erc20Session) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Transfer(&_Erc20.TransactOpts, to, value) } // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. // -// Solidity: function transfer(address recipient, uint256 amount) returns(bool) -func (_Erc20 *Erc20TransactorSession) Transfer(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _Erc20.Contract.Transfer(&_Erc20.TransactOpts, recipient, amount) +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_Erc20 *Erc20TransactorSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.Transfer(&_Erc20.TransactOpts, to, value) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address sender, address recipient, uint256 amount) returns(bool) -func (_Erc20 *Erc20Transactor) TransferFrom(opts *bind.TransactOpts, sender common.Address, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _Erc20.contract.Transact(opts, "transferFrom", sender, recipient, amount) +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_Erc20 *Erc20Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Erc20.contract.Transact(opts, "transferFrom", from, to, value) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address sender, address recipient, uint256 amount) returns(bool) -func (_Erc20 *Erc20Session) TransferFrom(sender common.Address, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _Erc20.Contract.TransferFrom(&_Erc20.TransactOpts, sender, recipient, amount) +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_Erc20 *Erc20Session) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.TransferFrom(&_Erc20.TransactOpts, from, to, value) } // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. // -// Solidity: function transferFrom(address sender, address recipient, uint256 amount) returns(bool) -func (_Erc20 *Erc20TransactorSession) TransferFrom(sender common.Address, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _Erc20.Contract.TransferFrom(&_Erc20.TransactOpts, sender, recipient, amount) +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_Erc20 *Erc20TransactorSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Erc20.Contract.TransferFrom(&_Erc20.TransactOpts, from, to, value) } // Erc20ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Erc20 contract. @@ -767,3 +757,4 @@ func (_Erc20 *Erc20Filterer) ParseTransfer(log types.Log) (*Erc20Transfer, error event.Raw = log return event, nil } + diff --git a/loadtest/contracts/evm/bindings/erc721/abi.json b/loadtest/contracts/evm/bindings/erc721/abi.json new file mode 100644 index 0000000000..096d6beb48 --- /dev/null +++ b/loadtest/contracts/evm/bindings/erc721/abi.json @@ -0,0 +1,318 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "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": "id", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "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": "id", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "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": "id", + "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": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/loadtest/contracts/evm/bindings/erc721/erc721.go b/loadtest/contracts/evm/bindings/erc721/erc721.go new file mode 100644 index 0000000000..fb90452d8f --- /dev/null +++ b/loadtest/contracts/evm/bindings/erc721/erc721.go @@ -0,0 +1,961 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package erc721 + +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 +) + +// Erc721MetaData contains all meta data concerning the Erc721 contract. +var Erc721MetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"id\",\"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\":\"id\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"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\":\"id\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"getApproved\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isApprovedForAll\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"ownerOf\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"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\":\"id\",\"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\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// Erc721ABI is the input ABI used to generate the binding from. +// Deprecated: Use Erc721MetaData.ABI instead. +var Erc721ABI = Erc721MetaData.ABI + +// Erc721 is an auto generated Go binding around an Ethereum contract. +type Erc721 struct { + Erc721Caller // Read-only binding to the contract + Erc721Transactor // Write-only binding to the contract + Erc721Filterer // Log filterer for contract events +} + +// Erc721Caller is an auto generated read-only Go binding around an Ethereum contract. +type Erc721Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Erc721Transactor is an auto generated write-only Go binding around an Ethereum contract. +type Erc721Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Erc721Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type Erc721Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Erc721Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type Erc721Session struct { + Contract *Erc721 // 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 +} + +// Erc721CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type Erc721CallerSession struct { + Contract *Erc721Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// Erc721TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type Erc721TransactorSession struct { + Contract *Erc721Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Erc721Raw is an auto generated low-level Go binding around an Ethereum contract. +type Erc721Raw struct { + Contract *Erc721 // Generic contract binding to access the raw methods on +} + +// Erc721CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type Erc721CallerRaw struct { + Contract *Erc721Caller // Generic read-only contract binding to access the raw methods on +} + +// Erc721TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type Erc721TransactorRaw struct { + Contract *Erc721Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewErc721 creates a new instance of Erc721, bound to a specific deployed contract. +func NewErc721(address common.Address, backend bind.ContractBackend) (*Erc721, error) { + contract, err := bindErc721(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Erc721{Erc721Caller: Erc721Caller{contract: contract}, Erc721Transactor: Erc721Transactor{contract: contract}, Erc721Filterer: Erc721Filterer{contract: contract}}, nil +} + +// NewErc721Caller creates a new read-only instance of Erc721, bound to a specific deployed contract. +func NewErc721Caller(address common.Address, caller bind.ContractCaller) (*Erc721Caller, error) { + contract, err := bindErc721(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &Erc721Caller{contract: contract}, nil +} + +// NewErc721Transactor creates a new write-only instance of Erc721, bound to a specific deployed contract. +func NewErc721Transactor(address common.Address, transactor bind.ContractTransactor) (*Erc721Transactor, error) { + contract, err := bindErc721(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &Erc721Transactor{contract: contract}, nil +} + +// NewErc721Filterer creates a new log filterer instance of Erc721, bound to a specific deployed contract. +func NewErc721Filterer(address common.Address, filterer bind.ContractFilterer) (*Erc721Filterer, error) { + contract, err := bindErc721(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &Erc721Filterer{contract: contract}, nil +} + +// bindErc721 binds a generic wrapper to an already deployed contract. +func bindErc721(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := Erc721MetaData.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 (_Erc721 *Erc721Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Erc721.Contract.Erc721Caller.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 (_Erc721 *Erc721Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Erc721.Contract.Erc721Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Erc721 *Erc721Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Erc721.Contract.Erc721Transactor.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 (_Erc721 *Erc721CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Erc721.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 (_Erc721 *Erc721TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Erc721.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Erc721 *Erc721TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Erc721.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 (_Erc721 *Erc721Caller) BalanceOf(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { + var out []interface{} + err := _Erc721.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 (_Erc721 *Erc721Session) BalanceOf(owner common.Address) (*big.Int, error) { + return _Erc721.Contract.BalanceOf(&_Erc721.CallOpts, owner) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address owner) view returns(uint256) +func (_Erc721 *Erc721CallerSession) BalanceOf(owner common.Address) (*big.Int, error) { + return _Erc721.Contract.BalanceOf(&_Erc721.CallOpts, owner) +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 id) view returns(address) +func (_Erc721 *Erc721Caller) GetApproved(opts *bind.CallOpts, id *big.Int) (common.Address, error) { + var out []interface{} + err := _Erc721.contract.Call(opts, &out, "getApproved", id) + + 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 id) view returns(address) +func (_Erc721 *Erc721Session) GetApproved(id *big.Int) (common.Address, error) { + return _Erc721.Contract.GetApproved(&_Erc721.CallOpts, id) +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 id) view returns(address) +func (_Erc721 *Erc721CallerSession) GetApproved(id *big.Int) (common.Address, error) { + return _Erc721.Contract.GetApproved(&_Erc721.CallOpts, id) +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address , address ) view returns(bool) +func (_Erc721 *Erc721Caller) IsApprovedForAll(opts *bind.CallOpts, arg0 common.Address, arg1 common.Address) (bool, error) { + var out []interface{} + err := _Erc721.contract.Call(opts, &out, "isApprovedForAll", arg0, arg1) + + 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 , address ) view returns(bool) +func (_Erc721 *Erc721Session) IsApprovedForAll(arg0 common.Address, arg1 common.Address) (bool, error) { + return _Erc721.Contract.IsApprovedForAll(&_Erc721.CallOpts, arg0, arg1) +} + +// IsApprovedForAll is a free data retrieval call binding the contract method 0xe985e9c5. +// +// Solidity: function isApprovedForAll(address , address ) view returns(bool) +func (_Erc721 *Erc721CallerSession) IsApprovedForAll(arg0 common.Address, arg1 common.Address) (bool, error) { + return _Erc721.Contract.IsApprovedForAll(&_Erc721.CallOpts, arg0, arg1) +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 id) view returns(address owner) +func (_Erc721 *Erc721Caller) OwnerOf(opts *bind.CallOpts, id *big.Int) (common.Address, error) { + var out []interface{} + err := _Erc721.contract.Call(opts, &out, "ownerOf", id) + + 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 id) view returns(address owner) +func (_Erc721 *Erc721Session) OwnerOf(id *big.Int) (common.Address, error) { + return _Erc721.Contract.OwnerOf(&_Erc721.CallOpts, id) +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 id) view returns(address owner) +func (_Erc721 *Erc721CallerSession) OwnerOf(id *big.Int) (common.Address, error) { + return _Erc721.Contract.OwnerOf(&_Erc721.CallOpts, id) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) +func (_Erc721 *Erc721Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _Erc721.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 (_Erc721 *Erc721Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Erc721.Contract.SupportsInterface(&_Erc721.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) +func (_Erc721 *Erc721CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Erc721.Contract.SupportsInterface(&_Erc721.CallOpts, interfaceId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 id) returns() +func (_Erc721 *Erc721Transactor) Approve(opts *bind.TransactOpts, spender common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.contract.Transact(opts, "approve", spender, id) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 id) returns() +func (_Erc721 *Erc721Session) Approve(spender common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.Approve(&_Erc721.TransactOpts, spender, id) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 id) returns() +func (_Erc721 *Erc721TransactorSession) Approve(spender common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.Approve(&_Erc721.TransactOpts, spender, id) +} + +// Burn is a paid mutator transaction binding the contract method 0x42966c68. +// +// Solidity: function burn(uint256 id) returns() +func (_Erc721 *Erc721Transactor) Burn(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _Erc721.contract.Transact(opts, "burn", id) +} + +// Burn is a paid mutator transaction binding the contract method 0x42966c68. +// +// Solidity: function burn(uint256 id) returns() +func (_Erc721 *Erc721Session) Burn(id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.Burn(&_Erc721.TransactOpts, id) +} + +// Burn is a paid mutator transaction binding the contract method 0x42966c68. +// +// Solidity: function burn(uint256 id) returns() +func (_Erc721 *Erc721TransactorSession) Burn(id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.Burn(&_Erc721.TransactOpts, id) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address to, uint256 id) returns() +func (_Erc721 *Erc721Transactor) Mint(opts *bind.TransactOpts, to common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.contract.Transact(opts, "mint", to, id) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address to, uint256 id) returns() +func (_Erc721 *Erc721Session) Mint(to common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.Mint(&_Erc721.TransactOpts, to, id) +} + +// Mint is a paid mutator transaction binding the contract method 0x40c10f19. +// +// Solidity: function mint(address to, uint256 id) returns() +func (_Erc721 *Erc721TransactorSession) Mint(to common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.Mint(&_Erc721.TransactOpts, to, id) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id) returns() +func (_Erc721 *Erc721Transactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.contract.Transact(opts, "safeTransferFrom", from, to, id) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id) returns() +func (_Erc721 *Erc721Session) SafeTransferFrom(from common.Address, to common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.SafeTransferFrom(&_Erc721.TransactOpts, from, to, id) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id) returns() +func (_Erc721 *Erc721TransactorSession) SafeTransferFrom(from common.Address, to common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.SafeTransferFrom(&_Erc721.TransactOpts, from, to, id) +} + +// SafeTransferFrom0 is a paid mutator transaction binding the contract method 0xb88d4fde. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id, bytes data) returns() +func (_Erc721 *Erc721Transactor) SafeTransferFrom0(opts *bind.TransactOpts, from common.Address, to common.Address, id *big.Int, data []byte) (*types.Transaction, error) { + return _Erc721.contract.Transact(opts, "safeTransferFrom0", from, to, id, data) +} + +// SafeTransferFrom0 is a paid mutator transaction binding the contract method 0xb88d4fde. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id, bytes data) returns() +func (_Erc721 *Erc721Session) SafeTransferFrom0(from common.Address, to common.Address, id *big.Int, data []byte) (*types.Transaction, error) { + return _Erc721.Contract.SafeTransferFrom0(&_Erc721.TransactOpts, from, to, id, data) +} + +// SafeTransferFrom0 is a paid mutator transaction binding the contract method 0xb88d4fde. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 id, bytes data) returns() +func (_Erc721 *Erc721TransactorSession) SafeTransferFrom0(from common.Address, to common.Address, id *big.Int, data []byte) (*types.Transaction, error) { + return _Erc721.Contract.SafeTransferFrom0(&_Erc721.TransactOpts, from, to, id, data) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_Erc721 *Erc721Transactor) SetApprovalForAll(opts *bind.TransactOpts, operator common.Address, approved bool) (*types.Transaction, error) { + return _Erc721.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 (_Erc721 *Erc721Session) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _Erc721.Contract.SetApprovalForAll(&_Erc721.TransactOpts, operator, approved) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_Erc721 *Erc721TransactorSession) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _Erc721.Contract.SetApprovalForAll(&_Erc721.TransactOpts, operator, approved) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 id) returns() +func (_Erc721 *Erc721Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.contract.Transact(opts, "transferFrom", from, to, id) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 id) returns() +func (_Erc721 *Erc721Session) TransferFrom(from common.Address, to common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.TransferFrom(&_Erc721.TransactOpts, from, to, id) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 id) returns() +func (_Erc721 *Erc721TransactorSession) TransferFrom(from common.Address, to common.Address, id *big.Int) (*types.Transaction, error) { + return _Erc721.Contract.TransferFrom(&_Erc721.TransactOpts, from, to, id) +} + +// Erc721ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Erc721 contract. +type Erc721ApprovalIterator struct { + Event *Erc721Approval // 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 *Erc721ApprovalIterator) 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(Erc721Approval) + 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(Erc721Approval) + 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 *Erc721ApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Erc721ApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Erc721Approval represents a Approval event raised by the Erc721 contract. +type Erc721Approval struct { + Owner common.Address + Spender common.Address + Id *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 spender, uint256 indexed id) +func (_Erc721 *Erc721Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address, id []*big.Int) (*Erc721ApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _Erc721.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule, idRule) + if err != nil { + return nil, err + } + return &Erc721ApprovalIterator{contract: _Erc721.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 spender, uint256 indexed id) +func (_Erc721 *Erc721Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *Erc721Approval, owner []common.Address, spender []common.Address, id []*big.Int) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _Erc721.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule, idRule) + 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(Erc721Approval) + if err := _Erc721.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 spender, uint256 indexed id) +func (_Erc721 *Erc721Filterer) ParseApproval(log types.Log) (*Erc721Approval, error) { + event := new(Erc721Approval) + if err := _Erc721.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// Erc721ApprovalForAllIterator is returned from FilterApprovalForAll and is used to iterate over the raw logs and unpacked data for ApprovalForAll events raised by the Erc721 contract. +type Erc721ApprovalForAllIterator struct { + Event *Erc721ApprovalForAll // 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 *Erc721ApprovalForAllIterator) 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(Erc721ApprovalForAll) + 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(Erc721ApprovalForAll) + 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 *Erc721ApprovalForAllIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Erc721ApprovalForAllIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Erc721ApprovalForAll represents a ApprovalForAll event raised by the Erc721 contract. +type Erc721ApprovalForAll 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 (_Erc721 *Erc721Filterer) FilterApprovalForAll(opts *bind.FilterOpts, owner []common.Address, operator []common.Address) (*Erc721ApprovalForAllIterator, 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 := _Erc721.contract.FilterLogs(opts, "ApprovalForAll", ownerRule, operatorRule) + if err != nil { + return nil, err + } + return &Erc721ApprovalForAllIterator{contract: _Erc721.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 (_Erc721 *Erc721Filterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *Erc721ApprovalForAll, 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 := _Erc721.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(Erc721ApprovalForAll) + if err := _Erc721.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 (_Erc721 *Erc721Filterer) ParseApprovalForAll(log types.Log) (*Erc721ApprovalForAll, error) { + event := new(Erc721ApprovalForAll) + if err := _Erc721.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// Erc721TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Erc721 contract. +type Erc721TransferIterator struct { + Event *Erc721Transfer // 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 *Erc721TransferIterator) 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(Erc721Transfer) + 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(Erc721Transfer) + 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 *Erc721TransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Erc721TransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Erc721Transfer represents a Transfer event raised by the Erc721 contract. +type Erc721Transfer struct { + From common.Address + To common.Address + Id *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 id) +func (_Erc721 *Erc721Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address, id []*big.Int) (*Erc721TransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _Erc721.contract.FilterLogs(opts, "Transfer", fromRule, toRule, idRule) + if err != nil { + return nil, err + } + return &Erc721TransferIterator{contract: _Erc721.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 id) +func (_Erc721 *Erc721Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *Erc721Transfer, from []common.Address, to []common.Address, id []*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 idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _Erc721.contract.WatchLogs(opts, "Transfer", fromRule, toRule, idRule) + 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(Erc721Transfer) + if err := _Erc721.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 id) +func (_Erc721 *Erc721Filterer) ParseTransfer(log types.Log) (*Erc721Transfer, error) { + event := new(Erc721Transfer) + if err := _Erc721.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/loadtest/contracts/evm/bindings/univ2_swapper/abi.json b/loadtest/contracts/evm/bindings/univ2_swapper/abi.json new file mode 100644 index 0000000000..156e860421 --- /dev/null +++ b/loadtest/contracts/evm/bindings/univ2_swapper/abi.json @@ -0,0 +1 @@ +[{"type":"constructor","inputs":[{"name":"t1_","type":"address","internalType":"address"},{"name":"t2_","type":"address","internalType":"address"},{"name":"uniV2Router_","type":"address","internalType":"address"}],"stateMutability":"nonpayable"},{"type":"function","name":"BIG_NUMBER","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"swap","inputs":[],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"t1","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"t2","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"uniV2Router","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"}] \ No newline at end of file diff --git a/loadtest/contracts/evm/bindings/univ2_swapper/univ2_swapper.go b/loadtest/contracts/evm/bindings/univ2_swapper/univ2_swapper.go new file mode 100644 index 0000000000..abd7c47f58 --- /dev/null +++ b/loadtest/contracts/evm/bindings/univ2_swapper/univ2_swapper.go @@ -0,0 +1,327 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package univ2_swapper + +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 +) + +// Univ2SwapperMetaData contains all meta data concerning the Univ2Swapper contract. +var Univ2SwapperMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"t1_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"t2_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"uniV2Router_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"BIG_NUMBER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"swap\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"t1\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"t2\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"uniV2Router\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"}]", +} + +// Univ2SwapperABI is the input ABI used to generate the binding from. +// Deprecated: Use Univ2SwapperMetaData.ABI instead. +var Univ2SwapperABI = Univ2SwapperMetaData.ABI + +// Univ2Swapper is an auto generated Go binding around an Ethereum contract. +type Univ2Swapper struct { + Univ2SwapperCaller // Read-only binding to the contract + Univ2SwapperTransactor // Write-only binding to the contract + Univ2SwapperFilterer // Log filterer for contract events +} + +// Univ2SwapperCaller is an auto generated read-only Go binding around an Ethereum contract. +type Univ2SwapperCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Univ2SwapperTransactor is an auto generated write-only Go binding around an Ethereum contract. +type Univ2SwapperTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Univ2SwapperFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type Univ2SwapperFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Univ2SwapperSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type Univ2SwapperSession struct { + Contract *Univ2Swapper // 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 +} + +// Univ2SwapperCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type Univ2SwapperCallerSession struct { + Contract *Univ2SwapperCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// Univ2SwapperTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type Univ2SwapperTransactorSession struct { + Contract *Univ2SwapperTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Univ2SwapperRaw is an auto generated low-level Go binding around an Ethereum contract. +type Univ2SwapperRaw struct { + Contract *Univ2Swapper // Generic contract binding to access the raw methods on +} + +// Univ2SwapperCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type Univ2SwapperCallerRaw struct { + Contract *Univ2SwapperCaller // Generic read-only contract binding to access the raw methods on +} + +// Univ2SwapperTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type Univ2SwapperTransactorRaw struct { + Contract *Univ2SwapperTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewUniv2Swapper creates a new instance of Univ2Swapper, bound to a specific deployed contract. +func NewUniv2Swapper(address common.Address, backend bind.ContractBackend) (*Univ2Swapper, error) { + contract, err := bindUniv2Swapper(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Univ2Swapper{Univ2SwapperCaller: Univ2SwapperCaller{contract: contract}, Univ2SwapperTransactor: Univ2SwapperTransactor{contract: contract}, Univ2SwapperFilterer: Univ2SwapperFilterer{contract: contract}}, nil +} + +// NewUniv2SwapperCaller creates a new read-only instance of Univ2Swapper, bound to a specific deployed contract. +func NewUniv2SwapperCaller(address common.Address, caller bind.ContractCaller) (*Univ2SwapperCaller, error) { + contract, err := bindUniv2Swapper(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &Univ2SwapperCaller{contract: contract}, nil +} + +// NewUniv2SwapperTransactor creates a new write-only instance of Univ2Swapper, bound to a specific deployed contract. +func NewUniv2SwapperTransactor(address common.Address, transactor bind.ContractTransactor) (*Univ2SwapperTransactor, error) { + contract, err := bindUniv2Swapper(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &Univ2SwapperTransactor{contract: contract}, nil +} + +// NewUniv2SwapperFilterer creates a new log filterer instance of Univ2Swapper, bound to a specific deployed contract. +func NewUniv2SwapperFilterer(address common.Address, filterer bind.ContractFilterer) (*Univ2SwapperFilterer, error) { + contract, err := bindUniv2Swapper(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &Univ2SwapperFilterer{contract: contract}, nil +} + +// bindUniv2Swapper binds a generic wrapper to an already deployed contract. +func bindUniv2Swapper(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := Univ2SwapperMetaData.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 (_Univ2Swapper *Univ2SwapperRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Univ2Swapper.Contract.Univ2SwapperCaller.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 (_Univ2Swapper *Univ2SwapperRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Univ2Swapper.Contract.Univ2SwapperTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Univ2Swapper *Univ2SwapperRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Univ2Swapper.Contract.Univ2SwapperTransactor.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 (_Univ2Swapper *Univ2SwapperCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Univ2Swapper.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 (_Univ2Swapper *Univ2SwapperTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Univ2Swapper.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Univ2Swapper *Univ2SwapperTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Univ2Swapper.Contract.contract.Transact(opts, method, params...) +} + +// BIGNUMBER is a free data retrieval call binding the contract method 0x2f4fda30. +// +// Solidity: function BIG_NUMBER() view returns(uint256) +func (_Univ2Swapper *Univ2SwapperCaller) BIGNUMBER(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Univ2Swapper.contract.Call(opts, &out, "BIG_NUMBER") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// BIGNUMBER is a free data retrieval call binding the contract method 0x2f4fda30. +// +// Solidity: function BIG_NUMBER() view returns(uint256) +func (_Univ2Swapper *Univ2SwapperSession) BIGNUMBER() (*big.Int, error) { + return _Univ2Swapper.Contract.BIGNUMBER(&_Univ2Swapper.CallOpts) +} + +// BIGNUMBER is a free data retrieval call binding the contract method 0x2f4fda30. +// +// Solidity: function BIG_NUMBER() view returns(uint256) +func (_Univ2Swapper *Univ2SwapperCallerSession) BIGNUMBER() (*big.Int, error) { + return _Univ2Swapper.Contract.BIGNUMBER(&_Univ2Swapper.CallOpts) +} + +// T1 is a free data retrieval call binding the contract method 0xfb5343f3. +// +// Solidity: function t1() view returns(address) +func (_Univ2Swapper *Univ2SwapperCaller) T1(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Univ2Swapper.contract.Call(opts, &out, "t1") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// T1 is a free data retrieval call binding the contract method 0xfb5343f3. +// +// Solidity: function t1() view returns(address) +func (_Univ2Swapper *Univ2SwapperSession) T1() (common.Address, error) { + return _Univ2Swapper.Contract.T1(&_Univ2Swapper.CallOpts) +} + +// T1 is a free data retrieval call binding the contract method 0xfb5343f3. +// +// Solidity: function t1() view returns(address) +func (_Univ2Swapper *Univ2SwapperCallerSession) T1() (common.Address, error) { + return _Univ2Swapper.Contract.T1(&_Univ2Swapper.CallOpts) +} + +// T2 is a free data retrieval call binding the contract method 0xbaf2f868. +// +// Solidity: function t2() view returns(address) +func (_Univ2Swapper *Univ2SwapperCaller) T2(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Univ2Swapper.contract.Call(opts, &out, "t2") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// T2 is a free data retrieval call binding the contract method 0xbaf2f868. +// +// Solidity: function t2() view returns(address) +func (_Univ2Swapper *Univ2SwapperSession) T2() (common.Address, error) { + return _Univ2Swapper.Contract.T2(&_Univ2Swapper.CallOpts) +} + +// T2 is a free data retrieval call binding the contract method 0xbaf2f868. +// +// Solidity: function t2() view returns(address) +func (_Univ2Swapper *Univ2SwapperCallerSession) T2() (common.Address, error) { + return _Univ2Swapper.Contract.T2(&_Univ2Swapper.CallOpts) +} + +// UniV2Router is a free data retrieval call binding the contract method 0x958c2e52. +// +// Solidity: function uniV2Router() view returns(address) +func (_Univ2Swapper *Univ2SwapperCaller) UniV2Router(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Univ2Swapper.contract.Call(opts, &out, "uniV2Router") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// UniV2Router is a free data retrieval call binding the contract method 0x958c2e52. +// +// Solidity: function uniV2Router() view returns(address) +func (_Univ2Swapper *Univ2SwapperSession) UniV2Router() (common.Address, error) { + return _Univ2Swapper.Contract.UniV2Router(&_Univ2Swapper.CallOpts) +} + +// UniV2Router is a free data retrieval call binding the contract method 0x958c2e52. +// +// Solidity: function uniV2Router() view returns(address) +func (_Univ2Swapper *Univ2SwapperCallerSession) UniV2Router() (common.Address, error) { + return _Univ2Swapper.Contract.UniV2Router(&_Univ2Swapper.CallOpts) +} + +// Swap is a paid mutator transaction binding the contract method 0x8119c065. +// +// Solidity: function swap() returns() +func (_Univ2Swapper *Univ2SwapperTransactor) Swap(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Univ2Swapper.contract.Transact(opts, "swap") +} + +// Swap is a paid mutator transaction binding the contract method 0x8119c065. +// +// Solidity: function swap() returns() +func (_Univ2Swapper *Univ2SwapperSession) Swap() (*types.Transaction, error) { + return _Univ2Swapper.Contract.Swap(&_Univ2Swapper.TransactOpts) +} + +// Swap is a paid mutator transaction binding the contract method 0x8119c065. +// +// Solidity: function swap() returns() +func (_Univ2Swapper *Univ2SwapperTransactorSession) Swap() (*types.Transaction, error) { + return _Univ2Swapper.Contract.Swap(&_Univ2Swapper.TransactOpts) +} + diff --git a/loadtest/contracts/evm/foundry.toml b/loadtest/contracts/evm/foundry.toml index 25b918f9c9..d250a76fb7 100644 --- a/loadtest/contracts/evm/foundry.toml +++ b/loadtest/contracts/evm/foundry.toml @@ -1,4 +1,27 @@ [profile.default] +# Foundry Configuration File +# Default definitions: https://github.com/gakonst/foundry/blob/b7917fa8491aedda4dd6db53fbb206ea233cd531/config/src/lib.rs#L782 +# See more config options at: https://github.com/gakonst/foundry/tree/master/config + +# The Default Profile +# Sets the concrete solc version to use +# This overrides the `auto_detect_solc` value +solc_version = '0.8.20' +auto_detect_solc = false +# Increase optimizer_runs +optimizer = true +optimizer_runs = 1_000 +# Fuzz more than the default 256 +fuzz_runs = 1_000 +# Configure remappings +remappings = [ + "@ds=lib/ds-test/src/", + "@std=lib/forge-std/src/", + "@solmate=lib/solmate/src/", + "@clones=lib/clones-with-immutable-args/src/", + "@openzeppelin=lib/openzeppelin-contracts/contracts/" +] + src = "src" out = "out" libs = ["lib"] diff --git a/loadtest/contracts/evm/lib/openzeppelin-contracts b/loadtest/contracts/evm/lib/openzeppelin-contracts new file mode 160000 index 0000000000..01ef448981 --- /dev/null +++ b/loadtest/contracts/evm/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 01ef448981be9d20ca85f2faf6ebdf591ce409f3 diff --git a/loadtest/contracts/evm/lib/solmate b/loadtest/contracts/evm/lib/solmate new file mode 160000 index 0000000000..c892309933 --- /dev/null +++ b/loadtest/contracts/evm/lib/solmate @@ -0,0 +1 @@ +Subproject commit c892309933b25c03d32b1b0d674df7ae292ba925 diff --git a/loadtest/contracts/evm/remappings.txt b/loadtest/contracts/evm/remappings.txt index f8107635f6..8dd4268b08 100644 --- a/loadtest/contracts/evm/remappings.txt +++ b/loadtest/contracts/evm/remappings.txt @@ -1,4 +1,4 @@ -@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ +@openzeppelin=lib/openzeppelin-contracts/contracts/ ds-test/=lib/forge-std/lib/ds-test/src/ erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/ forge-std/=lib/forge-std/src/ diff --git a/loadtest/contracts/evm/src/ERC20Token.sol b/loadtest/contracts/evm/src/ERC20Token.sol new file mode 100644 index 0000000000..16930d08c6 --- /dev/null +++ b/loadtest/contracts/evm/src/ERC20Token.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract ERC20Token is ERC20 { + constructor(string memory name, string memory symbol) ERC20(name, symbol) {} + function mint(address to, uint256 amount) public { + _mint(to, amount); + } +} \ No newline at end of file diff --git a/loadtest/contracts/evm/src/ERC721.sol b/loadtest/contracts/evm/src/ERC721.sol new file mode 100644 index 0000000000..d35102496c --- /dev/null +++ b/loadtest/contracts/evm/src/ERC721.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +interface IERC165 { + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} + +interface IERC721 is IERC165 { + function balanceOf(address owner) external view returns (uint balance); + + function ownerOf(uint tokenId) external view returns (address owner); + + function safeTransferFrom(address from, address to, uint tokenId) external; + + function safeTransferFrom( + address from, + address to, + uint tokenId, + bytes calldata data + ) external; + + function transferFrom(address from, address to, uint tokenId) external; + + function approve(address to, uint tokenId) external; + + function getApproved(uint tokenId) external view returns (address operator); + + function setApprovalForAll(address operator, bool _approved) external; + + function isApprovedForAll( + address owner, + address operator + ) external view returns (bool); +} + +interface IERC721Receiver { + function onERC721Received( + address operator, + address from, + uint tokenId, + bytes calldata data + ) external returns (bytes4); +} + +contract ERC721 is IERC721 { + event Transfer(address indexed from, address indexed to, uint indexed id); + event Approval(address indexed owner, address indexed spender, uint indexed id); + event ApprovalForAll( + address indexed owner, + address indexed operator, + bool approved + ); + + // Mapping from token ID to owner address + mapping(uint => address) internal _ownerOf; + + // Mapping owner address to token count + mapping(address => uint) internal _balanceOf; + + // Mapping from token ID to approved address + mapping(uint => address) internal _approvals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) public isApprovedForAll; + + function supportsInterface(bytes4 interfaceId) external pure returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC165).interfaceId; + } + + function ownerOf(uint id) external view returns (address owner) { + owner = _ownerOf[id]; + require(owner != address(0), "token doesn't exist"); + } + + function balanceOf(address owner) external view returns (uint) { + require(owner != address(0), "owner = zero address"); + return _balanceOf[owner]; + } + + function setApprovalForAll(address operator, bool approved) external { + isApprovedForAll[msg.sender][operator] = approved; + emit ApprovalForAll(msg.sender, operator, approved); + } + + function approve(address spender, uint id) external { + address owner = _ownerOf[id]; + require( + msg.sender == owner || isApprovedForAll[owner][msg.sender], + "not authorized" + ); + + _approvals[id] = spender; + + emit Approval(owner, spender, id); + } + + function getApproved(uint id) external view returns (address) { + require(_ownerOf[id] != address(0), "token doesn't exist"); + return _approvals[id]; + } + + function _isApprovedOrOwner( + address owner, + address spender, + uint id + ) internal view returns (bool) { + return (spender == owner || + isApprovedForAll[owner][spender] || + spender == _approvals[id]); + } + + function transferFrom(address from, address to, uint id) public { + require(from == _ownerOf[id], "from != owner"); + require(to != address(0), "transfer to zero address"); + + require(_isApprovedOrOwner(from, msg.sender, id), "not authorized"); + + _balanceOf[from]--; + _balanceOf[to]++; + _ownerOf[id] = to; + + delete _approvals[id]; + + emit Transfer(from, to, id); + } + + function safeTransferFrom(address from, address to, uint id) external { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + IERC721Receiver(to).onERC721Received(msg.sender, from, id, "") == + IERC721Receiver.onERC721Received.selector, + "unsafe recipient" + ); + } + + function safeTransferFrom( + address from, + address to, + uint id, + bytes calldata data + ) external { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + IERC721Receiver(to).onERC721Received(msg.sender, from, id, data) == + IERC721Receiver.onERC721Received.selector, + "unsafe recipient" + ); + } + + function _mint(address to, uint id) internal { + require(to != address(0), "mint to zero address"); + // remove this check so that it's repeatable + // require(_ownerOf[id] == address(0), "already minted"); + + _balanceOf[to]++; + _ownerOf[id] = to; + + emit Transfer(address(0), to, id); + } + + function _burn(uint id) internal { + address owner = _ownerOf[id]; + require(owner != address(0), "not minted"); + + _balanceOf[owner] -= 1; + + delete _ownerOf[id]; + delete _approvals[id]; + + emit Transfer(owner, address(0), id); + } +} + +contract MyNFT is ERC721 { + function mint(address to, uint id) external { + _mint(to, id); + } + + function burn(uint id) external { + require(msg.sender == _ownerOf[id], "not owner"); + _burn(id); + } +} diff --git a/loadtest/contracts/evm/src/UniV2Swapper.sol b/loadtest/contracts/evm/src/UniV2Swapper.sol new file mode 100644 index 0000000000..13d2957efc --- /dev/null +++ b/loadtest/contracts/evm/src/UniV2Swapper.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +import "./univ2/UniswapV2Router.sol"; +import "./univ2/interfaces/IERC20.sol"; + +pragma solidity ^0.8.0; + +// UniV2Swapper facilitates swapping between two tokens on UniswapV2. It is used by our loadtest +// to easily allow any of our evm tx clients to execute a swap on UniswapV2. Without it, we would +// need to mint tokens and approve the UniV2Router contract for each of our evm tx clients, which +// scales linearly with the number of clients, making the setup process very slow. +contract UniV2Swapper { + uint256 public constant BIG_NUMBER = 100000000000000000000000000000000000000000000000000; // 10^50 + address public t1; + address public t2; + address public uniV2Router; + constructor(address t1_, address t2_, address uniV2Router_) { + t1 = t1_; + t2 = t2_; + uniV2Router = uniV2Router_; + IERC20(t1).mint(address(this), BIG_NUMBER); + IERC20(t2).mint(address(this), BIG_NUMBER); + IERC20(t1).approve(uniV2Router, BIG_NUMBER); + IERC20(t2).approve(uniV2Router, BIG_NUMBER); + } + + function swap() public { + address[] memory tokenPath = new address[](2); + uint256 randomNum = uint256(keccak256(abi.encodePacked(block.timestamp))); + // randomly either swap t1 for t2 or t2 for t1 + if (randomNum % 2 == 0) { + tokenPath[0] = t1; + tokenPath[1] = t2; + } else { + tokenPath[0] = t2; + tokenPath[1] = t1; + } + UniswapV2Router(uniV2Router).swapExactTokensForTokens( + 100, + 0, + tokenPath, + address(this), + block.timestamp + 1 + ); + } +} \ No newline at end of file diff --git a/loadtest/contracts/evm/src/univ2/UniswapV2Factory.sol b/loadtest/contracts/evm/src/univ2/UniswapV2Factory.sol new file mode 100644 index 0000000000..6532806d16 --- /dev/null +++ b/loadtest/contracts/evm/src/univ2/UniswapV2Factory.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.10; + +import "./UniswapV2Pair.sol"; +import "./interfaces/IUniswapV2Pair.sol"; + +/// @title UniswapV2Factory +/// @author Uniswap Labs +/// @notice Creates pool pairs of tokens +contract UniswapV2Factory { + // ========= Custom Errors ========= + + error IdenticalTokens(); + error InvalidToken(); + error DuplicatePair(); + + // ========= State Variables ========= + + mapping(address => mapping(address => address)) public pairs; + address[] public allPairs; + + // ========= Events ========= + + event PairCreated( + address indexed token0, + address indexed token1, + address pair, + uint256 + ); + + // ========= Public Helper Functions ========= + + function getAllPairLength() external view returns (uint256) { + return allPairs.length; + } + + function getAllPairsIndex(uint256 index) external view returns (address) { + return allPairs[index]; + } + + // ========= Public Functions ========= + + /// @notice Creates a new pool of token pair + /// @param tokenA First token in the pair + /// @param tokenB Second token in the pair + /// @return pair Address of the pair created + function createPair(address tokenA, address tokenB) + public + returns (address pair) + { + if (tokenA == tokenB) revert IdenticalTokens(); + + (address token0, address token1) = tokenA < tokenB + ? (tokenA, tokenB) + : (tokenB, tokenA); + + if (token0 == address(0)) revert InvalidToken(); + if (pairs[token0][token1] != address(0)) revert DuplicatePair(); + + bytes memory bytecode = type(UniswapV2Pair).creationCode; + bytes32 salt = keccak256(abi.encodePacked(token0, token1)); + + // solhint-disable-next-line no-inline-assembly + assembly { + pair := create2(0, add(bytecode, 32), mload(bytecode), salt) + } + + IUniswapV2Pair(pair).initialize(token0, token1); + + pairs[token0][token1] = pair; + pairs[token1][token0] = pair; + allPairs.push(pair); + + emit PairCreated(token0, token1, pair, allPairs.length); + } +} diff --git a/loadtest/contracts/evm/src/univ2/UniswapV2Pair.sol b/loadtest/contracts/evm/src/univ2/UniswapV2Pair.sol new file mode 100644 index 0000000000..00235acbda --- /dev/null +++ b/loadtest/contracts/evm/src/univ2/UniswapV2Pair.sol @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.10; + +import "solmate/tokens/ERC20.sol"; +import "solmate/utils/FixedPointMathLib.sol"; +import "solmate/utils/ReentrancyGuard.sol"; +import "@openzeppelin/proxy/utils/Initializable.sol"; +import "./interfaces/IERC20.sol"; +import "./libraries/Math.sol"; +import "./libraries/UQ112x112.sol"; + +/// @title UniswapV2Pair +/// @author Uniswap Labs +/// @notice maintains a liquidity pool of a pair of tokens +contract UniswapV2Pair is ERC20, ReentrancyGuard, Initializable { + // ========= Custom Errors ========= + + error InsufficientLiquidityMinted(); + error InsufficientLiquidityBurned(); + error SafeTransferFailed(); + error SwapToSelf(); + error InsufficientLiquidity(); + error InvalidAmount(); + error InvalidConstantProductFormula(); + error BalanceOverflow(); + + // ========= Libraries ========= + + using Math for uint256; + using FixedPointMathLib for uint256; + + // ========= Constants ========= + + uint256 public constant MINIMUM_LIQUIDITY = 1e3; + bytes4 public constant SELECTOR = + bytes4(keccak256("transfer(address,uint256")); + + // ========= State Variables ========= + + address public token0; + address public token1; + + // reserves are tracked rather than balances to prevent price manipulation + // bit-packing is done to save gas + uint112 public reserve0; + uint112 public reserve1; + uint32 public blockTimestampLast; + + uint256 public price0CumulativeLast; + uint256 public price1CumulativeLast; + + // ======== Events ======== + + event Mint(address indexed _operator, uint256 _value); + event Burn(address indexed _operator, uint256 _value); + event Swap( + address indexed sender, + uint256 amount0Out, + uint256 amount1Out, + address indexed to + ); + event Sync(uint112 reserve0, uint112 reserve1); + + // ========= Constructor ========= + + constructor() ERC20("UniswapV2", "UNIV2", 18) {} + + // ========= Initializer ========= + + function initialize(address _token0, address _token1) external initializer { + token0 = _token0; + token1 = _token1; + } + + // ========= Public Functions ========= + + /// @notice Returns reserves and last synced block timestamp + /// @return reserve0 Reserve of token 0 + /// @return reserve1 Reserve of token 1 + /// @return blockTimestampLast Block timestamp of last sync + function getReserves() + public + view + returns ( + uint112, + uint112, + uint32 + ) + { + return (reserve0, reserve1, blockTimestampLast); + } + + /// @notice Calculate the pool tokens for the given new liquidity amount + /// @dev If new pool is created, then minimum liquidity is 1e3 transfered to 0x0 + /// @param to Address to which pool tokens are minted + /// @return liquidity Total liquidity minted + function mint(address to) public nonReentrant returns (uint256 liquidity) { + uint256 balance0 = IERC20(token0).balanceOf(address(this)); + uint256 balance1 = IERC20(token1).balanceOf(address(this)); + + uint256 amount0 = balance0 - uint256(reserve0); + uint256 amount1 = balance1 - uint256(reserve1); + + if (totalSupply == 0) { + // Initial liquidity = sqrt(a0 * a1) + liquidity = + FixedPointMathLib.sqrt(amount0 * amount1) - + MINIMUM_LIQUIDITY; + + // Prevents value of 1 LP token being too high + _mint(address(0), MINIMUM_LIQUIDITY); + } else { + // Minimum because max is prone to price manipulation + liquidity = Math.min( + (amount0 * totalSupply) / reserve0, + (amount1 * totalSupply) / reserve1 + ); + } + + if (liquidity == 0) revert InsufficientLiquidityMinted(); + + _mint(to, liquidity); + + _update(balance0, balance1, reserve0, reserve1); + + emit Mint(to, liquidity); + } + + /// @notice Burns pool tokens of a particular address + /// @dev Needs to transfer pool tokens to the pool first to be burnt + /// @param to Address whose tokens are burned + /// @return amount0 Amount of token0 burned + /// @return amount1 Amount of token1 burned + function burn(address to) + public + nonReentrant + returns (uint256 amount0, uint256 amount1) + { + uint256 balance0 = IERC20(token0).balanceOf(address(this)); + uint256 balance1 = IERC20(token1).balanceOf(address(this)); + + uint256 liquidity = balanceOf[address(this)]; + + amount0 = (liquidity * balance0) / uint256(reserve0); + amount1 = (liquidity * balance1) / uint256(reserve1); + + if (amount0 == 0 || amount1 == 0) revert InsufficientLiquidityBurned(); + + _burn(address(this), liquidity); + + _safeTransfer(token0, to, amount0); + _safeTransfer(token1, to, amount1); + + _update(balance0 - amount0, balance1 - amount1, reserve0, reserve1); + + emit Burn(to, liquidity); + } + + /// @notice Dwaps two tokens + /// @dev New balances should maintain the constant product formula + /// @param amount0Out Amount of token0 to be transfered + /// @param amount1Out Amount of token1 to be transfered + /// @param to Address o which tokens are transfered + function swap( + uint256 amount0Out, + uint256 amount1Out, + address to + ) public nonReentrant { + if (amount0Out == 0 && amount1Out == 0) revert InvalidAmount(); + + if (amount0Out > reserve0 || amount1Out > reserve1) + revert InsufficientLiquidity(); + + if (to == token0 || to == token1) revert SwapToSelf(); + + if (amount0Out != 0) _safeTransfer(token0, to, amount0Out); + if (amount1Out != 0) _safeTransfer(token1, to, amount1Out); + + uint256 balance0 = IERC20(token0).balanceOf(address(this)); + uint256 balance1 = IERC20(token1).balanceOf(address(this)); + + if (balance0 * balance1 < uint256(reserve0) * uint256(reserve1)) + revert InvalidConstantProductFormula(); + + _update(balance0, balance1, reserve0, reserve1); + + emit Swap(msg.sender, amount0Out, amount1Out, to); + } + + /// @notice Syncs reserves + function sync() public { + _update( + IERC20(token0).balanceOf(address(this)), + IERC20(token1).balanceOf(address(this)), + reserve0, + reserve1 + ); + } + + // ========= Internal functions ========= + + /// @notice Updates pool reserves and price accumulators + /// @param balance0 New balance of token0 in pool + /// @param balance1 New balance of token1 in pool + /// @param _reserve0 Reserve of token0 in pool + /// @param _reserve1 Reserve of token1 in pool + function _update( + uint256 balance0, + uint256 balance1, + uint112 _reserve0, + uint112 _reserve1 + ) internal { + if (balance0 > type(uint112).max || balance1 > type(uint112).max) + revert BalanceOverflow(); + + unchecked { + uint32 timeElapsed = uint32(block.timestamp) - blockTimestampLast; + if (timeElapsed > 0 && _reserve0 > 0 && _reserve1 > 0) { + price0CumulativeLast += + uint256( + UQ112x112.uqdiv(UQ112x112.encode(_reserve1), reserve0) + ) * + timeElapsed; + price1CumulativeLast += + uint256( + UQ112x112.uqdiv(UQ112x112.encode(_reserve0), _reserve1) + ) * + timeElapsed; + } + } + + reserve0 = uint112(balance0); + reserve1 = uint112(balance1); + blockTimestampLast = uint32(block.timestamp); + + emit Sync(reserve0, reserve1); + } + + function _safeTransfer( + address token, + address to, + uint256 amount + ) internal { + bool success = IERC20(token).transfer(to, amount); + if (!success) revert SafeTransferFailed(); + } +} diff --git a/loadtest/contracts/evm/src/univ2/UniswapV2Router.sol b/loadtest/contracts/evm/src/univ2/UniswapV2Router.sol new file mode 100644 index 0000000000..568c131d39 --- /dev/null +++ b/loadtest/contracts/evm/src/univ2/UniswapV2Router.sol @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.10; + +import "./interfaces/IUniswapV2Factory.sol"; +import "./interfaces/IUniswapV2Pair.sol"; +import "./interfaces/IERC20.sol"; +import "./libraries/UniswapV2Library.sol"; + +contract UniswapV2Router { + // ========= Custom Errors ========= + + error Expired(); + error SafeTransferFromFailed(); + error InsufficientAmountA(); + error InsufficientAmountB(); + + // ========= State Variables ========= + + IUniswapV2Factory public immutable factory; + + // ========= Constructor ========= + + constructor(address _factory) { + factory = IUniswapV2Factory(_factory); + } + + // ========= Modifiers ========= + modifier check(uint256 deadline) { + if (block.timestamp > deadline) revert Expired(); + _; + } + + // ========= Public Functions ========= + + /// @notice Add liquidity to token pool pair + /// @dev Creates pair if not already created + /// @param tokenA The first token + /// @param tokenB The second token + /// @param amountADesired The amount of tokenA desired + /// @param amountBDesired The amount of tokenB desired + /// @param amountAMin The minimum amount of tokenA to transfer + /// @param amountBMin The minimum amount of tokenB to transfer + /// @param to The address to transfer liquidity to + /// @param deadline The deadline for the transaction + /// @return amountA Amount of tokenA to transfer + /// @return amountB Amount of tokenB to transfer + /// @return liquidity Amount of liquidity transfered + function addLiquidity( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired, + uint256 amountAMin, + uint256 amountBMin, + address to, + uint256 deadline + ) + public + check(deadline) + returns ( + uint256 amountA, + uint256 amountB, + uint256 liquidity + ) + { + (amountA, amountB) = _computeLiquidityAmounts( + tokenA, + tokenB, + amountADesired, + amountBDesired, + amountAMin, + amountBMin + ); + address pair = factory.pairs(tokenA, tokenB); + _safeTransferFrom(tokenA, msg.sender, pair, amountA); + _safeTransferFrom(tokenB, msg.sender, pair, amountB); + liquidity = IUniswapV2Pair(pair).mint(to); + } + + /// @notice Remove liquidity from token pool pair + /// @param tokenA The first token + /// @param tokenB The second token + /// @param liquidity The amount of liquidity token to remove + /// @param amountAMin The minimum amount of tokenA needed + /// @param amountBMin The minimum amount of tokenB needed + /// @param to The address to transfer pair contracts to + /// @param deadline The deadline for the transaction + function removeLiquidity( + address tokenA, + address tokenB, + uint256 liquidity, + uint256 amountAMin, + uint256 amountBMin, + address to, + uint256 deadline + ) public check(deadline) returns (uint256 amountA, uint256 amountB) { + address pair = factory.pairs(tokenA, tokenB); + _safeTransferFrom(address(pair), msg.sender, address(pair), liquidity); + (uint256 amount0, uint256 amount1) = IUniswapV2Pair(pair).burn(to); + (address token0, ) = UniswapV2Library.sortPairs(tokenA, tokenB); + (amountA, amountB) = token0 == tokenA + ? (amount0, amount1) + : (amount1, amount0); + if (amountA < amountAMin) revert InsufficientAmountA(); + if (amountB < amountBMin) revert InsufficientAmountB(); + } + + // ========= Internal Functions ========= + + /// @notice computes token amounts according to marginal prices to be transfered + /// @dev Creates a token pool pair if not already created + function _computeLiquidityAmounts( + address tokenA, + address tokenB, + uint256 amountADesired, + uint256 amountBDesired, + uint256 amountAMin, + uint256 amountBMin + ) internal returns (uint256 amountA, uint256 amountB) { + if (factory.pairs(tokenA, tokenB) == address(0)) { + factory.createPair(tokenA, tokenB); + } + + // require(false, string(abi.encodePacked(factory))); + + (uint112 reserveA, uint112 reserveB) = UniswapV2Library.getReserves( + address(factory), + tokenA, + tokenB + ); + // require(false, "after getReserves"); + if (reserveA == 0 && reserveB == 0) { + (amountA, amountB) = (amountADesired, amountBDesired); + } else { + amountB = UniswapV2Library.quote(amountADesired, reserveA, reserveB); + if (amountB <= amountBDesired) { + if (amountB < amountBMin) { + require(false, "InsufficientAmountB"); + revert InsufficientAmountB(); + } + amountA = amountADesired; + } else { + amountA = UniswapV2Library.quote( + amountBDesired, + reserveB, + reserveA + ); + assert(amountA <= amountADesired); + + if (amountA < amountAMin) { + require(false, "InsufficientAmountA"); + revert InsufficientAmountA(); + } + amountB = amountBDesired; + } + } + } + + function _safeTransferFrom( + address token, + address from, + address to, + uint256 amount + ) internal returns (bool success) { + success = IERC20(token).transferFrom(from, to, amount); + if (!success) { + require(false, "SafeTransferFromFailed"); + revert SafeTransferFromFailed(); + } + } + + // **** SWAP **** + // requires the initial amount to have already been sent to the first pair + function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual { + for (uint i; i < path.length - 1; i++) { + (address input, address output) = (path[i], path[i + 1]); + (address token0,) = UniswapV2Library.sortPairs(input, output); + uint amountOut = amounts[i + 1]; + (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0)); + + address to = i < path.length - 2 ? UniswapV2Library.pairFor(address(factory), output, path[i + 2]) : _to; + IUniswapV2Pair(UniswapV2Library.pairFor(address(factory), input, output)).swap( + amount0Out, amount1Out, to + ); + } + } + + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external check(deadline) returns (uint[] memory amounts) { + amounts = UniswapV2Library.getAmountsOut(address(factory), amountIn, path); + require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); + (address token0, address token1) = UniswapV2Library.sortPairs(path[0], path[1]); + address pair = factory.pairs(token0, token1); + _safeTransferFrom( + path[0], msg.sender, pair, amounts[0] + ); + _swap(amounts, path, to); + } +} diff --git a/loadtest/contracts/evm/src/univ2/interfaces/IERC20.sol b/loadtest/contracts/evm/src/univ2/interfaces/IERC20.sol new file mode 100644 index 0000000000..9015c76869 --- /dev/null +++ b/loadtest/contracts/evm/src/univ2/interfaces/IERC20.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.10; + +interface IERC20 { + function mint(address to, uint256 amount) external; + + function balanceOf(address) external view returns (uint256); + + function transfer(address to, uint256 amount) external returns (bool); + + function transferFrom( + address from, + address to, + uint256 amount + ) external returns (bool); + + function approve(address spender, uint256 amount) external returns (bool); +} diff --git a/loadtest/contracts/evm/src/univ2/interfaces/IUniswapV2Factory.sol b/loadtest/contracts/evm/src/univ2/interfaces/IUniswapV2Factory.sol new file mode 100644 index 0000000000..04d0aabdd2 --- /dev/null +++ b/loadtest/contracts/evm/src/univ2/interfaces/IUniswapV2Factory.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.10; + +interface IUniswapV2Factory { + function pairs(address tokenA, address tokenB) + external + view + returns (address); + + function createPair(address, address) external returns (address); +} diff --git a/loadtest/contracts/evm/src/univ2/interfaces/IUniswapV2Pair.sol b/loadtest/contracts/evm/src/univ2/interfaces/IUniswapV2Pair.sol new file mode 100644 index 0000000000..c0cdedd164 --- /dev/null +++ b/loadtest/contracts/evm/src/univ2/interfaces/IUniswapV2Pair.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.10; + +interface IUniswapV2Pair { + function initialize(address, address) external; + + function getReserves() + external + view + returns ( + uint112, + uint112, + uint32 + ); + + function mint(address) external returns (uint256); + + function burn(address) external returns (uint256, uint256); + + function swap( + uint256, + uint256, + address + ) external; + + function sync() external; +} diff --git a/loadtest/contracts/evm/src/univ2/libraries/Math.sol b/loadtest/contracts/evm/src/univ2/libraries/Math.sol new file mode 100644 index 0000000000..44645f54f4 --- /dev/null +++ b/loadtest/contracts/evm/src/univ2/libraries/Math.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.10; + +library Math { + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } +} diff --git a/loadtest/contracts/evm/src/univ2/libraries/UQ112x112.sol b/loadtest/contracts/evm/src/univ2/libraries/UQ112x112.sol new file mode 100644 index 0000000000..5c0cc7bfb9 --- /dev/null +++ b/loadtest/contracts/evm/src/univ2/libraries/UQ112x112.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.10; + +/// @title UQ112x112 +/// @author [Uniswap Labs](https://github.com/Uniswap/v2-core/blob/master/contracts/libraries/UQ112x112.sol) +/// @notice Library for handling binary fixed point numbers +library UQ112x112 { + uint224 public constant Q112 = 2**112; + + // encode a uint112 as a UQ112x112 + function encode(uint112 y) internal pure returns (uint224 z) { + z = uint224(y) * Q112; // never overflows + } + + // divide a UQ112x112 by a uint112, returning a UQ112x112 + function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { + z = x / uint224(y); + } +} diff --git a/loadtest/contracts/evm/src/univ2/libraries/UniswapV2Library.sol b/loadtest/contracts/evm/src/univ2/libraries/UniswapV2Library.sol new file mode 100644 index 0000000000..03574d45b0 --- /dev/null +++ b/loadtest/contracts/evm/src/univ2/libraries/UniswapV2Library.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.10; + +import "../interfaces/IUniswapV2Pair.sol"; +import "../interfaces/IUniswapV2Factory.sol"; + +/// @title UniswapV2Library +/// @author Uniswap Labs +/// @notice Provides common functionality for UniswapV2 Contracts +library UniswapV2Library { + function sortPairs(address token0, address token1) + internal + pure + returns (address, address) + { + return token0 < token1 ? (token0, token1) : (token1, token0); + } + + function quote( + uint256 amount0, + uint256 reserve0, + uint256 reserve1 + ) internal pure returns (uint256) { + return (amount0 * reserve1) / reserve0; + } + + function getReserves( + address factory, + address tokenA, + address tokenB + ) internal view returns (uint112 reserveA, uint112 reserveB) { + (address token0, address token1) = sortPairs(tokenA, tokenB); + IUniswapV2Pair pair = IUniswapV2Pair(IUniswapV2Factory(factory).pairs(token0, token1)); + (uint112 reserve0, uint112 reserve1, ) = pair.getReserves(); + (reserveA, reserveB) = tokenA == token0 + ? (reserve0, reserve1) + : (reserve1, reserve0); + } + + // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { + require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); + require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); + uint amountInWithFee = amountIn * 997; + uint numerator = amountInWithFee * reserveOut; + uint denominator = reserveIn * 1000 + amountInWithFee; + amountOut = numerator / denominator; + } + + // performs chained getAmountOut calculations on any number of pairs + function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { + require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); + amounts = new uint[](path.length); + amounts[0] = amountIn; + for (uint i; i < path.length - 1; i++) { + (uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); + amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); + } + } + + function pairFor(address factory, address tokenA, address tokenB) internal view returns (address) { + (address token1, address token2) = UniswapV2Library.sortPairs(tokenA, tokenB); + return IUniswapV2Factory(factory).pairs(token1, token2); + } + + + // somehow doesn't work as expected--don't use + + // // calculates the CREATE2 address for a pair without making any external calls + // function pairFor( + // address factory, + // address tokenA, + // address tokenB + // ) internal pure returns (address pair) { + // pair = address( + // uint160( + // uint256( + // keccak256( + // abi.encodePacked( + // hex"ff", + // factory, + // keccak256(abi.encodePacked(tokenA, tokenB)), + // hex"c302b13384af22f2ca10ffae7c2446a6fb5da0a895f0e211d72f313408acf32a" // init code hash + // ) + // ) + // ) + // ) + // ); + // } +} diff --git a/loadtest/evm.go b/loadtest/evm.go index 790f7ca844..de31e64d83 100644 --- a/loadtest/evm.go +++ b/loadtest/evm.go @@ -20,6 +20,8 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/sei-protocol/sei-chain/loadtest/contracts/evm/bindings/erc20" + "github.com/sei-protocol/sei-chain/loadtest/contracts/evm/bindings/erc721" + "github.com/sei-protocol/sei-chain/loadtest/contracts/evm/bindings/univ2_swapper" ) type EvmTxClient struct { @@ -40,6 +42,9 @@ func NewEvmTxClient( ethClients []*ethclient.Client, evmAddresses *EVMAddresses, ) *EvmTxClient { + if evmAddresses == nil { + evmAddresses = &EVMAddresses{} + } txClient := &EvmTxClient{ chainId: chainId, gasPrice: gasPrice, @@ -77,6 +82,10 @@ func (txClient *EvmTxClient) GetTxForMsgType(msgType string) *ethtypes.Transacti return txClient.GenerateSendFundsTx() case ERC20: return txClient.GenerateERC20TransferTx() + case ERC721: + return txClient.GenerateERC721Mint() + case UNIV2: + return txClient.GenerateUniV2SwapTx() default: panic("invalid message type") } @@ -115,6 +124,36 @@ func (txClient *EvmTxClient) GenerateERC20TransferTx() *ethtypes.Transaction { if err != nil { panic(fmt.Sprintf("Failed to create ERC20 transfer: %v \n", err)) } + return txClient.sign(tx) +} + +func (txClient *EvmTxClient) GenerateUniV2SwapTx() *ethtypes.Transaction { + opts := txClient.getTransactOpts() + opts.GasLimit = uint64(200000) + univ2Swapper, err := univ2_swapper.NewUniv2Swapper(txClient.evmAddresses.UniV2Swapper, GetNextEthClient(txClient.ethClients)) + if err != nil { + panic(fmt.Sprintf("Failed to create univ2 swapper contract: %v \n", err)) + } + tx, err := univ2Swapper.Swap(opts) + if err != nil { + panic(fmt.Sprintf("Failed to create univ2 swap: %v \n", err)) + } + return txClient.sign(tx) +} + +func (txClient *EvmTxClient) GenerateERC721Mint() *ethtypes.Transaction { + opts := txClient.getTransactOpts() + // override gas limit for an ERC20 transfer + opts.GasLimit = uint64(100000) + tokenAddress := txClient.evmAddresses.ERC721 + token, err := erc721.NewErc721(tokenAddress, GetNextEthClient(txClient.ethClients)) + if err != nil { + panic(fmt.Sprintf("Failed to create ERC721 contract: %v \n", err)) + } + tx, err := token.Mint(opts, txClient.accountAddress, randomValue()) + if err != nil { + panic(fmt.Sprintf("Failed to create ERC20 transfer: %v \n", err)) + } return tx } @@ -180,6 +219,17 @@ func (txClient *EvmTxClient) GetTxReceipt(txHash common.Hash) error { return nil } +// check receipt success +func (txClient *EvmTxClient) EnsureTxSuccess(txHash common.Hash) { + receipt, err := GetNextEthClient(txClient.ethClients).TransactionReceipt(context.Background(), txHash) + if err != nil { + panic(fmt.Sprintf("Failed to get receipt for tx %v: %v \n", txHash.Hex(), err)) + } + if receipt.Status != 1 { + panic(fmt.Sprintf("Tx %v failed with status %v \n", txHash.Hex(), receipt.Status)) + } +} + // ResetNonce need to be called when tx failed func (txClient *EvmTxClient) ResetNonce() error { txClient.mtx.Lock() diff --git a/loadtest/loadtest_client.go b/loadtest/loadtest_client.go index dfe0af7b7b..9c4ee79db2 100644 --- a/loadtest/loadtest_client.go +++ b/loadtest/loadtest_client.go @@ -19,6 +19,7 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" + "github.com/sei-protocol/sei-chain/utils/metrics" "golang.org/x/sync/semaphore" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" @@ -51,14 +52,21 @@ type LoadTestClient struct { func NewLoadTestClient(config Config) *LoadTestClient { signerClient := NewSignerClient(config.NodeURI) keys := signerClient.GetTestAccountsKeys(int(config.MaxAccounts)) - txClients, grpcConns := BuildGrpcClients(config) + txClients, grpcConns := BuildGrpcClients(&config) var evmTxClients []*EvmTxClient if config.EvmRpcEndpoints != "" { - if config.ContainsAnyMessageTypes(EVM, ERC20) { - evmTxClients = BuildEvmTxClients(config, keys) + if config.ContainsAnyMessageTypes(EVM, ERC20, ERC721, UNIV2) { + evmTxClients = BuildEvmTxClients(&config, keys) } } + // Fill message type maps with empty values + for _, messageType := range config.MessageTypes { + producedCountPerMsgType[messageType] = new(int64) + sentCountPerMsgType[messageType] = new(int64) + prevSentCounterPerMsgType[messageType] = new(int64) + } + return &LoadTestClient{ LoadTestConfig: config, AccountKeys: keys, @@ -88,7 +96,7 @@ func (c *LoadTestClient) SetValidators() { } // BuildGrpcClients build a list of grpc clients -func BuildGrpcClients(config Config) ([]typestx.ServiceClient, []*grpc.ClientConn) { +func BuildGrpcClients(config *Config) ([]typestx.ServiceClient, []*grpc.ClientConn) { grpcEndpoints := strings.Split(config.GrpcEndpoints, ",") txClients := make([]typestx.ServiceClient, len(grpcEndpoints)) grpcConns := make([]*grpc.ClientConn, len(grpcEndpoints)) @@ -130,7 +138,7 @@ func BuildGrpcClients(config Config) ([]typestx.ServiceClient, []*grpc.ClientCon } // BuildEvmTxClients build a list of EvmTxClients with a list of go-ethereum client -func BuildEvmTxClients(config Config, keys []cryptotypes.PrivKey) []*EvmTxClient { +func BuildEvmTxClients(config *Config, keys []cryptotypes.PrivKey) []*EvmTxClient { clients := make([]*EvmTxClient, len(keys)) ethEndpoints := strings.Split(config.EvmRpcEndpoints, ",") if len(ethEndpoints) == 0 { @@ -173,7 +181,7 @@ func (c *LoadTestClient) BuildTxs( wg *sync.WaitGroup, done <-chan struct{}, rateLimiter *rate.Limiter, - producedCount *atomic.Int64, + producedCountPerMsgType map[string]*int64, ) { wg.Add(1) defer wg.Done() @@ -188,18 +196,21 @@ func (c *LoadTestClient) BuildTxs( } // Generate a message type first messageType := c.getRandomMessageType(config.MessageTypes) + metrics.IncrProducerEventCount(messageType) var signedTx SignedTx // Sign EVM and Cosmos TX differently switch messageType { - case EVM, ERC20: - signedTx = SignedTx{EvmTx: c.generateSignedEvmTx(keyIndex, messageType)} + case EVM, ERC20, ERC721, UNIV2: + signedTx = SignedTx{EvmTx: c.generateSignedEvmTx(keyIndex, messageType), MsgType: messageType} + EvmTxHashes = append(EvmTxHashes, signedTx.EvmTx.Hash()) default: - signedTx = SignedTx{TxBytes: c.generateSignedCosmosTxs(keyIndex, messageType, producedCount)} + msgTypeCount := atomic.LoadInt64(producedCountPerMsgType[messageType]) + signedTx = SignedTx{TxBytes: c.generateSignedCosmosTxs(keyIndex, messageType, msgTypeCount), MsgType: messageType} } select { case txQueue <- signedTx: - producedCount.Add(1) + atomic.AddInt64(producedCountPerMsgType[messageType], 1) case <-done: return } @@ -211,7 +222,7 @@ func (c *LoadTestClient) generateSignedEvmTx(keyIndex int, msgType string) *etht return c.EvmTxClients[keyIndex].GetTxForMsgType(msgType) } -func (c *LoadTestClient) generateSignedCosmosTxs(keyIndex int, msgType string, producedCount *atomic.Int64) []byte { +func (c *LoadTestClient) generateSignedCosmosTxs(keyIndex int, msgType string, msgTypeCount int64) []byte { key := c.AccountKeys[keyIndex] msgs, _, _, gas, fee := c.generateMessage(key, msgType) txBuilder := TestConfig.TxConfig.NewTxBuilder() @@ -221,7 +232,7 @@ func (c *LoadTestClient) generateSignedCosmosTxs(keyIndex int, msgType string, p types.NewCoin("usei", types.NewInt(fee)), }) // Use random seqno to get around txs that might already be seen in mempool - c.SignerClient.SignTx(c.ChainID, &txBuilder, key, uint64(producedCount.Load())) + c.SignerClient.SignTx(c.ChainID, &txBuilder, key, uint64(msgTypeCount)) txBytes, _ := TestConfig.TxConfig.TxEncoder()(txBuilder.GetTx()) return txBytes } @@ -230,7 +241,7 @@ func (c *LoadTestClient) SendTxs( txQueue chan SignedTx, keyIndex int, done <-chan struct{}, - sentCount *atomic.Int64, + sentCountPerMsgType map[string]*int64, semaphore *semaphore.Weighted, wg *sync.WaitGroup, ) { @@ -243,6 +254,8 @@ func (c *LoadTestClient) SendTxs( case <-done: return case tx, ok := <-txQueue: + atomic.AddInt64(sentCountPerMsgType[tx.MsgType], 1) + metrics.IncrConsumerEventCount(tx.MsgType) if !ok { fmt.Printf("Stopping consumers\n") return @@ -255,12 +268,12 @@ func (c *LoadTestClient) SendTxs( if tx.TxBytes != nil && len(tx.TxBytes) > 0 { // Send Cosmos Transactions if SendTx(ctx, tx.TxBytes, typestx.BroadcastMode_BROADCAST_MODE_BLOCK, *c) { - sentCount.Add(1) + atomic.AddInt64(producedCountPerMsgType[tx.MsgType], 1) } } else if tx.EvmTx != nil { // Send EVM Transactions c.EvmTxClients[keyIndex].SendEvmTx(tx.EvmTx, func() { - sentCount.Add(1) + atomic.AddInt64(producedCountPerMsgType[tx.MsgType], 1) }) } // Release the semaphore diff --git a/loadtest/main.go b/loadtest/main.go index 11a07c6db0..1779b57828 100644 --- a/loadtest/main.go +++ b/loadtest/main.go @@ -2,15 +2,18 @@ package main import ( "bytes" + "context" "encoding/json" "flag" "fmt" "io" + "math/big" "math/rand" "net/http" "os" "os/exec" "os/signal" + "regexp" "strconv" "strings" "sync" @@ -29,10 +32,12 @@ import ( distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" "golang.org/x/sync/semaphore" "golang.org/x/time/rate" "github.com/sei-protocol/sei-chain/app" + "github.com/sei-protocol/sei-chain/utils/metrics" dextypes "github.com/sei-protocol/sei-chain/x/dex/types" tokenfactorytypes "github.com/sei-protocol/sei-chain/x/tokenfactory/types" ) @@ -44,10 +49,13 @@ const ( ) var ( - FromMili = sdk.NewDec(1000000) - producedCount = atomic.Int64{} - sentCount = atomic.Int64{} - prevSentCount = atomic.Int64{} + FromMili = sdk.NewDec(1000000) + producedCountPerMsgType = make(map[string]*int64) + sentCountPerMsgType = make(map[string]*int64) + prevSentCounterPerMsgType = make(map[string]*int64) + + BlockHeightsWithTxs = []int{} + EvmTxHashes = []common.Hash{} ) type BlockData struct { @@ -100,8 +108,38 @@ func deployEvmContracts(config *Config) { fmt.Println("error deploying, make sure 0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 is funded") panic(err) } - config.EVMAddresses = &EVMAddresses{ - ERC20: erc20, + config.EVMAddresses.ERC20 = erc20 + } + if config.ContainsAnyMessageTypes(ERC721) { + fmt.Println("Deploying ERC721 contract") + erc721, err := deployEvmContract("loadtest/contracts/deploy_erc721.sh", config) + if err != nil { + fmt.Println("error deploying, make sure 0xF87A299e6bC7bEba58dbBe5a5Aa21d49bCD16D52 is funded") + panic(err) + } + config.EVMAddresses.ERC721 = erc721 + } +} + +//nolint:gosec +func deployUniswapContracts(client *LoadTestClient, config *Config) { + config.EVMAddresses = &EVMAddresses{} + if config.ContainsAnyMessageTypes(UNIV2) { + fmt.Println("Deploying Uniswap contracts") + cmd := exec.Command("loadtest/contracts/deploy_univ2.sh", config.EVMRpcEndpoint()) + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + fmt.Println("script output: ", out.String()) + if err != nil { + panic("deploy_univ2.sh failed with error: " + err.Error()) + } + UniV2SwapperRe := regexp.MustCompile(`Swapper Address: "(\w+)"`) + match := UniV2SwapperRe.FindStringSubmatch(out.String()) + uniV2SwapperAddress := common.HexToAddress(match[1]) + fmt.Println("Found UniV2Swapper Address: ", uniV2SwapperAddress.String()) + for _, txClient := range client.EvmTxClients { + txClient.evmAddresses.UniV2Swapper = uniV2SwapperAddress } } } @@ -111,16 +149,18 @@ func run(config *Config) { metricsServer := MetricsServer{} go metricsServer.StartMetricsClient(*config) + client := NewLoadTestClient(*config) + client.SetValidators() deployEvmContracts(config) - startLoadtestWorkers(*config) + deployUniswapContracts(client, config) + startLoadtestWorkers(client, *config) + runEvmQueries(*config) } // starts loadtest workers. If config.Constant is true, then we don't gather loadtest results and let producer/consumer // workers continue running. If config.Constant is false, then we will gather load test results in a file -func startLoadtestWorkers(config Config) { +func startLoadtestWorkers(client *LoadTestClient, config Config) { fmt.Printf("Starting loadtest workers\n") - client := NewLoadTestClient(config) - client.SetValidators() configString, _ := json.Marshal(config) fmt.Printf("Running with \n %s \n", string(configString)) @@ -144,12 +184,13 @@ func startLoadtestWorkers(config Config) { consumerSemaphore := semaphore.NewWeighted(int64(config.TargetTps)) var wg sync.WaitGroup for i := 0; i < len(keys); i++ { - go client.BuildTxs(txQueues[i], i, &wg, done, producerRateLimiter, &producedCount) - go client.SendTxs(txQueues[i], i, done, &sentCount, consumerSemaphore, &wg) + go client.BuildTxs(txQueues[i], i, &wg, done, producerRateLimiter, producedCountPerMsgType) + go client.SendTxs(txQueues[i], i, done, sentCountPerMsgType, consumerSemaphore, &wg) } // Statistics reporting goroutine ticker := time.NewTicker(10 * time.Second) + ticks := 0 go func() { start := time.Now() for { @@ -157,23 +198,31 @@ func startLoadtestWorkers(config Config) { case <-ticker.C: currHeight := getLastHeight(config.BlockchainEndpoint) for i := startHeight; i <= currHeight; i++ { - _, blockTime, err := getTxBlockInfo(config.BlockchainEndpoint, strconv.Itoa(i)) + txCnt, blockTime, err := getTxBlockInfo(config.BlockchainEndpoint, strconv.Itoa(i)) if err != nil { fmt.Printf("Encountered error scraping data: %s\n", err) return } blockHeights = append(blockHeights, i) blockTimes = append(blockTimes, blockTime) + if txCnt > 0 { + BlockHeightsWithTxs = append(BlockHeightsWithTxs, i) + } } - totalProduced := producedCount.Load() - totalSent := sentCount.Load() - prevTotalSent := prevSentCount.Load() - printStats(start, totalProduced, totalSent, prevTotalSent, blockHeights, blockTimes) + printStats(start, producedCountPerMsgType, sentCountPerMsgType, prevSentCounterPerMsgType, blockHeights, blockTimes) startHeight = currHeight blockHeights, blockTimes = nil, nil start = time.Now() - prevSentCount.Store(totalSent) + + for msgType := range sentCountPerMsgType { + count := atomic.LoadInt64(sentCountPerMsgType[msgType]) + atomic.StoreInt64(prevSentCounterPerMsgType[msgType], count) + } + ticks++ + if config.Ticks > 0 && ticks >= int(config.Ticks) { + close(done) + } case <-done: ticker.Stop() return @@ -182,9 +231,11 @@ func startLoadtestWorkers(config Config) { }() // Wait for a termination signal - <-signals - fmt.Println("SIGINT received, shutting down producers and consumers...") - close(done) + if config.Ticks == 0 { + <-signals + fmt.Println("SIGINT received, shutting down producers and consumers...") + close(done) + } fmt.Println("Waiting for wait groups...") @@ -195,9 +246,35 @@ func startLoadtestWorkers(config Config) { } } -func printStats(startTime time.Time, totalProduced int64, totalSent int64, prevTotalSent int64, blockHeights []int, blockTimes []string) { +func printStats( + startTime time.Time, + producedCountPerMsgType map[string]*int64, + sentCountPerMsgType map[string]*int64, + prevSentPerCounterPerMsgType map[string]*int64, + blockHeights []int, + blockTimes []string, +) { elapsed := time.Since(startTime) - tps := float64(totalSent-prevTotalSent) / elapsed.Seconds() + + totalSent := int64(0) + totalProduced := int64(0) + //nolint:gosec + for msg_type := range sentCountPerMsgType { + totalSent += atomic.LoadInt64(sentCountPerMsgType[msg_type]) + } + //nolint:gosec + for msg_type := range producedCountPerMsgType { + totalProduced += atomic.LoadInt64(producedCountPerMsgType[msg_type]) + } + + var tps float64 + for msgType := range sentCountPerMsgType { + sentCount := atomic.LoadInt64(sentCountPerMsgType[msgType]) + prevTotalSent := atomic.LoadInt64(prevSentPerCounterPerMsgType[msgType]) + //nolint:gosec + tps = float64(sentCount-prevTotalSent) / elapsed.Seconds() + defer metrics.SetThroughputMetricByType("tps", float32(tps), msgType) + } var totalDuration time.Duration var prevTime time.Time @@ -239,7 +316,6 @@ func (c *LoadTestClient) generateMessage(key cryptotypes.PrivKey, msgType string signer := key r := rand.New(rand.NewSource(time.Now().UnixNano())) - defer IncrTxMessageType(msgType) defaultMessageTypeConfig := config.PerMessageConfigs["default"] gas := defaultMessageTypeConfig.Gas @@ -697,6 +773,54 @@ func getTxBlockInfo(blockchainEndpoint string, height string) (int, string, erro return len(blockResponse.Block.Data.Txs), blockResponse.Block.Header.Time, nil } +func runEvmQueries(config Config) { + ethEndpoints := strings.Split(config.EvmRpcEndpoints, ",") + if len(ethEndpoints) == 0 { + return + } + ethClients := make([]*ethclient.Client, len(ethEndpoints)) + for i, endpoint := range ethEndpoints { + client, err := ethclient.Dial(endpoint) + if err != nil { + fmt.Printf("Failed to connect to endpoint %s with error %s", endpoint, err.Error()) + } + ethClients[i] = client + } + wg := sync.WaitGroup{} + start := time.Now() + for i := 0; i < config.PostTxEvmQueries.BlockByNumber; i++ { + wg.Add(1) + i := i + go func() { + defer func() { wg.Done() }() + height := int64(BlockHeightsWithTxs[i%len(BlockHeightsWithTxs)]) + _, err := ethClients[i%len(ethClients)].BlockByNumber(context.Background(), big.NewInt(height)) + if err != nil { + fmt.Printf("Failed to get full block of height %d due to %s\n", height, err) + } + }() + } + wg.Wait() + fmt.Printf("Querying %d blocks in parallel took %fs\n", config.PostTxEvmQueries.BlockByNumber, time.Since(start).Seconds()) + + wg = sync.WaitGroup{} + start = time.Now() + for i := 0; i < config.PostTxEvmQueries.Receipt; i++ { + wg.Add(1) + i := i + go func() { + defer func() { wg.Done() }() + hash := EvmTxHashes[i%len(EvmTxHashes)] + _, err := ethClients[i%len(ethClients)].TransactionReceipt(context.Background(), hash) + if err != nil { + fmt.Printf("Failed to get receipt of tx %s due to %s\n", hash.Hex(), err) + } + }() + } + wg.Wait() + fmt.Printf("Querying %d receipts in parallel took %fs\n", config.PostTxEvmQueries.Receipt, time.Since(start).Seconds()) +} + func GetDefaultConfigFilePath() string { pwd, _ := os.Getwd() return pwd + "/loadtest/config.json" diff --git a/loadtest/metrics.go b/loadtest/metrics.go index 042be0e2b6..8281480c51 100644 --- a/loadtest/metrics.go +++ b/loadtest/metrics.go @@ -7,7 +7,6 @@ import ( "net/http" "time" - metrics "github.com/armon/go-metrics" "github.com/cosmos/cosmos-sdk/telemetry" "github.com/cosmos/cosmos-sdk/types/rest" ) @@ -72,12 +71,3 @@ func (s *MetricsServer) healthzHandler(w http.ResponseWriter, _ *http.Request) { panic(err) } } - -// loadtest_client_sei_msg_type -func IncrTxMessageType(msgType string) { - metrics.IncrCounterWithLabels( - []string{"sei", "msg", "type"}, - float32(1), - []metrics.Label{telemetry.NewLabel("type", msgType)}, - ) -} diff --git a/loadtest/scripts/populate_genesis_accounts.py b/loadtest/scripts/populate_genesis_accounts.py index 3b408d1943..ac3e39afa2 100644 --- a/loadtest/scripts/populate_genesis_accounts.py +++ b/loadtest/scripts/populate_genesis_accounts.py @@ -25,9 +25,9 @@ def add_key(account_name, local=False): shell=True, ).decode() - splitted_outputs = add_key_output.split('\n') - address = splitted_outputs[3].split(': ')[1] - mnemonic = splitted_outputs[11] + splitted_outputs = add_key_output.strip().split('\n') + address = splitted_outputs[2].split(': ')[1] + mnemonic = splitted_outputs[-1] return address, mnemonic diff --git a/loadtest/types.go b/loadtest/types.go index adef7f342f..573cb839de 100644 --- a/loadtest/types.go +++ b/loadtest/types.go @@ -19,6 +19,7 @@ const ( Bank string = "bank" EVM string = "evm" ERC20 string = "erc20" + ERC721 string = "erc721" CollectRewards string = "collect_rewards" DistributeRewards string = "distribute_rewards" FailureBankMalformed string = "failure_bank_malformed" @@ -31,6 +32,7 @@ const ( Limit string = "limit" Market string = "market" WasmMintNft string = "wasm_mint_nft" + UNIV2 string = "univ2" Vortex string = "vortex" WasmInstantiate string = "wasm_instantiate" WasmOccIteratorWrite string = "wasm_occ_iterator_write" @@ -43,7 +45,9 @@ type WasmIteratorWriteMsg struct { } type EVMAddresses struct { - ERC20 common.Address + ERC20 common.Address + ERC721 common.Address + UniV2Swapper common.Address } type Config struct { @@ -65,6 +69,8 @@ type Config struct { MetricsPort uint64 `json:"metrics_port"` TLS bool `json:"tls"` SeiTesterAddress string `json:"sei_tester_address"` + PostTxEvmQueries PostTxEvmQueries `json:"post_tx_evm_queries"` + Ticks uint64 `json:"ticks"` // These are dynamically set at startup EVMAddresses *EVMAddresses @@ -207,7 +213,13 @@ type WasmInstantiateType struct { Payload string `json:"payload"` } +type PostTxEvmQueries struct { + BlockByNumber int `json:"block_by_number"` + Receipt int `json:"receipt"` +} + type SignedTx struct { TxBytes []byte EvmTx *ethtypes.Transaction + MsgType string } diff --git a/occ_tests/messages/test_msgs.go b/occ_tests/messages/test_msgs.go index 0a7f885364..a9f3c2d2a6 100644 --- a/occ_tests/messages/test_msgs.go +++ b/occ_tests/messages/test_msgs.go @@ -2,13 +2,17 @@ package messages import ( "fmt" + "math/big" "github.com/CosmWasm/wasmd/x/wasm" - sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/sei-protocol/sei-chain/occ_tests/utils" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" ) const instantiateMsg = `{"whitelist": ["sei1h9yjz89tl0dl6zu65dpxcqnxfhq60wxx8s5kag"], @@ -34,38 +38,98 @@ const instantiateMsg = `{"whitelist": ["sei1h9yjz89tl0dl6zu65dpxcqnxfhq60wxx8s5k "maintenance":"0.06" }}` -func WasmInstantiate(tCtx *utils.TestContext, count int) []sdk.Msg { - var msgs []sdk.Msg +func WasmInstantiate(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage for i := 0; i < count; i++ { - msgs = append(msgs, &wasm.MsgInstantiateContract{ - Sender: tCtx.TestAccounts[0].AccountAddress.String(), - Admin: tCtx.TestAccounts[1].AccountAddress.String(), - CodeID: tCtx.CodeID, - Label: fmt.Sprintf("test-%d", i), - Msg: []byte(instantiateMsg), - Funds: utils.Funds(100000), + msgs = append(msgs, &utils.TestMessage{ + Msg: &wasm.MsgInstantiateContract{ + Sender: tCtx.TestAccounts[0].AccountAddress.String(), + Admin: tCtx.TestAccounts[1].AccountAddress.String(), + CodeID: tCtx.CodeID, + Label: fmt.Sprintf("test-%d", i), + Msg: []byte(instantiateMsg), + Funds: utils.Funds(100000), + }, + Type: "WasmInstantitate", }) } return msgs } -func BankTransfer(tCtx *utils.TestContext, count int) []sdk.Msg { - var msgs []sdk.Msg +// EVMTransferNonConflicting generates a list of EVM transfer messages that do not conflict with each other +// each message will have a brand new address +func EVMTransferNonConflicting(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage for i := 0; i < count; i++ { - msgs = append(msgs, banktypes.NewMsgSend(tCtx.TestAccounts[0].AccountAddress, tCtx.TestAccounts[1].AccountAddress, utils.Funds(int64(i+1)))) + testAcct := utils.NewSigner() + msgs = append(msgs, evmTransfer(testAcct, testAcct.EvmAddress, "EVMTransferNonConflicting")) } return msgs } -func GovernanceSubmitProposal(tCtx *utils.TestContext, count int) []sdk.Msg { - var msgs []sdk.Msg +// EVMTransferConflicting generates a list of EVM transfer messages to the same address +func EVMTransferConflicting(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage + for i := 0; i < count; i++ { + testAcct := utils.NewSigner() + msgs = append(msgs, evmTransfer(testAcct, tCtx.TestAccounts[0].EvmAddress, "EVMTransferConflicting")) + } + return msgs +} + +// EVMTransferNonConflicting generates a list of EVM transfer messages that do not conflict with each other +// each message will have a brand new address +func evmTransfer(testAcct utils.TestAcct, to common.Address, scenario string) *utils.TestMessage { + signedTx, err := ethtypes.SignTx(ethtypes.NewTx(ðtypes.DynamicFeeTx{ + GasFeeCap: new(big.Int).SetUint64(1000000000000), + GasTipCap: new(big.Int).SetUint64(1000000000000), + Gas: 21000, + ChainID: big.NewInt(1), + To: &to, + Value: big.NewInt(1), + Nonce: 0, + }), testAcct.EvmSigner, testAcct.EvmPrivateKey) + + if err != nil { + panic(err) + } + + txData, err := ethtx.NewTxDataFromTx(signedTx) + if err != nil { + panic(err) + } + + msg, err := types.NewMsgEVMTransaction(txData) + if err != nil { + panic(err) + } + + return &utils.TestMessage{ + Msg: msg, + IsEVM: true, + EVMSigner: testAcct, + Type: scenario, + } +} + +func BankTransfer(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage + for i := 0; i < count; i++ { + msg := banktypes.NewMsgSend(tCtx.TestAccounts[0].AccountAddress, tCtx.TestAccounts[1].AccountAddress, utils.Funds(int64(i+1))) + msgs = append(msgs, &utils.TestMessage{Msg: msg, Type: "BankTransfer"}) + } + return msgs +} + +func GovernanceSubmitProposal(tCtx *utils.TestContext, count int) []*utils.TestMessage { + var msgs []*utils.TestMessage for i := 0; i < count; i++ { content := govtypes.NewTextProposal(fmt.Sprintf("Proposal %d", i), "test", true) mp, err := govtypes.NewMsgSubmitProposalWithExpedite(content, utils.Funds(10000), tCtx.TestAccounts[0].AccountAddress, true) if err != nil { panic(err) } - msgs = append(msgs, mp) + msgs = append(msgs, &utils.TestMessage{Msg: mp, Type: "GovernanceSubmitProposal"}) } return msgs } diff --git a/occ_tests/occ_test.go b/occ_tests/occ_test.go index 91b034ea83..ff5cb3c0ca 100644 --- a/occ_tests/occ_test.go +++ b/occ_tests/occ_test.go @@ -106,12 +106,12 @@ func TestParallelTransactions(t *testing.T) { runs int shuffle bool before func(tCtx *utils.TestContext) - txs func(tCtx *utils.TestContext) []sdk.Msg + txs func(tCtx *utils.TestContext) []*utils.TestMessage }{ { name: "Test wasm instantiations", runs: runs, - txs: func(tCtx *utils.TestContext) []sdk.Msg { + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { return utils.JoinMsgs( messages.WasmInstantiate(tCtx, 10), ) @@ -120,7 +120,7 @@ func TestParallelTransactions(t *testing.T) { { name: "Test bank transfer", runs: runs, - txs: func(tCtx *utils.TestContext) []sdk.Msg { + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { return utils.JoinMsgs( messages.BankTransfer(tCtx, 2), ) @@ -129,21 +129,41 @@ func TestParallelTransactions(t *testing.T) { { name: "Test governance proposal", runs: runs, - txs: func(tCtx *utils.TestContext) []sdk.Msg { + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { return utils.JoinMsgs( messages.GovernanceSubmitProposal(tCtx, 10), ) }, }, + { + name: "Test evm transfers non-conflicting", + runs: runs, + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { + return utils.JoinMsgs( + messages.EVMTransferNonConflicting(tCtx, 10), + ) + }, + }, + { + name: "Test evm transfers conflicting", + runs: runs, + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { + return utils.JoinMsgs( + messages.EVMTransferConflicting(tCtx, 10), + ) + }, + }, { name: "Test combinations", runs: runs, shuffle: true, - txs: func(tCtx *utils.TestContext) []sdk.Msg { + txs: func(tCtx *utils.TestContext) []*utils.TestMessage { return utils.JoinMsgs( messages.WasmInstantiate(tCtx, 10), messages.BankTransfer(tCtx, 10), messages.GovernanceSubmitProposal(tCtx, 10), + messages.EVMTransferConflicting(tCtx, 10), + messages.EVMTransferNonConflicting(tCtx, 10), ) }, }, @@ -178,8 +198,8 @@ func TestParallelTransactions(t *testing.T) { require.NoError(t, pErr, tt.name) require.Len(t, pResults, len(txs)) - assertEqualEvents(t, sEvts, pEvts, tt.name) assertExecTxResultCode(t, sResults, pResults, 0, tt.name) + assertEqualEvents(t, sEvts, pEvts, tt.name) assertEqualExecTxResults(t, sResults, pResults, tt.name) assertEqualState(t, sCtx.Ctx, pCtx.Ctx, tt.name) } diff --git a/occ_tests/utils/utils.go b/occ_tests/utils/utils.go index aae8527213..4b20702ef9 100644 --- a/occ_tests/utils/utils.go +++ b/occ_tests/utils/utils.go @@ -2,6 +2,9 @@ package utils import ( "context" + "crypto/ecdsa" + "encoding/hex" + "math/big" "math/rand" "os" "testing" @@ -20,14 +23,19 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx/signing" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/cosmos/cosmos-sdk/x/auth/tx" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/sei-protocol/sei-chain/app" + utils2 "github.com/sei-protocol/sei-chain/utils" dexcache "github.com/sei-protocol/sei-chain/x/dex/cache" dextypes "github.com/sei-protocol/sei-chain/x/dex/types" dexutils "github.com/sei-protocol/sei-chain/x/dex/utils" + types2 "github.com/sei-protocol/sei-chain/x/evm/types" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" ) @@ -38,6 +46,13 @@ var ignoredStoreKeys = map[string]struct{}{ "deferredcache": {}, } +type TestMessage struct { + Msg sdk.Msg + Type string + EVMSigner TestAcct + IsEVM bool +} + type TestContext struct { Ctx sdk.Context CodeID uint64 @@ -52,6 +67,9 @@ type TestAcct struct { AccountAddress sdk.AccAddress PrivateKey cryptotypes.PrivKey PublicKey cryptotypes.PubKey + EvmAddress common.Address + EvmSigner ethtypes.Signer + EvmPrivateKey *ecdsa.PrivateKey } func NewTestAccounts(count int) []TestAcct { @@ -66,11 +84,20 @@ func NewSigner() TestAcct { priv1, pubKey, acct := testdata.KeyTestPubAddr() val := addressToValAddress(acct) + pvKeyHex := hex.EncodeToString(priv1.Bytes()) + key, _ := crypto.HexToECDSA(pvKeyHex) + ethCfg := types2.DefaultChainConfig().EthereumConfig(big.NewInt(1)) + signer := ethtypes.MakeSigner(ethCfg, utils2.Big1, 1) + address := crypto.PubkeyToAddress(key.PublicKey) + return TestAcct{ ValidatorAddress: val, AccountAddress: acct, PrivateKey: priv1, PublicKey: pubKey, + EvmAddress: address, + EvmSigner: signer, + EvmPrivateKey: key, } } @@ -95,7 +122,7 @@ func addressToValAddress(addr sdk.AccAddress) sdk.ValAddress { // NewTestContext initializes a new TestContext with a new app and a new contract func NewTestContext(t *testing.T, testAccts []TestAcct, blockTime time.Time, workers int, occEnabled bool) *TestContext { contractFile := "../integration_test/contracts/mars.wasm" - wrapper := app.NewTestWrapper(t, blockTime, testAccts[0].PublicKey, func(ba *baseapp.BaseApp) { + wrapper := app.NewTestWrapper(t, blockTime, testAccts[0].PublicKey, false, func(ba *baseapp.BaseApp) { ba.SetOccEnabled(occEnabled) ba.SetConcurrencyWorkers(workers) }) @@ -130,14 +157,15 @@ func NewTestContext(t *testing.T, testAccts []TestAcct, blockTime time.Time, wor } } -func toTxBytes(testCtx *TestContext, msgs []sdk.Msg) [][]byte { +func toTxBytes(testCtx *TestContext, msgs []*TestMessage) [][]byte { txs := make([][]byte, 0, len(msgs)) tc := app.MakeEncodingConfig().TxConfig priv := testCtx.TestAccounts[0].PrivateKey acct := testCtx.TestApp.AccountKeeper.GetAccount(testCtx.Ctx, testCtx.TestAccounts[0].AccountAddress) - for _, m := range msgs { + for _, tm := range msgs { + m := tm.Msg a, err := codectypes.NewAnyWithValue(m) if err != nil { panic(err) @@ -157,6 +185,25 @@ func toTxBytes(testCtx *TestContext, msgs []sdk.Msg) [][]byte { }, }) + if tm.IsEVM { + amounts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000000000000000000)), sdk.NewCoin("uusdc", sdk.NewInt(1000000000000000))) + + // fund account so it has funds + if err := testCtx.TestApp.BankKeeper.MintCoins(testCtx.Ctx, minttypes.ModuleName, amounts); err != nil { + panic(err) + } + if err := testCtx.TestApp.BankKeeper.SendCoinsFromModuleToAccount(testCtx.Ctx, minttypes.ModuleName, tm.EVMSigner.AccountAddress, amounts); err != nil { + panic(err) + } + + b, err := tc.TxEncoder()(tBuilder.GetTx()) + if err != nil { + panic(err) + } + txs = append(txs, b) + continue + } + err = tBuilder.SetSignatures(signing.SignatureV2{ PubKey: priv.PubKey(), Data: &signing.SingleSignatureData{ @@ -202,16 +249,16 @@ func toTxBytes(testCtx *TestContext, msgs []sdk.Msg) [][]byte { } // RunWithOCC runs the given messages with OCC enabled, number of workers is configured via context -func RunWithOCC(testCtx *TestContext, msgs []sdk.Msg) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { +func RunWithOCC(testCtx *TestContext, msgs []*TestMessage) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { return runTxs(testCtx, msgs, true) } // RunWithoutOCC runs the given messages without OCC enabled -func RunWithoutOCC(testCtx *TestContext, msgs []sdk.Msg) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { +func RunWithoutOCC(testCtx *TestContext, msgs []*TestMessage) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { return runTxs(testCtx, msgs, false) } -func runTxs(testCtx *TestContext, msgs []sdk.Msg, occ bool) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { +func runTxs(testCtx *TestContext, msgs []*TestMessage, occ bool) ([]types.Event, []*types.ExecTxResult, types.ResponseEndBlock, error) { app.EnableOCC = occ txs := toTxBytes(testCtx, msgs) req := &types.RequestFinalizeBlock{ @@ -222,16 +269,16 @@ func runTxs(testCtx *TestContext, msgs []sdk.Msg, occ bool) ([]types.Event, []*t return testCtx.TestApp.ProcessBlock(testCtx.Ctx, txs, req, req.DecidedLastCommit) } -func JoinMsgs(msgsList ...[]sdk.Msg) []sdk.Msg { - var result []sdk.Msg - for _, msgs := range msgsList { - result = append(result, msgs...) +func JoinMsgs(msgsList ...[]*TestMessage) []*TestMessage { + var result []*TestMessage + for _, testMsg := range msgsList { + result = append(result, testMsg...) } return result } -func Shuffle(msgs []sdk.Msg) []sdk.Msg { - result := make([]sdk.Msg, 0, len(msgs)) +func Shuffle(msgs []*TestMessage) []*TestMessage { + result := make([]*TestMessage, 0, len(msgs)) for _, i := range rand.Perm(len(msgs)) { result = append(result, msgs[i]) } diff --git a/precompiles/addr/Addr.sol b/precompiles/addr/Addr.sol new file mode 100644 index 0000000000..d479747daf --- /dev/null +++ b/precompiles/addr/Addr.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant ADDR_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001004; + +IAddr constant ADDR_CONTRACT = IAddr( + ADDR_PRECOMPILE_ADDRESS +); + +interface IAddr { + // Queries + function getSeiAddr(address addr) external view returns (string memory response); + function getEvmAddr(string memory addr) external view returns (address response); +} diff --git a/precompiles/addr/abi.json b/precompiles/addr/abi.json new file mode 100755 index 0000000000..b9a6de2907 --- /dev/null +++ b/precompiles/addr/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"addr","type":"string"}],"name":"getEvmAddr","outputs":[{"internalType":"address","name":"response","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getSeiAddr","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/addr/addr.go b/precompiles/addr/addr.go new file mode 100644 index 0000000000..aff5b06c77 --- /dev/null +++ b/precompiles/addr/addr.go @@ -0,0 +1,145 @@ +package addr + +import ( + "bytes" + "embed" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" +) + +const ( + GetSeiAddressMethod = "getSeiAddr" + GetEvmAddressMethod = "getEvmAddr" +) + +const ( + AddrAddress = "0x0000000000000000000000000000000000001004" +) + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +type Precompile struct { + pcommon.Precompile + evmKeeper pcommon.EVMKeeper + address common.Address + + GetSeiAddressID []byte + GetEvmAddressID []byte +} + +func NewPrecompile(evmKeeper pcommon.EVMKeeper) (*Precompile, error) { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + return nil, fmt.Errorf("error loading the staking ABI %s", err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + return nil, err + } + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + evmKeeper: evmKeeper, + address: common.HexToAddress(AddrAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case GetSeiAddressMethod: + p.GetSeiAddressID = m.ID + case GetEvmAddressMethod: + p.GetEvmAddressID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } + + method, err := p.ABI.MethodById(methodID) + if err != nil { + // This should never happen since this method is going to fail during Run + return pcommon.UnknownMethodCallGas + } + + return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, err + } + + switch method.Name { + case GetSeiAddressMethod: + return p.getSeiAddr(ctx, method, args, value) + case GetEvmAddressMethod: + return p.getEvmAddr(ctx, method, args, value) + } + return +} + +func (p Precompile) getSeiAddr(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + + seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, args[0].(common.Address)) + if !found { + return nil, fmt.Errorf("EVM address %s is not associated", args[0].(common.Address).Hex()) + } + return method.Outputs.Pack(seiAddr.String()) +} + +func (p Precompile) getEvmAddr(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + + seiAddr, err := sdk.AccAddressFromBech32(args[0].(string)) + if err != nil { + return nil, err + } + + evmAddr, found := p.evmKeeper.GetEVMAddress(ctx, seiAddr) + if !found { + return nil, fmt.Errorf("sei address %s is not associated", args[0].(string)) + } + return method.Outputs.Pack(evmAddr) +} + +func (Precompile) IsTransaction(string) bool { + return false +} diff --git a/precompiles/bank/Bank.sol b/precompiles/bank/Bank.sol new file mode 100644 index 0000000000..e57a083efe --- /dev/null +++ b/precompiles/bank/Bank.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant BANK_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001001; + +IBank constant BANK_CONTRACT = IBank( + BANK_PRECOMPILE_ADDRESS +); + +interface IBank { + // Transactions + function send( + address fromAddress, + address toAddress, + string memory denom, + uint256 amount + ) external returns (bool success); + + function sendNative( + string memory toNativeAddress + ) payable external returns (bool success); + + // Queries + function balance( + address acc, + string memory denom + ) external view returns (uint256 amount); + + struct Coin { + uint256 amount; + string denom; + } + + function all_balances( + address acc + ) external view returns (Coin[] memory response); + + function name( + string memory denom + ) external view returns (string memory response); + + function symbol( + string memory denom + ) external view returns (string memory response); + + function decimals( + string memory denom + ) external view returns (uint8 response); + + function supply( + string memory denom + ) external view returns (uint256 response); +} diff --git a/precompiles/bank/abi.json b/precompiles/bank/abi.json new file mode 100644 index 0000000000..844ac48943 --- /dev/null +++ b/precompiles/bank/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"acc","type":"address"}],"name":"all_balances","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"denom","type":"string"}],"internalType":"struct IBank.Coin[]","name":"response","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"acc","type":"address"},{"internalType":"string","name":"denom","type":"string"}],"name":"balance","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"decimals","outputs":[{"internalType":"uint8","name":"response","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"name","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromAddress","type":"address"},{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"string","name":"denom","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"send","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"toNativeAddress","type":"string"}],"name":"sendNative","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"supply","outputs":[{"internalType":"uint256","name":"response","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"denom","type":"string"}],"name":"symbol","outputs":[{"internalType":"string","name":"response","type":"string"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go new file mode 100644 index 0000000000..c31b7e2f0f --- /dev/null +++ b/precompiles/bank/bank.go @@ -0,0 +1,370 @@ +package bank + +import ( + "bytes" + "embed" + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/utils" + "github.com/tendermint/tendermint/libs/log" +) + +const ( + SendMethod = "send" + SendNativeMethod = "sendNative" + BalanceMethod = "balance" + AllBalancesMethod = "all_balances" + NameMethod = "name" + SymbolMethod = "symbol" + DecimalsMethod = "decimals" + SupplyMethod = "supply" +) + +const ( + BankAddress = "0x0000000000000000000000000000000000001001" +) + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +func GetABI() abi.ABI { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + panic(err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + panic(err) + } + return newAbi +} + +type Precompile struct { + pcommon.Precompile + bankKeeper pcommon.BankKeeper + evmKeeper pcommon.EVMKeeper + address common.Address + + SendID []byte + SendNativeID []byte + BalanceID []byte + AllBalancesID []byte + NameID []byte + SymbolID []byte + DecimalsID []byte + SupplyID []byte +} + +type CoinBalance struct { + Amount *big.Int + Denom string +} + +func NewPrecompile(bankKeeper pcommon.BankKeeper, evmKeeper pcommon.EVMKeeper) (*Precompile, error) { + newAbi := GetABI() + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + bankKeeper: bankKeeper, + evmKeeper: evmKeeper, + address: common.HexToAddress(BankAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case SendMethod: + p.SendID = m.ID + case SendNativeMethod: + p.SendNativeID = m.ID + case BalanceMethod: + p.BalanceID = m.ID + case AllBalancesMethod: + p.AllBalancesID = m.ID + case NameMethod: + p.NameID = m.ID + case SymbolMethod: + p.SymbolID = m.ID + case DecimalsMethod: + p.DecimalsID = m.ID + case SupplyMethod: + p.SupplyID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } + + method, err := p.ABI.MethodById(methodID) + if err != nil { + // This should never happen since this method is going to fail during Run + return pcommon.UnknownMethodCallGas + } + + return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, err + } + + switch method.Name { + case SendMethod: + return p.send(ctx, caller, method, args, value, readOnly) + case SendNativeMethod: + return p.sendNative(ctx, method, args, caller, callingContract, value, readOnly) + case BalanceMethod: + return p.balance(ctx, method, args, value) + case AllBalancesMethod: + return p.all_balances(ctx, method, args, value) + case NameMethod: + return p.name(ctx, method, args, value) + case SymbolMethod: + return p.symbol(ctx, method, args, value) + case DecimalsMethod: + return p.decimals(ctx, method, args, value) + case SupplyMethod: + return p.totalSupply(ctx, method, args, value) + } + return +} + +func (p Precompile) send(ctx sdk.Context, caller common.Address, method *abi.Method, args []interface{}, value *big.Int, readOnly bool) ([]byte, error) { + if readOnly { + return nil, errors.New("cannot call send from staticcall") + } + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 4); err != nil { + return nil, err + } + denom := args[2].(string) + if denom == "" { + return nil, errors.New("invalid denom") + } + pointer, _, exists := p.evmKeeper.GetERC20NativePointer(ctx, denom) + if !exists || pointer.Cmp(caller) != 0 { + return nil, fmt.Errorf("only pointer %s can send %s but got %s", pointer.Hex(), denom, caller.Hex()) + } + amount := args[3].(*big.Int) + if amount.Cmp(utils.Big0) == 0 { + // short circuit + return method.Outputs.Pack(true) + } + // TODO: it's possible to extend evm module's balance to handle non-usei tokens as well + senderSeiAddr, err := p.accAddressFromArg(ctx, args[0]) + if err != nil { + return nil, err + } + receiverSeiAddr, err := p.accAddressFromArg(ctx, args[1]) + if err != nil { + return nil, err + } + + if err := p.bankKeeper.SendCoins(ctx, senderSeiAddr, receiverSeiAddr, sdk.NewCoins(sdk.NewCoin(denom, sdk.NewIntFromBigInt(amount)))); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} + +func (p Precompile) sendNative(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address, callingContract common.Address, value *big.Int, readOnly bool) ([]byte, error) { + if readOnly { + return nil, errors.New("cannot call sendNative from staticcall") + } + if caller.Cmp(callingContract) != 0 { + return nil, errors.New("cannot delegatecall sendNative") + } + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + if value == nil || value.Sign() == 0 { + return nil, errors.New("set `value` field to non-zero to send") + } + + senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) + if !ok { + return nil, errors.New("invalid addr") + } + + receiverAddr, ok := (args[0]).(string) + if !ok || receiverAddr == "" { + return nil, errors.New("invalid addr") + } + + receiverSeiAddr, err := sdk.AccAddressFromBech32(receiverAddr) + if err != nil { + return nil, err + } + + usei, wei, err := pcommon.HandlePaymentUseiWei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), senderSeiAddr, value, p.bankKeeper) + if err != nil { + return nil, err + } + + if err := p.bankKeeper.SendCoinsAndWei(ctx, senderSeiAddr, receiverSeiAddr, usei, wei); err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} + +func (p Precompile) balance(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } + + addr, err := p.accAddressFromArg(ctx, args[0]) + if err != nil { + return nil, err + } + denom := args[1].(string) + if denom == "" { + return nil, errors.New("invalid denom") + } + + return method.Outputs.Pack(p.bankKeeper.GetBalance(ctx, addr, denom).Amount.BigInt()) +} + +func (p Precompile) all_balances(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + + addr, err := p.accAddressFromArg(ctx, args[0]) + if err != nil { + return nil, err + } + + coins := p.bankKeeper.GetAllBalances(ctx, addr) + + // convert to coin balance structs + coinBalances := make([]CoinBalance, 0, len(coins)) + + for _, coin := range coins { + coinBalances = append(coinBalances, CoinBalance{ + Amount: coin.Amount.BigInt(), + Denom: coin.Denom, + }) + } + + return method.Outputs.Pack(coinBalances) +} + +func (p Precompile) name(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + + denom := args[0].(string) + metadata, found := p.bankKeeper.GetDenomMetaData(ctx, denom) + if !found { + return nil, fmt.Errorf("denom %s not found", denom) + } + return method.Outputs.Pack(metadata.Name) +} + +func (p Precompile) symbol(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + + denom := args[0].(string) + metadata, found := p.bankKeeper.GetDenomMetaData(ctx, denom) + if !found { + return nil, fmt.Errorf("denom %s not found", denom) + } + return method.Outputs.Pack(metadata.Symbol) +} + +func (p Precompile) decimals(_ sdk.Context, method *abi.Method, _ []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + // all native tokens are integer-based, returns decimals for microdenom (usei) + return method.Outputs.Pack(uint8(0)) +} + +func (p Precompile) totalSupply(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + + denom := args[0].(string) + coin := p.bankKeeper.GetSupply(ctx, denom) + return method.Outputs.Pack(coin.Amount.BigInt()) +} + +func (p Precompile) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { + addr := arg.(common.Address) + if addr == (common.Address{}) { + return nil, errors.New("invalid addr") + } + seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) + if !found { + return nil, fmt.Errorf("EVM address %s is not associated", addr.Hex()) + } + return seiAddr, nil +} + +func (Precompile) IsTransaction(method string) bool { + switch method { + case SendMethod: + return true + case SendNativeMethod: + return true + default: + return false + } +} + +func (p Precompile) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("precompile", "bank") +} diff --git a/precompiles/bank/bank_test.go b/precompiles/bank/bank_test.go new file mode 100644 index 0000000000..6e2e4b3282 --- /dev/null +++ b/precompiles/bank/bank_test.go @@ -0,0 +1,274 @@ +package bank_test + +import ( + "encoding/hex" + "fmt" + "math/big" + "strings" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/sei-protocol/sei-chain/precompiles/bank" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestRun(t *testing.T) { + testApp := testkeeper.EVMTestApp + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + k := &testApp.EvmKeeper + + // Setup sender addresses and environment + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + senderAddr, senderEVMAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, senderAddr, senderEVMAddr) + err := k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("ufoo", sdk.NewInt(10000000)))) + require.Nil(t, err) + err = k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, senderAddr, sdk.NewCoins(sdk.NewCoin("ufoo", sdk.NewInt(10000000)))) + require.Nil(t, err) + err = k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000)))) + require.Nil(t, err) + err = k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10000000)))) + require.Nil(t, err) + + // Setup receiving addresses + seiAddr, evmAddr := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, seiAddr, evmAddr) + p, err := bank.NewPrecompile(k.BankKeeper(), k) + require.Nil(t, err) + statedb := state.NewDBImpl(ctx, k, true) + evm := vm.EVM{ + StateDB: statedb, + TxContext: vm.TxContext{Origin: senderEVMAddr}, + } + + // Precompile send test + send, err := p.ABI.MethodById(p.SendID) + require.Nil(t, err) + args, err := send.Inputs.Pack(senderEVMAddr, evmAddr, "usei", big.NewInt(25)) + require.Nil(t, err) + _, err = p.Run(&evm, senderEVMAddr, senderEVMAddr, append(p.SendID, args...), nil, false) // should error because address is not whitelisted + require.NotNil(t, err) + + // Precompile sendNative test error + sendNative, err := p.ABI.MethodById(p.SendNativeID) + require.Nil(t, err) + seiAddrString := seiAddr.String() + argsNativeError, err := sendNative.Inputs.Pack(seiAddrString) + require.Nil(t, err) + // 0 amount disallowed + _, err = p.Run(&evm, senderEVMAddr, senderEVMAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(0), false) + require.NotNil(t, err) + argsNativeError, err = sendNative.Inputs.Pack("") + require.Nil(t, err) + _, err = p.Run(&evm, senderEVMAddr, senderEVMAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(100), false) + require.NotNil(t, err) + argsNativeError, err = sendNative.Inputs.Pack("invalidaddr") + require.Nil(t, err) + _, err = p.Run(&evm, senderEVMAddr, senderEVMAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(100), false) + require.NotNil(t, err) + argsNativeError, err = sendNative.Inputs.Pack(senderAddr.String()) + require.Nil(t, err) + _, err = p.Run(&evm, evmAddr, evmAddr, append(p.SendNativeID, argsNativeError...), big.NewInt(100), false) + require.NotNil(t, err) + + // Send native 10_000_000_000_100, split into 10 usei 100wei + // Test payable with eth LegacyTx + abi := bank.GetABI() + argsNative, err := abi.Pack(bank.SendNativeMethod, seiAddr.String()) + require.Nil(t, err) + require.Nil(t, err) + key, _ := crypto.HexToECDSA(testPrivHex) + addr := common.HexToAddress(bank.BankAddress) + txData := ethtypes.LegacyTx{ + GasPrice: big.NewInt(100000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(10_000_000_000_100), + Data: argsNative, + 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) + + // send the transaction + msgServer := keeper.NewMsgServerImpl(k) + ante.Preprocess(ctx, req) + ctx = ctx.WithEventManager(sdk.NewEventManager()) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + + evts := ctx.EventManager().ABCIEvents() + + for _, evt := range evts { + var lines []string + for _, attr := range evt.Attributes { + lines = append(lines, fmt.Sprintf("%s=%s", string(attr.Key), string(attr.Value))) + } + fmt.Printf("type=%s\t%s\n", evt.Type, strings.Join(lines, "\t")) + } + + var expectedEvts sdk.Events = []sdk.Event{ + // gas is sent from sender + banktypes.NewCoinSpentEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(2)))), + // sender sends coin to the receiver + banktypes.NewCoinSpentEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))), + banktypes.NewCoinReceivedEvent(seiAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))), + sdk.NewEvent( + banktypes.EventTypeTransfer, + sdk.NewAttribute(banktypes.AttributeKeyRecipient, seiAddr.String()), + sdk.NewAttribute(banktypes.AttributeKeySender, senderAddr.String()), + sdk.NewAttribute(sdk.AttributeKeyAmount, sdk.NewCoin("usei", sdk.NewInt(10)).String()), + ), + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(banktypes.AttributeKeySender, senderAddr.String()), + ), + // gas refund to the sender + banktypes.NewCoinReceivedEvent(senderAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1)))), + // tip is paid to the validator + banktypes.NewCoinReceivedEvent(sdk.MustAccAddressFromBech32("sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqqlve8dv"), sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(0)))), + } + + require.EqualValues(t, expectedEvts.ToABCIEvents(), evts) + + // Use precompile balance to verify sendNative usei amount succeeded + balance, err := p.ABI.MethodById(p.BalanceID) + require.Nil(t, err) + args, err = balance.Inputs.Pack(evmAddr, "usei") + require.Nil(t, err) + precompileRes, err := p.Run(&evm, common.Address{}, common.Address{}, append(p.BalanceID, args...), nil, false) + require.Nil(t, err) + is, err := balance.Outputs.Unpack(precompileRes) + require.Nil(t, err) + require.Equal(t, 1, len(is)) + require.Equal(t, big.NewInt(10), is[0].(*big.Int)) + weiBalance := k.BankKeeper().GetWeiBalance(ctx, seiAddr) + require.Equal(t, big.NewInt(100), weiBalance.BigInt()) + + // test get all balances + allBalances, err := p.ABI.MethodById(p.AllBalancesID) + require.Nil(t, err) + args, err = allBalances.Inputs.Pack(senderEVMAddr) + require.Nil(t, err) + precompileRes, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.AllBalancesID, args...), nil, false) + require.Nil(t, err) + balances, err := allBalances.Outputs.Unpack(precompileRes) + require.Nil(t, err) + require.Equal(t, 1, len(balances)) + parsedBalances := balances[0].([]struct { + Amount *big.Int `json:"amount"` + Denom string `json:"denom"` + }) + + require.Equal(t, 2, len(parsedBalances)) + require.Equal(t, bank.CoinBalance{ + Amount: big.NewInt(10000000), + Denom: "ufoo", + }, bank.CoinBalance(parsedBalances[0])) + require.Equal(t, bank.CoinBalance{ + Amount: big.NewInt(9999989), + Denom: "usei", + }, bank.CoinBalance(parsedBalances[1])) + + // Verify errors properly raised on bank balance calls with incorrect inputs + _, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.BalanceID, args[:1]...), nil, false) + require.NotNil(t, err) + args, err = balance.Inputs.Pack(evmAddr, "") + require.Nil(t, err) + _, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.BalanceID, args...), nil, false) + require.NotNil(t, err) + + // invalid input + _, err = p.Run(&evm, common.Address{}, common.Address{}, []byte{1, 2, 3, 4}, nil, false) + require.NotNil(t, err) +} + +func TestMetadata(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + k.BankKeeper().SetDenomMetaData(ctx, banktypes.Metadata{Name: "SEI", Symbol: "usei", Base: "usei"}) + p, err := bank.NewPrecompile(k.BankKeeper(), k) + require.Nil(t, err) + statedb := state.NewDBImpl(ctx, k, true) + evm := vm.EVM{ + StateDB: statedb, + } + name, err := p.ABI.MethodById(p.NameID) + require.Nil(t, err) + args, err := name.Inputs.Pack("usei") + require.Nil(t, err) + res, err := p.Run(&evm, common.Address{}, common.Address{}, append(p.NameID, args...), nil, false) + require.Nil(t, err) + outputs, err := name.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, "SEI", outputs[0]) + + symbol, err := p.ABI.MethodById(p.SymbolID) + require.Nil(t, err) + args, err = symbol.Inputs.Pack("usei") + require.Nil(t, err) + res, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.SymbolID, args...), nil, false) + require.Nil(t, err) + outputs, err = symbol.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, "usei", outputs[0]) + + decimal, err := p.ABI.MethodById(p.DecimalsID) + require.Nil(t, err) + args, err = decimal.Inputs.Pack("usei") + require.Nil(t, err) + res, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.DecimalsID, args...), nil, false) + require.Nil(t, err) + outputs, err = decimal.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, uint8(0), outputs[0]) + + supply, err := p.ABI.MethodById(p.SupplyID) + require.Nil(t, err) + args, err = supply.Inputs.Pack("usei") + require.Nil(t, err) + res, err = p.Run(&evm, common.Address{}, common.Address{}, append(p.SupplyID, args...), nil, false) + require.Nil(t, err) + outputs, err = supply.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, big.NewInt(10), outputs[0]) +} + +func TestRequiredGas(t *testing.T) { + k, _ := testkeeper.MockEVMKeeper() + p, err := bank.NewPrecompile(k.BankKeeper(), k) + require.Nil(t, err) + balanceRequiredGas := p.RequiredGas(p.BalanceID) + require.Equal(t, uint64(1000), balanceRequiredGas) + // invalid method + require.Equal(t, uint64(3000), p.RequiredGas([]byte{1, 1, 1, 1})) +} + +func TestAddress(t *testing.T) { + k, _ := testkeeper.MockEVMKeeper() + p, err := bank.NewPrecompile(k.BankKeeper(), k) + require.Nil(t, err) + require.Equal(t, common.HexToAddress(bank.BankAddress), p.Address()) +} diff --git a/precompiles/common/erc20_abi.json b/precompiles/common/erc20_abi.json new file mode 100644 index 0000000000..144952c1b4 --- /dev/null +++ b/precompiles/common/erc20_abi.json @@ -0,0 +1 @@ +[{"type":"constructor","inputs":[{"name":"denom_","type":"string","internalType":"string"},{"name":"name_","type":"string","internalType":"string"},{"name":"symbol_","type":"string","internalType":"string"},{"name":"decimals_","type":"uint8","internalType":"uint8"}],"stateMutability":"nonpayable"},{"type":"function","name":"BankPrecompile","inputs":[],"outputs":[{"name":"","type":"address","internalType":"contract IBank"}],"stateMutability":"view"},{"type":"function","name":"allowance","inputs":[{"name":"owner","type":"address","internalType":"address"},{"name":"spender","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"approve","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"balanceOf","inputs":[{"name":"account","type":"address","internalType":"address"}],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"ddecimals","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"decimals","inputs":[],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"denom","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"name","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"nname","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"ssymbol","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"symbol","inputs":[],"outputs":[{"name":"","type":"string","internalType":"string"}],"stateMutability":"view"},{"type":"function","name":"totalSupply","inputs":[],"outputs":[{"name":"","type":"uint256","internalType":"uint256"}],"stateMutability":"view"},{"type":"function","name":"transfer","inputs":[{"name":"to","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"function","name":"transferFrom","inputs":[{"name":"from","type":"address","internalType":"address"},{"name":"to","type":"address","internalType":"address"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"nonpayable"},{"type":"event","name":"Approval","inputs":[{"name":"owner","type":"address","indexed":true,"internalType":"address"},{"name":"spender","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"name":"from","type":"address","indexed":true,"internalType":"address"},{"name":"to","type":"address","indexed":true,"internalType":"address"},{"name":"value","type":"uint256","indexed":false,"internalType":"uint256"}],"anonymous":false},{"type":"error","name":"ERC20InsufficientAllowance","inputs":[{"name":"spender","type":"address","internalType":"address"},{"name":"allowance","type":"uint256","internalType":"uint256"},{"name":"needed","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ERC20InsufficientBalance","inputs":[{"name":"sender","type":"address","internalType":"address"},{"name":"balance","type":"uint256","internalType":"uint256"},{"name":"needed","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"ERC20InvalidApprover","inputs":[{"name":"approver","type":"address","internalType":"address"}]},{"type":"error","name":"ERC20InvalidReceiver","inputs":[{"name":"receiver","type":"address","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSender","inputs":[{"name":"sender","type":"address","internalType":"address"}]},{"type":"error","name":"ERC20InvalidSpender","inputs":[{"name":"spender","type":"address","internalType":"address"}]}] diff --git a/precompiles/common/expected_keepers.go b/precompiles/common/expected_keepers.go new file mode 100644 index 0000000000..3b85964315 --- /dev/null +++ b/precompiles/common/expected_keepers.go @@ -0,0 +1,81 @@ +package common + +import ( + "context" + + 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" + "github.com/ethereum/go-ethereum/common" + oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" +) + +type BankKeeper interface { + SendCoins(sdk.Context, sdk.AccAddress, sdk.AccAddress, sdk.Coins) error + SendCoinsAndWei(ctx sdk.Context, from sdk.AccAddress, to sdk.AccAddress, amt sdk.Int, wei sdk.Int) error + GetBalance(sdk.Context, sdk.AccAddress, string) sdk.Coin + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetWeiBalance(ctx sdk.Context, addr sdk.AccAddress) sdk.Int + GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool) + GetSupply(ctx sdk.Context, denom string) sdk.Coin +} + +type EVMKeeper interface { + GetSeiAddress(sdk.Context, common.Address) (sdk.AccAddress, bool) + GetSeiAddressOrDefault(ctx sdk.Context, evmAddress common.Address) sdk.AccAddress // only used for getting precompile Sei addresses + GetEVMAddress(sdk.Context, sdk.AccAddress) (common.Address, bool) + GetCodeHash(sdk.Context, common.Address) common.Hash + GetPriorityNormalizer(ctx sdk.Context) sdk.Dec + GetBaseDenom(ctx sdk.Context) string + SetERC20NativePointer(ctx sdk.Context, token string, addr common.Address) error + GetERC20NativePointer(ctx sdk.Context, token string) (addr common.Address, version uint16, exists bool) + SetERC20CW20Pointer(ctx sdk.Context, cw20Address string, addr common.Address) error + GetERC20CW20Pointer(ctx sdk.Context, cw20Address string) (addr common.Address, version uint16, exists bool) + SetERC721CW721Pointer(ctx sdk.Context, cw721Address string, addr common.Address) error + GetERC721CW721Pointer(ctx sdk.Context, cw721Address string) (addr common.Address, version uint16, exists bool) +} + +type OracleKeeper interface { + IterateBaseExchangeRates(ctx sdk.Context, handler func(denom string, exchangeRate oracletypes.OracleExchangeRate) (stop bool)) + CalculateTwaps(ctx sdk.Context, lookbackSeconds uint64) (oracletypes.OracleTwaps, error) +} + +type WasmdKeeper interface { + Instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins) (sdk.AccAddress, []byte, error) + Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error) +} + +type WasmdViewKeeper interface { + QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error) +} + +type StakingKeeper interface { + Delegate(goCtx context.Context, msg *stakingtypes.MsgDelegate) (*stakingtypes.MsgDelegateResponse, error) + BeginRedelegate(goCtx context.Context, msg *stakingtypes.MsgBeginRedelegate) (*stakingtypes.MsgBeginRedelegateResponse, error) + Undelegate(goCtx context.Context, msg *stakingtypes.MsgUndelegate) (*stakingtypes.MsgUndelegateResponse, error) +} + +type GovKeeper interface { + AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, options govtypes.WeightedVoteOptions) error + AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (bool, error) +} + +type DistributionKeeper interface { + SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error + WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) +} + +type TransferKeeper interface { + SendTransfer( + ctx sdk.Context, + sourcePort, + sourceChannel string, + token sdk.Coin, + sender sdk.AccAddress, + receiver string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + ) error +} diff --git a/precompiles/common/precompiles.go b/precompiles/common/precompiles.go new file mode 100644 index 0000000000..5a38be8d9a --- /dev/null +++ b/precompiles/common/precompiles.go @@ -0,0 +1,115 @@ +package common + +import ( + "errors" + "fmt" + "math/big" + + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/x/evm/state" +) + +const UnknownMethodCallGas uint64 = 3000 + +type Contexter interface { + Ctx() sdk.Context +} + +type Precompile struct { + abi.ABI +} + +func (p Precompile) RequiredGas(input []byte, isTransaction bool) uint64 { + argsBz := input[4:] // first four bytes are method ID + + if isTransaction { + return storetypes.KVGasConfig().WriteCostFlat + (storetypes.KVGasConfig().WriteCostPerByte * uint64(len(argsBz))) + } + + return storetypes.KVGasConfig().ReadCostFlat + (storetypes.KVGasConfig().ReadCostPerByte * uint64(len(argsBz))) +} + +func (p Precompile) Prepare(evm *vm.EVM, input []byte) (sdk.Context, *abi.Method, []interface{}, error) { + ctxer, ok := evm.StateDB.(Contexter) + if !ok { + return sdk.Context{}, nil, nil, errors.New("cannot get context from EVM") + } + methodID, err := ExtractMethodID(input) + if err != nil { + return sdk.Context{}, nil, nil, err + } + method, err := p.ABI.MethodById(methodID) + if err != nil { + return sdk.Context{}, nil, nil, err + } + + argsBz := input[4:] + args, err := method.Inputs.Unpack(argsBz) + if err != nil { + return sdk.Context{}, nil, nil, err + } + + return ctxer.Ctx(), method, args, nil +} + +func ValidateArgsLength(args []interface{}, length int) error { + if len(args) != length { + return fmt.Errorf("expected %d arguments but got %d", length, len(args)) + } + + return nil +} + +func ValidateNonPayable(value *big.Int) error { + if value != nil && value.Sign() != 0 { + return errors.New("sending funds to a non-payable function") + } + + return nil +} + +func HandlePaymentUsei(ctx sdk.Context, precompileAddr sdk.AccAddress, payer sdk.AccAddress, value *big.Int, bankKeeper BankKeeper) (sdk.Coin, error) { + usei, wei := state.SplitUseiWeiAmount(value) + if !wei.IsZero() { + return sdk.Coin{}, fmt.Errorf("selected precompile function does not allow payment with non-zero wei remainder: received %s", value) + } + coin := sdk.NewCoin(sdk.MustGetBaseDenom(), usei) + // refund payer because the following precompile logic will debit the payments from payer's account + // this creates a new event manager to avoid surfacing these as cosmos events + if err := bankKeeper.SendCoins(ctx.WithEventManager(sdk.NewEventManager()), precompileAddr, payer, sdk.NewCoins(coin)); err != nil { + return sdk.Coin{}, err + } + return coin, nil +} + +func HandlePaymentUseiWei(ctx sdk.Context, precompileAddr sdk.AccAddress, payer sdk.AccAddress, value *big.Int, bankKeeper BankKeeper) (sdk.Int, sdk.Int, error) { + usei, wei := state.SplitUseiWeiAmount(value) + // refund payer because the following precompile logic will debit the payments from payer's account + // this creates a new event manager to avoid surfacing these as cosmos events + if err := bankKeeper.SendCoinsAndWei(ctx.WithEventManager(sdk.NewEventManager()), precompileAddr, payer, usei, wei); err != nil { + return sdk.Int{}, sdk.Int{}, err + } + return usei, wei, nil +} + +/* +* +sei gas = evm gas * multiplier +sei gas price = fee / sei gas = fee / (evm gas * multiplier) = evm gas / multiplier +*/ +func GetRemainingGas(ctx sdk.Context, evmKeeper EVMKeeper) uint64 { + gasMultipler := evmKeeper.GetPriorityNormalizer(ctx) + seiGasRemaining := ctx.GasMeter().Limit() - ctx.GasMeter().GasConsumedToLimit() + return sdk.NewDecFromInt(sdk.NewIntFromUint64(seiGasRemaining)).Quo(gasMultipler).TruncateInt().Uint64() +} + +func ExtractMethodID(input []byte) ([]byte, error) { + // Check if the input has at least the length needed for methodID + if len(input) < 4 { + return nil, errors.New("input too short to extract method ID") + } + return input[:4], nil +} diff --git a/precompiles/common/precompiles_test.go b/precompiles/common/precompiles_test.go new file mode 100644 index 0000000000..5880397143 --- /dev/null +++ b/precompiles/common/precompiles_test.go @@ -0,0 +1,27 @@ +package common_test + +import ( + "math/big" + "testing" + + "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/stretchr/testify/require" +) + +func TestValidateArgsLength(t *testing.T) { + err := common.ValidateArgsLength(nil, 0) + require.Nil(t, err) + err = common.ValidateArgsLength([]interface{}{1, ""}, 2) + require.Nil(t, err) + err = common.ValidateArgsLength([]interface{}{""}, 2) + require.NotNil(t, err) +} + +func TestValidteNonPayable(t *testing.T) { + err := common.ValidateNonPayable(nil) + require.Nil(t, err) + err = common.ValidateNonPayable(big.NewInt(0)) + require.Nil(t, err) + err = common.ValidateNonPayable(big.NewInt(1)) + require.NotNil(t, err) +} diff --git a/precompiles/distribution/Distribution.sol b/precompiles/distribution/Distribution.sol new file mode 100644 index 0000000000..6c3217c5b7 --- /dev/null +++ b/precompiles/distribution/Distribution.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant DISTR_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001007; + +IDistr constant DISTR_CONTRACT = IDistr( + DISTR_PRECOMPILE_ADDRESS +); + +interface IDistr { + // Transactions + function setWithdrawAddress(address withdrawAddr) external returns (bool success); + + function withdrawDelegationRewards(string memory validator) external returns (bool success); +} \ No newline at end of file diff --git a/precompiles/distribution/abi.json b/precompiles/distribution/abi.json new file mode 100755 index 0000000000..23b0abd2df --- /dev/null +++ b/precompiles/distribution/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"address","name":"withdrawAddr","type":"address"}],"name":"setWithdrawAddress","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"validator","type":"string"}],"name":"withdrawDelegationRewards","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/precompiles/distribution/distribution.go b/precompiles/distribution/distribution.go new file mode 100644 index 0000000000..33dfb35338 --- /dev/null +++ b/precompiles/distribution/distribution.go @@ -0,0 +1,176 @@ +package distribution + +import ( + "bytes" + "embed" + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" +) + +const ( + SetWithdrawAddressMethod = "setWithdrawAddress" + WithdrawDelegationRewardsMethod = "withdrawDelegationRewards" +) + +const ( + DistrAddress = "0x0000000000000000000000000000000000001007" +) + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +func GetABI() abi.ABI { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + panic(err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + panic(err) + } + return newAbi +} + +type Precompile struct { + pcommon.Precompile + distrKeeper pcommon.DistributionKeeper + evmKeeper pcommon.EVMKeeper + address common.Address + + SetWithdrawAddrID []byte + WithdrawDelegationRewardsID []byte +} + +func NewPrecompile(distrKeeper pcommon.DistributionKeeper, evmKeeper pcommon.EVMKeeper) (*Precompile, error) { + newAbi := GetABI() + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + distrKeeper: distrKeeper, + evmKeeper: evmKeeper, + address: common.HexToAddress(DistrAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case SetWithdrawAddressMethod: + p.SetWithdrawAddrID = m.ID + case WithdrawDelegationRewardsMethod: + p.WithdrawDelegationRewardsID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } + + if bytes.Equal(methodID, p.SetWithdrawAddrID) { + return 30000 + } else if bytes.Equal(methodID, p.WithdrawDelegationRewardsID) { + return 50000 + } + + // This should never happen since this is going to fail during Run + return pcommon.UnknownMethodCallGas +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + if readOnly { + return nil, errors.New("cannot call distr precompile from staticcall") + } + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, err + } + if caller.Cmp(callingContract) != 0 { + return nil, errors.New("cannot delegatecall distr") + } + + switch method.Name { + case SetWithdrawAddressMethod: + return p.setWithdrawAddress(ctx, method, caller, args, value) + case WithdrawDelegationRewardsMethod: + return p.withdrawDelegationRewards(ctx, method, caller, args, value) + } + return +} + +func (p Precompile) setWithdrawAddress(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + delegator, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + return nil, fmt.Errorf("delegator %s is not associated", caller.Hex()) + } + withdrawAddr, err := p.accAddressFromArg(ctx, args[0]) + if err != nil { + return nil, err + } + err = p.distrKeeper.SetWithdrawAddr(ctx, delegator, withdrawAddr) + if err != nil { + return nil, err + } + return method.Outputs.Pack(true) +} + +func (p Precompile) withdrawDelegationRewards(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + delegator, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + return nil, fmt.Errorf("delegator %s is not associated", caller.Hex()) + } + validator, err := sdk.ValAddressFromBech32(args[0].(string)) + if err != nil { + return nil, err + } + _, err = p.distrKeeper.WithdrawDelegationRewards(ctx, delegator, validator) + if err != nil { + return nil, err + } + return method.Outputs.Pack(true) +} + +func (p Precompile) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { + addr := arg.(common.Address) + if addr == (common.Address{}) { + return nil, errors.New("invalid addr") + } + seiAddr, associated := p.evmKeeper.GetSeiAddress(ctx, addr) + if !associated { + return nil, errors.New("cannot use an unassociated address as withdraw address") + } + return seiAddr, nil +} diff --git a/precompiles/distribution/distribution_test.go b/precompiles/distribution/distribution_test.go new file mode 100644 index 0000000000..1790961250 --- /dev/null +++ b/precompiles/distribution/distribution_test.go @@ -0,0 +1,178 @@ +package distribution_test + +import ( + "encoding/hex" + "math/big" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + crptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking/teststaking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "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/app" + "github.com/sei-protocol/sei-chain/precompiles/distribution" + "github.com/sei-protocol/sei-chain/precompiles/staking" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + minttypes "github.com/sei-protocol/sei-chain/x/mint/types" + "github.com/stretchr/testify/require" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestWithdraw(t *testing.T) { + testApp := testkeeper.EVMTestApp + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + distrParams := testApp.DistrKeeper.GetParams(ctx) + distrParams.WithdrawAddrEnabled = true + testApp.DistrKeeper.SetParams(ctx, distrParams) + k := &testApp.EvmKeeper + valPub1 := secp256k1.GenPrivKey().PubKey() + val := setupValidator(t, ctx, testApp, stakingtypes.Unbonded, valPub1) + + // delegate + abi := staking.GetABI() + args, err := abi.Pack("delegate", val.String()) + require.Nil(t, err) + + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + addr := common.HexToAddress(staking.StakingAddress) + txData := ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(100_000_000_000_000), + Data: args, + Nonce: 0, + } + chainID := k.ChainID(ctx) + chainCfg := evmtypes.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 := evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) + require.Nil(t, k.BankKeeper().MintCoins(ctx, evmtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, evmtypes.ModuleName, seiAddr, amt)) + + msgServer := keeper.NewMsgServerImpl(k) + + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + + d, found := testApp.StakingKeeper.GetDelegation(ctx, seiAddr, val) + require.True(t, found) + require.Equal(t, int64(100), d.Shares.RoundInt().Int64()) + + // set withdraw addr + withdrawSeiAddr, withdrawAddr := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, withdrawSeiAddr, withdrawAddr) + abi = distribution.GetABI() + args, err = abi.Pack("setWithdrawAddress", withdrawAddr) + require.Nil(t, err) + addr = common.HexToAddress(distribution.DistrAddress) + txData = ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(0), + Data: args, + 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 = evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + ante.Preprocess(ctx, req) + res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + require.Equal(t, withdrawSeiAddr.String(), testApp.DistrKeeper.GetDelegatorWithdrawAddr(ctx, seiAddr).String()) + + // withdraw + args, err = abi.Pack("withdrawDelegationRewards", val.String()) + require.Nil(t, err) + txData = ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(0), + Data: args, + Nonce: 2, + } + tx, err = ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + txwrapper, err = ethtx.NewLegacyTx(tx) + require.Nil(t, err) + req, err = evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + ante.Preprocess(ctx, req) + res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + + // reinitialized + d, found = testApp.StakingKeeper.GetDelegation(ctx, seiAddr, val) + require.True(t, found) +} + +func setupValidator(t *testing.T, ctx sdk.Context, a *app.App, bondStatus stakingtypes.BondStatus, valPub crptotypes.PubKey) sdk.ValAddress { + valAddr := sdk.ValAddress(valPub.Address()) + bondDenom := a.StakingKeeper.GetParams(ctx).BondDenom + selfBond := sdk.NewCoins(sdk.Coin{Amount: sdk.NewInt(100), Denom: bondDenom}) + + err := a.BankKeeper.MintCoins(ctx, minttypes.ModuleName, selfBond) + require.NoError(t, err) + + err = a.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, sdk.AccAddress(valAddr), selfBond) + require.NoError(t, err) + + sh := teststaking.NewHelper(t, ctx, a.StakingKeeper) + msg := sh.CreateValidatorMsg(valAddr, valPub, selfBond[0].Amount) + sh.Handle(msg, true) + + val, found := a.StakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + + val = val.UpdateStatus(bondStatus) + a.StakingKeeper.SetValidator(ctx, val) + + consAddr, err := val.GetConsAddr() + require.NoError(t, err) + + signingInfo := slashingtypes.NewValidatorSigningInfo( + consAddr, + ctx.BlockHeight(), + 0, + time.Unix(0, 0), + false, + 0, + ) + a.SlashingKeeper.SetValidatorSigningInfo(ctx, consAddr, signingInfo) + + return valAddr +} diff --git a/precompiles/gov/Gov.sol b/precompiles/gov/Gov.sol new file mode 100644 index 0000000000..e311731f22 --- /dev/null +++ b/precompiles/gov/Gov.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant GOV_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001006; + +IGov constant GOV_CONTRACT = IGov( + GOV_PRECOMPILE_ADDRESS +); + +interface IGov { + // Transactions + function vote( + uint64 proposalID, + int32 option + ) external returns (bool success); + + function deposit( + uint64 proposalID + ) payable external returns (bool success); +} \ No newline at end of file diff --git a/precompiles/gov/abi.json b/precompiles/gov/abi.json new file mode 100755 index 0000000000..c74f5397c5 --- /dev/null +++ b/precompiles/gov/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"uint64","name":"proposalID","type":"uint64"}],"name":"deposit","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"proposalID","type":"uint64"},{"internalType":"int32","name":"option","type":"int32"}],"name":"vote","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/precompiles/gov/gov.go b/precompiles/gov/gov.go new file mode 100644 index 0000000000..e80f6f4f4c --- /dev/null +++ b/precompiles/gov/gov.go @@ -0,0 +1,165 @@ +package gov + +import ( + "bytes" + "embed" + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" +) + +const ( + VoteMethod = "vote" + DepositMethod = "deposit" +) + +const ( + GovAddress = "0x0000000000000000000000000000000000001006" +) + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +func GetABI() abi.ABI { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + panic(err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + panic(err) + } + return newAbi +} + +type Precompile struct { + pcommon.Precompile + govKeeper pcommon.GovKeeper + evmKeeper pcommon.EVMKeeper + bankKeeper pcommon.BankKeeper + address common.Address + + VoteID []byte + DepositID []byte +} + +func NewPrecompile(govKeeper pcommon.GovKeeper, evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper) (*Precompile, error) { + newAbi := GetABI() + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + govKeeper: govKeeper, + evmKeeper: evmKeeper, + address: common.HexToAddress(GovAddress), + bankKeeper: bankKeeper, + } + + for name, m := range newAbi.Methods { + switch name { + case VoteMethod: + p.VoteID = m.ID + case DepositMethod: + p.DepositID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } + + if bytes.Equal(methodID, p.VoteID) { + return 30000 + } else if bytes.Equal(methodID, p.DepositID) { + return 30000 + } + + // This should never happen since this is going to fail during Run + return pcommon.UnknownMethodCallGas +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + if readOnly { + return nil, errors.New("cannot call gov precompile from staticcall") + } + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, err + } + if caller.Cmp(callingContract) != 0 { + return nil, errors.New("cannot delegatecall gov") + } + + switch method.Name { + case VoteMethod: + return p.vote(ctx, method, caller, args, value) + case DepositMethod: + return p.deposit(ctx, method, caller, args, value) + } + return +} + +func (p Precompile) vote(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } + voter, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + return nil, fmt.Errorf("voter %s is not associated", caller.Hex()) + } + proposalID := args[0].(uint64) + voteOption := args[1].(int32) + err := p.govKeeper.AddVote(ctx, proposalID, voter, govtypes.NewNonSplitVoteOption(govtypes.VoteOption(voteOption))) + if err != nil { + return nil, err + } + return method.Outputs.Pack(true) +} + +func (p Precompile) deposit(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + depositor, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + return nil, fmt.Errorf("depositor %s is not associated", caller.Hex()) + } + proposalID := args[0].(uint64) + if value == nil || value.Sign() == 0 { + return nil, errors.New("set `value` field to non-zero to deposit fund") + } + coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), depositor, value, p.bankKeeper) + if err != nil { + return nil, err + } + res, err := p.govKeeper.AddDeposit(ctx, proposalID, depositor, sdk.NewCoins(coin)) + if err != nil { + return nil, err + } + return method.Outputs.Pack(res) +} diff --git a/precompiles/gov/gov_test.go b/precompiles/gov/gov_test.go new file mode 100644 index 0000000000..9e77c36afd --- /dev/null +++ b/precompiles/gov/gov_test.go @@ -0,0 +1,124 @@ +package gov_test + +import ( + "encoding/hex" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/sei-protocol/sei-chain/precompiles/gov" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestVoteDeposit(t *testing.T) { + testApp := testkeeper.EVMTestApp + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + content := govtypes.ContentFromProposalType("title", "description", govtypes.ProposalTypeText, false) + proposal, err := testApp.GovKeeper.SubmitProposal(ctx, content) + require.Nil(t, err) + k := &testApp.EvmKeeper + abi := gov.GetABI() + + // deposit + args, err := abi.Pack("deposit", proposal.ProposalId) + require.Nil(t, err) + + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + addr := common.HexToAddress(gov.GovAddress) + txData := ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: new(big.Int).Mul(big.NewInt(10000000), big.NewInt(1_000_000_000_000)), + Data: args, + Nonce: 0, + } + chainID := k.ChainID(ctx) + chainCfg := evmtypes.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 := evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) + require.Nil(t, k.BankKeeper().MintCoins(ctx, evmtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, evmtypes.ModuleName, seiAddr, amt)) + + msgServer := keeper.NewMsgServerImpl(k) + + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + + proposal, _ = testApp.GovKeeper.GetProposal(ctx, proposal.ProposalId) + require.Equal(t, govtypes.StatusVotingPeriod, proposal.Status) + + // vote + for _, opt := range []govtypes.VoteOption{govtypes.OptionYes, govtypes.OptionNo, govtypes.OptionAbstain} { + args, err := abi.Pack("vote", proposal.ProposalId, opt) + require.Nil(t, err) + + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + addr := common.HexToAddress(gov.GovAddress) + txData := ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(0), + Data: args, + Nonce: 0, + } + chainID := k.ChainID(ctx) + chainCfg := evmtypes.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 := evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) + require.Nil(t, k.BankKeeper().MintCoins(ctx, evmtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, evmtypes.ModuleName, seiAddr, amt)) + + msgServer := keeper.NewMsgServerImpl(k) + + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + + v, found := testApp.GovKeeper.GetVote(ctx, proposal.ProposalId, seiAddr) + require.True(t, found) + require.Equal(t, 1, len(v.Options)) + require.Equal(t, opt, v.Options[0].Option) + require.Equal(t, sdk.OneDec(), v.Options[0].Weight) + } +} diff --git a/precompiles/ibc/IBC.sol b/precompiles/ibc/IBC.sol new file mode 100644 index 0000000000..649d3a3b60 --- /dev/null +++ b/precompiles/ibc/IBC.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant IBC_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001009; + +IBC constant IBC_CONTRACT = IBC( + IBC_PRECOMPILE_ADDRESS +); + +interface IBC { + // Transactions + function transfer( + string toAddress, + string memory port, + string memory channel, + string memory denom, + uint256 amount, + uint64 revisionNumber, + uint64 revisionHeight, + uint64 timeoutTimestamp + ) external returns (bool success); +} diff --git a/precompiles/ibc/abi.json b/precompiles/ibc/abi.json new file mode 100644 index 0000000000..a1ff1e9fc2 --- /dev/null +++ b/precompiles/ibc/abi.json @@ -0,0 +1,56 @@ +[ + { + "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" + } +] diff --git a/precompiles/ibc/ibc.go b/precompiles/ibc/ibc.go new file mode 100644 index 0000000000..51f17b04bd --- /dev/null +++ b/precompiles/ibc/ibc.go @@ -0,0 +1,264 @@ +package ibc + +import ( + "bytes" + "embed" + "errors" + "fmt" + "math/big" + + "github.com/cosmos/cosmos-sdk/types/bech32" + + "github.com/sei-protocol/sei-chain/utils" + + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" +) + +const ( + TransferMethod = "transfer" +) + +const ( + IBCAddress = "0x0000000000000000000000000000000000001009" +) + +var _ vm.PrecompiledContract = &Precompile{} +var _ vm.DynamicGasPrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +func GetABI() abi.ABI { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + panic(err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + panic(err) + } + return newAbi +} + +type Precompile struct { + pcommon.Precompile + address common.Address + transferKeeper pcommon.TransferKeeper + evmKeeper pcommon.EVMKeeper + + TransferID []byte +} + +func NewPrecompile(transferKeeper pcommon.TransferKeeper, evmKeeper pcommon.EVMKeeper) (*Precompile, error) { + newAbi := GetABI() + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + address: common.HexToAddress(IBCAddress), + transferKeeper: transferKeeper, + evmKeeper: evmKeeper, + } + + for name, m := range newAbi.Methods { + switch name { + case TransferMethod: + p.TransferID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } + + method, err := p.ABI.MethodById(methodID) + if err != nil { + // This should never happen since this method is going to fail during Run + return pcommon.UnknownMethodCallGas + } + + return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) +} + +func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, _ *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if readOnly { + return nil, 0, errors.New("cannot call IBC precompile from staticcall") + } + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, 0, err + } + if caller.Cmp(callingContract) != 0 { + return nil, 0, errors.New("cannot delegatecall IBC") + } + + gasMultiplier := p.evmKeeper.GetPriorityNormalizer(ctx) + gasLimitBigInt := new(big.Int).Mul(new(big.Int).SetUint64(suppliedGas), gasMultiplier.TruncateInt().BigInt()) + if gasLimitBigInt.Cmp(utils.BigMaxU64) > 0 { + gasLimitBigInt = utils.BigMaxU64 + } + ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimitBigInt.Uint64())) + + switch method.Name { + case TransferMethod: + return p.transfer(ctx, method, args, caller) + } + return +} + +func (p Precompile) Run(*vm.EVM, common.Address, common.Address, []byte, *big.Int, bool) (bz []byte, err error) { + panic("static gas Run is not implemented for dynamic gas precompile") +} + +func (p Precompile) transfer(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, 8); err != nil { + rerr = err + return + } + senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) + if !ok { + rerr = errors.New("caller is not a valid SEI address") + return + } + + receiverAddressString, ok := args[0].(string) + if !ok { + rerr = errors.New("receiverAddress is not a string") + return + } + _, bz, err := bech32.DecodeAndConvert(receiverAddressString) + if err != nil { + rerr = err + return + } + err = sdk.VerifyAddressFormat(bz) + if err != nil { + rerr = err + return + } + + port, ok := args[1].(string) + if !ok { + rerr = errors.New("port is not a string") + return + } + if port == "" { + rerr = errors.New("port cannot be empty") + return + } + + channelID, ok := args[2].(string) + if !ok { + rerr = errors.New("channelID is not a string") + return + } + if channelID == "" { + rerr = errors.New("channelID cannot be empty") + return + } + + denom := args[3].(string) + if denom == "" { + rerr = errors.New("invalid denom") + return + } + + amount, ok := args[4].(*big.Int) + if !ok { + rerr = errors.New("amount is not a big.Int") + return + } + + if amount.Cmp(big.NewInt(0)) == 0 { + // short circuit + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) + ret, rerr = method.Outputs.Pack(true) + return + } + + coin := sdk.Coin{ + Denom: denom, + Amount: sdk.NewIntFromBigInt(amount), + } + + revisionNumber, ok := args[5].(uint64) + if !ok { + rerr = errors.New("revisionNumber is not a uint64") + return + } + + revisionHeight, ok := args[6].(uint64) + if !ok { + rerr = errors.New("revisionHeight is not a uint64") + return + } + + height := clienttypes.Height{ + RevisionNumber: revisionNumber, + RevisionHeight: revisionHeight, + } + + timeoutTimestamp, ok := args[7].(uint64) + if !ok { + rerr = errors.New("timeoutTimestamp is not a uint64") + return + } + + err = p.transferKeeper.SendTransfer(ctx, port, channelID, coin, senderSeiAddr, receiverAddressString, height, timeoutTimestamp) + + if err != nil { + rerr = err + return + } + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) + ret, rerr = method.Outputs.Pack(true) + return +} + +func (Precompile) IsTransaction(method string) bool { + switch method { + case TransferMethod: + return true + default: + return false + } +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { + addr := arg.(common.Address) + if addr == (common.Address{}) { + return nil, errors.New("invalid addr") + } + seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) + if !found { + return nil, fmt.Errorf("EVM address %s is not associated", addr.Hex()) + } + return seiAddr, nil +} diff --git a/precompiles/ibc/ibc_test.go b/precompiles/ibc/ibc_test.go new file mode 100644 index 0000000000..12579cc99c --- /dev/null +++ b/precompiles/ibc/ibc_test.go @@ -0,0 +1,243 @@ +package ibc_test + +import ( + "errors" + "math/big" + "reflect" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/precompiles/ibc" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +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 +} + +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 TestPrecompile_Run(t *testing.T) { + senderSeiAddress, senderEvmAddress := testkeeper.MockAddressPair() + receiverAddress := "cosmos1yykwxjzr2tv4mhx5tsf8090sdg96f2ax8fydk2" + + pre, _ := ibc.NewPrecompile(nil, nil) + testTransfer, _ := pre.ABI.MethodById(pre.TransferID) + packedTrue, _ := testTransfer.Outputs.Pack(true) + + type fields struct { + transferKeeper pcommon.TransferKeeper + } + + type input struct { + receiverAddr string + sourcePort string + sourceChannel string + denom string + amount *big.Int + revisionNumber uint64 + revisionHeight uint64 + timeoutTimestamp uint64 + } + 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), + revisionNumber: 1, + revisionHeight: 1, + timeoutTimestamp: 1, + }, + suppliedGas: uint64(1000000), + value: nil, + } + + tests := []struct { + name string + fields fields + args args + wantBz []byte + wantRemainingGas uint64 + wantErr bool + wantErrMsg string + }{ + { + name: "successful transfer: with amount > 0 between EVM addresses", + fields: fields{transferKeeper: &MockTransferKeeper{}}, + args: commonArgs, + wantBz: packedTrue, + wantRemainingGas: 992974, + wantErr: false, + }, + { + name: "failed transfer: internal error", + fields: fields{transferKeeper: &MockFailedTransferTransferKeeper{}}, + args: commonArgs, + wantBz: nil, + wantErr: true, + wantErrMsg: "failed to send transfer", + }, + { + 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), + revisionNumber: 1, + revisionHeight: 1, + timeoutTimestamp: 1, + }, + 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), + revisionNumber: 1, + revisionHeight: 1, + timeoutTimestamp: 1, + }, + 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), + revisionNumber: 1, + revisionHeight: 1, + timeoutTimestamp: 1, + }, + 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), + revisionNumber: 1, + revisionHeight: 1, + timeoutTimestamp: 1, + }, + 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) + 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) + 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 { + 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) + } + }) + } +} diff --git a/precompiles/json/Json.sol b/precompiles/json/Json.sol new file mode 100644 index 0000000000..18a7c2b433 --- /dev/null +++ b/precompiles/json/Json.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant JSON_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001003; + +IJson constant JSON_CONTRACT = IJson( + JSON_PRECOMPILE_ADDRESS +); + +interface IJson { + // Queries + function extractAsBytes(bytes memory input, string memory key) external view returns (bytes memory response); + + function extractAsBytesList(bytes memory input, string memory key) external view returns (bytes[] memory response); + + function extractAsUint256(bytes memory input, string memory key) external view returns (uint256 response); +} diff --git a/precompiles/json/abi.json b/precompiles/json/abi.json new file mode 100644 index 0000000000..0170dd5a9d --- /dev/null +++ b/precompiles/json/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"bytes","name":"input","type":"bytes"},{"internalType":"string","name":"key","type":"string"}],"name":"extractAsBytes","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"input","type":"bytes"},{"internalType":"string","name":"key","type":"string"}],"name":"extractAsBytesList","outputs":[{"internalType":"bytes[]","name":"response","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"input","type":"bytes"},{"internalType":"string","name":"key","type":"string"}],"name":"extractAsUint256","outputs":[{"internalType":"uint256","name":"response","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/json/json.go b/precompiles/json/json.go new file mode 100644 index 0000000000..3712bc292b --- /dev/null +++ b/precompiles/json/json.go @@ -0,0 +1,207 @@ +package json + +import ( + "bytes" + "embed" + gjson "encoding/json" + "errors" + "fmt" + "math/big" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/utils" +) + +const ( + ExtractAsBytesMethod = "extractAsBytes" + ExtractAsBytesListMethod = "extractAsBytesList" + ExtractAsUint256Method = "extractAsUint256" +) + +const JSONAddress = "0x0000000000000000000000000000000000001003" +const GasCostPerByte = 100 // TODO: parameterize + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +type Precompile struct { + pcommon.Precompile + address common.Address + + ExtractAsBytesID []byte + ExtractAsBytesListID []byte + ExtractAsUint256ID []byte +} + +func NewPrecompile() (*Precompile, error) { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + return nil, fmt.Errorf("error loading the staking ABI %s", err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + return nil, err + } + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + address: common.HexToAddress(JSONAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case ExtractAsBytesMethod: + p.ExtractAsBytesID = m.ID + case ExtractAsBytesListMethod: + p.ExtractAsBytesListID = m.ID + case ExtractAsUint256Method: + p.ExtractAsUint256ID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + if len(input) < 4 { + return pcommon.UnknownMethodCallGas + } + return uint64(GasCostPerByte * (len(input) - 4)) +} + +func (Precompile) IsTransaction(string) bool { + return false +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, err + } + + switch method.Name { + case ExtractAsBytesMethod: + return p.extractAsBytes(ctx, method, args, value) + case ExtractAsBytesListMethod: + return p.extractAsBytesList(ctx, method, args, value) + case ExtractAsUint256Method: + byteArr := make([]byte, 32) + uint_, err := p.ExtractAsUint256(ctx, method, args, value) + if err != nil { + return nil, err + } + + if uint_.BitLen() > 256 { + return nil, errors.New("value does not fit in 32 bytes") + } + + uint_.FillBytes(byteArr) + return byteArr, nil + } + return +} + +func (p Precompile) extractAsBytes(_ sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } + + // type assertion will always succeed because it's already validated in p.Prepare call in Run() + bz := args[0].([]byte) + decoded := map[string]gjson.RawMessage{} + if err := gjson.Unmarshal(bz, &decoded); err != nil { + return nil, err + } + key := args[1].(string) + result, ok := decoded[key] + if !ok { + return nil, fmt.Errorf("input does not contain key %s", key) + } + // in the case of a string value, remove the quotes + if len(result) >= 2 && result[0] == '"' && result[len(result)-1] == '"' { + result = result[1 : len(result)-1] + } + + return method.Outputs.Pack([]byte(result)) +} + +func (p Precompile) extractAsBytesList(_ sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } + + // type assertion will always succeed because it's already validated in p.Prepare call in Run() + bz := args[0].([]byte) + decoded := map[string]gjson.RawMessage{} + if err := gjson.Unmarshal(bz, &decoded); err != nil { + return nil, err + } + key := args[1].(string) + result, ok := decoded[key] + if !ok { + return nil, fmt.Errorf("input does not contain key %s", key) + } + decodedResult := []gjson.RawMessage{} + if err := gjson.Unmarshal(result, &decodedResult); err != nil { + return nil, err + } + + return method.Outputs.Pack(utils.Map(decodedResult, func(r gjson.RawMessage) []byte { return []byte(r) })) +} + +func (p Precompile) ExtractAsUint256(_ sdk.Context, _ *abi.Method, args []interface{}, value *big.Int) (*big.Int, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } + + // type assertion will always succeed because it's already validated in p.Prepare call in Run() + bz := args[0].([]byte) + decoded := map[string]gjson.RawMessage{} + if err := gjson.Unmarshal(bz, &decoded); err != nil { + return nil, err + } + key := args[1].(string) + result, ok := decoded[key] + if !ok { + return nil, fmt.Errorf("input does not contain key %s", key) + } + + // Assuming result is your byte slice + // Convert byte slice to string and trim quotation marks + strValue := strings.Trim(string(result), "\"") + + // Convert the string to big.Int + value, success := new(big.Int).SetString(strValue, 10) + if !success { + return nil, fmt.Errorf("failed to convert %s to big.Int", strValue) + } + + return value, nil +} diff --git a/precompiles/json/json_test.go b/precompiles/json/json_test.go new file mode 100644 index 0000000000..f4688e416f --- /dev/null +++ b/precompiles/json/json_test.go @@ -0,0 +1,123 @@ +package json_test + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/precompiles/json" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" +) + +func TestExtractAsBytes(t *testing.T) { + stateDB := &state.DBImpl{} + stateDB.WithCtx(sdk.Context{}) + evm := &vm.EVM{StateDB: stateDB} + p, err := json.NewPrecompile() + require.Nil(t, err) + method, err := p.MethodById(p.ExtractAsBytesID) + require.Nil(t, err) + for _, test := range []struct { + body []byte + expectedOutput []byte + }{ + { + []byte("{\"key\":1}"), + []byte("1"), + }, { + []byte("{\"key\":\"1\"}"), + []byte("1"), + }, { + []byte("{\"key\":[1,2,3]}"), + []byte("[1,2,3]"), + }, { + []byte("{\"key\":{\"nested\":1}}"), + []byte("{\"nested\":1}"), + }, + } { + args, err := method.Inputs.Pack(test.body, "key") + require.Nil(t, err) + input := append(p.ExtractAsBytesID, args...) + res, err := p.Run(evm, common.Address{}, common.Address{}, input, nil, true) + require.Nil(t, err) + output, err := method.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 1, len(output)) + require.Equal(t, output[0].([]byte), test.expectedOutput) + } +} + +func TestExtractAsBytesList(t *testing.T) { + stateDB := &state.DBImpl{} + stateDB.WithCtx(sdk.Context{}) + evm := &vm.EVM{StateDB: stateDB} + p, err := json.NewPrecompile() + require.Nil(t, err) + method, err := p.MethodById(p.ExtractAsBytesListID) + require.Nil(t, err) + for _, test := range []struct { + body []byte + expectedOutput [][]byte + }{ + { + []byte("{\"key\":[],\"key2\":1}"), + [][]byte{}, + }, { + []byte("{\"key\":[1,2,3],\"key2\":1}"), + [][]byte{[]byte("1"), []byte("2"), []byte("3")}, + }, { + []byte("{\"key\":[\"1\", \"2\"],\"key2\":1}"), + [][]byte{[]byte("\"1\""), []byte("\"2\"")}, + }, { + []byte("{\"key\":[{\"nested\":1}, {\"nested\":2}],\"key2\":1}"), + [][]byte{[]byte("{\"nested\":1}"), []byte("{\"nested\":2}")}, + }, + } { + args, err := method.Inputs.Pack(test.body, "key") + require.Nil(t, err) + input := append(p.ExtractAsBytesListID, args...) + res, err := p.Run(evm, common.Address{}, common.Address{}, input, nil, true) + require.Nil(t, err) + output, err := method.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 1, len(output)) + require.Equal(t, output[0].([][]byte), test.expectedOutput) + } +} + +func TestExtractAsUint256(t *testing.T) { + stateDB := &state.DBImpl{} + stateDB.WithCtx(sdk.Context{}) + evm := &vm.EVM{StateDB: stateDB} + p, err := json.NewPrecompile() + require.Nil(t, err) + method, err := p.MethodById(p.ExtractAsUint256ID) + require.Nil(t, err) + n := new(big.Int) + n.SetString("12345678901234567890", 10) + for _, test := range []struct { + body []byte + expectedOutput *big.Int + }{ + { + []byte("{\"key\":\"12345678901234567890\"}"), + n, + }, { + []byte("{\"key\":\"0\"}"), + big.NewInt(0), + }, + } { + args, err := method.Inputs.Pack(test.body, "key") + require.Nil(t, err) + input := append(p.ExtractAsUint256ID, args...) + res, err := p.Run(evm, common.Address{}, common.Address{}, input, nil, true) + require.Nil(t, err) + output, err := method.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 1, len(output)) + require.Equal(t, 0, output[0].(*big.Int).Cmp(test.expectedOutput)) + } +} diff --git a/precompiles/oracle/Oracle.sol b/precompiles/oracle/Oracle.sol new file mode 100644 index 0000000000..5de419d194 --- /dev/null +++ b/precompiles/oracle/Oracle.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant ORACLE_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001008; + +IOracle constant ORACLE_CONTRACT = IOracle(ORACLE_PRECOMPILE_ADDRESS); + +interface IOracle { + // Queries + function getExchangeRates() external view returns (DenomOracleExchangeRatePair[] memory); + function getOracleTwaps(uint64 lookback_seconds) external view returns (OracleTwap[] memory); + + // Structs + struct OracleExchangeRate { + string exchangeRate; + string lastUpdate; + int64 lastUpdateTimestamp; + } + + struct DenomOracleExchangeRatePair { + string denom; + OracleExchangeRate oracleExchangeRateVal; + } + + struct OracleTwap { + string denom; + string twap; + int64 lookbackSeconds; + } +} diff --git a/precompiles/oracle/abi.json b/precompiles/oracle/abi.json new file mode 100644 index 0000000000..1bb91d96aa --- /dev/null +++ b/precompiles/oracle/abi.json @@ -0,0 +1 @@ +[{"inputs":[],"name":"getExchangeRates","outputs":[{"components":[{"internalType":"string","name":"denom","type":"string"},{"components":[{"internalType":"string","name":"exchangeRate","type":"string"},{"internalType":"string","name":"lastUpdate","type":"string"},{"internalType":"int64","name":"lastUpdateTimestamp","type":"int64"}],"internalType":"struct IOracle.OracleExchangeRate","name":"oracleExchangeRateVal","type":"tuple"}],"internalType":"struct IOracle.DenomOracleExchangeRatePair[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"lookback_seconds","type":"uint64"}],"name":"getOracleTwaps","outputs":[{"components":[{"internalType":"string","name":"denom","type":"string"},{"internalType":"string","name":"twap","type":"string"},{"internalType":"int64","name":"lookbackSeconds","type":"int64"}],"internalType":"struct IOracle.OracleTwap[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/oracle/oracle.go b/precompiles/oracle/oracle.go new file mode 100644 index 0000000000..06f1dd60ad --- /dev/null +++ b/precompiles/oracle/oracle.go @@ -0,0 +1,171 @@ +package oracle + +import ( + "bytes" + "embed" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/x/oracle/types" +) + +const ( + GetExchangeRatesMethod = "getExchangeRates" + GetOracleTwapsMethod = "getOracleTwaps" +) + +const ( + OracleAddress = "0x0000000000000000000000000000000000001008" +) + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +func GetABI() abi.ABI { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + panic(err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + panic(err) + } + return newAbi +} + +type Precompile struct { + pcommon.Precompile + evmKeeper pcommon.EVMKeeper + oracleKeeper pcommon.OracleKeeper + address common.Address + + GetExchangeRatesId []byte + GetOracleTwapsId []byte +} + +// Define types which deviate slightly from cosmos types (ExchangeRate string vs sdk.Dec) +type OracleExchangeRate struct { + ExchangeRate string `json:"exchangeRate"` + LastUpdate string `json:"lastUpdate"` + LastUpdateTimestamp int64 `json:"lastUpdateTimestamp"` +} + +type DenomOracleExchangeRatePair struct { + Denom string `json:"denom"` + OracleExchangeRateVal OracleExchangeRate `json:"oracleExchangeRateVal"` +} + +type OracleTwap struct { + Denom string `json:"denom"` + Twap string `json:"twap"` + LookbackSeconds int64 `json:"lookbackSeconds"` +} + +func NewPrecompile(oracleKeeper pcommon.OracleKeeper, evmKeeper pcommon.EVMKeeper) (*Precompile, error) { + newAbi := GetABI() + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + evmKeeper: evmKeeper, + address: common.HexToAddress(OracleAddress), + oracleKeeper: oracleKeeper, + } + + for name, m := range newAbi.Methods { + switch name { + case GetExchangeRatesMethod: + p.GetExchangeRatesId = m.ID + case GetOracleTwapsMethod: + p.GetOracleTwapsId = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } + + method, err := p.ABI.MethodById(methodID) + if err != nil { + // This should never happen since this method is going to fail during Run + return pcommon.UnknownMethodCallGas + } + + return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, err + } + + switch method.Name { + case GetExchangeRatesMethod: + return p.getExchangeRates(ctx, method, args, value) + case GetOracleTwapsMethod: + return p.getOracleTwaps(ctx, method, args, value) + } + return +} + +func (p Precompile) getExchangeRates(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 0); err != nil { + return nil, err + } + exchangeRates := []DenomOracleExchangeRatePair{} + p.oracleKeeper.IterateBaseExchangeRates(ctx, func(denom string, rate types.OracleExchangeRate) (stop bool) { + exchangeRates = append(exchangeRates, DenomOracleExchangeRatePair{Denom: denom, OracleExchangeRateVal: OracleExchangeRate{ExchangeRate: rate.ExchangeRate.String(), LastUpdate: rate.LastUpdate.String(), LastUpdateTimestamp: rate.LastUpdateTimestamp}}) + return false + }) + + return method.Outputs.Pack(exchangeRates) +} + +func (p Precompile) getOracleTwaps(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + lookbackSeconds := args[0].(uint64) + twaps, err := p.oracleKeeper.CalculateTwaps(ctx, lookbackSeconds) + if err != nil { + return nil, err + } + // Convert twap to string + oracleTwaps := make([]OracleTwap, 0, len(twaps)) + for _, twap := range twaps { + oracleTwaps = append(oracleTwaps, OracleTwap{Denom: twap.Denom, Twap: twap.Twap.String(), LookbackSeconds: twap.LookbackSeconds}) + } + return method.Outputs.Pack(oracleTwaps) +} + +func (Precompile) IsTransaction(string) bool { + return false +} diff --git a/precompiles/oracle/oracle_test.go b/precompiles/oracle/oracle_test.go new file mode 100644 index 0000000000..5b86bc2b6e --- /dev/null +++ b/precompiles/oracle/oracle_test.go @@ -0,0 +1,134 @@ +package oracle_test + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/precompiles/oracle" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/oracle/types" + "github.com/sei-protocol/sei-chain/x/oracle/utils" + "github.com/stretchr/testify/require" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestGetExchangeRate(t *testing.T) { + testApp := testkeeper.EVMTestApp + rate := sdk.NewDec(1700) + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + testApp.OracleKeeper.SetBaseExchangeRate(ctx, utils.MicroAtomDenom, rate) + k := &testApp.EvmKeeper + + // Setup sender addresses and environment + privKey := testkeeper.MockPrivateKey() + senderAddr, senderEVMAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, senderAddr, senderEVMAddr) + statedb := state.NewDBImpl(ctx, k, true) + evm := vm.EVM{ + StateDB: statedb, + TxContext: vm.TxContext{Origin: senderEVMAddr}, + } + + p, err := oracle.NewPrecompile(testApp.OracleKeeper, k) + require.Nil(t, err) + + query, err := p.ABI.MethodById(p.GetExchangeRatesId) + require.Nil(t, err) + precompileRes, err := p.Run(&evm, common.Address{}, common.Address{}, p.GetExchangeRatesId, nil, true) + require.Nil(t, err) + exchangeRates, err := query.Outputs.Unpack(precompileRes) + require.Nil(t, err) + require.Equal(t, 1, len(exchangeRates)) + + // TODO: Use type assertion for nested struct + require.Equal(t, []struct { + Denom string `json:"denom"` + OracleExchangeRateVal struct { + ExchangeRate string `json:"exchangeRate"` + LastUpdate string `json:"lastUpdate"` + LastUpdateTimestamp int64 `json:"lastUpdateTimestamp"` + } `json:"oracleExchangeRateVal"` + }{ + { + Denom: "uatom", + OracleExchangeRateVal: struct { + ExchangeRate string `json:"exchangeRate"` + LastUpdate string `json:"lastUpdate"` + LastUpdateTimestamp int64 `json:"lastUpdateTimestamp"` + }{ + ExchangeRate: "1700.000000000000000000", + LastUpdate: "2", + LastUpdateTimestamp: -62135596800000, + }, + }, + }, exchangeRates[0]) +} + +func TestGetOracleTwaps(t *testing.T) { + testApp := testkeeper.EVMTestApp + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockTime(time.Unix(5400, 0)) + + priceSnapshots := types.PriceSnapshots{ + types.NewPriceSnapshot(types.PriceSnapshotItems{ + types.NewPriceSnapshotItem(utils.MicroEthDenom, types.OracleExchangeRate{ + ExchangeRate: sdk.NewDec(10), + LastUpdate: sdk.NewInt(3600), + }), + }, 3600), + types.NewPriceSnapshot(types.PriceSnapshotItems{ + types.NewPriceSnapshotItem(utils.MicroEthDenom, types.OracleExchangeRate{ + ExchangeRate: sdk.NewDec(20), + LastUpdate: sdk.NewInt(4500), + }), + }, 4500), + } + for _, snap := range priceSnapshots { + testApp.OracleKeeper.SetPriceSnapshot(ctx, snap) + } + + k := &testApp.EvmKeeper + defaults := types.DefaultParams() + testApp.OracleKeeper.SetParams(ctx, defaults) + for _, denom := range defaults.Whitelist { + testApp.OracleKeeper.SetVoteTarget(ctx, denom.Name) + } + + // Setup sender addresses and environment + privKey := testkeeper.MockPrivateKey() + senderAddr, senderEVMAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, senderAddr, senderEVMAddr) + statedb := state.NewDBImpl(ctx, k, true) + evm := vm.EVM{ + StateDB: statedb, + TxContext: vm.TxContext{Origin: senderEVMAddr}, + } + + p, err := oracle.NewPrecompile(testApp.OracleKeeper, k) + require.Nil(t, err) + + query, err := p.ABI.MethodById(p.GetOracleTwapsId) + require.Nil(t, err) + args, err := query.Inputs.Pack(uint64(3600)) + require.Nil(t, err) + precompileRes, err := p.Run(&evm, common.Address{}, common.Address{}, append(p.GetOracleTwapsId, args...), nil, true) + require.Nil(t, err) + twap, err := query.Outputs.Unpack(precompileRes) + require.Nil(t, err) + require.Equal(t, 1, len(twap)) + + require.Equal(t, []struct { + Denom string `json:"denom"` + Twap string `json:"twap"` + LookbackSeconds int64 `json:"lookbackSeconds"` + }{ + { + Denom: "ueth", + Twap: "15.000000000000000000", + LookbackSeconds: 1800, + }, + }, twap[0]) +} diff --git a/precompiles/pointer/Pointer.sol b/precompiles/pointer/Pointer.sol new file mode 100644 index 0000000000..d85893949c --- /dev/null +++ b/precompiles/pointer/Pointer.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant POINTER_PRECOMPILE_ADDRESS = 0x000000000000000000000000000000000000100b; + +IPointer constant POINTER_CONTRACT = IPointer(POINTER_PRECOMPILE_ADDRESS); + +interface IPointer { + function addNativePointer( + string memory token + ) payable external returns (address ret); + + function addCW20Pointer( + string memory cwAddr + ) payable external returns (address ret); + + function addCW721Pointer( + string memory cwAddr + ) payable external returns (address ret); +} diff --git a/precompiles/pointer/abi.json b/precompiles/pointer/abi.json new file mode 100644 index 0000000000..8fb8238da0 --- /dev/null +++ b/precompiles/pointer/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"cwAddr","type":"string"}],"name":"addCW20Pointer","outputs":[{"internalType":"address","name":"ret","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"cwAddr","type":"string"}],"name":"addCW721Pointer","outputs":[{"internalType":"address","name":"ret","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"token","type":"string"}],"name":"addNativePointer","outputs":[{"internalType":"address","name":"ret","type":"address"}],"stateMutability":"payable","type":"function"}] \ No newline at end of file diff --git a/precompiles/pointer/pointer.go b/precompiles/pointer/pointer.go new file mode 100644 index 0000000000..8fb594b848 --- /dev/null +++ b/precompiles/pointer/pointer.go @@ -0,0 +1,279 @@ +package pointer + +import ( + "bytes" + "embed" + "encoding/json" + "errors" + "fmt" + "math" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethabi "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +const ( + AddNativePointer = "addNativePointer" + AddCW20Pointer = "addCW20Pointer" + AddCW721Pointer = "addCW721Pointer" +) + +const PointerAddress = "0x000000000000000000000000000000000000100b" + +var _ vm.PrecompiledContract = &Precompile{} +var _ vm.DynamicGasPrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +type Precompile struct { + pcommon.Precompile + evmKeeper pcommon.EVMKeeper + bankKeeper pcommon.BankKeeper + wasmdKeeper pcommon.WasmdViewKeeper + address common.Address + + AddNativePointerID []byte + AddCW20PointerID []byte + AddCW721PointerID []byte +} + +func NewPrecompile(evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper, wasmdKeeper pcommon.WasmdViewKeeper) (*Precompile, error) { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + return nil, fmt.Errorf("error loading the pointer ABI %s", err) + } + + newAbi, err := ethabi.JSON(bytes.NewReader(abiBz)) + if err != nil { + return nil, err + } + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + evmKeeper: evmKeeper, + bankKeeper: bankKeeper, + wasmdKeeper: wasmdKeeper, + address: common.HexToAddress(PointerAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case AddNativePointer: + p.AddNativePointerID = m.ID + case AddCW20Pointer: + p.AddCW20PointerID = m.ID + case AddCW721Pointer: + p.AddCW721PointerID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + // gas is calculated dynamically + return pcommon.UnknownMethodCallGas +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, _ *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { + if readOnly { + return nil, 0, errors.New("cannot call pointer precompile from staticcall") + } + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, 0, err + } + if caller.Cmp(callingContract) != 0 { + return nil, 0, errors.New("cannot delegatecall pointer") + } + + switch method.Name { + case AddNativePointer: + return p.AddNative(ctx, method, caller, args, value, evm, suppliedGas) + case AddCW20Pointer: + return p.AddCW20(ctx, method, caller, args, value, evm, suppliedGas) + case AddCW721Pointer: + return p.AddCW721(ctx, method, caller, args, value, evm, suppliedGas) + default: + err = fmt.Errorf("unknown method %s", method.Name) + } + return +} + +func (p Precompile) Run(*vm.EVM, common.Address, common.Address, []byte, *big.Int, bool) ([]byte, error) { + panic("static gas Run is not implemented for dynamic gas precompile") +} + +func (p Precompile) AddNative(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, 0, err + } + token := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC20NativePointer(ctx, token) + if exists && existingVersion >= native.CurrentVersion { + return nil, 0, fmt.Errorf("pointer at %s with version %d exists when trying to set pointer for version %d", existingAddr.Hex(), existingVersion, native.CurrentVersion) + } + metadata, metadataExists := p.bankKeeper.GetDenomMetaData(ctx, token) + if !metadataExists { + return nil, 0, fmt.Errorf("denom %s does not have metadata stored and thus can only have its pointer set through gov proposal", token) + } + name := metadata.Name + symbol := metadata.Symbol + var decimals uint8 + for _, denomUnit := range metadata.DenomUnits { + if denomUnit.Exponent > uint32(decimals) && denomUnit.Exponent <= math.MaxUint8 { + decimals = uint8(denomUnit.Exponent) + name = denomUnit.Denom + symbol = denomUnit.Denom + if len(denomUnit.Aliases) > 0 { + name = denomUnit.Aliases[0] + } + } + } + constructorArguments := []interface{}{ + token, name, symbol, decimals, + } + + packedArgs, err := native.GetParsedABI().Pack("", constructorArguments...) + if err != nil { + panic(err) + } + bin := append(native.GetBin(), packedArgs...) + if value == nil { + value = utils.Big0 + } + ret, contractAddr, remainingGas, err := evm.Create(vm.AccountRef(caller), bin, suppliedGas, value) + if err != nil { + return + } + err = p.evmKeeper.SetERC20NativePointer(ctx, token, contractAddr) + if err != nil { + return + } + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "native"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, contractAddr.Hex()), sdk.NewAttribute(types.AttributeKeyPointee, token), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", native.CurrentVersion)))) + ret, err = method.Outputs.Pack(contractAddr) + return +} + +func (p Precompile) AddCW20(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, 0, err + } + cwAddr := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC20CW20Pointer(ctx, cwAddr) + if exists && existingVersion >= cw20.CurrentVersion { + return nil, 0, fmt.Errorf("pointer at %s with version %d exists when trying to set pointer for version %d", existingAddr.Hex(), existingVersion, cw20.CurrentVersion) + } + cwAddress, err := sdk.AccAddressFromBech32(cwAddr) + if err != nil { + return nil, 0, err + } + res, err := p.wasmdKeeper.QuerySmart(ctx, cwAddress, []byte("{\"token_info\":{}}")) + if err != nil { + return nil, 0, err + } + formattedRes := map[string]interface{}{} + if err := json.Unmarshal(res, &formattedRes); err != nil { + return nil, 0, err + } + name := formattedRes["name"].(string) + symbol := formattedRes["symbol"].(string) + constructorArguments := []interface{}{ + cwAddr, name, symbol, + } + + packedArgs, err := cw20.GetParsedABI().Pack("", constructorArguments...) + if err != nil { + panic(err) + } + bin := append(cw20.GetBin(), packedArgs...) + if value == nil { + value = utils.Big0 + } + ret, contractAddr, remainingGas, err := evm.Create(vm.AccountRef(caller), bin, suppliedGas, value) + if err != nil { + return + } + err = p.evmKeeper.SetERC20CW20Pointer(ctx, cwAddr, contractAddr) + if err != nil { + return + } + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "cw20"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, contractAddr.Hex()), sdk.NewAttribute(types.AttributeKeyPointee, cwAddr), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", cw20.CurrentVersion)))) + ret, err = method.Outputs.Pack(contractAddr) + return +} + +func (p Precompile) AddCW721(ctx sdk.Context, method *ethabi.Method, caller common.Address, args []interface{}, value *big.Int, evm *vm.EVM, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, 0, err + } + cwAddr := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC721CW721Pointer(ctx, cwAddr) + if exists && existingVersion >= cw721.CurrentVersion { + return nil, 0, fmt.Errorf("pointer at %s with version %d exists when trying to set pointer for version %d", existingAddr.Hex(), existingVersion, cw721.CurrentVersion) + } + cwAddress, err := sdk.AccAddressFromBech32(cwAddr) + if err != nil { + return nil, 0, err + } + res, err := p.wasmdKeeper.QuerySmart(ctx, cwAddress, []byte("{\"contract_info\":{}}")) + if err != nil { + return nil, 0, err + } + formattedRes := map[string]interface{}{} + if err := json.Unmarshal(res, &formattedRes); err != nil { + return nil, 0, err + } + name := formattedRes["name"].(string) + symbol := formattedRes["symbol"].(string) + constructorArguments := []interface{}{ + cwAddr, name, symbol, + } + + packedArgs, err := cw721.GetParsedABI().Pack("", constructorArguments...) + if err != nil { + panic(err) + } + bin := append(cw721.GetBin(), packedArgs...) + if value == nil { + value = utils.Big0 + } + ret, contractAddr, remainingGas, err := evm.Create(vm.AccountRef(caller), bin, suppliedGas, value) + if err != nil { + return + } + err = p.evmKeeper.SetERC721CW721Pointer(ctx, cwAddr, contractAddr) + if err != nil { + return + } + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "cw721"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, contractAddr.Hex()), sdk.NewAttribute(types.AttributeKeyPointee, cwAddr), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", cw721.CurrentVersion)))) + ret, err = method.Outputs.Pack(contractAddr) + return +} diff --git a/precompiles/pointer/pointer_test.go b/precompiles/pointer/pointer_test.go new file mode 100644 index 0000000000..f621a66c39 --- /dev/null +++ b/precompiles/pointer/pointer_test.go @@ -0,0 +1,83 @@ +package pointer_test + +import ( + "testing" + "time" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/app" + "github.com/sei-protocol/sei-chain/precompiles/pointer" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestAddNative(t *testing.T) { + testApp := app.Setup(false, false) + p, err := pointer.NewPrecompile(&testApp.EvmKeeper, testApp.BankKeeper, testApp.WasmKeeper) + require.Nil(t, err) + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + _, caller := testkeeper.MockAddressPair() + suppliedGas := uint64(10000000) + cfg := types.DefaultChainConfig().EthereumConfig(testApp.EvmKeeper.ChainID(ctx)) + + // token has no metadata + m, err := p.ABI.MethodById(p.AddNativePointerID) + require.Nil(t, err) + args, err := m.Inputs.Pack("test") + require.Nil(t, err) + statedb := state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + blockCtx, _ := testApp.EvmKeeper.GetVMBlockContext(ctx, core.GasPool(suppliedGas)) + evm := vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, cfg, vm.Config{}) + _, g, err := p.RunAndCalculateGas(evm, caller, caller, append(p.AddNativePointerID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + _, _, exists := testApp.EvmKeeper.GetERC20NativePointer(statedb.Ctx(), "test") + require.False(t, exists) + + // token has metadata + testApp.BankKeeper.SetDenomMetaData(ctx, banktypes.Metadata{ + Base: "test", + Name: "base_name", + Symbol: "base_symbol", + DenomUnits: []*banktypes.DenomUnit{{ + Exponent: 6, + Denom: "denom", + Aliases: []string{"DENOM"}, + }}, + }) + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, cfg, vm.Config{}) + ret, g, err := p.RunAndCalculateGas(evm, caller, caller, append(p.AddNativePointerID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + require.Equal(t, uint64(8907806), g) + outputs, err := m.Outputs.Unpack(ret) + require.Nil(t, err) + addr := outputs[0].(common.Address) + pointerAddr, version, exists := testApp.EvmKeeper.GetERC20NativePointer(statedb.Ctx(), "test") + require.Equal(t, addr, pointerAddr) + require.Equal(t, native.CurrentVersion, version) + require.True(t, exists) + hasRegisteredEvent := false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + require.Equal(t, types.EventTypePointerRegistered, e.Type) + require.Equal(t, "native", string(e.Attributes[0].Value)) + } + require.True(t, hasRegisteredEvent) + + // pointer already exists + statedb = state.NewDBImpl(statedb.Ctx(), &testApp.EvmKeeper, true) + evm = vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, cfg, vm.Config{}) + _, g, err = p.RunAndCalculateGas(evm, caller, caller, append(p.AddNativePointerID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) +} diff --git a/precompiles/pointerview/Pointerview.sol b/precompiles/pointerview/Pointerview.sol new file mode 100644 index 0000000000..497c977fdc --- /dev/null +++ b/precompiles/pointerview/Pointerview.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant POINTERVIEW_PRECOMPILE_ADDRESS = 0x000000000000000000000000000000000000100A; + +IPointerview constant POINTERVIEW_CONTRACT = IPointerview(POINTERVIEW_PRECOMPILE_ADDRESS); + +interface IPointerview { + function getNativePointer( + string memory token + ) view external returns (address addr, uint16 version, bool exists); + + function getCW20Pointer( + string memory cwAddr + ) view external returns (address addr, uint16 version, bool exists); + + function getCW721Pointer( + string memory cwAddr + ) view external returns (address addr, uint16 version, bool exists); +} diff --git a/precompiles/pointerview/abi.json b/precompiles/pointerview/abi.json new file mode 100644 index 0000000000..a469eff127 --- /dev/null +++ b/precompiles/pointerview/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"cwAddr","type":"string"}],"name":"getCW20Pointer","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"cwAddr","type":"string"}],"name":"getCW721Pointer","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"token","type":"string"}],"name":"getNativePointer","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint16","name":"version","type":"uint16"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/pointerview/pointerview.go b/precompiles/pointerview/pointerview.go new file mode 100644 index 0000000000..acbc975616 --- /dev/null +++ b/precompiles/pointerview/pointerview.go @@ -0,0 +1,125 @@ +package pointerview + +import ( + "bytes" + "embed" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" +) + +const ( + GetNativePointer = "getNativePointer" + GetCW20Pointer = "getCW20Pointer" + GetCW721Pointer = "getCW721Pointer" +) + +const PointerViewAddress = "0x000000000000000000000000000000000000100A" + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +type Precompile struct { + pcommon.Precompile + evmKeeper pcommon.EVMKeeper + address common.Address + + GetNativePointerID []byte + GetCW20PointerID []byte + GetCW721PointerID []byte +} + +func NewPrecompile(evmKeeper pcommon.EVMKeeper) (*Precompile, error) { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + return nil, fmt.Errorf("error loading the pointer ABI %s", err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + return nil, err + } + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + evmKeeper: evmKeeper, + address: common.HexToAddress(PointerViewAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case GetNativePointer: + p.GetNativePointerID = m.ID + case GetCW20Pointer: + p.GetCW20PointerID = m.ID + case GetCW721Pointer: + p.GetCW721PointerID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + return 2000 +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, _ *big.Int, _ bool) (ret []byte, err error) { + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, err + } + + switch method.Name { + case GetNativePointer: + return p.GetNative(ctx, method, args) + case GetCW20Pointer: + return p.GetCW20(ctx, method, args) + case GetCW721Pointer: + return p.GetCW721(ctx, method, args) + default: + err = fmt.Errorf("unknown method %s", method.Name) + } + return +} + +func (p Precompile) GetNative(ctx sdk.Context, method *abi.Method, args []interface{}) (ret []byte, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + token := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC20NativePointer(ctx, token) + return method.Outputs.Pack(existingAddr, existingVersion, exists) +} + +func (p Precompile) GetCW20(ctx sdk.Context, method *abi.Method, args []interface{}) (ret []byte, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + addr := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC20CW20Pointer(ctx, addr) + return method.Outputs.Pack(existingAddr, existingVersion, exists) +} + +func (p Precompile) GetCW721(ctx sdk.Context, method *abi.Method, args []interface{}) (ret []byte, err error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + addr := args[0].(string) + existingAddr, existingVersion, exists := p.evmKeeper.GetERC721CW721Pointer(ctx, addr) + return method.Outputs.Pack(existingAddr, existingVersion, exists) +} diff --git a/precompiles/pointerview/pointerview_test.go b/precompiles/pointerview/pointerview_test.go new file mode 100644 index 0000000000..ad6d28bff3 --- /dev/null +++ b/precompiles/pointerview/pointerview_test.go @@ -0,0 +1,67 @@ +package pointerview_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/precompiles/pointerview" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/stretchr/testify/require" +) + +func TestPointerView(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + p, err := pointerview.NewPrecompile(k) + require.Nil(t, err) + _, pointer := testkeeper.MockAddressPair() + k.SetERC20NativePointer(ctx, "test", pointer) + k.SetERC20CW20Pointer(ctx, "test", pointer) + k.SetERC721CW721Pointer(ctx, "test", pointer) + m, err := p.ABI.MethodById(p.GetNativePointerID) + require.Nil(t, err) + ret, err := p.GetNative(ctx, m, []interface{}{"test"}) + require.Nil(t, err) + outputs, err := m.Outputs.Unpack(ret) + require.Nil(t, err) + require.Equal(t, pointer, outputs[0].(common.Address)) + require.Equal(t, native.CurrentVersion, outputs[1].(uint16)) + require.True(t, outputs[2].(bool)) + ret, err = p.GetNative(ctx, m, []interface{}{"test2"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.False(t, outputs[2].(bool)) + + m, err = p.ABI.MethodById(p.GetCW20PointerID) + require.Nil(t, err) + ret, err = p.GetCW20(ctx, m, []interface{}{"test"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.Equal(t, pointer, outputs[0].(common.Address)) + require.Equal(t, cw20.CurrentVersion, outputs[1].(uint16)) + require.True(t, outputs[2].(bool)) + ret, err = p.GetCW20(ctx, m, []interface{}{"test2"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.False(t, outputs[2].(bool)) + + m, err = p.ABI.MethodById(p.GetCW721PointerID) + require.Nil(t, err) + ret, err = p.GetCW721(ctx, m, []interface{}{"test"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.Equal(t, pointer, outputs[0].(common.Address)) + require.Equal(t, cw721.CurrentVersion, outputs[1].(uint16)) + require.True(t, outputs[2].(bool)) + ret, err = p.GetCW721(ctx, m, []interface{}{"test2"}) + require.Nil(t, err) + outputs, err = m.Outputs.Unpack(ret) + require.Nil(t, err) + require.False(t, outputs[2].(bool)) +} diff --git a/precompiles/setup.go b/precompiles/setup.go new file mode 100644 index 0000000000..a0908d4963 --- /dev/null +++ b/precompiles/setup.go @@ -0,0 +1,114 @@ +package precompiles + +import ( + "sync" + + ecommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/precompiles/addr" + "github.com/sei-protocol/sei-chain/precompiles/bank" + "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/precompiles/distribution" + "github.com/sei-protocol/sei-chain/precompiles/gov" + "github.com/sei-protocol/sei-chain/precompiles/ibc" + "github.com/sei-protocol/sei-chain/precompiles/json" + "github.com/sei-protocol/sei-chain/precompiles/oracle" + "github.com/sei-protocol/sei-chain/precompiles/pointer" + "github.com/sei-protocol/sei-chain/precompiles/pointerview" + "github.com/sei-protocol/sei-chain/precompiles/staking" + "github.com/sei-protocol/sei-chain/precompiles/wasmd" +) + +var SetupMtx = &sync.Mutex{} +var Initialized = false + +func InitializePrecompiles( + evmKeeper common.EVMKeeper, + bankKeeper common.BankKeeper, + wasmdKeeper common.WasmdKeeper, + wasmdViewKeeper common.WasmdViewKeeper, + stakingKeeper common.StakingKeeper, + govKeeper common.GovKeeper, + distrKeeper common.DistributionKeeper, + oracleKeeper common.OracleKeeper, + transferKeeper common.TransferKeeper, +) error { + SetupMtx.Lock() + defer SetupMtx.Unlock() + if Initialized { + panic("precompiles already initialized") + } + bankp, err := bank.NewPrecompile(bankKeeper, evmKeeper) + if err != nil { + return err + } + addPrecompileToVM(bankp, bankp.Address()) + wasmdp, err := wasmd.NewPrecompile(evmKeeper, wasmdKeeper, wasmdViewKeeper, bankKeeper) + if err != nil { + return err + } + addPrecompileToVM(wasmdp, wasmdp.Address()) + jsonp, err := json.NewPrecompile() + if err != nil { + return err + } + addPrecompileToVM(jsonp, jsonp.Address()) + addrp, err := addr.NewPrecompile(evmKeeper) + if err != nil { + return err + } + addPrecompileToVM(addrp, addrp.Address()) + stakingp, err := staking.NewPrecompile(stakingKeeper, evmKeeper, bankKeeper) + if err != nil { + return err + } + addPrecompileToVM(stakingp, stakingp.Address()) + govp, err := gov.NewPrecompile(govKeeper, evmKeeper, bankKeeper) + if err != nil { + return err + } + addPrecompileToVM(govp, govp.Address()) + distrp, err := distribution.NewPrecompile(distrKeeper, evmKeeper) + if err != nil { + return err + } + addPrecompileToVM(distrp, distrp.Address()) + oraclep, err := oracle.NewPrecompile(oracleKeeper, evmKeeper) + if err != nil { + return err + } + addPrecompileToVM(oraclep, oraclep.Address()) + ibcp, err := ibc.NewPrecompile(transferKeeper, evmKeeper) + if err != nil { + return err + } + addPrecompileToVM(ibcp, ibcp.Address()) + pointerp, err := pointer.NewPrecompile(evmKeeper, bankKeeper, wasmdViewKeeper) + if err != nil { + return err + } + addPrecompileToVM(pointerp, pointerp.Address()) + pointerviewp, err := pointerview.NewPrecompile(evmKeeper) + if err != nil { + return err + } + addPrecompileToVM(pointerviewp, pointerviewp.Address()) + Initialized = true + return nil +} + +// This function modifies global variable in `vm` module. It should only be called once +// per precompile during initialization +func addPrecompileToVM(p vm.PrecompiledContract, addr ecommon.Address) { + vm.PrecompiledContractsHomestead[addr] = p + vm.PrecompiledContractsByzantium[addr] = p + vm.PrecompiledContractsIstanbul[addr] = p + vm.PrecompiledContractsBerlin[addr] = p + vm.PrecompiledContractsCancun[addr] = p + vm.PrecompiledContractsBLS[addr] = p + vm.PrecompiledAddressesHomestead = append(vm.PrecompiledAddressesHomestead, addr) + vm.PrecompiledAddressesByzantium = append(vm.PrecompiledAddressesByzantium, addr) + vm.PrecompiledAddressesIstanbul = append(vm.PrecompiledAddressesIstanbul, addr) + vm.PrecompiledAddressesBerlin = append(vm.PrecompiledAddressesBerlin, addr) + vm.PrecompiledAddressesCancun = append(vm.PrecompiledAddressesCancun, addr) +} diff --git a/precompiles/staking/Staking.sol b/precompiles/staking/Staking.sol new file mode 100644 index 0000000000..b061ea18d6 --- /dev/null +++ b/precompiles/staking/Staking.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant STAKING_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001005; + +IStaking constant STAKING_CONTRACT = IStaking( + STAKING_PRECOMPILE_ADDRESS +); + +interface IStaking { + // Transactions + function delegate( + string memory valAddress + ) payable external returns (bool success); + + function redelegate( + string memory srcAddress, + string memory dstAddress, + uint256 amount + ) external returns (bool success); + + function undelegate( + string memory valAddress, + uint256 amount + ) external returns (bool success); +} \ No newline at end of file diff --git a/precompiles/staking/abi.json b/precompiles/staking/abi.json new file mode 100755 index 0000000000..0be519e4d8 --- /dev/null +++ b/precompiles/staking/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"valAddress","type":"string"}],"name":"delegate","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"srcAddress","type":"string"},{"internalType":"string","name":"dstAddress","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"redelegate","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"valAddress","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"undelegate","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go new file mode 100644 index 0000000000..1c96a56661 --- /dev/null +++ b/precompiles/staking/staking.go @@ -0,0 +1,211 @@ +package staking + +import ( + "bytes" + "embed" + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" +) + +const ( + DelegateMethod = "delegate" + RedelegateMethod = "redelegate" + UndelegateMethod = "undelegate" +) + +const ( + StakingAddress = "0x0000000000000000000000000000000000001005" +) + +var _ vm.PrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +func GetABI() abi.ABI { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + panic(err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + panic(err) + } + return newAbi +} + +type Precompile struct { + pcommon.Precompile + stakingKeeper pcommon.StakingKeeper + evmKeeper pcommon.EVMKeeper + bankKeeper pcommon.BankKeeper + address common.Address + + DelegateID []byte + RedelegateID []byte + UndelegateID []byte +} + +func NewPrecompile(stakingKeeper pcommon.StakingKeeper, evmKeeper pcommon.EVMKeeper, bankKeeper pcommon.BankKeeper) (*Precompile, error) { + newAbi := GetABI() + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + stakingKeeper: stakingKeeper, + evmKeeper: evmKeeper, + bankKeeper: bankKeeper, + address: common.HexToAddress(StakingAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case DelegateMethod: + p.DelegateID = m.ID + case RedelegateMethod: + p.RedelegateID = m.ID + case UndelegateMethod: + p.UndelegateID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } + + if bytes.Equal(methodID, p.DelegateID) { + return 50000 + } else if bytes.Equal(methodID, p.RedelegateID) { + return 70000 + } else if bytes.Equal(methodID, p.UndelegateID) { + return 50000 + } + + // This should never happen since this is going to fail during Run + return pcommon.UnknownMethodCallGas +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { + if readOnly { + return nil, errors.New("cannot call staking precompile from staticcall") + } + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, err + } + if caller.Cmp(callingContract) != 0 { + return nil, errors.New("cannot delegatecall staking") + } + + switch method.Name { + case DelegateMethod: + return p.delegate(ctx, method, caller, args, value) + case RedelegateMethod: + return p.redelegate(ctx, method, caller, args, value) + case UndelegateMethod: + return p.undelegate(ctx, method, caller, args, value) + } + return +} + +func (p Precompile) delegate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + return nil, err + } + // if delegator is associated, then it must have Account set already + // if delegator is not associated, then it can't delegate anyway (since + // there is no good way to merge delegations if it becomes associated) + delegator, associated := p.evmKeeper.GetSeiAddress(ctx, caller) + if !associated { + return nil, fmt.Errorf("delegator %s is not associated/doesn't have an Account set yet", caller.Hex()) + } + validatorBech32 := args[0].(string) + if value == nil || value.Sign() == 0 { + return nil, errors.New("set `value` field to non-zero to send delegate fund") + } + coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), delegator, value, p.bankKeeper) + if err != nil { + return nil, err + } + _, err = p.stakingKeeper.Delegate(sdk.WrapSDKContext(ctx), &stakingtypes.MsgDelegate{ + DelegatorAddress: delegator.String(), + ValidatorAddress: validatorBech32, + Amount: coin, + }) + if err != nil { + return nil, err + } + return method.Outputs.Pack(true) +} + +func (p Precompile) redelegate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 3); err != nil { + return nil, err + } + delegator, associated := p.evmKeeper.GetSeiAddress(ctx, caller) + if !associated { + return nil, fmt.Errorf("redelegator %s is not associated/doesn't have an Account set yet", caller.Hex()) + } + srcValidatorBech32 := args[0].(string) + dstValidatorBech32 := args[1].(string) + amount := args[2].(*big.Int) + _, err := p.stakingKeeper.BeginRedelegate(sdk.WrapSDKContext(ctx), &stakingtypes.MsgBeginRedelegate{ + DelegatorAddress: delegator.String(), + ValidatorSrcAddress: srcValidatorBech32, + ValidatorDstAddress: dstValidatorBech32, + Amount: sdk.NewCoin(sdk.MustGetBaseDenom(), sdk.NewIntFromBigInt(amount)), + }) + if err != nil { + return nil, err + } + return method.Outputs.Pack(true) +} + +func (p Precompile) undelegate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}, value *big.Int) ([]byte, error) { + if err := pcommon.ValidateNonPayable(value); err != nil { + return nil, err + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + return nil, err + } + delegator, associated := p.evmKeeper.GetSeiAddress(ctx, caller) + if !associated { + return nil, fmt.Errorf("undelegator %s is not associated/doesn't have an Account set yet", caller.Hex()) + } + validatorBech32 := args[0].(string) + amount := args[1].(*big.Int) + _, err := p.stakingKeeper.Undelegate(sdk.WrapSDKContext(ctx), &stakingtypes.MsgUndelegate{ + DelegatorAddress: delegator.String(), + ValidatorAddress: validatorBech32, + Amount: sdk.NewCoin(p.evmKeeper.GetBaseDenom(ctx), sdk.NewIntFromBigInt(amount)), + }) + if err != nil { + return nil, err + } + return method.Outputs.Pack(true) +} diff --git a/precompiles/staking/staking_test.go b/precompiles/staking/staking_test.go new file mode 100644 index 0000000000..682dbcf2b3 --- /dev/null +++ b/precompiles/staking/staking_test.go @@ -0,0 +1,248 @@ +package staking_test + +import ( + "encoding/hex" + "math/big" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + crptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking/teststaking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "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/app" + "github.com/sei-protocol/sei-chain/precompiles/staking" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + minttypes "github.com/sei-protocol/sei-chain/x/mint/types" + "github.com/stretchr/testify/require" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestStaking(t *testing.T) { + testApp := testkeeper.EVMTestApp + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + k := &testApp.EvmKeeper + valPub1 := secp256k1.GenPrivKey().PubKey() + valPub2 := secp256k1.GenPrivKey().PubKey() + val := setupValidator(t, ctx, testApp, stakingtypes.Unbonded, valPub1) + val2 := setupValidator(t, ctx, testApp, stakingtypes.Unbonded, valPub2) + + // delegate + abi := staking.GetABI() + args, err := abi.Pack("delegate", val.String()) + require.Nil(t, err) + + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + addr := common.HexToAddress(staking.StakingAddress) + txData := ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(100_000_000_000_000), + Data: args, + Nonce: 0, + } + chainID := k.ChainID(ctx) + chainCfg := evmtypes.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 := evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) + require.Nil(t, k.BankKeeper().MintCoins(ctx, evmtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, evmtypes.ModuleName, seiAddr, amt)) + + msgServer := keeper.NewMsgServerImpl(k) + + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + + d, found := testApp.StakingKeeper.GetDelegation(ctx, seiAddr, val) + require.True(t, found) + require.Equal(t, int64(100), d.Shares.RoundInt().Int64()) + + // redelegate + args, err = abi.Pack("redelegate", val.String(), val2.String(), big.NewInt(50)) + require.Nil(t, err) + txData = ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(0), + Data: args, + 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 = evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + ante.Preprocess(ctx, req) + res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + + d, found = testApp.StakingKeeper.GetDelegation(ctx, seiAddr, val) + require.True(t, found) + require.Equal(t, int64(50), d.Shares.RoundInt().Int64()) + + // undelegate + args, err = abi.Pack("undelegate", val.String(), big.NewInt(30)) + require.Nil(t, err) + txData = ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(0), + Data: args, + Nonce: 2, + } + tx, err = ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + txwrapper, err = ethtx.NewLegacyTx(tx) + require.Nil(t, err) + req, err = evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + ante.Preprocess(ctx, req) + res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + + d, found = testApp.StakingKeeper.GetDelegation(ctx, seiAddr, val) + require.True(t, found) + require.Equal(t, int64(20), d.Shares.RoundInt().Int64()) +} + +func TestStakingError(t *testing.T) { + testApp := testkeeper.EVMTestApp + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + k := &testApp.EvmKeeper + valPub1 := secp256k1.GenPrivKey().PubKey() + valPub2 := secp256k1.GenPrivKey().PubKey() + val := setupValidator(t, ctx, testApp, stakingtypes.Unbonded, valPub1) + val2 := setupValidator(t, ctx, testApp, stakingtypes.Unbonded, valPub2) + + abi := staking.GetABI() + args, err := abi.Pack("undelegate", val.String(), big.NewInt(100)) + require.Nil(t, err) + + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + addr := common.HexToAddress(staking.StakingAddress) + txData := ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(0), + Data: args, + Nonce: 0, + } + chainID := k.ChainID(ctx) + chainCfg := evmtypes.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 := evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + _, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) + require.Nil(t, k.BankKeeper().MintCoins(ctx, evmtypes.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, evmtypes.ModuleName, evmAddr[:], amt)) + + msgServer := keeper.NewMsgServerImpl(k) + + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.NotEmpty(t, res.VmError) + + // redelegate + args, err = abi.Pack("redelegate", val.String(), val2.String(), big.NewInt(50)) + require.Nil(t, err) + txData = ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: &addr, + Value: big.NewInt(0), + Data: args, + 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 = evmtypes.NewMsgEVMTransaction(txwrapper) + require.Nil(t, err) + + ante.Preprocess(ctx, req) + res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.NotEmpty(t, res.VmError) +} + +func setupValidator(t *testing.T, ctx sdk.Context, a *app.App, bondStatus stakingtypes.BondStatus, valPub crptotypes.PubKey) sdk.ValAddress { + valAddr := sdk.ValAddress(valPub.Address()) + bondDenom := a.StakingKeeper.GetParams(ctx).BondDenom + selfBond := sdk.NewCoins(sdk.Coin{Amount: sdk.NewInt(100), Denom: bondDenom}) + + err := a.BankKeeper.MintCoins(ctx, minttypes.ModuleName, selfBond) + require.NoError(t, err) + + err = a.BankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, sdk.AccAddress(valAddr), selfBond) + require.NoError(t, err) + + sh := teststaking.NewHelper(t, ctx, a.StakingKeeper) + msg := sh.CreateValidatorMsg(valAddr, valPub, selfBond[0].Amount) + sh.Handle(msg, true) + + val, found := a.StakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + + val = val.UpdateStatus(bondStatus) + a.StakingKeeper.SetValidator(ctx, val) + + consAddr, err := val.GetConsAddr() + require.NoError(t, err) + + signingInfo := slashingtypes.NewValidatorSigningInfo( + consAddr, + ctx.BlockHeight(), + 0, + time.Unix(0, 0), + false, + 0, + ) + a.SlashingKeeper.SetValidatorSigningInfo(ctx, consAddr, signingInfo) + + return valAddr +} diff --git a/precompiles/wasmd/Wasmd.sol b/precompiles/wasmd/Wasmd.sol new file mode 100644 index 0000000000..58d6851882 --- /dev/null +++ b/precompiles/wasmd/Wasmd.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +address constant WASMD_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001002; + +IWasmd constant WASMD_CONTRACT = IWasmd( + WASMD_PRECOMPILE_ADDRESS +); + +interface IWasmd { + // Transactions + function instantiate( + uint64 codeID, + string memory admin, + bytes memory msg, + string memory label, + bytes memory coins + ) payable external returns (string memory contractAddr, bytes memory data); + + function execute( + string memory contractAddress, + bytes memory msg, + bytes memory coins + ) payable external returns (bytes memory response); + + struct ExecuteMsg { + string contractAddress; + bytes msg; + bytes coins; + } + + function execute_batch(ExecuteMsg[] memory executeMsgs) payable external returns (bytes[] memory responses); + + // Queries + function query(string memory contractAddress, bytes memory req) external view returns (bytes memory response); +} diff --git a/precompiles/wasmd/abi.json b/precompiles/wasmd/abi.json new file mode 100644 index 0000000000..c5e5b1b3f6 --- /dev/null +++ b/precompiles/wasmd/abi.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"bytes","name":"coins","type":"bytes"}],"internalType":"struct IWasmd.ExecuteMsg[]","name":"executeMsgs","type":"tuple[]"}],"name":"execute_batch","outputs":[{"internalType":"bytes[]","name":"responses","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"codeID","type":"uint64"},{"internalType":"string","name":"admin","type":"string"},{"internalType":"bytes","name":"msg","type":"bytes"},{"internalType":"string","name":"label","type":"string"},{"internalType":"bytes","name":"coins","type":"bytes"}],"name":"instantiate","outputs":[{"internalType":"string","name":"contractAddr","type":"string"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"string","name":"contractAddress","type":"string"},{"internalType":"bytes","name":"req","type":"bytes"}],"name":"query","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/precompiles/wasmd/wasmd.go b/precompiles/wasmd/wasmd.go new file mode 100644 index 0000000000..06d9db2530 --- /dev/null +++ b/precompiles/wasmd/wasmd.go @@ -0,0 +1,499 @@ +package wasmd + +import ( + "bytes" + "embed" + "encoding/json" + "errors" + "fmt" + "math/big" + + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/vm" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/state" +) + +const ( + InstantiateMethod = "instantiate" + ExecuteMethod = "execute" + ExecuteBatchMethod = "execute_batch" + QueryMethod = "query" +) + +const WasmdAddress = "0x0000000000000000000000000000000000001002" + +var _ vm.PrecompiledContract = &Precompile{} +var _ vm.DynamicGasPrecompiledContract = &Precompile{} + +// Embed abi json file to the executable binary. Needed when importing as dependency. +// +//go:embed abi.json +var f embed.FS + +type Precompile struct { + pcommon.Precompile + evmKeeper pcommon.EVMKeeper + bankKeeper pcommon.BankKeeper + wasmdKeeper pcommon.WasmdKeeper + wasmdViewKeeper pcommon.WasmdViewKeeper + address common.Address + + InstantiateID []byte + ExecuteID []byte + ExecuteBatchID []byte + QueryID []byte +} + +type ExecuteMsg struct { + ContractAddress string `json:"contractAddress"` + Msg []byte `json:"msg"` + Coins []byte `json:"coins"` +} + +func NewPrecompile(evmKeeper pcommon.EVMKeeper, wasmdKeeper pcommon.WasmdKeeper, wasmdViewKeeper pcommon.WasmdViewKeeper, bankKeeper pcommon.BankKeeper) (*Precompile, error) { + abiBz, err := f.ReadFile("abi.json") + if err != nil { + return nil, fmt.Errorf("error loading the staking ABI %s", err) + } + + newAbi, err := abi.JSON(bytes.NewReader(abiBz)) + if err != nil { + return nil, err + } + + p := &Precompile{ + Precompile: pcommon.Precompile{ABI: newAbi}, + wasmdKeeper: wasmdKeeper, + wasmdViewKeeper: wasmdViewKeeper, + evmKeeper: evmKeeper, + bankKeeper: bankKeeper, + address: common.HexToAddress(WasmdAddress), + } + + for name, m := range newAbi.Methods { + switch name { + case InstantiateMethod: + p.InstantiateID = m.ID + case ExecuteMethod: + p.ExecuteID = m.ID + case ExecuteBatchMethod: + p.ExecuteBatchID = m.ID + case QueryMethod: + p.QueryID = m.ID + } + } + + return p, nil +} + +// RequiredGas returns the required bare minimum gas to execute the precompile. +func (p Precompile) RequiredGas(input []byte) uint64 { + methodID, err := pcommon.ExtractMethodID(input) + if err != nil { + return pcommon.UnknownMethodCallGas + } + + method, err := p.ABI.MethodById(methodID) + if err != nil { + // This should never happen since this method is going to fail during Run + return pcommon.UnknownMethodCallGas + } + + return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) +} + +func (Precompile) IsTransaction(method string) bool { + switch method { + case ExecuteMethod: + return true + case ExecuteBatchMethod: + return true + case InstantiateMethod: + return true + default: + return false + } +} + +func (p Precompile) Address() common.Address { + return p.address +} + +func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, _ *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { + ctx, method, args, err := p.Prepare(evm, input) + if err != nil { + return nil, 0, err + } + gasMultipler := p.evmKeeper.GetPriorityNormalizer(ctx) + gasLimitBigInt := sdk.NewDecFromInt(sdk.NewIntFromUint64(suppliedGas)).Mul(gasMultipler).TruncateInt().BigInt() + if gasLimitBigInt.Cmp(utils.BigMaxU64) > 0 { + gasLimitBigInt = utils.BigMaxU64 + } + ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimitBigInt.Uint64())) + + switch method.Name { + case InstantiateMethod: + return p.instantiate(ctx, method, caller, callingContract, args, value, readOnly) + 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) + case QueryMethod: + return p.query(ctx, method, args, value) + } + return +} + +func (p Precompile) Run(*vm.EVM, common.Address, common.Address, []byte, *big.Int, bool) ([]byte, error) { + panic("static gas Run is not implemented for dynamic gas precompile") +} + +func (p Precompile) instantiate(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool) (ret []byte, remainingGas uint64, rerr error) { + defer func() { + if err := recover(); err != nil { + ret = nil + remainingGas = 0 + rerr = fmt.Errorf("%s", err) + return + } + }() + if readOnly { + rerr = errors.New("cannot call instantiate from staticcall") + return + } + if err := pcommon.ValidateArgsLength(args, 5); err != nil { + rerr = err + return + } + if caller.Cmp(callingContract) != 0 { + rerr = errors.New("cannot delegatecall instantiate") + return + } + + // type assertion will always succeed because it's already validated in p.Prepare call in Run() + codeID := args[0].(uint64) + creatorAddr, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + rerr = fmt.Errorf("creator %s is not associated", caller.Hex()) + return + } + var adminAddr sdk.AccAddress + adminAddrStr := args[1].(string) + if len(adminAddrStr) > 0 { + adminAddrDecoded, err := sdk.AccAddressFromBech32(adminAddrStr) + if err != nil { + rerr = err + return + } + adminAddr = adminAddrDecoded + } + msg := args[2].([]byte) + label := args[3].(string) + coins := sdk.NewCoins() + coinsBz := args[4].([]byte) + + if err := json.Unmarshal(coinsBz, &coins); err != nil { + rerr = err + return + } + coinsValue := coins.AmountOf(sdk.MustGetBaseDenom()).Mul(state.SdkUseiToSweiMultiplier).BigInt() + if (value == nil && coinsValue.Sign() == 1) || (value != nil && coinsValue.Cmp(value) != 0) { + rerr = errors.New("coin amount must equal value specified") + return + } + + // Run basic validation, can also just expose validateLabel and validate validateWasmCode in sei-wasmd + msgInstantiate := wasmtypes.MsgInstantiateContract{ + Sender: creatorAddr.String(), + CodeID: codeID, + Label: label, + Funds: coins, + Msg: msg, + Admin: adminAddrStr, + } + + if err := msgInstantiate.ValidateBasic(); err != nil { + rerr = err + return + } + useiAmt := coins.AmountOf(sdk.MustGetBaseDenom()) + if value != nil && !useiAmt.IsZero() { + useiAmtAsWei := useiAmt.Mul(state.SdkUseiToSweiMultiplier).BigInt() + coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), creatorAddr, useiAmtAsWei, p.bankKeeper) + if err != nil { + rerr = err + return + } + // sanity check coin amounts match + if !coin.Amount.Equal(useiAmt) { + rerr = errors.New("mismatch between coins and payment value") + return + } + } + + addr, data, err := p.wasmdKeeper.Instantiate(ctx, codeID, creatorAddr, adminAddr, msg, label, coins) + if err != nil { + rerr = err + return + } + ret, rerr = method.Outputs.Pack(addr.String(), data) + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) + 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) { + defer func() { + if err := recover(); err != nil { + ret = nil + remainingGas = 0 + rerr = fmt.Errorf("%s", err) + return + } + }() + if readOnly { + rerr = errors.New("cannot call execute from staticcall") + return + } + + if err := pcommon.ValidateArgsLength(args, 1); err != nil { + rerr = err + return + } + + executeMsgs := args[0].([]struct { + ContractAddress string `json:"contractAddress"` + Msg []byte `json:"msg"` + Coins []byte `json:"coins"` + }) + + responses := make([][]byte, 0, len(executeMsgs)) + + // validate coins add up to value + validateValue := big.NewInt(0) + for i := 0; i < len(executeMsgs); i++ { + executeMsg := ExecuteMsg(executeMsgs[i]) + coinsBz := executeMsg.Coins + coins := sdk.NewCoins() + if err := json.Unmarshal(coinsBz, &coins); err != nil { + rerr = err + return + } + messageAmount := coins.AmountOf(sdk.MustGetBaseDenom()).Mul(state.SdkUseiToSweiMultiplier).BigInt() + validateValue.Add(validateValue, messageAmount) + } + // if validateValue is greater than zero, then value must be provided, and they must be equal + if (value == nil && validateValue.Sign() == 1) || (value != nil && validateValue.Cmp(value) != 0) { + rerr = errors.New("sum of coin amounts must equal value specified") + return + } + for i := 0; i < len(executeMsgs); i++ { + executeMsg := ExecuteMsg(executeMsgs[i]) + + // type assertion will always succeed because it's already validated in p.Prepare call in Run() + contractAddrStr := executeMsg.ContractAddress + if caller.Cmp(callingContract) != 0 { + erc20pointer, _, erc20exists := p.evmKeeper.GetERC20CW20Pointer(ctx, contractAddrStr) + erc721pointer, _, erc721exists := p.evmKeeper.GetERC721CW721Pointer(ctx, contractAddrStr) + if (!erc20exists || erc20pointer.Cmp(callingContract) != 0) && (!erc721exists || erc721pointer.Cmp(callingContract) != 0) { + return nil, 0, fmt.Errorf("%s is not a pointer of %s", callingContract.Hex(), contractAddrStr) + } + } + + contractAddr, err := sdk.AccAddressFromBech32(contractAddrStr) + if err != nil { + rerr = err + return + } + senderAddr := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + msg := executeMsg.Msg + coinsBz := executeMsg.Coins + coins := sdk.NewCoins() + if err := json.Unmarshal(coinsBz, &coins); err != nil { + rerr = err + return + } + useiAmt := coins.AmountOf(sdk.MustGetBaseDenom()) + if value != 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) + if err != nil { + rerr = err + return + } + value.Sub(value, useiAmtAsWei) + if value.Sign() == -1 { + rerr = errors.New("insufficient value provided for payment") + return + } + // sanity check coin amounts match + if !coin.Amount.Equal(useiAmt) { + rerr = errors.New("mismatch between coins and payment value") + return + } + } + // Run basic validation, can also just expose validateLabel and validate validateWasmCode in sei-wasmd + msgExecute := wasmtypes.MsgExecuteContract{ + Sender: senderAddr.String(), + Contract: contractAddr.String(), + Msg: msg, + Funds: coins, + } + if err := msgExecute.ValidateBasic(); err != nil { + rerr = err + return + } + + res, err := p.wasmdKeeper.Execute(ctx, contractAddr, senderAddr, msg, coins) + if err != nil { + rerr = err + return + } + responses = append(responses, res) + } + if value != nil && value.Sign() != 0 { + rerr = errors.New("value remaining after execution, must match provided amounts exactly") + return + } + ret, rerr = method.Outputs.Pack(responses) + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) + return +} + +func (p Precompile) execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool) (ret []byte, remainingGas uint64, rerr error) { + defer func() { + if err := recover(); err != nil { + ret = nil + remainingGas = 0 + rerr = fmt.Errorf("%s", err) + return + } + }() + if readOnly { + rerr = errors.New("cannot call execute from staticcall") + return + } + if err := pcommon.ValidateArgsLength(args, 3); err != nil { + rerr = err + return + } + + // type assertion will always succeed because it's already validated in p.Prepare call in Run() + contractAddrStr := args[0].(string) + if caller.Cmp(callingContract) != 0 { + erc20pointer, _, erc20exists := p.evmKeeper.GetERC20CW20Pointer(ctx, contractAddrStr) + erc721pointer, _, erc721exists := p.evmKeeper.GetERC721CW721Pointer(ctx, contractAddrStr) + if (!erc20exists || erc20pointer.Cmp(callingContract) != 0) && (!erc721exists || erc721pointer.Cmp(callingContract) != 0) { + return nil, 0, fmt.Errorf("%s is not a pointer of %s", callingContract.Hex(), contractAddrStr) + } + } + // addresses will be sent in Sei format + contractAddr, err := sdk.AccAddressFromBech32(contractAddrStr) + if err != nil { + rerr = err + return + } + senderAddr, found := p.evmKeeper.GetSeiAddress(ctx, caller) + if !found { + rerr = fmt.Errorf("sender %s is not associated", caller.Hex()) + return + } + msg := args[1].([]byte) + coins := sdk.NewCoins() + coinsBz := args[2].([]byte) + if err := json.Unmarshal(coinsBz, &coins); err != nil { + rerr = err + return + } + coinsValue := coins.AmountOf(sdk.MustGetBaseDenom()).Mul(state.SdkUseiToSweiMultiplier).BigInt() + if (value == nil && coinsValue.Sign() == 1) || (value != nil && coinsValue.Cmp(value) != 0) { + rerr = errors.New("coin amount must equal value specified") + return + } + + // Run basic validation, can also just expose validateLabel and validate validateWasmCode in sei-wasmd + msgExecute := wasmtypes.MsgExecuteContract{ + Sender: senderAddr.String(), + Contract: contractAddr.String(), + Msg: msg, + Funds: coins, + } + + if err := msgExecute.ValidateBasic(); err != nil { + rerr = err + return + } + + useiAmt := coins.AmountOf(sdk.MustGetBaseDenom()) + if value != nil && !useiAmt.IsZero() { + useiAmtAsWei := useiAmt.Mul(state.SdkUseiToSweiMultiplier).BigInt() + coin, err := pcommon.HandlePaymentUsei(ctx, p.evmKeeper.GetSeiAddressOrDefault(ctx, p.address), senderAddr, useiAmtAsWei, p.bankKeeper) + if err != nil { + rerr = err + return + } + // sanity check coin amounts match + if !coin.Amount.Equal(useiAmt) { + rerr = errors.New("mismatch between coins and payment value") + return + } + } + res, err := p.wasmdKeeper.Execute(ctx, contractAddr, senderAddr, msg, coins) + if err != nil { + rerr = err + return + } + ret, rerr = method.Outputs.Pack(res) + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) + return +} + +func (p Precompile) query(ctx sdk.Context, method *abi.Method, args []interface{}, value *big.Int) (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.ValidateNonPayable(value); err != nil { + rerr = err + return + } + + if err := pcommon.ValidateArgsLength(args, 2); err != nil { + rerr = err + return + } + + contractAddrStr := args[0].(string) + // addresses will be sent in Sei format + contractAddr, err := sdk.AccAddressFromBech32(contractAddrStr) + if err != nil { + rerr = err + return + } + req := args[1].([]byte) + + rawContractMessage := wasmtypes.RawContractMessage(req) + if err := rawContractMessage.ValidateBasic(); err != nil { + rerr = err + return + } + + res, err := p.wasmdViewKeeper.QuerySmart(ctx, contractAddr, req) + if err != nil { + rerr = err + return + } + ret, rerr = method.Outputs.Pack(res) + remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) + return +} diff --git a/precompiles/wasmd/wasmd_test.go b/precompiles/wasmd/wasmd_test.go new file mode 100644 index 0000000000..9322386fcb --- /dev/null +++ b/precompiles/wasmd/wasmd_test.go @@ -0,0 +1,504 @@ +package wasmd_test + +import ( + "fmt" + "math/big" + "os" + "testing" + "time" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/app" + "github.com/sei-protocol/sei-chain/precompiles/wasmd" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" +) + +func TestRequiredGas(t *testing.T) { + testApp := app.Setup(false, false) + p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper), testApp.WasmKeeper, testApp.BankKeeper) + require.Nil(t, err) + require.Equal(t, uint64(2000), p.RequiredGas(p.ExecuteID)) + require.Equal(t, uint64(2000), p.RequiredGas(p.InstantiateID)) + require.Equal(t, uint64(2000), p.RequiredGas(p.ExecuteBatchID)) + require.Equal(t, uint64(1000), p.RequiredGas(p.QueryID)) + require.Equal(t, uint64(3000), p.RequiredGas([]byte{15, 15, 15, 15})) // invalid method +} + +func TestAddress(t *testing.T) { + testApp := app.Setup(false, false) + p, err := wasmd.NewPrecompile(&testApp.EvmKeeper, wasmkeeper.NewDefaultPermissionKeeper(testApp.WasmKeeper), testApp.WasmKeeper, testApp.BankKeeper) + require.Nil(t, err) + require.Equal(t, "0x0000000000000000000000000000000000001002", p.Address().Hex()) +} + +func TestInstantiate(t *testing.T) { + testApp := app.Setup(false, false) + mockAddr, mockEVMAddr := testkeeper.MockAddressPair() + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + 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) + instantiateMethod, err := p.ABI.MethodById(p.InstantiateID) + require.Nil(t, err) + amts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000))) + amtsbz, err := amts.MarshalJSON() + 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) + require.Nil(t, err) + args, err := instantiateMethod.Inputs.Pack( + codeID, + mockAddr.String(), + []byte("{}"), + "test", + amtsbz, + ) + require.Nil(t, err) + statedb := state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm := vm.EVM{ + StateDB: statedb, + } + testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) + suppliedGas := uint64(1000000) + res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.Nil(t, err) + outputs, err := instantiateMethod.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 2, len(outputs)) + require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) + require.Empty(t, outputs[1].([]byte)) + require.Equal(t, uint64(879782), g) + + amtsbz, err = sdk.NewCoins().MarshalJSON() + require.Nil(t, err) + args, err = instantiateMethod.Inputs.Pack( + codeID, + mockAddr.String(), + []byte("{}"), + "test", + amtsbz, + ) + require.Nil(t, err) + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + res, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + outputs, err = instantiateMethod.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 2, len(outputs)) + require.Equal(t, "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n", outputs[0].(string)) + require.Empty(t, outputs[1].([]byte)) + require.Equal(t, uint64(902838), g) + + // non-existent code ID + args, _ = instantiateMethod.Inputs.Pack( + codeID+1, + mockAddr.String(), + []byte("{}"), + "test", + amtsbz, + ) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + + // bad inputs + badArgs, _ := instantiateMethod.Inputs.Pack(codeID, "not bech32", []byte("{}"), "test", amtsbz) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, badArgs...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + badArgs, _ = instantiateMethod.Inputs.Pack(codeID, mockAddr.String(), []byte("{}"), "test", []byte("bad coins")) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.InstantiateID, badArgs...), suppliedGas, nil, nil, false) + require.NotNil(t, err) +} + +func TestExecute(t *testing.T) { + testApp := app.Setup(false, false) + mockAddr, mockEVMAddr := testkeeper.MockAddressPair() + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + 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.ExecuteID) + require.Nil(t, err) + args, err := executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + 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) + 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(906041), g) + require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) + + amtsbz, err = sdk.NewCoins().MarshalJSON() + require.Nil(t, err) + args, err = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + require.Nil(t, err) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.NotNil(t, err) // used coins instead of `value` to send usei to the contract + + args, err = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + require.Nil(t, err) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.NotNil(t, err) + + amtsbz, err = sdk.NewCoins().MarshalJSON() + require.Nil(t, err) + args, err = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + require.Nil(t, err) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.NotNil(t, err) + + // allowed delegatecall + contractAddrAllowed := common.BytesToAddress([]byte("contractA")) + testApp.EvmKeeper.SetERC20CW20Pointer(ctx, contractAddr.String(), contractAddrAllowed) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrAllowed, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + + // disallowed delegatecall + contractAddrDisallowed := common.BytesToAddress([]byte("contractB")) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrDisallowed, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + + // bad contract address + args, _ = executeMethod.Inputs.Pack(mockAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + + // bad inputs + args, _ = executeMethod.Inputs.Pack("not bech32", []byte("{\"echo\":{\"message\":\"test msg\"}}"), amtsbz) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + args, _ = executeMethod.Inputs.Pack(contractAddr.String(), []byte("{\"echo\":{\"message\":\"test msg\"}}"), []byte("bad coins")) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) +} + +func TestQuery(t *testing.T) { + testApp := app.Setup(false, false) + mockAddr, mockEVMAddr := testkeeper.MockAddressPair() + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + 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) + + queryMethod, err := p.ABI.MethodById(p.QueryID) + require.Nil(t, err) + args, err := queryMethod.Inputs.Pack(contractAddr.String(), []byte("{\"info\":{}}")) + require.Nil(t, err) + statedb := state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm := vm.EVM{ + StateDB: statedb, + } + suppliedGas := uint64(1000000) + res, g, err := p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.QueryID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + outputs, err := queryMethod.Outputs.Unpack(res) + require.Nil(t, err) + require.Equal(t, 1, len(outputs)) + require.Equal(t, "{\"message\":\"query test\"}", string(outputs[0].([]byte))) + require.Equal(t, uint64(930367), g) + + // bad contract address + args, _ = queryMethod.Inputs.Pack(mockAddr.String(), []byte("{\"info\":{}}")) + _, g, err = p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + + // bad input + args, _ = queryMethod.Inputs.Pack("not bech32", []byte("{\"info\":{}}")) + _, g, err = p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + args, _ = queryMethod.Inputs.Pack(contractAddr.String(), []byte("{\"bad\":{}}")) + _, g, err = p.RunAndCalculateGas(&evm, common.Address{}, common.Address{}, append(p.ExecuteID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) +} + +func TestExecuteBatchOneMessage(t *testing.T) { + testApp := app.Setup(false, false) + mockAddr, mockEVMAddr := testkeeper.MockAddressPair() + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + 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) + res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, 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))[0])) + require.Equal(t, uint64(906041), g) + require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) + + amtsbz, err = sdk.NewCoins().MarshalJSON() + 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) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(1000_000_000_000_000), nil, false) + require.NotNil(t, err) // value and amounts not equal + + // allowed delegatecall + contractAddrAllowed := common.BytesToAddress([]byte("contractA")) + testApp.EvmKeeper.SetERC20CW20Pointer(ctx, contractAddr.String(), contractAddrAllowed) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrAllowed, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + + // disallowed delegatecall + contractAddrDisallowed := common.BytesToAddress([]byte("contractB")) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrDisallowed, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + + // bad contract address + executeMsg = wasmd.ExecuteMsg{ + ContractAddress: mockAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsg}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + + // bad inputs + executeMsg = wasmd.ExecuteMsg{ + ContractAddress: "not bech32", + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsg}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + executeMsg = wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: []byte("bad coins"), + } + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsg}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) +} + +func TestExecuteBatchMultipleMessages(t *testing.T) { + testApp := app.Setup(false, false) + mockAddr, mockEVMAddr := testkeeper.MockAddressPair() + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockTime(time.Now()) + 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))) + largeAmts := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(3000))) + testApp.BankKeeper.MintCoins(ctx, "evm", sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(13000)))) + testApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", mockAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(13000)))) + amtsbz, err := amts.MarshalJSON() + require.Nil(t, err) + executeMethod, err := p.ABI.MethodById(p.ExecuteBatchID) + require.Nil(t, err) + executeMsgWithCoinsAmt := wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + + statedb := state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm := vm.EVM{ + StateDB: statedb, + } + suppliedGas := uint64(1000000) + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), largeAmts) + require.Nil(t, err) + args, err := executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithCoinsAmt, executeMsgWithCoinsAmt, executeMsgWithCoinsAmt}) + require.Nil(t, err) + res, g, err := p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(3000_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)) + parsedOutputs := outputs[0].([][]byte) + 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(725379), g) + require.Equal(t, int64(3000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) + + amtsbz2, err := sdk.NewCoins().MarshalJSON() + require.Nil(t, err) + executeMsgWithNoCoins := wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz2, + } + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), amts) + require.Nil(t, err) + args, err = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithNoCoins, executeMsgWithCoinsAmt, executeMsgWithNoCoins}) + require.Nil(t, err) + res, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, 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)) + parsedOutputs = outputs[0].([][]byte) + 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(773900), g) + require.Equal(t, int64(1000), testApp.BankKeeper.GetBalance(statedb.Ctx(), contractAddr, "usei").Amount.Int64()) + + // allowed delegatecall + args, err = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithNoCoins, executeMsgWithNoCoins}) + require.Nil(t, err) + contractAddrAllowed := common.BytesToAddress([]byte("contractA")) + testApp.EvmKeeper.SetERC20CW20Pointer(ctx, contractAddr.String(), contractAddrAllowed) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrAllowed, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.Nil(t, err) + + // disallowed delegatecall + contractAddrDisallowed := common.BytesToAddress([]byte("contractB")) + _, _, err = p.RunAndCalculateGas(&evm, mockEVMAddr, contractAddrDisallowed, append(p.ExecuteBatchID, args...), suppliedGas, nil, nil, false) + require.NotNil(t, err) + + // bad contract address + executeMsgBadContract := wasmd.ExecuteMsg{ + ContractAddress: mockAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), largeAmts) + require.Nil(t, err) + args, err = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithCoinsAmt, executeMsgBadContract, executeMsgWithCoinsAmt}) + require.Nil(t, err) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(3000_000_000_000_000), nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + + // bad inputs + executeMsgBadInputs := wasmd.ExecuteMsg{ + ContractAddress: "not bech32", + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: amtsbz, + } + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), largeAmts) + require.Nil(t, err) + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithCoinsAmt, executeMsgBadInputs, executeMsgWithCoinsAmt}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(3000_000_000_000_000), nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) + executeMsgBadInputCoins := wasmd.ExecuteMsg{ + ContractAddress: contractAddr.String(), + Msg: []byte("{\"echo\":{\"message\":\"test msg\"}}"), + Coins: []byte("bad coins"), + } + statedb = state.NewDBImpl(ctx, &testApp.EvmKeeper, true) + evm = vm.EVM{ + StateDB: statedb, + } + err = testApp.BankKeeper.SendCoins(ctx, mockAddr, testApp.EvmKeeper.GetSeiAddressOrDefault(ctx, common.HexToAddress(wasmd.WasmdAddress)), largeAmts) + require.Nil(t, err) + args, _ = executeMethod.Inputs.Pack([]wasmd.ExecuteMsg{executeMsgWithCoinsAmt, executeMsgBadInputCoins, executeMsgWithCoinsAmt}) + _, g, err = p.RunAndCalculateGas(&evm, mockEVMAddr, mockEVMAddr, append(p.ExecuteBatchID, args...), suppliedGas, big.NewInt(3000_000_000_000_000), nil, false) + require.NotNil(t, err) + require.Equal(t, uint64(0), g) +} diff --git a/proto/eth/tx.proto b/proto/eth/tx.proto new file mode 100644 index 0000000000..2374ba03a5 --- /dev/null +++ b/proto/eth/tx.proto @@ -0,0 +1,157 @@ +syntax = "proto3"; +package seiprotocol.seichain.eth; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types/ethtx"; + +// Source: https://github.com/evmos/evmos/blob/main/proto/ethermint/evm/v1/tx.proto + +message AccessTuple { + option (gogoproto.goproto_getters) = false; + + string address = 1; + repeated string storage_keys = 2 [ + (gogoproto.jsontag) = "storageKeys" + ]; + } + + message AssociateTx { + option (gogoproto.goproto_getters) = false; + // signature values + bytes v = 1; + bytes r = 2; + bytes s = 3; + string custom_message = 4; + } + +message LegacyTx { + option (gogoproto.goproto_getters) = false; + + uint64 nonce = 1; + string gas_price = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int" + ]; + uint64 gas_limit = 3; + string to = 4; + string value = 5 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.customname) = "Amount" + ]; + bytes data = 6; + // signature values + bytes v = 7; + bytes r = 8; + bytes s = 9; +} + +message AccessListTx { + option (gogoproto.goproto_getters) = false; + +string chain_id = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.customname) = "ChainID", + (gogoproto.jsontag) = "chainID" +]; +uint64 nonce = 2; +string gas_price = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int" +]; +uint64 gas_limit = 4; +string to = 5; +string value = 6 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.customname) = "Amount" +]; +bytes data = 7; +repeated AccessTuple accesses = 8 [ + (gogoproto.castrepeated) = "AccessList", + (gogoproto.jsontag) = "accessList", + (gogoproto.nullable) = false +]; +// signature values +bytes v = 9; +bytes r = 10; +bytes s = 11; +} + +message DynamicFeeTx { + option (gogoproto.goproto_getters) = false; + +string chain_id = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.customname) = "ChainID", + (gogoproto.jsontag) = "chainID" +]; +uint64 nonce = 2; +string gas_tip_cap = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int" +]; +string gas_fee_cap = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int" +]; +uint64 gas_limit = 5; +string to = 6; +string value = 7 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.customname) = "Amount" +]; +bytes data = 8; +repeated AccessTuple accesses = 9 [ + (gogoproto.castrepeated) = "AccessList", + (gogoproto.jsontag) = "accessList", + (gogoproto.nullable) = false +]; +// signature values +bytes v = 10; +bytes r = 11; +bytes s = 12; +} + +message BlobTx { + option (gogoproto.goproto_getters) = false; + +string chain_id = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.customname) = "ChainID", + (gogoproto.jsontag) = "chainID" +]; +uint64 nonce = 2; +string gas_tip_cap = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int" +]; +string gas_fee_cap = 4 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int" +]; +uint64 gas_limit = 5; +string to = 6; +string value = 7 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.customname) = "Amount" +]; +bytes data = 8; +repeated AccessTuple accesses = 9 [ + (gogoproto.castrepeated) = "AccessList", + (gogoproto.jsontag) = "accessList", + (gogoproto.nullable) = false +]; +string blob_fee_cap = 10 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int" +]; +repeated bytes blob_hashes = 11; +BlobTxSidecar sidecar = 12; +// signature values +bytes v = 13; +bytes r = 14; +bytes s = 15; +} + +message BlobTxSidecar { + repeated bytes blobs = 1; + repeated bytes commitments = 2; + repeated bytes proofs = 3; +} + +message ExtensionOptionsEthereumTx { +option (gogoproto.goproto_getters) = false; +} \ No newline at end of file diff --git a/proto/evm/config.proto b/proto/evm/config.proto new file mode 100644 index 0000000000..bcde98afbe --- /dev/null +++ b/proto/evm/config.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +/* +* +XXTime fields indicate upgrade timestamps. For example, a ShanghaiTime +of 42198537129 means the chain upgraded to the Shanghai version at timestamp 42198537129. +A value of 0 means the upgrade is included in the genesis of the EVM on Sei. +-1 means upgrade not reached yet. +*/ +message ChainConfig { + int64 cancun_time = 1 [ + (gogoproto.moretags) = "yaml:\"cancun_time\"" + ]; + int64 prague_time = 2 [ + (gogoproto.moretags) = "yaml:\"prague_time\"" + ]; + int64 verkle_time = 3 [ + (gogoproto.moretags) = "yaml:\"verkle_time\"" + ]; + } \ No newline at end of file diff --git a/proto/evm/enums.proto b/proto/evm/enums.proto new file mode 100644 index 0000000000..fefdee9abc --- /dev/null +++ b/proto/evm/enums.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +enum PointerType { + ERC20 = 0; + ERC721 = 1; + NATIVE = 2; + CW20 = 3; + CW721 = 4; + } \ No newline at end of file diff --git a/proto/evm/genesis.proto b/proto/evm/genesis.proto new file mode 100644 index 0000000000..6862e42f9f --- /dev/null +++ b/proto/evm/genesis.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +import "gogoproto/gogo.proto"; +import "evm/params.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +// AddressAssociation represents an association between a Cosmos and an Ethereum address. +message AddressAssociation { + string sei_address = 1; // Sei address + string eth_address = 2; // Ethereum address +} + +// 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 +} diff --git a/proto/evm/gov.proto b/proto/evm/gov.proto new file mode 100644 index 0000000000..0425df2de3 --- /dev/null +++ b/proto/evm/gov.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +message AddERCNativePointerProposal { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; + string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; + string token = 3 [(gogoproto.moretags) = "yaml:\"token\""]; + string pointer = 4 [(gogoproto.moretags) = "yaml:\"pointer\""]; + uint32 version = 5 [(gogoproto.moretags) = "yaml:\"version\""]; +} + +message AddERCCW20PointerProposal { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; + string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; + string pointee = 3 [(gogoproto.moretags) = "yaml:\"pointee\""]; + string pointer = 4 [(gogoproto.moretags) = "yaml:\"pointer\""]; + uint32 version = 5 [(gogoproto.moretags) = "yaml:\"version\""]; +} + +message AddERCCW721PointerProposal { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; + string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; + string pointee = 3 [(gogoproto.moretags) = "yaml:\"pointee\""]; + string pointer = 4 [(gogoproto.moretags) = "yaml:\"pointer\""]; + uint32 version = 5 [(gogoproto.moretags) = "yaml:\"version\""]; +} diff --git a/proto/evm/params.proto b/proto/evm/params.proto new file mode 100644 index 0000000000..5bdfb7221a --- /dev/null +++ b/proto/evm/params.proto @@ -0,0 +1,50 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +import "gogoproto/gogo.proto"; +import "evm/config.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +// Params defines the parameters for the module. +message Params { + option (gogoproto.goproto_stringer) = false; + + // string base_denom = 1 [ + // (gogoproto.moretags) = "yaml:\"base_denom\"", + // (gogoproto.jsontag) = "base_denom" + // ]; + string priority_normalizer = 2 [ + (gogoproto.moretags) = "yaml:\"priority_normalizer\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "priority_normalizer" + ]; + string base_fee_per_gas = 3 [ + (gogoproto.moretags) = "yaml:\"base_fee_per_gas\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "base_fee_per_gas" +]; +string minimum_fee_per_gas = 4 [ + (gogoproto.moretags) = "yaml:\"minimum_fee_per_gas\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "minimum_fee_per_gas" +]; + // ChainConfig chain_config = 5 [(gogoproto.moretags) = "yaml:\"chain_config\"", (gogoproto.nullable) = false]; + string chain_id = 6 [ + (gogoproto.moretags) = "yaml:\"chain_id\"", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "chain_id" +]; + // repeated string whitelisted_codehashes_bank_send = 7 [ + // (gogoproto.moretags) = "yaml:\"whitelisted_codehashes_bank_send\"", + // (gogoproto.jsontag) = "whitelisted_codehashes_bank_send" + // ]; + repeated bytes whitelisted_cw_code_hashes_for_delegate_call = 8 [ + (gogoproto.moretags) = "yaml:\"whitelisted_cw_code_hashes_for_delegate_call\"", + (gogoproto.jsontag) = "whitelisted_cw_code_hashes_for_delegate_call" + ]; +} \ No newline at end of file diff --git a/proto/evm/query.proto b/proto/evm/query.proto new file mode 100644 index 0000000000..6f90daa9bd --- /dev/null +++ b/proto/evm/query.proto @@ -0,0 +1,64 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +import "google/api/annotations.proto"; +import "evm/enums.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +// Query defines the gRPC querier service. +service Query { + rpc SeiAddressByEVMAddress(QuerySeiAddressByEVMAddressRequest) returns (QuerySeiAddressByEVMAddressResponse) { + option (google.api.http).get = "/sei-protocol/seichain/evm/sei_address"; + } + + rpc EVMAddressBySeiAddress(QueryEVMAddressBySeiAddressRequest) returns (QueryEVMAddressBySeiAddressResponse) { + option (google.api.http).get = "/sei-protocol/seichain/evm/evm_address"; + } + + rpc StaticCall(QueryStaticCallRequest) returns (QueryStaticCallResponse) { + option (google.api.http).get = "/sei-protocol/seichain/evm/static_call"; + } + + rpc Pointer(QueryPointerRequest) returns (QueryPointerResponse) { + option (google.api.http).get = "/sei-protocol/seichain/evm/pointer"; + } +} + +message QuerySeiAddressByEVMAddressRequest { + string evm_address = 1; +} + +message QuerySeiAddressByEVMAddressResponse { + string sei_address = 1; + bool associated = 2; +} + +message QueryEVMAddressBySeiAddressRequest { + string sei_address = 1; +} + +message QueryEVMAddressBySeiAddressResponse { + string evm_address = 1; + bool associated = 2; +} + +message QueryStaticCallRequest { + bytes data = 1; + string to = 2; +} + +message QueryStaticCallResponse { + bytes data = 1; +} + +message QueryPointerRequest { + PointerType pointer_type = 1; + string pointee = 2; +} + +message QueryPointerResponse { + string pointer = 1; + uint32 version = 2; + bool exists = 3; +} diff --git a/proto/evm/receipt.proto b/proto/evm/receipt.proto new file mode 100644 index 0000000000..49751bb01e --- /dev/null +++ b/proto/evm/receipt.proto @@ -0,0 +1,54 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +message Log { + string address = 1; + repeated string topics = 2; + bytes data = 3; + uint32 index = 4; +} + +message Receipt { + uint32 tx_type = 1 [ + (gogoproto.moretags) = "yaml:\"tx_type\"" + ]; + uint64 cumulative_gas_used = 2 [ + (gogoproto.moretags) = "yaml:\"cumulative_gas_used\"" + ]; + string contract_address = 3 [ + (gogoproto.moretags) = "yaml:\"contract_address\"" + ]; + string tx_hash_hex = 4 [ + (gogoproto.moretags) = "yaml:\"tx_hash_hex\"" + ]; + uint64 gas_used = 5 [ + (gogoproto.moretags) = "yaml:\"gas_used\"" + ]; + uint64 effective_gas_price = 6 [ + (gogoproto.moretags) = "yaml:\"effective_gas_price\"" + ]; + uint64 block_number = 7 [ + (gogoproto.moretags) = "yaml:\"block_number\"" + ]; + uint32 transaction_index = 8 [ + (gogoproto.moretags) = "yaml:\"transaction_index\"" + ]; + uint32 status = 9 [ + (gogoproto.moretags) = "yaml:\"status\"" + ]; + string from = 10 [ + (gogoproto.moretags) = "yaml:\"from\"" + ]; + string to = 11 [ + (gogoproto.moretags) = "yaml:\"to\"" + ]; + string vm_error = 12 [ + (gogoproto.moretags) = "yaml:\"vm_error\"" + ]; + repeated Log logs = 13; + bytes logsBloom = 14; +} diff --git a/proto/evm/tx.proto b/proto/evm/tx.proto new file mode 100644 index 0000000000..03eaa8ce90 --- /dev/null +++ b/proto/evm/tx.proto @@ -0,0 +1,67 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +import "google/protobuf/any.proto"; +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "evm/enums.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +service Msg { + rpc EVMTransaction(MsgEVMTransaction) returns (MsgEVMTransactionResponse); + rpc Send(MsgSend) returns (MsgSendResponse); + rpc RegisterPointer(MsgRegisterPointer) returns (MsgRegisterPointerResponse); +} + +message MsgEVMTransaction { + google.protobuf.Any data = 1; + bytes derived = 2 [(gogoproto.customtype) = "github.com/sei-protocol/sei-chain/x/evm/derived.Derived"]; +} + +message MsgEVMTransactionResponse { + uint64 gas_used = 1; + string vm_error = 2; + bytes return_data = 3; + string hash = 4; +} + +message MsgInternalEVMCall { + string sender = 1; + string value = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int" + ]; + string to = 3; + bytes data = 4; +} + +message MsgInternalEVMCallResponse {} + +message MsgInternalEVMDelegateCall { + string sender = 1; + bytes codeHash = 2; + string to = 3; + bytes data = 4; + string fromContract = 5; +} + +message MsgInternalEVMDelegateCallResponse {} + +message MsgSend { + string from_address = 1; + string to_address = 2; + repeated cosmos.base.v1beta1.Coin amount = 3 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} + +message MsgSendResponse {} + +message MsgRegisterPointer { + string sender = 1; + PointerType pointer_type = 2; + string erc_address = 3; +} + +message MsgRegisterPointerResponse { + string pointer_address = 1; +} diff --git a/proto/evm/types.proto b/proto/evm/types.proto new file mode 100644 index 0000000000..221781a9df --- /dev/null +++ b/proto/evm/types.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package seiprotocol.seichain.evm; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/sei-protocol/sei-chain/x/evm/types"; + +message Whitelist { + repeated string hashes = 1 [ + (gogoproto.moretags) = "yaml:\"hashes\"" + ]; +} \ No newline at end of file diff --git a/run_blocktests.sh b/run_blocktests.sh new file mode 100755 index 0000000000..05367f6d54 --- /dev/null +++ b/run_blocktests.sh @@ -0,0 +1,101 @@ +#!/bin/bash + +set -e + +# mode options are list, run, or all +block_tests_path=$1 +runner_index=$2 +runner_total=$3 + +if [ -z "$runner_index" ]; then + runner_index=0 + runner_total=1 +fi + +echo $mode +echo $block_tests_path + +# Define an array of test directories to run +declare -a test_path_run_list=( + # run all valid block tests + "ValidBlocks/" + + # run only certain invalid block tests + "InvalidBlocks/bcEIP1559/" + "InvalidBlocks/bcStateTests/" +) + +# Define an array of tests to skip +declare -a test_name_skip_list=( + # valid block tests + "DelegateCallSpam" # passes, but takes super long + "blockhashTests" # failing + "blockhashNonConstArg" # failing + "BLOCKHASH_Bounds" # failing + "logRevert" # uses an invalid opcode (0xBA) + "blockWithAllTransactionTypes" # recently started failing + + # invalid block tests - state tests + "gasLimitTooHigh" # block header gas limit doesn't apply to us + "transactionFromSelfDestructedContract" # failing + + # InvaldBlockTests/bcEIP1559 + "badUncles" # reorgs don't apply to us + "checkGasLimit" # not sure what issue is +) + +# list out all paths to json files starting from the block_tests_dir +block_tests=$(find "$block_tests_path" -name "*.json" | sort) + +i=0 + +# for each json file, run the block test +for test_path in $block_tests; do + test_name=$(basename "$test_path" .json) + match_found=false + + # Iterate through the test_path_run_list to check for a match + for run_path in "${test_path_run_list[@]}"; do + if [[ "$test_path" == *"$run_path"* ]]; then + match_found=true + break + fi + done + + # Skip the test if no match is found + if [ "$match_found" = false ]; then + continue + fi + + echo "test file: $test_path" + echo "test dir: $test_path" + + # Check if the test name is in the skip list + if printf '%s\n' "${test_name_skip_list[@]}" | grep -qx "$test_name"; then + echo "Skipping test in skip list: $test_path" + continue + fi + + # Check if "${test_name}_Cancun" is not in the test file + if ! grep -q "${test_name}_Cancun" "$test_path"; then + echo "Skipping test due to missing Cancun tag: $test_path" + continue + fi + + if [ $((i % runner_total)) -ne $runner_index ]; then + i=$((i+1)) + runner_id=$((i % runner_total)) + echo "Skipping test not in runner index: $test_path, runner index: $runner_id" + continue + fi + + i=$((i+1)) + + echo -e "\n*********************************************************\n" + echo "Running block test: $test_path" + echo "test name: ${test_name}_Cancun" + echo -e "\n*********************************************************\n" + rm -r ~/.sei || true + NO_RUN=1 ./scripts/initialize_local_chain.sh + seid blocktest --block-test $test_path --test-name "${test_name}_Cancun" +done diff --git a/scripts/hardhat.sh b/scripts/hardhat.sh new file mode 100755 index 0000000000..d38f62b1de --- /dev/null +++ b/scripts/hardhat.sh @@ -0,0 +1,4 @@ +cd contracts +npm ci +npx hardhat test --network seilocal test/EVMCompatabilityTester.js +npx hardhat test --network seilocal test/EVMPrecompileTester.js diff --git a/scripts/initialize_local_chain.sh b/scripts/initialize_local_chain.sh index a2f5d24034..08b3d6b012 100755 --- a/scripts/initialize_local_chain.sh +++ b/scripts/initialize_local_chain.sh @@ -36,7 +36,7 @@ make install ~/go/bin/seid init demo --chain-id sei-chain ~/go/bin/seid keys add $keyname --keyring-backend test # add the key as a genesis account with massive balances of several different tokens -~/go/bin/seid add-genesis-account $(~/go/bin/seid keys show $keyname -a --keyring-backend test) 100000000000000000000usei,100000000000000000000uusdc,100000000000000000000uatom +~/go/bin/seid add-genesis-account $(~/go/bin/seid keys show $keyname -a --keyring-backend test) 100000000000000000000usei,100000000000000000000uusdc,100000000000000000000uatom --keyring-backend test # gentx for account ~/go/bin/seid gentx $keyname 7000000000000000usei --chain-id sei-chain --keyring-backend test # add validator information to genesis file @@ -60,6 +60,7 @@ cat ~/.sei/config/genesis.json | jq '.app_state["oracle"]["params"]["whitelist"] cat ~/.sei/config/genesis.json | jq '.app_state["distribution"]["params"]["community_tax"]="0.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.consensus_params["block"]["max_gas"]="35000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json cat ~/.sei/config/genesis.json | jq '.app_state["staking"]["params"]["max_voting_power_ratio"]="1.000000000000000000"' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json +cat ~/.sei/config/genesis.json | jq '.app_state["bank"]["denom_metadata"]=[{"denom_units":[{"denom":"UATOM","exponent":6,"aliases":["UATOM"]}],"base":"uatom","display":"uatom","name":"UATOM","symbol":"UATOM"}]' > ~/.sei/config/tmp_genesis.json && mv ~/.sei/config/tmp_genesis.json ~/.sei/config/genesis.json # Use the Python command to get the dates START_DATE=$($PYTHON_CMD -c "from datetime import datetime; print(datetime.now().strftime('%Y-%m-%d'))") @@ -76,6 +77,12 @@ else CONFIG_PATH="$HOME/.sei/config/config.toml" fi +if [ ! -z "$2" ]; then + APP_PATH="$2" +else + APP_PATH="$HOME/.sei/config/app.toml" +fi + if [[ "$OSTYPE" == "linux-gnu"* ]]; then sed -i 's/mode = "full"/mode = "validator"/g' $CONFIG_PATH sed -i 's/indexer = \["null"\]/indexer = \["kv"\]/g' $CONFIG_PATH @@ -83,6 +90,7 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then sed -i 's/timeout_precommit =.*/timeout_precommit = "2000ms"/g' $CONFIG_PATH sed -i 's/timeout_commit =.*/timeout_commit = "2000ms"/g' $CONFIG_PATH sed -i 's/skip_timeout_commit =.*/skip_timeout_commit = false/g' $CONFIG_PATH + # sed -i 's/slow = false/slow = true/g' $APP_PATH elif [[ "$OSTYPE" == "darwin"* ]]; then sed -i '' 's/mode = "full"/mode = "validator"/g' $CONFIG_PATH sed -i '' 's/indexer = \["null"\]/indexer = \["kv"\]/g' $CONFIG_PATH @@ -91,6 +99,7 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then sed -i '' 's/unsafe-vote-timeout-override =.*/unsafe-vote-timeout-override = "2s"/g' $CONFIG_PATH sed -i '' 's/unsafe-vote-timeout-delta-override =.*/unsafe-vote-timeout-delta-override = "2s"/g' $CONFIG_PATH sed -i '' 's/unsafe-commit-timeout-override =.*/unsafe-commit-timeout-override = "2s"/g' $CONFIG_PATH + # sed -i '' 's/slow = false/slow = true/g' $APP_PATH else printf "Platform not supported, please ensure that the following values are set in your config.toml:\n" printf "### Consensus Configuration Options ###\n" @@ -103,5 +112,10 @@ fi ~/go/bin/seid config keyring-backend test +if [ $NO_RUN = 1 ]; then + echo "No run flag set, exiting without starting the chain" + exit 0 +fi + # start the chain with log tracing GORACE="log_path=/tmp/race/seid_race" ~/go/bin/seid start --trace --chain-id sei-chain diff --git a/testutil/keeper/dex.go b/testutil/keeper/dex.go index 8f6dad8dce..5681676b7b 100644 --- a/testutil/keeper/dex.go +++ b/testutil/keeper/dex.go @@ -48,7 +48,7 @@ var ( ) func TestApp() *app.App { - return app.Setup(false) + return app.Setup(false, false) } func DexKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { diff --git a/testutil/keeper/evm.go b/testutil/keeper/evm.go new file mode 100644 index 0000000000..d5449ad590 --- /dev/null +++ b/testutil/keeper/evm.go @@ -0,0 +1,102 @@ +package keeper + +import ( + "encoding/hex" + "sync" + "time" + + "github.com/cosmos/cosmos-sdk/crypto/hd" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/go-bip39" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/sei-protocol/sei-chain/app" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" +) + +var EVMTestApp = app.Setup(false, true) +var mockKeeper *evmkeeper.Keeper +var mockCtx sdk.Context +var mtx = &sync.Mutex{} + +func MockEVMKeeperWithPrecompiles() (*evmkeeper.Keeper, sdk.Context) { + mtx.Lock() + defer mtx.Unlock() + if mockKeeper != nil { + return mockKeeper, mockCtx + } + ctx := EVMTestApp.GetContextForDeliverTx([]byte{}).WithBlockHeight(8) + k := EVMTestApp.EvmKeeper + k.InitGenesis(ctx, *evmtypes.DefaultGenesis()) + + // mint some coins to a sei address + seiAddr, err := sdk.AccAddressFromHex(common.Bytes2Hex([]byte("seiAddr"))) + if err != nil { + panic(err) + } + err = EVMTestApp.BankKeeper.MintCoins(ctx, "evm", sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))) + if err != nil { + panic(err) + } + err = EVMTestApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", seiAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))) + if err != nil { + panic(err) + } + mockKeeper = &k + mockCtx = ctx + return &k, ctx +} + +func MockEVMKeeper() (*evmkeeper.Keeper, sdk.Context) { + testApp := app.Setup(false, false) + ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockHeight(8).WithBlockTime(time.Now()) + k := testApp.EvmKeeper + k.InitGenesis(ctx, *evmtypes.DefaultGenesis()) + + // mint some coins to a sei address + seiAddr, err := sdk.AccAddressFromHex(common.Bytes2Hex([]byte("seiAddr"))) + if err != nil { + panic(err) + } + err = testApp.BankKeeper.MintCoins(ctx, "evm", sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))) + if err != nil { + panic(err) + } + err = testApp.BankKeeper.SendCoinsFromModuleToAccount(ctx, "evm", seiAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10)))) + if err != nil { + panic(err) + } + return &k, ctx +} + +func MockAddressPair() (sdk.AccAddress, common.Address) { + return PrivateKeyToAddresses(MockPrivateKey()) +} + +func MockPrivateKey() cryptotypes.PrivKey { + // Generate a new Sei private key + entropySeed, _ := bip39.NewEntropy(256) + mnemonic, _ := bip39.NewMnemonic(entropySeed) + algo := hd.Secp256k1 + derivedPriv, _ := algo.Derive()(mnemonic, "", "") + return algo.Generate()(derivedPriv) +} + +func PrivateKeyToAddresses(privKey cryptotypes.PrivKey) (sdk.AccAddress, common.Address) { + // Encode the private key to hex (i.e. what wallets do behind the scene when users reveal private keys) + testPrivHex := hex.EncodeToString(privKey.Bytes()) + + // Sign an Ethereum transaction with the hex private key + key, _ := crypto.HexToECDSA(testPrivHex) + msg := crypto.Keccak256([]byte("foo")) + sig, _ := crypto.Sign(msg, key) + + // Recover the public keys from the Ethereum signature + recoveredPub, _ := crypto.Ecrecover(msg, sig) + pubKey, _ := crypto.UnmarshalPubkey(recoveredPub) + + return sdk.AccAddress(privKey.PubKey().Address()), crypto.PubkeyToAddress(*pubKey) +} diff --git a/testutil/network/network.go b/testutil/network/network.go index 5759e53193..836703fa6f 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -10,7 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/hd" "github.com/cosmos/cosmos-sdk/crypto/keyring" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/simapp" storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" @@ -26,6 +25,21 @@ type ( Config = network.Config ) +type TestAppOptions struct{} + +func (t TestAppOptions) Get(s string) interface{} { + if s == "chain-id" { + return "test-chain" + } + if s == "evm.http_enabled" { + return false + } + if s == "evm.ws_enabled" { + return false + } + return nil +} + // New creates instance with fully configured cosmos network. // Accepts optional config, that will be used in place of the DefaultConfig() if provided. func New(t *testing.T, configs ...network.Config) *network.Network { @@ -55,11 +69,11 @@ func DefaultConfig() network.Config { AccountRetriever: authtypes.AccountRetriever{}, AppConstructor: func(val network.Validator) servertypes.Application { return app.New( - val.Ctx.Logger, tmdb.NewMemDB(), nil, true, map[int64]bool{}, val.Ctx.Config.RootDir, 0, + val.Ctx.Logger, tmdb.NewMemDB(), nil, true, map[int64]bool{}, val.Ctx.Config.RootDir, 0, false, nil, encoding, wasm.EnableAllProposals, - &simapp.EmptyAppOptions{}, + &TestAppOptions{}, nil, app.EmptyACLOpts, baseapp.SetPruning(storetypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), diff --git a/testutil/processblock/common.go b/testutil/processblock/common.go index 7c703f8861..07e8a500c8 100644 --- a/testutil/processblock/common.go +++ b/testutil/processblock/common.go @@ -33,7 +33,7 @@ type App struct { func NewTestApp() *App { a := &App{ - App: app.Setup(false), + App: app.Setup(false, false), height: 1, accToMnemonic: map[string]string{}, accToSeqDelta: map[string]uint64{}, diff --git a/utils/constants.go b/utils/constants.go new file mode 100644 index 0000000000..f25c156e1e --- /dev/null +++ b/utils/constants.go @@ -0,0 +1,19 @@ +package utils + +import ( + "math" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var Big0 = big.NewInt(0) +var Big1 = big.NewInt(1) +var Big2 = big.NewInt(2) +var Big8 = big.NewInt(8) +var Big27 = big.NewInt(27) +var Big35 = big.NewInt(35) +var BigMaxI64 = big.NewInt(math.MaxInt64) +var BigMaxU64 = new(big.Int).SetUint64(math.MaxUint64) + +var Sdk0 = sdk.NewInt(0) diff --git a/utils/metrics/metrics_util.go b/utils/metrics/metrics_util.go index 2520cee38f..ae9d625ae9 100644 --- a/utils/metrics/metrics_util.go +++ b/utils/metrics/metrics_util.go @@ -176,6 +176,18 @@ func IncrPriceUpdateDenom(denom string) { ) } +// Measures throughput per message type +// Metric Name: +// +// sei_throughput_ +func SetThroughputMetricByType(metricName string, value float32, msgType string) { + telemetry.SetGaugeWithLabels( + []string{"sei", "loadtest", "tps", metricName}, + value, + []metrics.Label{telemetry.NewLabel("msg_type", msgType)}, + ) +} + // Measures the number of times the total block gas wanted in the proposal exceeds the max // Metric Name: // @@ -235,3 +247,56 @@ func IncrementOptimisticProcessingCounter(enabled bool) { []metrics.Label{telemetry.NewLabel("enabled", strconv.FormatBool(enabled))}, ) } + +// Measures RPC endpoint request throughput +// Metric Name: +// +// sei_rpc_request_counter +func IncrementRpcRequestCounter(endpoint string, success bool) { + telemetry.IncrCounterWithLabels( + []string{"sei", "rpc", "request", "counter"}, + float32(1), + []metrics.Label{ + telemetry.NewLabel("endpoint", endpoint), + telemetry.NewLabel("success", strconv.FormatBool(success)), + }, + ) +} + +// Measures the RPC request latency in milliseconds +// Metric Name: +// +// sei_rpc_request_latency_ms +func MeasureRpcRequestLatency(endpoint string, startTime time.Time) { + metrics.MeasureSinceWithLabels( + []string{"sei", "rpc", "request", "latency_ms"}, + startTime.UTC(), + []metrics.Label{telemetry.NewLabel("endpoint", endpoint)}, + ) +} + +// IncrProducerEventCount increments the counter for events produced. +// This metric counts the number of events produced by the system. +// Metric Name: +// +// sei_loadtest_produce_count +func IncrProducerEventCount(msgType string) { + telemetry.IncrCounterWithLabels( + []string{"sei", "loadtest", "produce", "count"}, + 1, + []metrics.Label{telemetry.NewLabel("msg_type", msgType)}, + ) +} + +// IncrConsumerEventCount increments the counter for events consumed. +// This metric counts the number of events consumed by the system. +// Metric Name: +// +// sei_loadtest_consume_count +func IncrConsumerEventCount(msgType string) { + telemetry.IncrCounterWithLabels( + []string{"sei", "loadtest", "consume", "count"}, + 1, + []metrics.Label{telemetry.NewLabel("msg_type", msgType)}, + ) +} diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index 2d26e5375c..7e633640db 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -46,3 +46,14 @@ type CancelOrders struct { Cancellations []*types.Cancellation `json:"cancellations"` ContractAddr string `json:"contract_address"` } + +type CallEVM struct { + Value *sdk.Int `json:"value"` + To string `json:"to"` + Data string `json:"data"` // base64 +} + +type DelegateCallEVM struct { + To string `json:"to"` + Data string `json:"data"` // base64 +} diff --git a/wasmbinding/encoder.go b/wasmbinding/encoder.go index bdd2dfcb21..1e691b8d61 100644 --- a/wasmbinding/encoder.go +++ b/wasmbinding/encoder.go @@ -8,20 +8,23 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" dexwasm "github.com/sei-protocol/sei-chain/x/dex/client/wasm" + evmwasm "github.com/sei-protocol/sei-chain/x/evm/client/wasm" tokenfactorywasm "github.com/sei-protocol/sei-chain/x/tokenfactory/client/wasm" ) type SeiWasmMessage struct { - PlaceOrders json.RawMessage `json:"place_orders,omitempty"` - CancelOrders json.RawMessage `json:"cancel_orders,omitempty"` - CreateDenom json.RawMessage `json:"create_denom,omitempty"` - MintTokens json.RawMessage `json:"mint_tokens,omitempty"` - BurnTokens json.RawMessage `json:"burn_tokens,omitempty"` - ChangeAdmin json.RawMessage `json:"change_admin,omitempty"` - SetMetadata json.RawMessage `json:"set_metadata,omitempty"` + PlaceOrders json.RawMessage `json:"place_orders,omitempty"` + CancelOrders json.RawMessage `json:"cancel_orders,omitempty"` + CreateDenom json.RawMessage `json:"create_denom,omitempty"` + MintTokens json.RawMessage `json:"mint_tokens,omitempty"` + BurnTokens json.RawMessage `json:"burn_tokens,omitempty"` + ChangeAdmin json.RawMessage `json:"change_admin,omitempty"` + SetMetadata json.RawMessage `json:"set_metadata,omitempty"` + CallEVM json.RawMessage `json:"call_evm,omitempty"` + DelegateCallEVM json.RawMessage `json:"delegate_call_evm,omitempty"` } -func CustomEncoder(sender sdk.AccAddress, msg json.RawMessage, _ wasmvmtypes.MessageInfo, _ wasmtypes.CodeInfo) ([]sdk.Msg, error) { +func CustomEncoder(sender sdk.AccAddress, msg json.RawMessage, info wasmvmtypes.MessageInfo, codeInfo wasmtypes.CodeInfo) ([]sdk.Msg, error) { var parsedMessage SeiWasmMessage if err := json.Unmarshal(msg, &parsedMessage); err != nil { return []sdk.Msg{}, sdkerrors.Wrap(err, "Error parsing Sei Wasm Message") @@ -41,6 +44,10 @@ func CustomEncoder(sender sdk.AccAddress, msg json.RawMessage, _ wasmvmtypes.Mes return tokenfactorywasm.EncodeTokenFactoryChangeAdmin(parsedMessage.ChangeAdmin, sender) case parsedMessage.SetMetadata != nil: return tokenfactorywasm.EncodeTokenFactorySetMetadata(parsedMessage.SetMetadata, sender) + case parsedMessage.CallEVM != nil: + return evmwasm.EncodeCallEVM(parsedMessage.CallEVM, sender, info) + case parsedMessage.DelegateCallEVM != nil: + return evmwasm.EncodeDelegateCallEVM(parsedMessage.DelegateCallEVM, sender, info, codeInfo) default: return []sdk.Msg{}, wasmvmtypes.UnsupportedRequest{Kind: "Unknown Sei Wasm Message"} } diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index d34a240a88..8a5cf96877 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -3,18 +3,44 @@ package wasmbinding import ( wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/cosmos/cosmos-sdk/baseapp" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" aclkeeper "github.com/cosmos/cosmos-sdk/x/accesscontrol/keeper" acltypes "github.com/cosmos/cosmos-sdk/x/accesscontrol/types" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" ) +type CustomRouter struct { + wasmkeeper.MessageRouter + + evmKeeper *evmkeeper.Keeper +} + +func (r *CustomRouter) Handler(msg sdk.Msg) baseapp.MsgServiceHandler { + switch m := msg.(type) { + case *evmtypes.MsgInternalEVMCall: + return func(ctx sdk.Context, _ sdk.Msg) (*sdk.Result, error) { + return r.evmKeeper.HandleInternalEVMCall(ctx, m) + } + case *evmtypes.MsgInternalEVMDelegateCall: + return func(ctx sdk.Context, _ sdk.Msg) (*sdk.Result, error) { + return r.evmKeeper.HandleInternalEVMDelegateCall(ctx, m) + } + default: + return r.MessageRouter.Handler(msg) + } +} + // forked from wasm func CustomMessageHandler( router wasmkeeper.MessageRouter, channelKeeper wasmtypes.ChannelKeeper, capabilityKeeper wasmtypes.CapabilityKeeper, bankKeeper wasmtypes.Burner, + evmKeeper *evmkeeper.Keeper, unpacker codectypes.AnyUnpacker, portSource wasmtypes.ICS20TransferPortSource, _ aclkeeper.Keeper, @@ -25,7 +51,7 @@ func CustomMessageHandler( Custom: CustomEncoder, }) return wasmkeeper.NewMessageHandlerChain( - wasmkeeper.NewSDKMessageHandler(router, encoders), + wasmkeeper.NewSDKMessageHandler(&CustomRouter{MessageRouter: router, evmKeeper: evmKeeper}, encoders), wasmkeeper.NewIBCRawPacketHandler(channelKeeper, capabilityKeeper), wasmkeeper.NewBurnCoinMessageHandler(bankKeeper), ) diff --git a/wasmbinding/queries.go b/wasmbinding/queries.go index 1cf8545b33..6acbe57d04 100644 --- a/wasmbinding/queries.go +++ b/wasmbinding/queries.go @@ -2,6 +2,7 @@ package wasmbinding import ( "encoding/json" + "errors" sdk "github.com/cosmos/cosmos-sdk/types" dexwasm "github.com/sei-protocol/sei-chain/x/dex/client/wasm" @@ -10,6 +11,8 @@ import ( epochwasm "github.com/sei-protocol/sei-chain/x/epoch/client/wasm" epochbindings "github.com/sei-protocol/sei-chain/x/epoch/client/wasm/bindings" epochtypes "github.com/sei-protocol/sei-chain/x/epoch/types" + evmwasm "github.com/sei-protocol/sei-chain/x/evm/client/wasm" + evmbindings "github.com/sei-protocol/sei-chain/x/evm/client/wasm/bindings" oraclewasm "github.com/sei-protocol/sei-chain/x/oracle/client/wasm" oraclebindings "github.com/sei-protocol/sei-chain/x/oracle/client/wasm/bindings" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" @@ -23,15 +26,17 @@ type QueryPlugin struct { dexHandler dexwasm.DexWasmQueryHandler epochHandler epochwasm.EpochWasmQueryHandler tokenfactoryHandler tokenfactorywasm.TokenFactoryWasmQueryHandler + evmHandler evmwasm.EVMQueryHandler } // NewQueryPlugin returns a reference to a new QueryPlugin. -func NewQueryPlugin(oh *oraclewasm.OracleWasmQueryHandler, dh *dexwasm.DexWasmQueryHandler, eh *epochwasm.EpochWasmQueryHandler, th *tokenfactorywasm.TokenFactoryWasmQueryHandler) *QueryPlugin { +func NewQueryPlugin(oh *oraclewasm.OracleWasmQueryHandler, dh *dexwasm.DexWasmQueryHandler, eh *epochwasm.EpochWasmQueryHandler, th *tokenfactorywasm.TokenFactoryWasmQueryHandler, evmh *evmwasm.EVMQueryHandler) *QueryPlugin { return &QueryPlugin{ oracleHandler: *oh, dexHandler: *dh, epochHandler: *eh, tokenfactoryHandler: *th, + evmHandler: *evmh, } } @@ -188,3 +193,65 @@ func (qp QueryPlugin) HandleTokenFactoryQuery(ctx sdk.Context, queryData json.Ra return nil, tokenfactorytypes.ErrUnknownSeiTokenFactoryQuery } } + +func (qp QueryPlugin) HandleEVMQuery(ctx sdk.Context, queryData json.RawMessage) ([]byte, error) { + var parsedQuery evmbindings.SeiEVMQuery + if err := json.Unmarshal(queryData, &parsedQuery); err != nil { + return nil, errors.New("invalid EVM query") + } + switch { + case parsedQuery.StaticCall != nil: + c := parsedQuery.StaticCall + return qp.evmHandler.HandleStaticCall(ctx, c.From, c.To, c.Data) + case parsedQuery.ERC20TransferPayload != nil: + c := parsedQuery.ERC20TransferPayload + return qp.evmHandler.HandleERC20TransferPayload(ctx, c.Recipient, c.Amount) + case parsedQuery.ERC20TransferFromPayload != nil: + c := parsedQuery.ERC20TransferFromPayload + return qp.evmHandler.HandleERC20TransferFromPayload(ctx, c.Owner, c.Recipient, c.Amount) + case parsedQuery.ERC20ApprovePayload != nil: + c := parsedQuery.ERC20ApprovePayload + return qp.evmHandler.HandleERC20ApprovePayload(ctx, c.Spender, c.Amount) + case parsedQuery.ERC20Allowance != nil: + c := parsedQuery.ERC20Allowance + return qp.evmHandler.HandleERC20Allowance(ctx, c.ContractAddress, c.Owner, c.Spender) + case parsedQuery.ERC20TokenInfo != nil: + c := parsedQuery.ERC20TokenInfo + return qp.evmHandler.HandleERC20TokenInfo(ctx, c.ContractAddress, c.Caller) + case parsedQuery.ERC20Balance != nil: + c := parsedQuery.ERC20Balance + return qp.evmHandler.HandleERC20Balance(ctx, c.ContractAddress, c.Account) + case parsedQuery.ERC721Owner != nil: + c := parsedQuery.ERC721Owner + return qp.evmHandler.HandleERC721Owner(ctx, c.Caller, c.ContractAddress, c.TokenID) + case parsedQuery.ERC721TransferPayload != nil: + c := parsedQuery.ERC721TransferPayload + return qp.evmHandler.HandleERC721TransferPayload(ctx, c.From, c.Recipient, c.TokenID) + case parsedQuery.ERC721ApprovePayload != nil: + c := parsedQuery.ERC721ApprovePayload + return qp.evmHandler.HandleERC721ApprovePayload(ctx, c.Spender, c.TokenID) + case parsedQuery.ERC721SetApprovalAllPayload != nil: + c := parsedQuery.ERC721SetApprovalAllPayload + return qp.evmHandler.HandleERC721SetApprovalAllPayload(ctx, c.To, c.Approved) + case parsedQuery.ERC721Approved != nil: + c := parsedQuery.ERC721Approved + return qp.evmHandler.HandleERC721Approved(ctx, c.Caller, c.ContractAddress, c.TokenID) + case parsedQuery.ERC721IsApprovedForAll != nil: + c := parsedQuery.ERC721IsApprovedForAll + return qp.evmHandler.HandleERC721IsApprovedForAll(ctx, c.Caller, c.ContractAddress, c.Owner, c.Operator) + 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.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) + default: + return nil, errors.New("unknown EVM query") + } +} diff --git a/wasmbinding/query_plugin.go b/wasmbinding/query_plugin.go index f1dff2c603..db21e94040 100644 --- a/wasmbinding/query_plugin.go +++ b/wasmbinding/query_plugin.go @@ -13,6 +13,7 @@ const ( DexRoute = "dex" EpochRoute = "epoch" TokenFactoryRoute = "tokenfactory" + EVMRoute = "evm" ) type SeiQueryWrapper struct { @@ -37,6 +38,8 @@ func CustomQuerier(qp *QueryPlugin) func(ctx sdk.Context, request json.RawMessag return qp.HandleEpochQuery(ctx, contractQuery.QueryData) case TokenFactoryRoute: return qp.HandleTokenFactoryQuery(ctx, contractQuery.QueryData) + case EVMRoute: + return qp.HandleEVMQuery(ctx, contractQuery.QueryData) default: return nil, wasmvmtypes.UnsupportedRequest{Kind: "Unknown Sei Query Route"} } diff --git a/wasmbinding/test/query_test.go b/wasmbinding/test/query_test.go index f902743806..c4dd219bba 100644 --- a/wasmbinding/test/query_test.go +++ b/wasmbinding/test/query_test.go @@ -22,6 +22,7 @@ import ( epochwasm "github.com/sei-protocol/sei-chain/x/epoch/client/wasm" epochbinding "github.com/sei-protocol/sei-chain/x/epoch/client/wasm/bindings" epochtypes "github.com/sei-protocol/sei-chain/x/epoch/types" + evmwasm "github.com/sei-protocol/sei-chain/x/evm/client/wasm" oraclewasm "github.com/sei-protocol/sei-chain/x/oracle/client/wasm" oraclebinding "github.com/sei-protocol/sei-chain/x/oracle/client/wasm/bindings" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" @@ -36,13 +37,14 @@ func SetupWasmbindingTest(t *testing.T) (*app.TestWrapper, func(ctx sdk.Context, tm := time.Now().UTC() valPub := secp256k1.GenPrivKey().PubKey() - testWrapper := app.NewTestWrapper(t, tm, valPub) + testWrapper := app.NewTestWrapper(t, tm, valPub, false) oh := oraclewasm.NewOracleWasmQueryHandler(&testWrapper.App.OracleKeeper) dh := dexwasm.NewDexWasmQueryHandler(&testWrapper.App.DexKeeper) eh := epochwasm.NewEpochWasmQueryHandler(&testWrapper.App.EpochKeeper) th := tokenfactorywasm.NewTokenFactoryWasmQueryHandler(&testWrapper.App.TokenFactoryKeeper) - qp := wasmbinding.NewQueryPlugin(oh, dh, eh, th) + evmh := evmwasm.NewEVMQueryHandler(&testWrapper.App.EvmKeeper) + qp := wasmbinding.NewQueryPlugin(oh, dh, eh, th, evmh) return testWrapper, wasmbinding.CustomQuerier(qp) } diff --git a/wasmbinding/wasm.go b/wasmbinding/wasm.go index 83f92bb44c..0d50fb0cb6 100644 --- a/wasmbinding/wasm.go +++ b/wasmbinding/wasm.go @@ -11,6 +11,8 @@ import ( dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" epochwasm "github.com/sei-protocol/sei-chain/x/epoch/client/wasm" epochkeeper "github.com/sei-protocol/sei-chain/x/epoch/keeper" + evmwasm "github.com/sei-protocol/sei-chain/x/evm/client/wasm" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" oraclewasm "github.com/sei-protocol/sei-chain/x/oracle/client/wasm" oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper" tokenfactorywasm "github.com/sei-protocol/sei-chain/x/tokenfactory/client/wasm" @@ -30,18 +32,20 @@ func RegisterCustomPlugins( unpacker codectypes.AnyUnpacker, portSource wasmtypes.ICS20TransferPortSource, aclKeeper aclkeeper.Keeper, + evmKeeper *evmkeeper.Keeper, ) []wasmkeeper.Option { dexHandler := dexwasm.NewDexWasmQueryHandler(dex) oracleHandler := oraclewasm.NewOracleWasmQueryHandler(oracle) epochHandler := epochwasm.NewEpochWasmQueryHandler(epoch) tokenfactoryHandler := tokenfactorywasm.NewTokenFactoryWasmQueryHandler(tokenfactory) - wasmQueryPlugin := NewQueryPlugin(oracleHandler, dexHandler, epochHandler, tokenfactoryHandler) + evmHandler := evmwasm.NewEVMQueryHandler(evmKeeper) + wasmQueryPlugin := NewQueryPlugin(oracleHandler, dexHandler, epochHandler, tokenfactoryHandler, evmHandler) queryPluginOpt := wasmkeeper.WithQueryPlugins(&wasmkeeper.QueryPlugins{ Custom: CustomQuerier(wasmQueryPlugin), }) messengerHandlerOpt := wasmkeeper.WithMessageHandler( - CustomMessageHandler(router, channelKeeper, capabilityKeeper, bankKeeper, unpacker, portSource, aclKeeper), + CustomMessageHandler(router, channelKeeper, capabilityKeeper, bankKeeper, evmKeeper, unpacker, portSource, aclKeeper), ) return []wasm.Option{ diff --git a/x/dex/keeper/msgserver/msg_server_register_contract_test.go b/x/dex/keeper/msgserver/msg_server_register_contract_test.go index 415087eeba..9b989ed790 100644 --- a/x/dex/keeper/msgserver/msg_server_register_contract_test.go +++ b/x/dex/keeper/msgserver/msg_server_register_contract_test.go @@ -22,7 +22,7 @@ import ( ) const ( - TestContractA = "sei14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sh9m79m" + TestContractA = "sei1hrpna9v7vs3stzyd4z3xf00676kf78zpe2u5ksvljswn2vnjp3yslucc3n" TestContractB = "sei1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrqms7u8a" TestContractC = "sei1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3shh3qfl" TestContractD = "sei1up07dctjqud4fns75cnpejr4frmjtddzsmwgcktlyxd4zekhwecqghxqcp" diff --git a/x/epoch/handler_test.go b/x/epoch/handler_test.go index f853f553e0..1d47749bcf 100644 --- a/x/epoch/handler_test.go +++ b/x/epoch/handler_test.go @@ -15,7 +15,7 @@ import ( ) func TestNewHandler(t *testing.T) { - app := app.Setup(false) // Your setup function here + app := app.Setup(false, false) // Your setup function here handler := epoch.NewHandler(app.EpochKeeper) // Test unrecognized message type diff --git a/x/epoch/keeper/epoch_test.go b/x/epoch/keeper/epoch_test.go index 943a60353a..4b8e3b2816 100644 --- a/x/epoch/keeper/epoch_test.go +++ b/x/epoch/keeper/epoch_test.go @@ -11,7 +11,7 @@ import ( ) func TestEpochKeeper(t *testing.T) { - app := app.Setup(false) // Your setup function here + app := app.Setup(false, false) // Your setup function here ctx := app.BaseApp.NewContext(false, tmproto.Header{}) // Define an epoch diff --git a/x/epoch/module_test.go b/x/epoch/module_test.go index 16c91715f1..4c41e5de85 100644 --- a/x/epoch/module_test.go +++ b/x/epoch/module_test.go @@ -16,7 +16,7 @@ import ( func TestBasic(t *testing.T) { t.Parallel() // Create a mock context and keeper - app := app.Setup(false) + app := app.Setup(false, false) appModule := epoch.NewAppModule( app.AppCodec(), app.EpochKeeper, @@ -38,7 +38,7 @@ func TestBasic(t *testing.T) { func TestExportGenesis(t *testing.T) { t.Parallel() // Create a mock context and keeper - app := app.Setup(false) + app := app.Setup(false, false) appModule := epoch.NewAppModule( app.AppCodec(), app.EpochKeeper, @@ -62,7 +62,7 @@ func hasEventType(ctx sdk.Context, eventType string) bool { func TestBeginBlock(t *testing.T) { t.Parallel() // Create a mock context and keeper - app := app.Setup(false) + app := app.Setup(false, false) appModule := epoch.NewAppModule( app.AppCodec(), app.EpochKeeper, diff --git a/x/evm/ante/basic.go b/x/evm/ante/basic.go new file mode 100644 index 0000000000..e9db85dcae --- /dev/null +++ b/x/evm/ante/basic.go @@ -0,0 +1,108 @@ +package ante + +import ( + "crypto/sha256" + "fmt" + + 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/core" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/params" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" +) + +type BasicDecorator struct { +} + +func NewBasicDecorator() *BasicDecorator { + return &BasicDecorator{} +} + +// cherrypicked from go-ethereum:txpool:ValidateTransaction +func (gl BasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + msg := evmtypes.MustGetEVMTransactionMessage(tx) + etx, _ := msg.AsTransaction() + + if etx.To() == nil && len(etx.Data()) > params.MaxInitCodeSize { + return ctx, fmt.Errorf("%w: code size %v, limit %v", core.ErrMaxInitCodeSizeExceeded, len(etx.Data()), params.MaxInitCodeSize) + } + + if etx.Value().Sign() < 0 { + return ctx, sdkerrors.ErrInvalidCoins + } + + intrGas, err := core.IntrinsicGas(etx.Data(), etx.AccessList(), etx.To() == nil, true, true, true) + if err != nil { + return ctx, err + } + if etx.Gas() < intrGas { + return ctx, sdkerrors.ErrOutOfGas + } + + if etx.Type() == ethtypes.BlobTxType { + return ctx, sdkerrors.ErrUnsupportedTxType + } + + //TODO: support blobs (leaving this commented out) + // Ensure blob transactions have valid commitments + //if etx.Type() == ethtypes.BlobTxType { + // sidecar := etx.BlobTxSidecar() + // if sidecar == nil { + // return ctx, fmt.Errorf("missing sidecar in blob transaction") + // } + // // Ensure the number of items in the blob transaction and various side + // // data match up before doing any expensive validations + // hashes := etx.BlobHashes() + // if len(hashes) == 0 { + // return ctx, fmt.Errorf("blobless blob transaction") + // } + // if len(hashes) > params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob { + // return ctx, fmt.Errorf("too many blobs in transaction: have %d, permitted %d", len(hashes), params.MaxBlobGasPerBlock/params.BlobTxBlobGasPerBlob) + // } + // if err := validateBlobSidecar(hashes, sidecar); err != nil { + // return ctx, err + // } + //} + + return next(ctx, tx, simulate) +} + +//nolint:deadcode +func validateBlobSidecar(hashes []common.Hash, sidecar *ethtypes.BlobTxSidecar) error { + if len(sidecar.Blobs) != len(hashes) { + return fmt.Errorf("invalid number of %d blobs compared to %d blob hashes", len(sidecar.Blobs), len(hashes)) + } + if len(sidecar.Commitments) != len(hashes) { + return fmt.Errorf("invalid number of %d blob commitments compared to %d blob hashes", len(sidecar.Commitments), len(hashes)) + } + if len(sidecar.Proofs) != len(hashes) { + return fmt.Errorf("invalid number of %d blob proofs compared to %d blob hashes", len(sidecar.Proofs), len(hashes)) + } + // Blob quantities match up, validate that the provers match with the + // transaction hash before getting to the cryptography + hasher := sha256.New() + for i, want := range hashes { + hasher.Write(sidecar.Commitments[i][:]) + hash := hasher.Sum(nil) + hasher.Reset() + + var vhash common.Hash + vhash[0] = params.BlobTxHashVersion + copy(vhash[1:], hash[1:]) + + if vhash != want { + return fmt.Errorf("blob %d: computed hash %#x mismatches transaction one %#x", i, vhash, want) + } + } + // Blob commitments match with the hashes in the transaction, verify the + // blobs themselves via KZG + for i := range sidecar.Blobs { + if err := kzg4844.VerifyBlobProof(sidecar.Blobs[i], sidecar.Commitments[i], sidecar.Proofs[i]); err != nil { + return fmt.Errorf("invalid blob %d: %v", i, err) + } + } + return nil +} diff --git a/x/evm/ante/basic_test.go b/x/evm/ante/basic_test.go new file mode 100644 index 0000000000..c7d5255f04 --- /dev/null +++ b/x/evm/ante/basic_test.go @@ -0,0 +1,56 @@ +package ante_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/ethereum/go-ethereum/params" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" +) + +func TestBasicDecorator(t *testing.T) { + _, ctx := testkeeper.MockEVMKeeper() + a := ante.NewBasicDecorator() + msg, _ := types.NewMsgEVMTransaction(ðtx.LegacyTx{}) + ctx, err := a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) // expect out of gas err + dataTooLarge := make([]byte, params.MaxInitCodeSize+1) + for i := 0; i <= params.MaxInitCodeSize; i++ { + dataTooLarge[i] = 1 + } + msg, _ = types.NewMsgEVMTransaction(ðtx.LegacyTx{Data: dataTooLarge}) + ctx, err = a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) + require.Contains(t, err.Error(), "code size") + negAmount := sdk.NewInt(-1) + msg, _ = types.NewMsgEVMTransaction(ðtx.LegacyTx{Amount: &negAmount}) + ctx, err = a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Equal(t, sdkerrors.ErrInvalidCoins, err) + data := make([]byte, 10) + for i := 0; i < 10; i++ { + dataTooLarge[i] = 1 + } + msg, _ = types.NewMsgEVMTransaction(ðtx.LegacyTx{Data: data}) + ctx, err = a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Equal(t, sdkerrors.ErrOutOfGas, err) + + msg, _ = types.NewMsgEVMTransaction(ðtx.BlobTx{GasLimit: 21000}) + ctx, err = a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) + require.Error(t, err, sdkerrors.ErrUnsupportedTxType) +} diff --git a/x/evm/ante/error.go b/x/evm/ante/error.go new file mode 100644 index 0000000000..d1d7ab5a67 --- /dev/null +++ b/x/evm/ante/error.go @@ -0,0 +1,40 @@ +package ante + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "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" +) + +type AnteErrorHandler struct { + wrapped sdk.AnteHandler + k *keeper.Keeper +} + +func NewAnteErrorHandler(wrapped sdk.AnteHandler, k *keeper.Keeper) *AnteErrorHandler { + return &AnteErrorHandler{wrapped: wrapped, k: k} +} + +// if there is any error in ante handler, record it in deferred info so that a receipt +// can be written for it in the EndBlock. (we can't directly write receipt here since +// we still need to return an error which will cause any write here to revert) +func (a *AnteErrorHandler) Handle(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + newCtx, err = a.wrapped(ctx, tx, simulate) + if err != nil && !ctx.IsCheckTx() && !ctx.IsReCheckTx() && !simulate { + msg := types.MustGetEVMTransactionMessage(tx) + txData, unpackerr := types.UnpackTxData(msg.Data) + if unpackerr != nil { + ctx.Logger().Error(fmt.Sprintf("failed to unpack message data %X", msg.Data.Value)) + return + } + if _, ok := txData.(*ethtx.AssociateTx); ok { + return + } + a.k.AppendErrorToEvmTxDeferredInfo(ctx, ethtypes.NewTx(txData.AsEthereumData()).Hash(), err.Error()) + } + return +} diff --git a/x/evm/ante/fee.go b/x/evm/ante/fee.go new file mode 100644 index 0000000000..a3210b3f2e --- /dev/null +++ b/x/evm/ante/fee.go @@ -0,0 +1,92 @@ +package ante + +import ( + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/sei-protocol/sei-chain/app/antedecorators" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/derived" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" +) + +type EVMFeeCheckDecorator struct { + evmKeeper *evmkeeper.Keeper +} + +func NewEVMFeeCheckDecorator(evmKeeper *evmkeeper.Keeper) *EVMFeeCheckDecorator { + return &EVMFeeCheckDecorator{ + evmKeeper: evmKeeper, + } +} + +func (fc EVMFeeCheckDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + if simulate { + return next(ctx, tx, simulate) + } + + msg := evmtypes.MustGetEVMTransactionMessage(tx) + txData, err := evmtypes.UnpackTxData(msg.Data) + if err != nil { + return ctx, err + } + + ver := msg.Derived.Version + + if txData.GetGasFeeCap().Cmp(fc.getBaseFee(ctx)) < 0 { + return ctx, sdkerrors.ErrInsufficientFee + } + if txData.GetGasFeeCap().Cmp(fc.getMinimumFee(ctx)) < 0 { + return ctx, sdkerrors.ErrInsufficientFee + } + + // if EVM version is Cancun or later, and the transaction contains at least one blob, we need to + // make sure the transaction carries a non-zero blob fee cap. + if ver >= derived.Cancun && len(txData.GetBlobHashes()) > 0 { + // For now we are simply assuming excessive blob gas is 0. In the future we might change it to be + // dynamic based on prior block usage. + if txData.GetBlobFeeCap().Cmp(eip4844.CalcBlobFee(0)) < 0 { + return ctx, sdkerrors.ErrInsufficientFee + } + } + + // fee + value + anteCharge := txData.Cost() // this would include blob fee if it's a blob tx + + senderEVMAddr := evmtypes.MustGetEVMTransactionMessage(tx).Derived.SenderEVMAddr + // check if the sender has enough balance to cover fees + if state.NewDBImpl(ctx, fc.evmKeeper, true).GetBalance(senderEVMAddr).Cmp(anteCharge) < 0 { + return ctx, sdkerrors.ErrInsufficientFunds + } + + // calculate the priority by dividing the total fee with the native gas limit (i.e. the effective native gas price) + priority := fc.CalculatePriority(ctx, txData) + ctx = ctx.WithPriority(priority.Int64()) + + return next(ctx, tx, simulate) +} + +// fee per gas to be burnt +func (fc EVMFeeCheckDecorator) getBaseFee(ctx sdk.Context) *big.Int { + return fc.evmKeeper.GetBaseFeePerGas(ctx).TruncateInt().BigInt() +} + +// lowest allowed fee per gas +func (fc EVMFeeCheckDecorator) getMinimumFee(ctx sdk.Context) *big.Int { + return fc.evmKeeper.GetMinimumFeePerGas(ctx).TruncateInt().BigInt() +} + +// CalculatePriority returns a priority based on the effective gas price of the transaction +func (fc EVMFeeCheckDecorator) CalculatePriority(ctx sdk.Context, txData ethtx.TxData) *big.Int { + gp := txData.EffectiveGasPrice(utils.Big0) + priority := sdk.NewDecFromBigInt(gp).Quo(fc.evmKeeper.GetPriorityNormalizer(ctx)).TruncateInt().BigInt() + if priority.Cmp(big.NewInt(antedecorators.MaxPriority)) > 0 { + priority = big.NewInt(antedecorators.MaxPriority) + } + return priority +} diff --git a/x/evm/ante/fee_test.go b/x/evm/ante/fee_test.go new file mode 100644 index 0000000000..4fcb3572b9 --- /dev/null +++ b/x/evm/ante/fee_test.go @@ -0,0 +1,285 @@ +package ante_test + +import ( + "encoding/hex" + "math" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/holiman/uint256" + "github.com/sei-protocol/sei-chain/app/antedecorators" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" +) + +func TestEVMFeeCheckDecoratorCancun(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + handler := ante.NewEVMFeeCheckDecorator(k) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + to := new(common.Address) + copy(to[:], []byte("0x1234567890abcdef1234567890abcdef12345678")) + chainID := k.ChainID(ctx) + txData := ethtypes.DynamicFeeTx{ + Nonce: 1, + GasFeeCap: big.NewInt(10000000000000), + Gas: 1000, + To: to, + Value: big.NewInt(1000000000000000), + Data: []byte("abc"), + ChainID: chainID, + } + 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.NewDynamicFeeTx(tx) + require.Nil(t, err) + msg, err := types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + + preprocessor := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + + // should return error because gas fee cap is too low + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) + + txData.GasFeeCap = k.GetMinimumFeePerGas(ctx).TruncateInt().BigInt() + tx, err = ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + typedTx, err = ethtx.NewDynamicFeeTx(tx) + require.Nil(t, err) + msg, err = types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + + // should return error because the sender does not have enough funds + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) + + amt := typedTx.Cost() + coinsAmt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewIntFromBigInt(amt).Quo(sdk.NewIntFromBigInt(state.UseiToSweiMultiplier)).Add(sdk.OneInt()))) + k.BankKeeper().MintCoins(ctx, types.ModuleName, coinsAmt) + seiAddr := sdk.AccAddress(msg.Derived.SenderSeiAddr) + k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, seiAddr, coinsAmt) + + // should succeed now that the sender has enough funds + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + + // should fail because blob gas fee cap is too low + blobTxData := ethtypes.BlobTx{ + Nonce: 1, + GasFeeCap: uint256.MustFromBig(txData.GasFeeCap), + Gas: 1000, + To: *to, + Value: uint256.NewInt(1000000000000000), + Data: []byte("abc"), + BlobHashes: []common.Hash{{}}, + ChainID: uint256.MustFromBig(chainID), + } + tx, err = ethtypes.SignTx(ethtypes.NewTx(&blobTxData), signer, key) + require.Nil(t, err) + typedBlobTx, err := ethtx.NewBlobTx(tx) + require.Nil(t, err) + msg, err = types.NewMsgEVMTransaction(typedBlobTx) + require.Nil(t, err) + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) + + // should fail because insufficient balance due to additional blob cost + blobTxData.BlobFeeCap = uint256.NewInt(1000000000000) + tx, err = ethtypes.SignTx(ethtypes.NewTx(&blobTxData), signer, key) + require.Nil(t, err) + typedBlobTx, err = ethtx.NewBlobTx(tx) + require.Nil(t, err) + msg, err = types.NewMsgEVMTransaction(typedBlobTx) + require.Nil(t, err) + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) + + // should succeed + amt = new(big.Int).Mul(typedBlobTx.GetBlobFeeCap(), new(big.Int).SetUint64(typedBlobTx.BlobGas())) + coinsAmt = sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewIntFromBigInt(amt))) + k.BankKeeper().MintCoins(ctx, types.ModuleName, coinsAmt) + k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, seiAddr, coinsAmt) + + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + + // should fail because of minimum fee + txData.GasFeeCap = big.NewInt(0) + tx, err = ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + require.Nil(t, err) + typedTx, err = ethtx.NewDynamicFeeTx(tx) + require.Nil(t, err) + msg, err = types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) +} + +func TestCalculatePriorityScenarios(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + decorator := ante.NewEVMFeeCheckDecorator(k) + + _1gwei := big.NewInt(100000000000) + _1_1gwei := big.NewInt(1100000000000) + _2gwei := big.NewInt(200000000000) + maxInt := big.NewInt(math.MaxInt64) + maxPriority := big.NewInt(antedecorators.MaxPriority) + + scenarios := []struct { + name string + txData ethtypes.TxData + expectedPriority *big.Int + }{ + { + name: "DynamicFeeTx with tip", + txData: ðtypes.DynamicFeeTx{ + GasFeeCap: _1gwei, + GasTipCap: _1gwei, + Value: _1gwei, + }, + expectedPriority: _1gwei, + }, + { + name: "DynamicFeeTx with higher gas fee cap and gas tip cap", + txData: ðtypes.DynamicFeeTx{ + GasFeeCap: _1_1gwei, + GasTipCap: _1_1gwei, + Value: _1gwei, + }, + expectedPriority: _1_1gwei, + }, + { + name: "DynamicFeeTx value does not change priority", + txData: ðtypes.DynamicFeeTx{ + GasFeeCap: _1gwei, + GasTipCap: _1gwei, + Value: _2gwei, + }, + expectedPriority: _1gwei, + }, + { + name: "DynamicFeeTx with no tip", + txData: ðtypes.DynamicFeeTx{ + GasFeeCap: _1gwei, + GasTipCap: big.NewInt(0), + Value: _1gwei, + }, + expectedPriority: big.NewInt(0), // if you don't tip, you get lowest priority + }, + { + name: "DynamicFeeTx with a non-multiple of 10 tip", + txData: ðtypes.DynamicFeeTx{ + GasFeeCap: big.NewInt(1000000000000000), + GasTipCap: big.NewInt(9999999999999), + Value: big.NewInt(1000000000), + }, + expectedPriority: big.NewInt(9999999999999), + }, + { + name: "DynamicFeeTx test overflow", + txData: ðtypes.DynamicFeeTx{ + GasFeeCap: new(big.Int).Add(maxInt, big.NewInt(1)), + GasTipCap: new(big.Int).Add(maxInt, big.NewInt(1)), + Value: big.NewInt(1000000000), + }, + expectedPriority: maxPriority, + }, + { + name: "LegacyTx has priority with gas price", + txData: ðtypes.LegacyTx{ + GasPrice: _1gwei, + Value: _1gwei, + }, + expectedPriority: _1gwei, + }, + { + name: "LegacyTx has zero priority with zero gas price", + txData: ðtypes.LegacyTx{ + GasPrice: big.NewInt(0), + Value: _1gwei, + }, + expectedPriority: big.NewInt(0), + }, + { + name: "LegacyTx with a non-multiple of 10 gas price", + txData: ðtypes.LegacyTx{ + GasPrice: big.NewInt(9999999999999), + Value: big.NewInt(1000000000000000), + }, + expectedPriority: big.NewInt(9999999999999), + }, + } + + // Run each scenario + for _, s := range scenarios { + t.Run(s.name, func(t *testing.T) { + tx := ethtypes.NewTx(s.txData) + txData, err := ethtx.NewTxDataFromTx(tx) + require.NoError(t, err) + priority := decorator.CalculatePriority(ctx, txData) + + if s.expectedPriority != nil { + // Check the returned value + if priority.Cmp(s.expectedPriority) != 0 { + t.Errorf("Expected priority %v, but got %v", s.expectedPriority, priority) + } + } + }) + } +} diff --git a/x/evm/ante/gas.go b/x/evm/ante/gas.go new file mode 100644 index 0000000000..5a04f2f51c --- /dev/null +++ b/x/evm/ante/gas.go @@ -0,0 +1,28 @@ +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" +) + +type GasLimitDecorator struct { + evmKeeper *evmkeeper.Keeper +} + +func NewGasLimitDecorator(evmKeeper *evmkeeper.Keeper) *GasLimitDecorator { + return &GasLimitDecorator{evmKeeper: evmKeeper} +} + +// Called at the end of the ante chain to set gas limit properly +func (gl GasLimitDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + msg := evmtypes.MustGetEVMTransactionMessage(tx) + txData, err := evmtypes.UnpackTxData(msg.Data) + if err != nil { + return ctx, err + } + + adjustedGasLimit := gl.evmKeeper.GetPriorityNormalizer(ctx).MulInt64(int64(txData.GetGas())) + ctx = ctx.WithGasMeter(sdk.NewGasMeter(adjustedGasLimit.TruncateInt().Uint64())) + return next(ctx, tx, simulate) +} diff --git a/x/evm/ante/gas_test.go b/x/evm/ante/gas_test.go new file mode 100644 index 0000000000..53a57155c4 --- /dev/null +++ b/x/evm/ante/gas_test.go @@ -0,0 +1,23 @@ +package ante_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/ante" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" +) + +func TestGasLimitDecorator(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + a := ante.NewGasLimitDecorator(k) + limitMsg, _ := types.NewMsgEVMTransaction(ðtx.LegacyTx{GasLimit: 100}) + ctx, err := a.AnteHandle(ctx, &mockTx{msgs: []sdk.Msg{limitMsg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + require.Equal(t, 100, int(ctx.GasMeter().Limit())) +} diff --git a/x/evm/ante/preprocess.go b/x/evm/ante/preprocess.go new file mode 100644 index 0000000000..30bbd9c1e4 --- /dev/null +++ b/x/evm/ante/preprocess.go @@ -0,0 +1,372 @@ +package ante + +import ( + "encoding/hex" + "errors" + "fmt" + "math/big" + + "github.com/btcsuite/btcd/btcec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + 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" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" + "github.com/sei-protocol/sei-chain/app/antedecorators" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/derived" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" +) + +// Accounts need to have at least 1Sei to force association. Note that account won't be charged. +const BalanceThreshold uint64 = 1000000 + +var BigBalanceThreshold *big.Int = new(big.Int).SetUint64(BalanceThreshold) +var BigBalanceThresholdMinus1 *big.Int = new(big.Int).SetUint64(BalanceThreshold - 1) + +var SignerMap = map[derived.SignerVersion]func(*big.Int) ethtypes.Signer{ + derived.London: ethtypes.NewLondonSigner, + derived.Cancun: ethtypes.NewCancunSigner, +} +var AllowedTxTypes = map[derived.SignerVersion][]uint8{ + derived.London: {ethtypes.LegacyTxType, ethtypes.AccessListTxType, ethtypes.DynamicFeeTxType}, + derived.Cancun: {ethtypes.LegacyTxType, ethtypes.AccessListTxType, ethtypes.DynamicFeeTxType, ethtypes.BlobTxType}, +} + +type EVMPreprocessDecorator struct { + evmKeeper *evmkeeper.Keeper + accountKeeper *accountkeeper.AccountKeeper +} + +func NewEVMPreprocessDecorator(evmKeeper *evmkeeper.Keeper, accountKeeper *accountkeeper.AccountKeeper) *EVMPreprocessDecorator { + return &EVMPreprocessDecorator{evmKeeper: evmKeeper, accountKeeper: accountKeeper} +} + +//nolint:revive +func (p *EVMPreprocessDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + msg := evmtypes.MustGetEVMTransactionMessage(tx) + if err := Preprocess(ctx, msg); err != nil { + return ctx, err + } + + // use infinite gas meter for EVM transaction because EVM handles gas checking from within + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) + + derived := msg.Derived + seiAddr := derived.SenderSeiAddr + evmAddr := derived.SenderEVMAddr + pubkey := derived.PubKey + isAssociateTx := derived.IsAssociate + _, isAssociated := p.evmKeeper.GetEVMAddress(ctx, seiAddr) + if isAssociateTx && isAssociated { + 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 err := p.associateAddresses(ctx, seiAddr, evmAddr, pubkey); err != nil { + return ctx, err + } + return ctx.WithPriority(antedecorators.EVMAssociatePriority), nil // short-circuit without calling next + } else if isAssociated { + // noop; for readability + } else { + // not associatedTx and not already associated + if err := p.associateAddresses(ctx, seiAddr, evmAddr, pubkey); err != nil { + return ctx, err + } + if p.evmKeeper.EthReplayConfig.Enabled { + p.evmKeeper.PrepareReplayedAddr(ctx, evmAddr) + } + } + + return next(ctx, tx, simulate) +} + +func (p *EVMPreprocessDecorator) associateAddresses(ctx sdk.Context, seiAddr sdk.AccAddress, evmAddr common.Address, pubkey cryptotypes.PubKey) error { + p.evmKeeper.SetAddressMapping(ctx, seiAddr, evmAddr) + if acc := p.accountKeeper.GetAccount(ctx, seiAddr); acc.GetPubKey() == nil { + if err := acc.SetPubKey(pubkey); err != nil { + return err + } + 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 + } + } + 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 + } + } + p.evmKeeper.AccountKeeper().RemoveAccount(ctx, authtypes.NewBaseAccountWithAddress(castAddr)) + return nil +} + +// stateless +func Preprocess(ctx sdk.Context, msgEVMTransaction *evmtypes.MsgEVMTransaction) error { + if msgEVMTransaction.Derived != nil { + if msgEVMTransaction.Derived.PubKey == nil { + // this means the message has `Derived` set from the outside, in which case we should reject + return sdkerrors.ErrInvalidPubKey + } + // already preprocessed + return nil + } + txData, err := evmtypes.UnpackTxData(msgEVMTransaction.Data) + if err != nil { + return err + } + + if atx, ok := txData.(*ethtx.AssociateTx); ok { + V, R, S := atx.GetRawSignatureValues() + V = new(big.Int).Add(V, utils.Big27) + // Hash custom message passed in + customMessageHash := crypto.Keccak256Hash([]byte(atx.CustomMessage)) + evmAddr, seiAddr, pubkey, err := getAddresses(V, R, S, customMessageHash) + if err != nil { + return err + } + msgEVMTransaction.Derived = &derived.Derived{ + SenderEVMAddr: evmAddr, + SenderSeiAddr: seiAddr, + PubKey: &secp256k1.PubKey{Key: pubkey.Bytes()}, + Version: derived.Cancun, + IsAssociate: true, + } + return nil + } + + ethTx := ethtypes.NewTx(txData.AsEthereumData()) + chainID := ethTx.ChainId() + chainCfg := evmtypes.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + version := GetVersion(ctx, ethCfg) + signer := SignerMap[version](chainID) + if !isTxTypeAllowed(version, ethTx.Type()) { + return ethtypes.ErrInvalidChainId + } + + var txHash common.Hash + V, R, S := ethTx.RawSignatureValues() + if ethTx.Protected() { + V = AdjustV(V, ethTx.Type(), ethCfg.ChainID) + txHash = signer.Hash(ethTx) + } else { + txHash = ethtypes.FrontierSigner{}.Hash(ethTx) + } + evmAddr, seiAddr, seiPubkey, err := getAddresses(V, R, S, txHash) + if err != nil { + return err + } + msgEVMTransaction.Derived = &derived.Derived{ + SenderEVMAddr: evmAddr, + SenderSeiAddr: seiAddr, + PubKey: &secp256k1.PubKey{Key: seiPubkey.Bytes()}, + Version: version, + IsAssociate: false, + } + return nil +} + +func (p *EVMPreprocessDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int, next sdk.AnteDepGenerator) (newTxDeps []sdkacltypes.AccessOperation, err error) { + msg := evmtypes.MustGetEVMTransactionMessage(tx) + return next(append(txDeps, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_S2E, + IdentifierTemplate: hex.EncodeToString(evmtypes.SeiAddressToEVMAddressKey(msg.Derived.SenderSeiAddr)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_EVM_S2E, + IdentifierTemplate: hex.EncodeToString(evmtypes.SeiAddressToEVMAddressKey(msg.Derived.SenderSeiAddr)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_EVM_E2S, + IdentifierTemplate: hex.EncodeToString(evmtypes.EVMAddressToSeiAddressKey(msg.Derived.SenderEVMAddr)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, + IdentifierTemplate: hex.EncodeToString(banktypes.CreateAccountBalancesPrefix(msg.Derived.SenderSeiAddr)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, + IdentifierTemplate: hex.EncodeToString(banktypes.CreateAccountBalancesPrefix(msg.Derived.SenderSeiAddr)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, + IdentifierTemplate: hex.EncodeToString(banktypes.CreateAccountBalancesPrefix(msg.Derived.SenderEVMAddr[:])), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_BANK_BALANCES, + IdentifierTemplate: hex.EncodeToString(banktypes.CreateAccountBalancesPrefix(msg.Derived.SenderEVMAddr[:])), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_AUTH_ADDRESS_STORE, + IdentifierTemplate: hex.EncodeToString(authtypes.AddressStoreKey(msg.Derived.SenderSeiAddr)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_AUTH_ADDRESS_STORE, + IdentifierTemplate: hex.EncodeToString(authtypes.AddressStoreKey(msg.Derived.SenderSeiAddr)), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_AUTH_ADDRESS_STORE, + IdentifierTemplate: hex.EncodeToString(authtypes.AddressStoreKey(msg.Derived.SenderEVMAddr[:])), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_WRITE, + ResourceType: sdkacltypes.ResourceType_KV_AUTH_ADDRESS_STORE, + IdentifierTemplate: hex.EncodeToString(authtypes.AddressStoreKey(msg.Derived.SenderEVMAddr[:])), + }, sdkacltypes.AccessOperation{ + AccessType: sdkacltypes.AccessType_READ, + ResourceType: sdkacltypes.ResourceType_KV_EVM_NONCE, + IdentifierTemplate: hex.EncodeToString(append(evmtypes.NonceKeyPrefix, msg.Derived.SenderEVMAddr[:]...)), + }), tx, txIndex) +} + +func getAddresses(V *big.Int, R *big.Int, S *big.Int, data common.Hash) (common.Address, sdk.AccAddress, cryptotypes.PubKey, error) { + pubkey, err := recoverPubkey(data, R, S, V, true) + if err != nil { + return common.Address{}, sdk.AccAddress{}, nil, err + } + evmAddr, err := pubkeyToEVMAddress(pubkey) + if err != nil { + return common.Address{}, sdk.AccAddress{}, nil, err + } + seiPubkey := pubkeyBytesToSeiPubKey(pubkey) + seiAddr := sdk.AccAddress(seiPubkey.Address()) + return evmAddr, seiAddr, &seiPubkey, nil +} + +// first half of go-ethereum/core/types/transaction_signing.go:recoverPlain +func recoverPubkey(sighash common.Hash, R, S, Vb *big.Int, homestead bool) ([]byte, error) { + if Vb.BitLen() > 8 { + return []byte{}, ethtypes.ErrInvalidSig + } + V := byte(Vb.Uint64() - 27) + if !crypto.ValidateSignatureValues(V, R, S, homestead) { + return []byte{}, ethtypes.ErrInvalidSig + } + // encode the signature in uncompressed format + r, s := R.Bytes(), S.Bytes() + sig := make([]byte, crypto.SignatureLength) + copy(sig[32-len(r):32], r) + copy(sig[64-len(s):64], s) + sig[64] = V + // recover the public key from the signature + return crypto.Ecrecover(sighash[:], sig) +} + +// second half of go-ethereum/core/types/transaction_signing.go:recoverPlain +func pubkeyToEVMAddress(pub []byte) (common.Address, error) { + if len(pub) == 0 || pub[0] != 4 { + return common.Address{}, errors.New("invalid public key") + } + var addr common.Address + copy(addr[:], crypto.Keccak256(pub[1:])[12:]) + return addr, nil +} + +func pubkeyBytesToSeiPubKey(pub []byte) secp256k1.PubKey { + pubKey, _ := crypto.UnmarshalPubkey(pub) + pubkeyObj := (*btcec.PublicKey)(pubKey) + return secp256k1.PubKey{Key: pubkeyObj.SerializeCompressed()} +} + +func isTxTypeAllowed(version derived.SignerVersion, txType uint8) bool { + for _, t := range AllowedTxTypes[version] { + if t == txType { + return true + } + } + return false +} + +func AdjustV(V *big.Int, txType uint8, chainID *big.Int) *big.Int { + // Non-legacy TX always needs to be bumped by 27 + if txType != ethtypes.LegacyTxType { + return new(big.Int).Add(V, utils.Big27) + } + + // legacy TX needs to be adjusted based on chainID + V = new(big.Int).Sub(V, new(big.Int).Mul(chainID, utils.Big2)) + return V.Sub(V, utils.Big8) +} + +func GetVersion(ctx sdk.Context, ethCfg *params.ChainConfig) derived.SignerVersion { + blockNum := big.NewInt(ctx.BlockHeight()) + ts := uint64(ctx.BlockTime().Unix()) + switch { + case ethCfg.IsCancun(blockNum, ts): + return derived.Cancun + default: + return derived.London + } +} + +type EVMAddressDecorator struct { + evmKeeper *evmkeeper.Keeper + accountKeeper *accountkeeper.AccountKeeper +} + +func NewEVMAddressDecorator(evmKeeper *evmkeeper.Keeper, accountKeeper *accountkeeper.AccountKeeper) *EVMAddressDecorator { + return &EVMAddressDecorator{evmKeeper: evmKeeper, accountKeeper: accountKeeper} +} + +//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) + if !ok { + return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type") + } + signers := sigTx.GetSigners() + for _, signer := range signers { + if _, associated := p.evmKeeper.GetEVMAddress(ctx, signer); associated { + continue + } + acc := p.accountKeeper.GetAccount(ctx, signer) + if acc.GetPubKey() == nil { + ctx.Logger().Error(fmt.Sprintf("missing pubkey for %s", signer.String())) + continue + } + pk, err := btcec.ParsePubKey(acc.GetPubKey().Bytes(), btcec.S256()) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("failed to parse pubkey for %s", err)) + 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)) + continue + } + p.evmKeeper.SetAddressMapping(ctx, signer, evmAddr) + } + return next(ctx, tx, simulate) +} diff --git a/x/evm/ante/preprocess_test.go b/x/evm/ante/preprocess_test.go new file mode 100644 index 0000000000..cdc39ce952 --- /dev/null +++ b/x/evm/ante/preprocess_test.go @@ -0,0 +1,221 @@ +package ante_test + +import ( + "encoding/hex" + "fmt" + "math/big" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + 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" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/derived" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" +) + +func TestPreprocessAnteHandler(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + privKey := testkeeper.MockPrivateKey() + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + require.Nil(t, k.BankKeeper().AddCoins(ctx, sdk.AccAddress(evmAddr[:]), sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(100))), true)) + require.Nil(t, k.BankKeeper().AddWei(ctx, sdk.AccAddress(evmAddr[:]), sdk.NewInt(10))) + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + to := new(common.Address) + copy(to[:], []byte("0x1234567890abcdef1234567890abcdef12345678")) + txData := ethtypes.LegacyTx{ + Nonce: 1, + GasPrice: big.NewInt(10), + Gas: 1000, + To: to, + Value: big.NewInt(1000), + Data: []byte("abc"), + } + 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) + ctx, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + require.Equal(t, sdk.AccAddress(privKey.PubKey().Address()), sdk.AccAddress(msg.Derived.SenderSeiAddr)) + require.Equal(t, sdk.NewInt(100), k.BankKeeper().GetBalance(ctx, seiAddr, "usei").Amount) + require.Equal(t, sdk.NewInt(10), k.BankKeeper().GetWeiBalance(ctx, seiAddr)) + require.Equal(t, sdk.ZeroInt(), k.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), "usei").Amount) + require.Equal(t, sdk.ZeroInt(), k.BankKeeper().GetWeiBalance(ctx, sdk.AccAddress(evmAddr[:]))) +} + +func TestPreprocessAnteHandlerUnprotected(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + gasPrice := sdk.NewInt(73141930316) + amt := sdk.NewInt(270000000000000000) + v, _ := hex.DecodeString("1c") + s, _ := hex.DecodeString("16842c738042c72834d256b8aaf4e8cf14beb03c9e2e98bc29bedf29ef7d1ccf") + r, _ := hex.DecodeString("f7ab1c21ab782e07bc680f3a42972e38d6b42ee9a4cce76ac4c182fe54b08ae7") + txData := ethtx.LegacyTx{ + Nonce: 62908, + GasPrice: &gasPrice, + GasLimit: 93638, + To: "0xbb19ce0c0ad13cca2a75f73f163edc8bdae7fb70", + Amount: &amt, + Data: []byte{}, + V: v, + S: s, + R: r, + } + msg, err := types.NewMsgEVMTransaction(&txData) + require.Nil(t, err) + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + require.Equal(t, "0xc39BDF685F289B1F261EE9b0b1B2Bf9eae4C1980", msg.Derived.SenderEVMAddr.Hex()) +} + +func TestPreprocessAssociateTx(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + + emptyData := make([]byte, 32) + prefixedMessage := fmt.Sprintf("\x19Ethereum Signed Message:\n%d", len(emptyData)) + string(emptyData) + hash := crypto.Keccak256Hash([]byte(prefixedMessage)) + sig, err := crypto.Sign(hash.Bytes(), key) + require.Nil(t, err) + R, S, _, _ := ethtx.DecodeSignature(sig) + V := big.NewInt(int64(sig[64])) + + txData := ethtx.AssociateTx{V: V.Bytes(), R: R.Bytes(), S: S.Bytes(), CustomMessage: prefixedMessage} + msg, err := types.NewMsgEVMTransaction(&txData) + require.Nil(t, err) + 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 + require.NotNil(t, err) + seiAddr := sdk.AccAddress(privKey.PubKey().Address()) + evmAddr := crypto.PubkeyToAddress(key.PublicKey) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(int64(ante.BalanceThreshold)))) + k.BankKeeper().MintCoins(ctx, types.ModuleName, amt) + k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, seiAddr, amt) + 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") + }) + require.Nil(t, err) + associated, ok := k.GetEVMAddress(ctx, seiAddr) + 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) { + panic("should not be called") + }) + // already associated + require.NotNil(t, err) +} + +func TestPreprocessAssociateTxWithWeiBalance(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + + emptyData := make([]byte, 32) + prefixedMessage := fmt.Sprintf("\x19Ethereum Signed Message:\n%d", len(emptyData)) + string(emptyData) + hash := crypto.Keccak256Hash([]byte(prefixedMessage)) + sig, err := crypto.Sign(hash.Bytes(), key) + require.Nil(t, err) + R, S, _, _ := ethtx.DecodeSignature(sig) + V := big.NewInt(int64(sig[64])) + + txData := ethtx.AssociateTx{V: V.Bytes(), R: R.Bytes(), S: S.Bytes(), CustomMessage: prefixedMessage} + msg, err := types.NewMsgEVMTransaction(&txData) + 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) { + panic("should not be called") + }) + require.Nil(t, err) + associated, ok := k.GetEVMAddress(ctx, seiAddr) + require.True(t, ok) + require.Equal(t, evmAddr, associated) +} + +func TestGetVersion(t *testing.T) { + ethCfg := ¶ms.ChainConfig{} + ctx := sdk.Context{}.WithBlockHeight(10).WithBlockTime(time.Now()) + zero := uint64(0) + + ethCfg.LondonBlock = big.NewInt(0) + ethCfg.CancunTime = &zero + require.Equal(t, derived.Cancun, ante.GetVersion(ctx, ethCfg)) + + ethCfg.CancunTime = nil + require.Equal(t, derived.London, ante.GetVersion(ctx, ethCfg)) +} + +func TestAnteDeps(t *testing.T) { + k, _ := testkeeper.MockEVMKeeper() + handler := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + msg, _ := types.NewMsgEVMTransaction(ðtx.LegacyTx{GasLimit: 100}) + msg.Derived = &derived.Derived{ + SenderEVMAddr: common.BytesToAddress([]byte("senderevm")), + SenderSeiAddr: []byte("sendersei"), + PubKey: &secp256k1.PubKey{Key: []byte("pubkey")}, + } + deps, err := handler.AnteDeps(nil, mockTx{msgs: []sdk.Msg{msg}}, 0, func(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int) ([]sdkacltypes.AccessOperation, error) { + return txDeps, nil + }) + require.Nil(t, err) + require.Equal(t, 12, len(deps)) +} + +func TestEVMAddressDecorator(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + privKey := testkeeper.MockPrivateKey() + sender, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + recipient, _ := testkeeper.MockAddressPair() + handler := ante.NewEVMAddressDecorator(k, k.AccountKeeper()) + msg := banktypes.NewMsgSend(sender, recipient, sdk.NewCoins(sdk.NewCoin("usei", sdk.OneInt()))) + k.AccountKeeper().SetAccount(ctx, authtypes.NewBaseAccount(sender, privKey.PubKey(), 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) { + return ctx, nil + }) + require.Nil(t, err) + associatedEvmAddr, associated := k.GetEVMAddress(ctx, sender) + require.True(t, associated) + require.Equal(t, evmAddr, associatedEvmAddr) +} diff --git a/x/evm/ante/router.go b/x/evm/ante/router.go new file mode 100644 index 0000000000..51bbd0d6ae --- /dev/null +++ b/x/evm/ante/router.go @@ -0,0 +1,69 @@ +package ante + +import ( + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +type EVMRouterDecorator struct { + defaultAnteHandler sdk.AnteHandler + evmAnteHandler sdk.AnteHandler + + defaultAnteDepGenerator sdk.AnteDepGenerator + evmAnteDepGenerator sdk.AnteDepGenerator +} + +func NewEVMRouterDecorator( + defaultAnteHandler sdk.AnteHandler, + evmAnteHandler sdk.AnteHandler, + defaultAnteDepGenerator sdk.AnteDepGenerator, + evmAnteDepGenerator sdk.AnteDepGenerator, +) *EVMRouterDecorator { + return &EVMRouterDecorator{ + defaultAnteHandler: defaultAnteHandler, + evmAnteHandler: evmAnteHandler, + defaultAnteDepGenerator: defaultAnteDepGenerator, + evmAnteDepGenerator: evmAnteDepGenerator, + } +} + +func (r EVMRouterDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { + if isEVM, err := IsEVMMessage(tx); err != nil { + return ctx, err + } else if isEVM { + return r.evmAnteHandler(ctx, tx, simulate) + } + + return r.defaultAnteHandler(ctx, tx, simulate) +} + +func (r EVMRouterDecorator) AnteDeps(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int) (newTxDeps []sdkacltypes.AccessOperation, err error) { + if isEVM, err := IsEVMMessage(tx); err != nil { + return nil, err + } else if isEVM { + return r.evmAnteDepGenerator(txDeps, tx, txIndex) + } + + return r.defaultAnteDepGenerator(txDeps, tx, txIndex) +} + +func IsEVMMessage(tx sdk.Tx) (bool, error) { + hasEVMMsg := false + for _, msg := range tx.GetMsgs() { + switch msg.(type) { + case *types.MsgEVMTransaction: + hasEVMMsg = true + default: + continue + } + } + + if hasEVMMsg && len(tx.GetMsgs()) != 1 { + return false, errors.New("EVM tx must have exactly one message") + } + + return hasEVMMsg, nil +} diff --git a/x/evm/ante/router_test.go b/x/evm/ante/router_test.go new file mode 100644 index 0000000000..86e16cca98 --- /dev/null +++ b/x/evm/ante/router_test.go @@ -0,0 +1,65 @@ +package ante_test + +import ( + "testing" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkacltypes "github.com/cosmos/cosmos-sdk/types/accesscontrol" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" +) + +type mockAnteState struct { + call string +} + +func (m *mockAnteState) regularAnteHandler(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + m.call = "regular" + return ctx, nil +} + +func (m *mockAnteState) evmAnteHandler(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + m.call = "evm" + return ctx, nil +} + +func (m *mockAnteState) regularAnteDepGenerator(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int) (newTxDeps []sdkacltypes.AccessOperation, err error) { + m.call = "regulardep" + return []sdkacltypes.AccessOperation{}, nil +} + +func (m *mockAnteState) evmAnteDepGenerator(txDeps []sdkacltypes.AccessOperation, tx sdk.Tx, txIndex int) (newTxDeps []sdkacltypes.AccessOperation, err error) { + m.call = "evmdep" + return []sdkacltypes.AccessOperation{}, nil +} + +type mockTx struct { + msgs []sdk.Msg + signers []sdk.AccAddress +} + +func (tx mockTx) GetMsgs() []sdk.Msg { return tx.msgs } +func (tx mockTx) ValidateBasic() error { return nil } +func (tx mockTx) GetSigners() []sdk.AccAddress { return tx.signers } +func (tx mockTx) GetPubKeys() ([]cryptotypes.PubKey, error) { return nil, nil } +func (tx mockTx) GetSignaturesV2() ([]signing.SignatureV2, error) { return nil, nil } + +func TestRouter(t *testing.T) { + bankMsg := &banktypes.MsgSend{} + evmMsg, _ := types.NewMsgEVMTransaction(ðtx.LegacyTx{}) + mockAnte := mockAnteState{} + router := ante.NewEVMRouterDecorator(mockAnte.regularAnteHandler, mockAnte.evmAnteHandler, mockAnte.regularAnteDepGenerator, mockAnte.evmAnteDepGenerator) + _, err := router.AnteHandle(sdk.Context{}, mockTx{msgs: []sdk.Msg{bankMsg}}, false) + require.Nil(t, err) + require.Equal(t, "regular", mockAnte.call) + _, err = router.AnteHandle(sdk.Context{}, mockTx{msgs: []sdk.Msg{evmMsg}}, false) + require.Nil(t, err) + require.Equal(t, "evm", mockAnte.call) + _, err = router.AnteHandle(sdk.Context{}, mockTx{msgs: []sdk.Msg{evmMsg, bankMsg}}, false) + require.NotNil(t, err) +} diff --git a/x/evm/ante/sig.go b/x/evm/ante/sig.go new file mode 100644 index 0000000000..25e0233e4f --- /dev/null +++ b/x/evm/ante/sig.go @@ -0,0 +1,87 @@ +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +type EVMSigVerifyDecorator struct { + evmKeeper *evmkeeper.Keeper + latestCtxGetter func() sdk.Context // should be read-only +} + +func NewEVMSigVerifyDecorator(evmKeeper *evmkeeper.Keeper, latestCtxGetter func() sdk.Context) *EVMSigVerifyDecorator { + return &EVMSigVerifyDecorator{ + evmKeeper: evmKeeper, + latestCtxGetter: latestCtxGetter, + } +} + +func (svd *EVMSigVerifyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + ethTx, _ := types.MustGetEVMTransactionMessage(tx).AsTransaction() + + evmAddr := types.MustGetEVMTransactionMessage(tx).Derived.SenderEVMAddr + + nextNonce := svd.evmKeeper.GetNonce(ctx, evmAddr) + txNonce := ethTx.Nonce() + + // set EVM properties + ctx = ctx.WithIsEVM(true) + ctx = ctx.WithEVMNonce(txNonce) + ctx = ctx.WithEVMSenderAddress(evmAddr.Hex()) + + if ctx.IsCheckTx() { + if txNonce < nextNonce { + return ctx, sdkerrors.ErrWrongSequence + } + ctx = ctx.WithCheckTxCallback(func(thenCtx sdk.Context, e error) { + if e != nil { + return + } + txKey := tmtypes.Tx(ctx.TxBytes()).Key() + svd.evmKeeper.AddPendingNonce(txKey, evmAddr, txNonce, thenCtx.Priority()) + }) + + // if the mempool expires a transaction, this handler is invoked + ctx = ctx.WithExpireTxHandler(func() { + txKey := tmtypes.Tx(ctx.TxBytes()).Key() + svd.evmKeeper.RemovePendingNonce(txKey) + }) + + if txNonce > nextNonce { + // transaction shall be added to mempool as a pending transaction + ctx = ctx.WithPendingTxChecker(func() abci.PendingTxCheckerResponse { + latestCtx := svd.latestCtxGetter() + + // nextNonceToBeMined is the next nonce that will be mined + // geth calls SetNonce(n+1) after a transaction is mined + nextNonceToBeMined := svd.evmKeeper.GetNonce(latestCtx, evmAddr) + + // nextPendingNonce is the minimum nonce a user may send without stomping on an already-sent + // nonce, including non-mined or pending transactions + // If a user skips a nonce [1,2,4], then this will be the value of that hole (e.g., 3) + nextPendingNonce := svd.evmKeeper.CalculateNextNonce(latestCtx, evmAddr, true) + + if txNonce < nextNonceToBeMined { + // this nonce has already been mined, we cannot accept it again + return abci.Rejected + } else if txNonce < nextPendingNonce { + // this nonce is allowed to process as it is part of the + // consecutive nonces from nextNonceToBeMined to nextPendingNonce + // This logic allows multiple nonces from an account to be processed in a block. + return abci.Accepted + } + return abci.Pending + }) + } + } else if txNonce != nextNonce { + return ctx, sdkerrors.ErrWrongSequence + } + + return next(ctx, tx, simulate) +} diff --git a/x/evm/ante/sig_test.go b/x/evm/ante/sig_test.go new file mode 100644 index 0000000000..5580d24be5 --- /dev/null +++ b/x/evm/ante/sig_test.go @@ -0,0 +1,150 @@ +package ante_test + +import ( + "encoding/hex" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" +) + +func TestEVMSigVerifyDecorator(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + handler := ante.NewEVMSigVerifyDecorator(k, func() sdk.Context { return ctx }) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + to := new(common.Address) + copy(to[:], []byte("0x1234567890abcdef1234567890abcdef12345678")) + txData := ethtypes.LegacyTx{ + Nonce: 1, + GasPrice: big.NewInt(10), + Gas: 1000, + To: to, + Value: big.NewInt(1000), + Data: []byte("abc"), + } + 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) + + preprocessor := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + + // should return error because nonce is incorrect + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) + + // should return error if acc is not found (i.e. preprocess not called) + txData.Nonce = 0 + 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) + + require.Panics(t, func() { + handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + }) + + // should succeed + txData.Nonce = 0 + 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) + + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) +} + +func TestSigVerifyPendingTransaction(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + ctx = ctx.WithIsCheckTx(true) + handler := ante.NewEVMSigVerifyDecorator(k, func() sdk.Context { return ctx }) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + _, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + to := new(common.Address) + copy(to[:], []byte("0x1234567890abcdef1234567890abcdef12345678")) + txData := ethtypes.LegacyTx{ + Nonce: 1, + GasPrice: big.NewInt(10), + Gas: 1000, + To: to, + Value: big.NewInt(1000), + Data: []byte("abc"), + } + 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) + + preprocessor := ante.NewEVMPreprocessDecorator(k, k.AccountKeeper()) + ctx, err = preprocessor.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + + // should not return error but include pending tx checker + newCtx, err := handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.Nil(t, err) + require.NotNil(t, newCtx.PendingTxChecker()) + newCtx.CheckTxCallback()(newCtx, err) + + // test checker + require.Equal(t, abci.Pending, newCtx.PendingTxChecker()()) + k.SetNonce(ctx, evmAddr, 1) + require.Equal(t, abci.Accepted, newCtx.PendingTxChecker()()) + k.SetNonce(ctx, evmAddr, 2) + require.Equal(t, abci.Rejected, newCtx.PendingTxChecker()()) + + // should return error because current nonce is larger than tx nonce + _, err = handler.AnteHandle(ctx, mockTx{msgs: []sdk.Msg{msg}}, false, func(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) { + return ctx, nil + }) + require.NotNil(t, err) +} diff --git a/x/evm/artifacts/README b/x/evm/artifacts/README new file mode 100644 index 0000000000..2972e92bef --- /dev/null +++ b/x/evm/artifacts/README @@ -0,0 +1,5 @@ +The source files are under contracts/src. The artifacts should be updated whenever the source files change. To update run the following (with NativeSeiTokensERC20 as an example): +- `solc --overwrite @openzeppelin=contracts/lib/openzeppelin-contracts --bin -o x/evm/artifacts/cw721 contracts/src/CW721ERC721Pointer.sol` +- `solc --overwrite @openzeppelin=contracts/lib/openzeppelin-contracts --abi -o x/evm/artifacts/cw721 contracts/src/CW721ERC721Pointer.sol` +- (clean up any artifact that is not CW721ERC721Pointer.bin/abi) +- `abigen --abi=x/evm/artifacts/cw721/CW721ERC721Pointer.abi --pkg=cw721 --out=x/evm/artifacts/cw721/cw721.go` \ No newline at end of file diff --git a/x/evm/artifacts/cw20/CW20ERC20Pointer.abi b/x/evm/artifacts/cw20/CW20ERC20Pointer.abi new file mode 100644 index 0000000000..07521079d6 --- /dev/null +++ b/x/evm/artifacts/cw20/CW20ERC20Pointer.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"Cw20Address_","type":"string"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"AddrPrecompile","outputs":[{"internalType":"contract IAddr","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"Cw20Address","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":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/x/evm/artifacts/cw20/CW20ERC20Pointer.bin b/x/evm/artifacts/cw20/CW20ERC20Pointer.bin new file mode 100644 index 0000000000..aa46404f80 --- /dev/null +++ b/x/evm/artifacts/cw20/CW20ERC20Pointer.bin @@ -0,0 +1 @@ +608060405234801562000010575f80fd5b506040516200333f3803806200333f8339818101604052810190620000369190620002c4565b81818160039081620000499190620005b1565b5080600490816200005b9190620005b1565b50505061100260065f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100360075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100460085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260059081620001359190620005b1565b5050505062000695565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620001a08262000158565b810181811067ffffffffffffffff82111715620001c257620001c162000168565b5b80604052505050565b5f620001d66200013f565b9050620001e4828262000195565b919050565b5f67ffffffffffffffff82111562000206576200020562000168565b5b620002118262000158565b9050602081019050919050565b5f5b838110156200023d57808201518184015260208101905062000220565b5f8484015250505050565b5f6200025e6200025884620001e9565b620001cb565b9050828152602081018484840111156200027d576200027c62000154565b5b6200028a8482856200021e565b509392505050565b5f82601f830112620002a957620002a862000150565b5b8151620002bb84826020860162000248565b91505092915050565b5f805f60608486031215620002de57620002dd62000148565b5b5f84015167ffffffffffffffff811115620002fe57620002fd6200014c565b5b6200030c8682870162000292565b935050602084015167ffffffffffffffff81111562000330576200032f6200014c565b5b6200033e8682870162000292565b925050604084015167ffffffffffffffff8111156200036257620003616200014c565b5b620003708682870162000292565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620003c957607f821691505b602082108103620003df57620003de62000384565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000406565b6200044f868362000406565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000499620004936200048d8462000467565b62000470565b62000467565b9050919050565b5f819050919050565b620004b48362000479565b620004cc620004c382620004a0565b84845462000412565b825550505050565b5f90565b620004e2620004d4565b620004ef818484620004a9565b505050565b5b8181101562000516576200050a5f82620004d8565b600181019050620004f5565b5050565b601f82111562000565576200052f81620003e5565b6200053a84620003f7565b810160208510156200054a578190505b620005626200055985620003f7565b830182620004f4565b50505b505050565b5f82821c905092915050565b5f620005875f19846008026200056a565b1980831691505092915050565b5f620005a1838362000576565b9150826002028217905092915050565b620005bc826200037a565b67ffffffffffffffff811115620005d857620005d762000168565b5b620005e48254620003b1565b620005f18282856200051a565b5f60209050601f83116001811462000627575f841562000612578287015190505b6200061e858262000594565b8655506200068d565b601f1984166200063786620003e5565b5f5b82811015620006605784890151825560018201915060208501945060208101905062000639565b868310156200068057848901516200067c601f89168262000576565b8355505b6001600288020188555050505b505050505050565b612c9c80620006a35f395ff3fe608060405234801561000f575f80fd5b50600436106100cd575f3560e01c806395d89b411161008a578063da73d16b11610064578063da73d16b14610227578063dd62ed3e14610245578063de4725cc14610275578063f00b025514610293576100cd565b806395d89b41146101bb578063a9059cbb146101d9578063c2aed30214610209576100cd565b806306fdde03146100d1578063095ea7b3146100ef57806318160ddd1461011f57806323b872dd1461013d578063313ce5671461016d57806370a082311461018b575b5f80fd5b6100d96102b1565b6040516100e69190611f12565b60405180910390f35b61010960048036038101906101049190611fd0565b610341565b6040516101169190612028565b60405180910390f35b610127610796565b6040516101349190612050565b60405180910390f35b61015760048036038101906101529190612069565b610958565b6040516101649190612028565b60405180910390f35b610175610d31565b60405161018291906120d4565b60405180910390f35b6101a560048036038101906101a091906120ed565b610ef3565b6040516101b29190612050565b60405180910390f35b6101c36111de565b6040516101d09190611f12565b60405180910390f35b6101f360048036038101906101ee9190611fd0565b61126e565b6040516102009190612028565b60405180910390f35b610211611521565b60405161021e9190612173565b60405180910390f35b61022f611546565b60405161023c9190611f12565b60405180910390f35b61025f600480360381019061025a919061218c565b6115d2565b60405161026c9190612050565b60405180910390f35b61027d611975565b60405161028a91906121ea565b60405180910390f35b61029b61199a565b6040516102a89190612223565b60405180910390f35b6060600380546102c090612269565b80601f01602080910402602001604051908101604052809291908181526020018280546102ec90612269565b80156103375780601f1061030e57610100808354040283529160200191610337565b820191905f5260205f20905b81548152906001019060200180831161031a57829003601f168201915b5050505050905090565b5f8061034d33856115d2565b90508281111561053c575f61043a6040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061043560085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed896040518263ffffffff1660e01b81526004016103ee91906122a8565b5f60405180830381865afa158015610408573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061043091906123df565b6119bf565b611a07565b90505f6104976040518060400160405280600681526020017f616d6f756e74000000000000000000000000000000000000000000000000000081525061049261048d88876104889190612453565b611a59565b6119bf565b611a07565b90505f6105286105236040518060400160405280601281526020017f64656372656173655f616c6c6f77616e6365000000000000000000000000000081525061051e61051987876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b905061053381611bb9565b50505050610726565b82811015610725575f6106276040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061062260085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed896040518263ffffffff1660e01b81526004016105db91906122a8565b5f60405180830381865afa1580156105f5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061061d91906123df565b6119bf565b611a07565b90505f6106846040518060400160405280600681526020017f616d6f756e74000000000000000000000000000000000000000000000000000081525061067f61067a86896106759190612453565b611a59565b6119bf565b611a07565b90505f6107156107106040518060400160405280601281526020017f696e6372656173655f616c6c6f77616e6365000000000000000000000000000081525061070b61070687876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b905061072081611bb9565b505050505b5b8373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040516107839190612050565b60405180910390a3600191505092915050565b5f8061081461080f6040518060400160405280600a81526020017f746f6b656e5f696e666f000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f7b7d000000000000000000000000000000000000000000000000000000000000815250611a07565b611b71565b90505f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296005846040518363ffffffff1660e01b815260040161087492919061256b565b5f60405180830381865afa15801561088e573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906108b6919061263e565b905060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982826040518263ffffffff1660e01b815260040161091291906126cf565b602060405180830381865afa15801561092d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109519190612716565b9250505090565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036109c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109be906127b1565b60405180910390fd5b5f610aaa6040518060400160405280600581526020017f6f776e6572000000000000000000000000000000000000000000000000000000815250610aa560085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed896040518263ffffffff1660e01b8152600401610a5e91906122a8565b5f60405180830381865afa158015610a78573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610aa091906123df565b6119bf565b611a07565b90505f610b8f6040518060400160405280600981526020017f726563697069656e740000000000000000000000000000000000000000000000815250610b8a60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed896040518263ffffffff1660e01b8152600401610b4391906122a8565b5f60405180830381865afa158015610b5d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610b8591906123df565b6119bf565b611a07565b90505f610be16040518060400160405280600681526020017f616d6f756e740000000000000000000000000000000000000000000000000000815250610bdc610bd788611a59565b6119bf565b611a07565b90505f610cb1610cac6040518060400160405280600d81526020017f7472616e736665725f66726f6d00000000000000000000000000000000000000815250610ca7610ca2610c6689896040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b9050610cbc81611bb9565b508673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88604051610d1a9190612050565b60405180910390a360019450505050509392505050565b5f80610daf610daa6040518060400160405280600a81526020017f746f6b656e5f696e666f000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f7b7d000000000000000000000000000000000000000000000000000000000000815250611a07565b611b71565b90505f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296005846040518363ffffffff1660e01b8152600401610e0f92919061256b565b5f60405180830381865afa158015610e29573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610e51919061263e565b905060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982826040518263ffffffff1660e01b8152600401610ead9190612819565b602060405180830381865afa158015610ec8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eec9190612716565b9250505090565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610f62576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f59906128bc565b60405180910390fd5b5f6110456040518060400160405280600781526020017f616464726573730000000000000000000000000000000000000000000000000081525061104060085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401610ff991906122a8565b5f60405180830381865afa158015611013573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061103b91906123df565b6119bf565b611a07565b90505f6110976110926040518060400160405280600781526020017f62616c616e63650000000000000000000000000000000000000000000000000081525061108d85611b71565b611a07565b611b71565b90505f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296005846040518363ffffffff1660e01b81526004016110f792919061256b565b5f60405180830381865afa158015611111573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611139919061263e565b905060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982826040518263ffffffff1660e01b81526004016111959190612924565b602060405180830381865afa1580156111b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111d49190612716565b9350505050919050565b6060600480546111ed90612269565b80601f016020809104026020016040519081016040528092919081815260200182805461121990612269565b80156112645780601f1061123b57610100808354040283529160200191611264565b820191905f5260205f20905b81548152906001019060200180831161124757829003601f168201915b5050505050905090565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036112dd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d4906127b1565b60405180910390fd5b5f6113c06040518060400160405280600981526020017f726563697069656e7400000000000000000000000000000000000000000000008152506113bb60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161137491906122a8565b5f60405180830381865afa15801561138e573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906113b691906123df565b6119bf565b611a07565b90505f6114126040518060400160405280600681526020017f616d6f756e74000000000000000000000000000000000000000000000000000081525061140d61140887611a59565b6119bf565b611a07565b90505f6114a361149e6040518060400160405280600881526020017f7472616e7366657200000000000000000000000000000000000000000000000081525061149961149487876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b90506114ae81611bb9565b508573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8760405161150c9190612050565b60405180910390a36001935050505092915050565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6005805461155390612269565b80601f016020809104026020016040519081016040528092919081815260200182805461157f90612269565b80156115ca5780601f106115a1576101008083540402835291602001916115ca565b820191905f5260205f20905b8154815290600101906020018083116115ad57829003601f168201915b505050505081565b5f806116b66040518060400160405280600581526020017f6f776e65720000000000000000000000000000000000000000000000000000008152506116b160085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161166a91906122a8565b5f60405180830381865afa158015611684573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906116ac91906123df565b6119bf565b611a07565b90505f61179b6040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061179660085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161174f91906122a8565b5f60405180830381865afa158015611769573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061179191906123df565b6119bf565b611a07565b90505f61182c6118276040518060400160405280600981526020017f616c6c6f77616e6365000000000000000000000000000000000000000000000081525061182261181d87876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b90505f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296005846040518363ffffffff1660e01b815260040161188c92919061256b565b5f60405180830381865afa1580156118a6573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906118ce919061263e565b905060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982826040518263ffffffff1660e01b815260040161192a91906129a1565b602060405180830381865afa158015611945573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119699190612716565b94505050505092915050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060816040516020016119d29190612a34565b6040516020818303038152906040526040516020016119f19190612a59565b6040516020818303038152906040529050919050565b6060611a51611a15846119bf565b836040518060400160405280600181526020017f3a00000000000000000000000000000000000000000000000000000000000000815250611b23565b905092915050565b60605f6001611a6784611d37565b0190505f8167ffffffffffffffff811115611a8557611a846122c9565b5b6040519080825280601f01601f191660200182016040528015611ab75781602001600182028036833780820191505090505b5090505f82602001820190505b600115611b18578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581611b0d57611b0c612a7e565b5b0494505f8503611ac4575b819350505050919050565b6060838284604051602001611b39929190612aab565b604051602081830303815290604052604051602001611b59929190612aab565b60405160208183030381529060405290509392505050565b606081604051602001611b849190612af4565b604051602081830303815290604052604051602001611ba39190612b3f565b6040516020818303038152906040529050919050565b60605f8061100273ffffffffffffffffffffffffffffffffffffffff166005856040518060400160405280600281526020017f5b5d000000000000000000000000000000000000000000000000000000000000815250604051602401611c2193929190612b64565b6040516020818303038152906040527f44d227ae000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051611cab9190612be8565b5f60405180830381855af49150503d805f8114611ce3576040519150601f19603f3d011682016040523d82523d5f602084013e611ce8565b606091505b509150915081611d2d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2490612c48565b60405180910390fd5b8092505050919050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310611d93577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381611d8957611d88612a7e565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310611dd0576d04ee2d6d415b85acef81000000008381611dc657611dc5612a7e565b5b0492506020810190505b662386f26fc100008310611dff57662386f26fc100008381611df557611df4612a7e565b5b0492506010810190505b6305f5e1008310611e28576305f5e1008381611e1e57611e1d612a7e565b5b0492506008810190505b6127108310611e4d576127108381611e4357611e42612a7e565b5b0492506004810190505b60648310611e705760648381611e6657611e65612a7e565b5b0492506002810190505b600a8310611e7f576001810190505b80915050919050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015611ebf578082015181840152602081019050611ea4565b5f8484015250505050565b5f601f19601f8301169050919050565b5f611ee482611e88565b611eee8185611e92565b9350611efe818560208601611ea2565b611f0781611eca565b840191505092915050565b5f6020820190508181035f830152611f2a8184611eda565b905092915050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611f6c82611f43565b9050919050565b611f7c81611f62565b8114611f86575f80fd5b50565b5f81359050611f9781611f73565b92915050565b5f819050919050565b611faf81611f9d565b8114611fb9575f80fd5b50565b5f81359050611fca81611fa6565b92915050565b5f8060408385031215611fe657611fe5611f3b565b5b5f611ff385828601611f89565b925050602061200485828601611fbc565b9150509250929050565b5f8115159050919050565b6120228161200e565b82525050565b5f60208201905061203b5f830184612019565b92915050565b61204a81611f9d565b82525050565b5f6020820190506120635f830184612041565b92915050565b5f805f606084860312156120805761207f611f3b565b5b5f61208d86828701611f89565b935050602061209e86828701611f89565b92505060406120af86828701611fbc565b9150509250925092565b5f60ff82169050919050565b6120ce816120b9565b82525050565b5f6020820190506120e75f8301846120c5565b92915050565b5f6020828403121561210257612101611f3b565b5b5f61210f84828501611f89565b91505092915050565b5f819050919050565b5f61213b61213661213184611f43565b612118565b611f43565b9050919050565b5f61214c82612121565b9050919050565b5f61215d82612142565b9050919050565b61216d81612153565b82525050565b5f6020820190506121865f830184612164565b92915050565b5f80604083850312156121a2576121a1611f3b565b5b5f6121af85828601611f89565b92505060206121c085828601611f89565b9150509250929050565b5f6121d482612142565b9050919050565b6121e4816121ca565b82525050565b5f6020820190506121fd5f8301846121db565b92915050565b5f61220d82612142565b9050919050565b61221d81612203565b82525050565b5f6020820190506122365f830184612214565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061228057607f821691505b6020821081036122935761229261223c565b5b50919050565b6122a281611f62565b82525050565b5f6020820190506122bb5f830184612299565b92915050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6122ff82611eca565b810181811067ffffffffffffffff8211171561231e5761231d6122c9565b5b80604052505050565b5f612330611f32565b905061233c82826122f6565b919050565b5f67ffffffffffffffff82111561235b5761235a6122c9565b5b61236482611eca565b9050602081019050919050565b5f61238361237e84612341565b612327565b90508281526020810184848401111561239f5761239e6122c5565b5b6123aa848285611ea2565b509392505050565b5f82601f8301126123c6576123c56122c1565b5b81516123d6848260208601612371565b91505092915050565b5f602082840312156123f4576123f3611f3b565b5b5f82015167ffffffffffffffff81111561241157612410611f3f565b5b61241d848285016123b2565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61245d82611f9d565b915061246883611f9d565b92508282039050818111156124805761247f612426565b5b92915050565b5f819050815f5260205f209050919050565b5f81546124a481612269565b6124ae8186611e92565b9450600182165f81146124c857600181146124de57612510565b60ff198316865281151560200286019350612510565b6124e785612486565b5f5b83811015612508578154818901526001820191506020810190506124e9565b808801955050505b50505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f61253d82612519565b6125478185612523565b9350612557818560208601611ea2565b61256081611eca565b840191505092915050565b5f6040820190508181035f8301526125838185612498565b905081810360208301526125978184612533565b90509392505050565b5f67ffffffffffffffff8211156125ba576125b96122c9565b5b6125c382611eca565b9050602081019050919050565b5f6125e26125dd846125a0565b612327565b9050828152602081018484840111156125fe576125fd6122c5565b5b612609848285611ea2565b509392505050565b5f82601f830112612625576126246122c1565b5b81516126358482602086016125d0565b91505092915050565b5f6020828403121561265357612652611f3b565b5b5f82015167ffffffffffffffff8111156126705761266f611f3f565b5b61267c84828501612611565b91505092915050565b7f746f74616c5f737570706c7900000000000000000000000000000000000000005f82015250565b5f6126b9600c83611e92565b91506126c482612685565b602082019050919050565b5f6040820190508181035f8301526126e78184612533565b905081810360208301526126fa816126ad565b905092915050565b5f8151905061271081611fa6565b92915050565b5f6020828403121561272b5761272a611f3b565b5b5f61273884828501612702565b91505092915050565b7f45524332303a207472616e7366657220746f20746865207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f61279b602383611e92565b91506127a682612741565b604082019050919050565b5f6020820190508181035f8301526127c88161278f565b9050919050565b7f646563696d616c730000000000000000000000000000000000000000000000005f82015250565b5f612803600883611e92565b915061280e826127cf565b602082019050919050565b5f6040820190508181035f8301526128318184612533565b90508181036020830152612844816127f7565b905092915050565b7f45524332303a2062616c616e636520717565727920666f7220746865207a65725f8201527f6f20616464726573730000000000000000000000000000000000000000000000602082015250565b5f6128a6602983611e92565b91506128b18261284c565b604082019050919050565b5f6020820190508181035f8301526128d38161289a565b9050919050565b7f62616c616e6365000000000000000000000000000000000000000000000000005f82015250565b5f61290e600783611e92565b9150612919826128da565b602082019050919050565b5f6040820190508181035f83015261293c8184612533565b9050818103602083015261294f81612902565b905092915050565b7f616c6c6f77616e636500000000000000000000000000000000000000000000005f82015250565b5f61298b600983611e92565b915061299682612957565b602082019050919050565b5f6040820190508181035f8301526129b98184612533565b905081810360208301526129cc8161297f565b905092915050565b5f81905092915050565b5f6129e882611e88565b6129f281856129d4565b9350612a02818560208601611ea2565b80840191505092915050565b7f2200000000000000000000000000000000000000000000000000000000000000815250565b5f612a3f82846129de565b9150612a4a82612a0e565b60018201915081905092915050565b5f612a6382612a0e565b600182019150612a7382846129de565b915081905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f612ab682856129de565b9150612ac282846129de565b91508190509392505050565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b5f612aff82846129de565b9150612b0a82612ace565b60018201915081905092915050565b7f7b00000000000000000000000000000000000000000000000000000000000000815250565b5f612b4982612b19565b600182019150612b5982846129de565b915081905092915050565b5f6060820190508181035f830152612b7c8186612498565b90508181036020830152612b908185612533565b90508181036040830152612ba48184612533565b9050949350505050565b5f81905092915050565b5f612bc282612519565b612bcc8185612bae565b9350612bdc818560208601611ea2565b80840191505092915050565b5f612bf38284612bb8565b915081905092915050565b7f436f736d5761736d2065786563757465206661696c65640000000000000000005f82015250565b5f612c32601783611e92565b9150612c3d82612bfe565b602082019050919050565b5f6020820190508181035f830152612c5f81612c26565b905091905056fea264697066735822122075eae9bc52a66b043c6987fba673e9d43c7834f3d9cc1286e3931e1f398dcedc64736f6c63430008150033 \ No newline at end of file diff --git a/x/evm/artifacts/cw20/artifacts.go b/x/evm/artifacts/cw20/artifacts.go new file mode 100644 index 0000000000..073971723e --- /dev/null +++ b/x/evm/artifacts/cw20/artifacts.go @@ -0,0 +1,101 @@ +package cw20 + +import ( + "bytes" + "embed" + "encoding/hex" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +const CurrentVersion uint16 = 1 + +//go:embed CW20ERC20Pointer.abi +//go:embed CW20ERC20Pointer.bin +//go:embed legacy.bin +var f embed.FS + +var cachedBin []byte +var cachedLegacyBin []byte +var cachedABI *abi.ABI + +func GetABI() []byte { + bz, err := f.ReadFile("CW20ERC20Pointer.abi") + if err != nil { + panic("failed to read CW20ERC20 contract ABI") + } + return bz +} + +func GetParsedABI() *abi.ABI { + if cachedABI != nil { + return cachedABI + } + parsedABI, err := abi.JSON(strings.NewReader(string(GetABI()))) + if err != nil { + panic(err) + } + cachedABI = &parsedABI + return cachedABI +} + +func GetBin() []byte { + if cachedBin != nil { + return cachedBin + } + code, err := f.ReadFile("CW20ERC20Pointer.bin") + if err != nil { + panic("failed to read CW20ERC20 contract binary") + } + bz, err := hex.DecodeString(string(code)) + if err != nil { + panic("failed to decode CW20ERC20 contract binary") + } + cachedBin = bz + return bz +} + +func GetLegacyBin() []byte { + if cachedLegacyBin != nil { + return cachedLegacyBin + } + code, err := f.ReadFile("legacy.bin") + if err != nil { + panic("failed to read CW20ERC20 legacy contract binary") + } + bz, err := hex.DecodeString(string(code)) + if err != nil { + panic("failed to decode CW20ERC20 legacy contract binary") + } + cachedLegacyBin = bz + return bz +} + +func IsCodeFromBin(code []byte) bool { + return isCodeFromBin(code, GetBin()) || isCodeFromBin(code, GetLegacyBin()) +} + +func isCodeFromBin(code []byte, bin []byte) bool { + binLen := len(bin) + if len(code) < binLen { + return false + } + if !bytes.Equal(code[:binLen], bin) { + return false + } + abi, err := Cw20MetaData.GetAbi() + if err != nil { + fmt.Printf("error getting metadata ABI: %s\n", err) + return false + } + args, err := abi.Constructor.Inputs.Unpack(code[binLen:]) + if err != nil || len(args) != 3 { + return false + } + _, isA0String := args[0].(string) + _, isA1String := args[1].(string) + _, isA2String := args[2].(string) + return isA0String && isA1String && isA2String +} diff --git a/x/evm/artifacts/cw20/cw20.go b/x/evm/artifacts/cw20/cw20.go new file mode 100644 index 0000000000..bd272eca95 --- /dev/null +++ b/x/evm/artifacts/cw20/cw20.go @@ -0,0 +1,862 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package cw20 + +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 +) + +// Cw20MetaData contains all meta data concerning the Cw20 contract. +var Cw20MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"Cw20Address_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"AddrPrecompile\",\"outputs\":[{\"internalType\":\"contractIAddr\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Cw20Address\",\"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\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// Cw20ABI is the input ABI used to generate the binding from. +// Deprecated: Use Cw20MetaData.ABI instead. +var Cw20ABI = Cw20MetaData.ABI + +// Cw20 is an auto generated Go binding around an Ethereum contract. +type Cw20 struct { + Cw20Caller // Read-only binding to the contract + Cw20Transactor // Write-only binding to the contract + Cw20Filterer // Log filterer for contract events +} + +// Cw20Caller is an auto generated read-only Go binding around an Ethereum contract. +type Cw20Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Cw20Transactor is an auto generated write-only Go binding around an Ethereum contract. +type Cw20Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Cw20Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type Cw20Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Cw20Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type Cw20Session struct { + Contract *Cw20 // 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 +} + +// Cw20CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type Cw20CallerSession struct { + Contract *Cw20Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// Cw20TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type Cw20TransactorSession struct { + Contract *Cw20Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Cw20Raw is an auto generated low-level Go binding around an Ethereum contract. +type Cw20Raw struct { + Contract *Cw20 // Generic contract binding to access the raw methods on +} + +// Cw20CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type Cw20CallerRaw struct { + Contract *Cw20Caller // Generic read-only contract binding to access the raw methods on +} + +// Cw20TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type Cw20TransactorRaw struct { + Contract *Cw20Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewCw20 creates a new instance of Cw20, bound to a specific deployed contract. +func NewCw20(address common.Address, backend bind.ContractBackend) (*Cw20, error) { + contract, err := bindCw20(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Cw20{Cw20Caller: Cw20Caller{contract: contract}, Cw20Transactor: Cw20Transactor{contract: contract}, Cw20Filterer: Cw20Filterer{contract: contract}}, nil +} + +// NewCw20Caller creates a new read-only instance of Cw20, bound to a specific deployed contract. +func NewCw20Caller(address common.Address, caller bind.ContractCaller) (*Cw20Caller, error) { + contract, err := bindCw20(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &Cw20Caller{contract: contract}, nil +} + +// NewCw20Transactor creates a new write-only instance of Cw20, bound to a specific deployed contract. +func NewCw20Transactor(address common.Address, transactor bind.ContractTransactor) (*Cw20Transactor, error) { + contract, err := bindCw20(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &Cw20Transactor{contract: contract}, nil +} + +// NewCw20Filterer creates a new log filterer instance of Cw20, bound to a specific deployed contract. +func NewCw20Filterer(address common.Address, filterer bind.ContractFilterer) (*Cw20Filterer, error) { + contract, err := bindCw20(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &Cw20Filterer{contract: contract}, nil +} + +// bindCw20 binds a generic wrapper to an already deployed contract. +func bindCw20(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := Cw20MetaData.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 (_Cw20 *Cw20Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Cw20.Contract.Cw20Caller.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 (_Cw20 *Cw20Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Cw20.Contract.Cw20Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Cw20 *Cw20Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Cw20.Contract.Cw20Transactor.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 (_Cw20 *Cw20CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Cw20.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 (_Cw20 *Cw20TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Cw20.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Cw20 *Cw20TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Cw20.Contract.contract.Transact(opts, method, params...) +} + +// AddrPrecompile is a free data retrieval call binding the contract method 0xc2aed302. +// +// Solidity: function AddrPrecompile() view returns(address) +func (_Cw20 *Cw20Caller) AddrPrecompile(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Cw20.contract.Call(opts, &out, "AddrPrecompile") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// AddrPrecompile is a free data retrieval call binding the contract method 0xc2aed302. +// +// Solidity: function AddrPrecompile() view returns(address) +func (_Cw20 *Cw20Session) AddrPrecompile() (common.Address, error) { + return _Cw20.Contract.AddrPrecompile(&_Cw20.CallOpts) +} + +// AddrPrecompile is a free data retrieval call binding the contract method 0xc2aed302. +// +// Solidity: function AddrPrecompile() view returns(address) +func (_Cw20 *Cw20CallerSession) AddrPrecompile() (common.Address, error) { + return _Cw20.Contract.AddrPrecompile(&_Cw20.CallOpts) +} + +// Cw20Address is a free data retrieval call binding the contract method 0xda73d16b. +// +// Solidity: function Cw20Address() view returns(string) +func (_Cw20 *Cw20Caller) Cw20Address(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Cw20.contract.Call(opts, &out, "Cw20Address") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Cw20Address is a free data retrieval call binding the contract method 0xda73d16b. +// +// Solidity: function Cw20Address() view returns(string) +func (_Cw20 *Cw20Session) Cw20Address() (string, error) { + return _Cw20.Contract.Cw20Address(&_Cw20.CallOpts) +} + +// Cw20Address is a free data retrieval call binding the contract method 0xda73d16b. +// +// Solidity: function Cw20Address() view returns(string) +func (_Cw20 *Cw20CallerSession) Cw20Address() (string, error) { + return _Cw20.Contract.Cw20Address(&_Cw20.CallOpts) +} + +// JsonPrecompile is a free data retrieval call binding the contract method 0xde4725cc. +// +// Solidity: function JsonPrecompile() view returns(address) +func (_Cw20 *Cw20Caller) JsonPrecompile(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Cw20.contract.Call(opts, &out, "JsonPrecompile") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// JsonPrecompile is a free data retrieval call binding the contract method 0xde4725cc. +// +// Solidity: function JsonPrecompile() view returns(address) +func (_Cw20 *Cw20Session) JsonPrecompile() (common.Address, error) { + return _Cw20.Contract.JsonPrecompile(&_Cw20.CallOpts) +} + +// JsonPrecompile is a free data retrieval call binding the contract method 0xde4725cc. +// +// Solidity: function JsonPrecompile() view returns(address) +func (_Cw20 *Cw20CallerSession) JsonPrecompile() (common.Address, error) { + return _Cw20.Contract.JsonPrecompile(&_Cw20.CallOpts) +} + +// WasmdPrecompile is a free data retrieval call binding the contract method 0xf00b0255. +// +// Solidity: function WasmdPrecompile() view returns(address) +func (_Cw20 *Cw20Caller) WasmdPrecompile(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Cw20.contract.Call(opts, &out, "WasmdPrecompile") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// WasmdPrecompile is a free data retrieval call binding the contract method 0xf00b0255. +// +// Solidity: function WasmdPrecompile() view returns(address) +func (_Cw20 *Cw20Session) WasmdPrecompile() (common.Address, error) { + return _Cw20.Contract.WasmdPrecompile(&_Cw20.CallOpts) +} + +// WasmdPrecompile is a free data retrieval call binding the contract method 0xf00b0255. +// +// Solidity: function WasmdPrecompile() view returns(address) +func (_Cw20 *Cw20CallerSession) WasmdPrecompile() (common.Address, error) { + return _Cw20.Contract.WasmdPrecompile(&_Cw20.CallOpts) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Cw20 *Cw20Caller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _Cw20.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Cw20 *Cw20Session) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Cw20.Contract.Allowance(&_Cw20.CallOpts, owner, spender) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Cw20 *Cw20CallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Cw20.Contract.Allowance(&_Cw20.CallOpts, owner, spender) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address owner) view returns(uint256) +func (_Cw20 *Cw20Caller) BalanceOf(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { + var out []interface{} + err := _Cw20.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 (_Cw20 *Cw20Session) BalanceOf(owner common.Address) (*big.Int, error) { + return _Cw20.Contract.BalanceOf(&_Cw20.CallOpts, owner) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address owner) view returns(uint256) +func (_Cw20 *Cw20CallerSession) BalanceOf(owner common.Address) (*big.Int, error) { + return _Cw20.Contract.BalanceOf(&_Cw20.CallOpts, owner) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Cw20 *Cw20Caller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _Cw20.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Cw20 *Cw20Session) Decimals() (uint8, error) { + return _Cw20.Contract.Decimals(&_Cw20.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Cw20 *Cw20CallerSession) Decimals() (uint8, error) { + return _Cw20.Contract.Decimals(&_Cw20.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Cw20 *Cw20Caller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Cw20.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 (_Cw20 *Cw20Session) Name() (string, error) { + return _Cw20.Contract.Name(&_Cw20.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Cw20 *Cw20CallerSession) Name() (string, error) { + return _Cw20.Contract.Name(&_Cw20.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Cw20 *Cw20Caller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Cw20.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 (_Cw20 *Cw20Session) Symbol() (string, error) { + return _Cw20.Contract.Symbol(&_Cw20.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Cw20 *Cw20CallerSession) Symbol() (string, error) { + return _Cw20.Contract.Symbol(&_Cw20.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Cw20 *Cw20Caller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Cw20.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 (_Cw20 *Cw20Session) TotalSupply() (*big.Int, error) { + return _Cw20.Contract.TotalSupply(&_Cw20.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Cw20 *Cw20CallerSession) TotalSupply() (*big.Int, error) { + return _Cw20.Contract.TotalSupply(&_Cw20.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_Cw20 *Cw20Transactor) Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _Cw20.contract.Transact(opts, "approve", spender, amount) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_Cw20 *Cw20Session) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _Cw20.Contract.Approve(&_Cw20.TransactOpts, spender, amount) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 amount) returns(bool) +func (_Cw20 *Cw20TransactorSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { + return _Cw20.Contract.Approve(&_Cw20.TransactOpts, spender, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_Cw20 *Cw20Transactor) Transfer(opts *bind.TransactOpts, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Cw20.contract.Transact(opts, "transfer", to, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_Cw20 *Cw20Session) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Cw20.Contract.Transfer(&_Cw20.TransactOpts, to, amount) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 amount) returns(bool) +func (_Cw20 *Cw20TransactorSession) Transfer(to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Cw20.Contract.Transfer(&_Cw20.TransactOpts, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_Cw20 *Cw20Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Cw20.contract.Transact(opts, "transferFrom", from, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_Cw20 *Cw20Session) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Cw20.Contract.TransferFrom(&_Cw20.TransactOpts, from, to, amount) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 amount) returns(bool) +func (_Cw20 *Cw20TransactorSession) TransferFrom(from common.Address, to common.Address, amount *big.Int) (*types.Transaction, error) { + return _Cw20.Contract.TransferFrom(&_Cw20.TransactOpts, from, to, amount) +} + +// Cw20ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Cw20 contract. +type Cw20ApprovalIterator struct { + Event *Cw20Approval // 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 *Cw20ApprovalIterator) 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(Cw20Approval) + 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(Cw20Approval) + 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 *Cw20ApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Cw20ApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Cw20Approval represents a Approval event raised by the Cw20 contract. +type Cw20Approval struct { + Owner common.Address + Spender common.Address + Value *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 spender, uint256 value) +func (_Cw20 *Cw20Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*Cw20ApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Cw20.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &Cw20ApprovalIterator{contract: _Cw20.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 spender, uint256 value) +func (_Cw20 *Cw20Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *Cw20Approval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Cw20.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + 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(Cw20Approval) + if err := _Cw20.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 spender, uint256 value) +func (_Cw20 *Cw20Filterer) ParseApproval(log types.Log) (*Cw20Approval, error) { + event := new(Cw20Approval) + if err := _Cw20.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// Cw20TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Cw20 contract. +type Cw20TransferIterator struct { + Event *Cw20Transfer // 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 *Cw20TransferIterator) 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(Cw20Transfer) + 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(Cw20Transfer) + 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 *Cw20TransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Cw20TransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Cw20Transfer represents a Transfer event raised by the Cw20 contract. +type Cw20Transfer struct { + From common.Address + To common.Address + Value *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 value) +func (_Cw20 *Cw20Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*Cw20TransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Cw20.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &Cw20TransferIterator{contract: _Cw20.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 value) +func (_Cw20 *Cw20Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *Cw20Transfer, from []common.Address, to []common.Address) (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) + } + + logs, sub, err := _Cw20.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + 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(Cw20Transfer) + if err := _Cw20.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 value) +func (_Cw20 *Cw20Filterer) ParseTransfer(log types.Log) (*Cw20Transfer, error) { + event := new(Cw20Transfer) + if err := _Cw20.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/x/evm/artifacts/cw20/legacy.bin b/x/evm/artifacts/cw20/legacy.bin new file mode 100644 index 0000000000..280ef16320 --- /dev/null +++ b/x/evm/artifacts/cw20/legacy.bin @@ -0,0 +1 @@ +608060405234801562000010575f80fd5b506040516200333f3803806200333f8339818101604052810190620000369190620002c4565b81818160039081620000499190620005b1565b5080600490816200005b9190620005b1565b50505061100260065f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100360075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100460085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260059081620001359190620005b1565b5050505062000695565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620001a08262000158565b810181811067ffffffffffffffff82111715620001c257620001c162000168565b5b80604052505050565b5f620001d66200013f565b9050620001e4828262000195565b919050565b5f67ffffffffffffffff82111562000206576200020562000168565b5b620002118262000158565b9050602081019050919050565b5f5b838110156200023d57808201518184015260208101905062000220565b5f8484015250505050565b5f6200025e6200025884620001e9565b620001cb565b9050828152602081018484840111156200027d576200027c62000154565b5b6200028a8482856200021e565b509392505050565b5f82601f830112620002a957620002a862000150565b5b8151620002bb84826020860162000248565b91505092915050565b5f805f60608486031215620002de57620002dd62000148565b5b5f84015167ffffffffffffffff811115620002fe57620002fd6200014c565b5b6200030c8682870162000292565b935050602084015167ffffffffffffffff81111562000330576200032f6200014c565b5b6200033e8682870162000292565b925050604084015167ffffffffffffffff8111156200036257620003616200014c565b5b620003708682870162000292565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620003c957607f821691505b602082108103620003df57620003de62000384565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000406565b6200044f868362000406565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000499620004936200048d8462000467565b62000470565b62000467565b9050919050565b5f819050919050565b620004b48362000479565b620004cc620004c382620004a0565b84845462000412565b825550505050565b5f90565b620004e2620004d4565b620004ef818484620004a9565b505050565b5b8181101562000516576200050a5f82620004d8565b600181019050620004f5565b5050565b601f82111562000565576200052f81620003e5565b6200053a84620003f7565b810160208510156200054a578190505b620005626200055985620003f7565b830182620004f4565b50505b505050565b5f82821c905092915050565b5f620005875f19846008026200056a565b1980831691505092915050565b5f620005a1838362000576565b9150826002028217905092915050565b620005bc826200037a565b67ffffffffffffffff811115620005d857620005d762000168565b5b620005e48254620003b1565b620005f18282856200051a565b5f60209050601f83116001811462000627575f841562000612578287015190505b6200061e858262000594565b8655506200068d565b601f1984166200063786620003e5565b5f5b82811015620006605784890151825560018201915060208501945060208101905062000639565b868310156200068057848901516200067c601f89168262000576565b8355505b6001600288020188555050505b505050505050565b612c9c80620006a35f395ff3fe608060405234801561000f575f80fd5b50600436106100cd575f3560e01c806395d89b411161008a578063da73d16b11610064578063da73d16b14610227578063dd62ed3e14610245578063de4725cc14610275578063f00b025514610293576100cd565b806395d89b41146101bb578063a9059cbb146101d9578063c2aed30214610209576100cd565b806306fdde03146100d1578063095ea7b3146100ef57806318160ddd1461011f57806323b872dd1461013d578063313ce5671461016d57806370a082311461018b575b5f80fd5b6100d96102b1565b6040516100e69190611f12565b60405180910390f35b61010960048036038101906101049190611fd0565b610341565b6040516101169190612028565b60405180910390f35b610127610796565b6040516101349190612050565b60405180910390f35b61015760048036038101906101529190612069565b610958565b6040516101649190612028565b60405180910390f35b610175610d31565b60405161018291906120d4565b60405180910390f35b6101a560048036038101906101a091906120ed565b610ef3565b6040516101b29190612050565b60405180910390f35b6101c36111de565b6040516101d09190611f12565b60405180910390f35b6101f360048036038101906101ee9190611fd0565b61126e565b6040516102009190612028565b60405180910390f35b610211611521565b60405161021e9190612173565b60405180910390f35b61022f611546565b60405161023c9190611f12565b60405180910390f35b61025f600480360381019061025a919061218c565b6115d2565b60405161026c9190612050565b60405180910390f35b61027d611975565b60405161028a91906121ea565b60405180910390f35b61029b61199a565b6040516102a89190612223565b60405180910390f35b6060600380546102c090612269565b80601f01602080910402602001604051908101604052809291908181526020018280546102ec90612269565b80156103375780601f1061030e57610100808354040283529160200191610337565b820191905f5260205f20905b81548152906001019060200180831161031a57829003601f168201915b5050505050905090565b5f8061034d33856115d2565b90508281111561053c575f61043a6040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061043560085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed896040518263ffffffff1660e01b81526004016103ee91906122a8565b5f60405180830381865afa158015610408573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061043091906123df565b6119bf565b611a07565b90505f6104976040518060400160405280600681526020017f616d6f756e74000000000000000000000000000000000000000000000000000081525061049261048d88876104889190612453565b611a59565b6119bf565b611a07565b90505f6105286105236040518060400160405280601281526020017f64656372656173655f616c6c6f77616e6365000000000000000000000000000081525061051e61051987876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b905061053381611bb9565b50505050610726565b82811015610725575f6106276040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061062260085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed896040518263ffffffff1660e01b81526004016105db91906122a8565b5f60405180830381865afa1580156105f5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061061d91906123df565b6119bf565b611a07565b90505f6106846040518060400160405280600681526020017f616d6f756e74000000000000000000000000000000000000000000000000000081525061067f61067a86896106759190612453565b611a59565b6119bf565b611a07565b90505f6107156107106040518060400160405280601281526020017f696e6372656173655f616c6c6f77616e6365000000000000000000000000000081525061070b61070687876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b905061072081611bb9565b505050505b5b8373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040516107839190612050565b60405180910390a3600191505092915050565b5f8061081461080f6040518060400160405280600a81526020017f746f6b656e5f696e666f000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f7b7d000000000000000000000000000000000000000000000000000000000000815250611a07565b611b71565b90505f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296005846040518363ffffffff1660e01b815260040161087492919061256b565b5f60405180830381865afa15801561088e573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906108b6919061263e565b905060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982826040518263ffffffff1660e01b815260040161091291906126cf565b602060405180830381865afa15801561092d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109519190612716565b9250505090565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036109c7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109be906127b1565b60405180910390fd5b5f610aaa6040518060400160405280600581526020017f6f776e6572000000000000000000000000000000000000000000000000000000815250610aa560085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed896040518263ffffffff1660e01b8152600401610a5e91906122a8565b5f60405180830381865afa158015610a78573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610aa091906123df565b6119bf565b611a07565b90505f610b8f6040518060400160405280600981526020017f726563697069656e740000000000000000000000000000000000000000000000815250610b8a60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed896040518263ffffffff1660e01b8152600401610b4391906122a8565b5f60405180830381865afa158015610b5d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610b8591906123df565b6119bf565b611a07565b90505f610be16040518060400160405280600681526020017f616d6f756e740000000000000000000000000000000000000000000000000000815250610bdc610bd788611a59565b6119bf565b611a07565b90505f610cb1610cac6040518060400160405280600d81526020017f7472616e736665725f66726f6d00000000000000000000000000000000000000815250610ca7610ca2610c6689896040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b9050610cbc81611bb9565b508673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef88604051610d1a9190612050565b60405180910390a360019450505050509392505050565b5f80610daf610daa6040518060400160405280600a81526020017f746f6b656e5f696e666f000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f7b7d000000000000000000000000000000000000000000000000000000000000815250611a07565b611b71565b90505f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296005846040518363ffffffff1660e01b8152600401610e0f92919061256b565b5f60405180830381865afa158015610e29573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610e51919061263e565b905060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982826040518263ffffffff1660e01b8152600401610ead9190612819565b602060405180830381865afa158015610ec8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610eec9190612716565b9250505090565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610f62576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f59906128bc565b60405180910390fd5b5f6110456040518060400160405280600781526020017f616464726573730000000000000000000000000000000000000000000000000081525061104060085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401610ff991906122a8565b5f60405180830381865afa158015611013573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061103b91906123df565b6119bf565b611a07565b90505f6110976110926040518060400160405280600781526020017f62616c616e63650000000000000000000000000000000000000000000000000081525061108d85611b71565b611a07565b611b71565b90505f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296005846040518363ffffffff1660e01b81526004016110f792919061256b565b5f60405180830381865afa158015611111573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611139919061263e565b905060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982826040518263ffffffff1660e01b81526004016111959190612924565b602060405180830381865afa1580156111b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111d49190612716565b9350505050919050565b6060600480546111ed90612269565b80601f016020809104026020016040519081016040528092919081815260200182805461121990612269565b80156112645780601f1061123b57610100808354040283529160200191611264565b820191905f5260205f20905b81548152906001019060200180831161124757829003601f168201915b5050505050905090565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036112dd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d4906127b1565b60405180910390fd5b5f6113c06040518060400160405280600981526020017f726563697069656e7400000000000000000000000000000000000000000000008152506113bb60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161137491906122a8565b5f60405180830381865afa15801561138e573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906113b691906123df565b6119bf565b611a07565b90505f6114126040518060400160405280600681526020017f616d6f756e74000000000000000000000000000000000000000000000000000081525061140d61140887611a59565b6119bf565b611a07565b90505f6114a361149e6040518060400160405280600881526020017f7472616e7366657200000000000000000000000000000000000000000000000081525061149961149487876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b90506114ae81611bb9565b508573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8760405161150c9190612050565b60405180910390a36001935050505092915050565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6005805461155390612269565b80601f016020809104026020016040519081016040528092919081815260200182805461157f90612269565b80156115ca5780601f106115a1576101008083540402835291602001916115ca565b820191905f5260205f20905b8154815290600101906020018083116115ad57829003601f168201915b505050505081565b5f806116b66040518060400160405280600581526020017f6f776e65720000000000000000000000000000000000000000000000000000008152506116b160085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161166a91906122a8565b5f60405180830381865afa158015611684573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906116ac91906123df565b6119bf565b611a07565b90505f61179b6040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061179660085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161174f91906122a8565b5f60405180830381865afa158015611769573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061179191906123df565b6119bf565b611a07565b90505f61182c6118276040518060400160405280600981526020017f616c6c6f77616e6365000000000000000000000000000000000000000000000081525061182261181d87876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611b23565b611b71565b611a07565b611b71565b90505f60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296005846040518363ffffffff1660e01b815260040161188c92919061256b565b5f60405180830381865afa1580156118a6573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906118ce919061263e565b905060075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635a558982826040518263ffffffff1660e01b815260040161192a91906129a1565b602060405180830381865afa158015611945573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119699190612716565b94505050505092915050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60065f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6060816040516020016119d29190612a34565b6040516020818303038152906040526040516020016119f19190612a59565b6040516020818303038152906040529050919050565b6060611a51611a15846119bf565b836040518060400160405280600181526020017f3a00000000000000000000000000000000000000000000000000000000000000815250611b23565b905092915050565b60605f6001611a6784611d37565b0190505f8167ffffffffffffffff811115611a8557611a846122c9565b5b6040519080825280601f01601f191660200182016040528015611ab75781602001600182028036833780820191505090505b5090505f82602001820190505b600115611b18578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581611b0d57611b0c612a7e565b5b0494505f8503611ac4575b819350505050919050565b6060838284604051602001611b39929190612aab565b604051602081830303815290604052604051602001611b59929190612aab565b60405160208183030381529060405290509392505050565b606081604051602001611b849190612af4565b604051602081830303815290604052604051602001611ba39190612b3f565b6040516020818303038152906040529050919050565b60605f8061100273ffffffffffffffffffffffffffffffffffffffff166005856040518060400160405280600281526020017f5b5d000000000000000000000000000000000000000000000000000000000000815250604051602401611c2193929190612b64565b6040516020818303038152906040527f44d227ae000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051611cab9190612be8565b5f60405180830381855af49150503d805f8114611ce3576040519150601f19603f3d011682016040523d82523d5f602084013e611ce8565b606091505b509150915081611d2d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d2490612c48565b60405180910390fd5b8092505050919050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310611d93577a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008381611d8957611d88612a7e565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310611dd0576d04ee2d6d415b85acef81000000008381611dc657611dc5612a7e565b5b0492506020810190505b662386f26fc100008310611dff57662386f26fc100008381611df557611df4612a7e565b5b0492506010810190505b6305f5e1008310611e28576305f5e1008381611e1e57611e1d612a7e565b5b0492506008810190505b6127108310611e4d576127108381611e4357611e42612a7e565b5b0492506004810190505b60648310611e705760648381611e6657611e65612a7e565b5b0492506002810190505b600a8310611e7f576001810190505b80915050919050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015611ebf578082015181840152602081019050611ea4565b5f8484015250505050565b5f601f19601f8301169050919050565b5f611ee482611e88565b611eee8185611e92565b9350611efe818560208601611ea2565b611f0781611eca565b840191505092915050565b5f6020820190508181035f830152611f2a8184611eda565b905092915050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611f6c82611f43565b9050919050565b611f7c81611f62565b8114611f86575f80fd5b50565b5f81359050611f9781611f73565b92915050565b5f819050919050565b611faf81611f9d565b8114611fb9575f80fd5b50565b5f81359050611fca81611fa6565b92915050565b5f8060408385031215611fe657611fe5611f3b565b5b5f611ff385828601611f89565b925050602061200485828601611fbc565b9150509250929050565b5f8115159050919050565b6120228161200e565b82525050565b5f60208201905061203b5f830184612019565b92915050565b61204a81611f9d565b82525050565b5f6020820190506120635f830184612041565b92915050565b5f805f606084860312156120805761207f611f3b565b5b5f61208d86828701611f89565b935050602061209e86828701611f89565b92505060406120af86828701611fbc565b9150509250925092565b5f60ff82169050919050565b6120ce816120b9565b82525050565b5f6020820190506120e75f8301846120c5565b92915050565b5f6020828403121561210257612101611f3b565b5b5f61210f84828501611f89565b91505092915050565b5f819050919050565b5f61213b61213661213184611f43565b612118565b611f43565b9050919050565b5f61214c82612121565b9050919050565b5f61215d82612142565b9050919050565b61216d81612153565b82525050565b5f6020820190506121865f830184612164565b92915050565b5f80604083850312156121a2576121a1611f3b565b5b5f6121af85828601611f89565b92505060206121c085828601611f89565b9150509250929050565b5f6121d482612142565b9050919050565b6121e4816121ca565b82525050565b5f6020820190506121fd5f8301846121db565b92915050565b5f61220d82612142565b9050919050565b61221d81612203565b82525050565b5f6020820190506122365f830184612214565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061228057607f821691505b6020821081036122935761229261223c565b5b50919050565b6122a281611f62565b82525050565b5f6020820190506122bb5f830184612299565b92915050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6122ff82611eca565b810181811067ffffffffffffffff8211171561231e5761231d6122c9565b5b80604052505050565b5f612330611f32565b905061233c82826122f6565b919050565b5f67ffffffffffffffff82111561235b5761235a6122c9565b5b61236482611eca565b9050602081019050919050565b5f61238361237e84612341565b612327565b90508281526020810184848401111561239f5761239e6122c5565b5b6123aa848285611ea2565b509392505050565b5f82601f8301126123c6576123c56122c1565b5b81516123d6848260208601612371565b91505092915050565b5f602082840312156123f4576123f3611f3b565b5b5f82015167ffffffffffffffff81111561241157612410611f3f565b5b61241d848285016123b2565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61245d82611f9d565b915061246883611f9d565b92508282039050818111156124805761247f612426565b5b92915050565b5f819050815f5260205f209050919050565b5f81546124a481612269565b6124ae8186611e92565b9450600182165f81146124c857600181146124de57612510565b60ff198316865281151560200286019350612510565b6124e785612486565b5f5b83811015612508578154818901526001820191506020810190506124e9565b808801955050505b50505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f61253d82612519565b6125478185612523565b9350612557818560208601611ea2565b61256081611eca565b840191505092915050565b5f6040820190508181035f8301526125838185612498565b905081810360208301526125978184612533565b90509392505050565b5f67ffffffffffffffff8211156125ba576125b96122c9565b5b6125c382611eca565b9050602081019050919050565b5f6125e26125dd846125a0565b612327565b9050828152602081018484840111156125fe576125fd6122c5565b5b612609848285611ea2565b509392505050565b5f82601f830112612625576126246122c1565b5b81516126358482602086016125d0565b91505092915050565b5f6020828403121561265357612652611f3b565b5b5f82015167ffffffffffffffff8111156126705761266f611f3f565b5b61267c84828501612611565b91505092915050565b7f746f74616c5f737570706c7900000000000000000000000000000000000000005f82015250565b5f6126b9600c83611e92565b91506126c482612685565b602082019050919050565b5f6040820190508181035f8301526126e78184612533565b905081810360208301526126fa816126ad565b905092915050565b5f8151905061271081611fa6565b92915050565b5f6020828403121561272b5761272a611f3b565b5b5f61273884828501612702565b91505092915050565b7f45524332303a207472616e7366657220746f20746865207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f61279b602383611e92565b91506127a682612741565b604082019050919050565b5f6020820190508181035f8301526127c88161278f565b9050919050565b7f646563696d616c730000000000000000000000000000000000000000000000005f82015250565b5f612803600883611e92565b915061280e826127cf565b602082019050919050565b5f6040820190508181035f8301526128318184612533565b90508181036020830152612844816127f7565b905092915050565b7f45524332303a2062616c616e636520717565727920666f7220746865207a65725f8201527f6f20616464726573730000000000000000000000000000000000000000000000602082015250565b5f6128a6602983611e92565b91506128b18261284c565b604082019050919050565b5f6020820190508181035f8301526128d38161289a565b9050919050565b7f62616c616e6365000000000000000000000000000000000000000000000000005f82015250565b5f61290e600783611e92565b9150612919826128da565b602082019050919050565b5f6040820190508181035f83015261293c8184612533565b9050818103602083015261294f81612902565b905092915050565b7f616c6c6f77616e636500000000000000000000000000000000000000000000005f82015250565b5f61298b600983611e92565b915061299682612957565b602082019050919050565b5f6040820190508181035f8301526129b98184612533565b905081810360208301526129cc8161297f565b905092915050565b5f81905092915050565b5f6129e882611e88565b6129f281856129d4565b9350612a02818560208601611ea2565b80840191505092915050565b7f2200000000000000000000000000000000000000000000000000000000000000815250565b5f612a3f82846129de565b9150612a4a82612a0e565b60018201915081905092915050565b5f612a6382612a0e565b600182019150612a7382846129de565b915081905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f612ab682856129de565b9150612ac282846129de565b91508190509392505050565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b5f612aff82846129de565b9150612b0a82612ace565b60018201915081905092915050565b7f7b00000000000000000000000000000000000000000000000000000000000000815250565b5f612b4982612b19565b600182019150612b5982846129de565b915081905092915050565b5f6060820190508181035f830152612b7c8186612498565b90508181036020830152612b908185612533565b90508181036040830152612ba48184612533565b9050949350505050565b5f81905092915050565b5f612bc282612519565b612bcc8185612bae565b9350612bdc818560208601611ea2565b80840191505092915050565b5f612bf38284612bb8565b915081905092915050565b7f436f736d5761736d2065786563757465206661696c65640000000000000000005f82015250565b5f612c32601783611e92565b9150612c3d82612bfe565b602082019050919050565b5f6020820190508181035f830152612c5f81612c26565b905091905056fea2646970667358221220ff1461e9f01249d9d75d807a30883553ebbfc4ab43e3115358dbfc2da0efcd5c64736f6c63430008150033 \ No newline at end of file diff --git a/x/evm/artifacts/cw721/CW721ERC721Pointer.abi b/x/evm/artifacts/cw721/CW721ERC721Pointer.abi new file mode 100644 index 0000000000..fccb8a07ad --- /dev/null +++ b/x/evm/artifacts/cw721/CW721ERC721Pointer.abi @@ -0,0 +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 diff --git a/x/evm/artifacts/cw721/CW721ERC721Pointer.bin b/x/evm/artifacts/cw721/CW721ERC721Pointer.bin new file mode 100644 index 0000000000..700510ae78 --- /dev/null +++ b/x/evm/artifacts/cw721/CW721ERC721Pointer.bin @@ -0,0 +1 @@ +608060405234801562000010575f80fd5b5060405162003cc638038062003cc68339818101604052810190620000369190620002c3565b8181815f9081620000489190620005b0565b5080600190816200005a9190620005b0565b50505061100260075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100360085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100460095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260069081620001349190620005b0565b5050505062000694565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200019f8262000157565b810181811067ffffffffffffffff82111715620001c157620001c062000167565b5b80604052505050565b5f620001d56200013e565b9050620001e3828262000194565b919050565b5f67ffffffffffffffff82111562000205576200020462000167565b5b620002108262000157565b9050602081019050919050565b5f5b838110156200023c5780820151818401526020810190506200021f565b5f8484015250505050565b5f6200025d6200025784620001e8565b620001ca565b9050828152602081018484840111156200027c576200027b62000153565b5b620002898482856200021d565b509392505050565b5f82601f830112620002a857620002a76200014f565b5b8151620002ba84826020860162000247565b91505092915050565b5f805f60608486031215620002dd57620002dc62000147565b5b5f84015167ffffffffffffffff811115620002fd57620002fc6200014b565b5b6200030b8682870162000291565b935050602084015167ffffffffffffffff8111156200032f576200032e6200014b565b5b6200033d8682870162000291565b925050604084015167ffffffffffffffff8111156200036157620003606200014b565b5b6200036f8682870162000291565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620003c857607f821691505b602082108103620003de57620003dd62000383565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004427fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000405565b6200044e868362000405565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000498620004926200048c8462000466565b6200046f565b62000466565b9050919050565b5f819050919050565b620004b38362000478565b620004cb620004c2826200049f565b84845462000411565b825550505050565b5f90565b620004e1620004d3565b620004ee818484620004a8565b505050565b5b818110156200051557620005095f82620004d7565b600181019050620004f4565b5050565b601f82111562000564576200052e81620003e4565b6200053984620003f6565b8101602085101562000549578190505b620005616200055885620003f6565b830182620004f3565b50505b505050565b5f82821c905092915050565b5f620005865f198460080262000569565b1980831691505092915050565b5f620005a0838362000575565b9150826002028217905092915050565b620005bb8262000379565b67ffffffffffffffff811115620005d757620005d662000167565b5b620005e38254620003b0565b620005f082828562000519565b5f60209050601f83116001811462000626575f841562000611578287015190505b6200061d858262000593565b8655506200068c565b601f1984166200063686620003e4565b5f5b828110156200065f5784890151825560018201915060208501945060208101905062000638565b868310156200067f57848901516200067b601f89168262000575565b8355505b6001600288020188555050505b505050505050565b61362480620006a25f395ff3fe608060405234801561000f575f80fd5b5060043610610109575f3560e01c806370a08231116100a0578063c2aed3021161006f578063c2aed302146102b3578063c87b56dd146102d1578063de4725cc14610301578063e985e9c51461031f578063f00b02551461034f57610109565b806370a082311461022d57806395d89b411461025d578063a22cb4651461027b578063b88d4fde1461029757610109565b806323b872dd116100dc57806323b872dd146101a757806342842e0e146101c35780635c4aead7146101df5780636352211e146101fd57610109565b806301ffc9a71461010d57806306fdde031461013d578063081812fc1461015b578063095ea7b31461018b575b5f80fd5b61012760048036038101906101229190612462565b61036d565b60405161013491906124a7565b60405180910390f35b61014561044e565b604051610152919061254a565b60405180910390f35b6101756004803603810190610170919061259d565b6104dd565b6040516101829190612607565b60405180910390f35b6101a560048036038101906101a0919061264a565b610837565b005b6101c160048036038101906101bc9190612688565b610a73565b005b6101dd60048036038101906101d89190612688565b610d8e565b005b6101e7610dad565b6040516101f4919061254a565b60405180910390f35b6102176004803603810190610212919061259d565b610e39565b6040516102249190612607565b60405180910390f35b610247600480360381019061024291906126d8565b6110c3565b6040516102549190612712565b60405180910390f35b6102656113b9565b604051610272919061254a565b60405180910390f35b61029560048036038101906102909190612755565b611449565b005b6102b160048036038101906102ac91906128bf565b61164c565b005b6102bb611671565b6040516102c8919061299a565b60405180910390f35b6102eb60048036038101906102e6919061259d565b611696565b6040516102f8919061254a565b60405180910390f35b610309611893565b60405161031691906129d3565b60405180910390f35b610339600480360381019061033491906129ec565b6118b8565b60405161034691906124a7565b60405180910390f35b610357611cf2565b6040516103649190612a4a565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061043757507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610447575061044682611d17565b5b9050919050565b60605f805461045c90612a90565b80601f016020809104026020016040519081016040528092919081815260200182805461048890612a90565b80156104d35780601f106104aa576101008083540402835291602001916104d3565b820191905f5260205f20905b8154815290600101906020018083116104b657829003601f168201915b5050505050905090565b5f8061052e6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061052961052486611d80565b611e4a565b611e92565b90505f61058061057b6040518060400160405280600981526020017f617070726f76616c73000000000000000000000000000000000000000000000081525061057685611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016105e0929190612ba5565b5f60405180830381865afa1580156105fa573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106229190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b815260040161067f9190612cd9565b5f60405180830381865afa158015610699573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106c19190612dee565b90505f8151111561082a575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5835f8151811061071d5761071c612e35565b5b60200260200101516040518263ffffffff1660e01b81526004016107419190612eac565b5f60405180830381865afa15801561075b573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906107839190612c48565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b81526004016107df919061254a565b602060405180830381865afa1580156107fa573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061081e9190612ef3565b95505050505050610832565b5f9450505050505b919050565b5f61091a6040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061091560095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b81526004016108ce9190612607565b5f60405180830381865afa1580156108e8573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906109109190612fbc565b611e4a565b611e92565b90505f61096c6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061096761096286611d80565b611e4a565b611e92565b90505f6109fd6109f86040518060400160405280600781526020017f617070726f7665000000000000000000000000000000000000000000000000008152506109f36109ee87876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611f2c565b611ee4565b611e92565b611ee4565b9050610a0881611f7a565b50838573ffffffffffffffffffffffffffffffffffffffff16610a2a86610e39565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ae3575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ada9190612607565b60405180910390fd5b610aec81610e39565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610b59576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b509061304d565b60405180910390fd5b5f610c3c6040518060400160405280600981526020017f726563697069656e740000000000000000000000000000000000000000000000815250610c3760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401610bf09190612607565b5f60405180830381865afa158015610c0a573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610c329190612fbc565b611e4a565b611e92565b90505f610c8e6040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610c89610c8486611d80565b611e4a565b611e92565b90505f610d1f610d1a6040518060400160405280600c81526020017f7472616e736665725f6e66740000000000000000000000000000000000000000815250610d15610d1087876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611f2c565b611ee4565b611e92565b611ee4565b9050610d2a81611f7a565b50838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b610da883838360405180602001604052805f81525061164c565b505050565b60068054610dba90612a90565b80601f0160208091040260200160405190810160405280929190818152602001828054610de690612a90565b8015610e315780601f10610e0857610100808354040283529160200191610e31565b820191905f5260205f20905b815481529060010190602001808311610e1457829003601f168201915b505050505081565b5f80610e8a6040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610e85610e8086611d80565b611e4a565b611e92565b90505f610edc610ed76040518060400160405280600881526020017f6f776e65725f6f66000000000000000000000000000000000000000000000000815250610ed285611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401610f3c929190612ba5565b5f60405180830381865afa158015610f56573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610f7e9190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b8152600401610fdb91906130b5565b5f60405180830381865afa158015610ff5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061101d9190612c48565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b8152600401611079919061254a565b602060405180830381865afa158015611094573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110b89190612ef3565b945050505050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611134575f6040517f89c62b6400000000000000000000000000000000000000000000000000000000815260040161112b9190612607565b60405180910390fd5b5f6112176040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061121260095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b81526004016111cb9190612607565b5f60405180830381865afa1580156111e5573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061120d9190612fbc565b611e4a565b611e92565b90505f6112696112646040518060400160405280600681526020017f746f6b656e73000000000000000000000000000000000000000000000000000081525061125f85611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016112c9929190612ba5565b5f60405180830381865afa1580156112e3573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f8201168201806040525081019061130b9190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b81526004016113689190613132565b5f60405180830381865afa158015611382573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906113aa9190612dee565b90508051945050505050919050565b6060600180546113c890612a90565b80601f01602080910402602001604051908101604052809291908181526020018280546113f490612a90565b801561143f5780601f106114165761010080835404028352916020019161143f565b820191905f5260205f20905b81548152906001019060200180831161142257829003601f168201915b5050505050905090565b5f61153461152f6040518060400160405280600881526020017f6f70657261746f7200000000000000000000000000000000000000000000000081525061152a60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b81526004016114e39190612607565b5f60405180830381865afa1580156114fd573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906115259190612fbc565b611e4a565b611e92565b611ee4565b905081156115915761158b6115866115816040518060400160405280600b81526020017f617070726f76655f616c6c00000000000000000000000000000000000000000081525084611e92565b611ee4565b611f7a565b506115e2565b6115e06115db6115d66040518060400160405280600a81526020017f7265766f6b655f616c6c0000000000000000000000000000000000000000000081525084611e92565b611ee4565b611f7a565b505b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c318460405161163f91906124a7565b60405180910390a3505050565b611657848484610a73565b61166b6116626120f8565b858585856120ff565b50505050565b60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60606116a182610e39565b505f6116f26040518060400160405280600881526020017f746f6b656e5f69640000000000000000000000000000000000000000000000008152506116ed6116e886611d80565b611e4a565b611e92565b90505f61174461173f6040518060400160405280600881526020017f6e66745f696e666f00000000000000000000000000000000000000000000000081525061173a85611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016117a4929190612ba5565b5f60405180830381865afa1580156117be573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906117e69190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b815260040161184391906131af565b5f60405180830381865afa15801561185d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906118859190612c48565b905080945050505050919050565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f8061199c6040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061199760095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b81526004016119509190612607565b5f60405180830381865afa15801561196a573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906119929190612fbc565b611e4a565b611e92565b90505f6119ee6119e96040518060400160405280600d81526020017f616c6c5f6f70657261746f7273000000000000000000000000000000000000008152506119e485611ee4565b611e92565b611ee4565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401611a4e929190612ba5565b5f60405180830381865afa158015611a68573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611a909190612c48565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b8152600401611aed919061322c565b5f60405180830381865afa158015611b07573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611b2f9190612dee565b90505f5b8151811015611ce3575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5848481518110611b8d57611b8c612e35565b5b60200260200101516040518263ffffffff1660e01b8152600401611bb19190612eac565b5f60405180830381865afa158015611bcb573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611bf39190612c48565b90508773ffffffffffffffffffffffffffffffffffffffff1660095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539836040518263ffffffff1660e01b8152600401611c66919061254a565b602060405180830381865afa158015611c81573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ca59190612ef3565b73ffffffffffffffffffffffffffffffffffffffff1603611ccf5760019650505050505050611cec565b508080611cdb9061328c565b915050611b33565b505f9450505050505b92915050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60605f6001611d8e846122ab565b0190505f8167ffffffffffffffff811115611dac57611dab61279b565b5b6040519080825280601f01601f191660200182016040528015611dde5781602001600182028036833780820191505090505b5090505f82602001820190505b600115611e3f578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581611e3457611e336132d3565b5b0494505f8503611deb575b819350505050919050565b606081604051602001611e5d9190613360565b604051602081830303815290604052604051602001611e7c9190613385565b6040516020818303038152906040529050919050565b6060611edc611ea084611e4a565b836040518060400160405280600181526020017f3a00000000000000000000000000000000000000000000000000000000000000815250611f2c565b905092915050565b606081604051602001611ef791906133d0565b604051602081830303815290604052604051602001611f16919061341b565b6040516020818303038152906040529050919050565b6060838284604051602001611f42929190613440565b604051602081830303815290604052604051602001611f62929190613440565b60405160208183030381529060405290509392505050565b60605f8061100273ffffffffffffffffffffffffffffffffffffffff166006856040518060400160405280600281526020017f5b5d000000000000000000000000000000000000000000000000000000000000815250604051602401611fe293929190613463565b6040516020818303038152906040527f44d227ae000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161206c91906134e7565b5f60405180830381855af49150503d805f81146120a4576040519150601f19603f3d011682016040523d82523d5f602084013e6120a9565b606091505b5091509150816120ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120e590613547565b60405180910390fd5b8092505050919050565b5f33905090565b5f8373ffffffffffffffffffffffffffffffffffffffff163b11156122a4578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02868685856040518563ffffffff1660e01b815260040161215d9493929190613565565b6020604051808303815f875af192505050801561219857506040513d601f19601f8201168201806040525081019061219591906135c3565b60015b612219573d805f81146121c6576040519150601f19603f3d011682016040523d82523d5f602084013e6121cb565b606091505b505f81510361221157836040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016122089190612607565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916146122a257836040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016122999190612607565b60405180910390fd5b505b5050505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612307577a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083816122fd576122fc6132d3565b5b0492506040810190505b6d04ee2d6d415b85acef81000000008310612344576d04ee2d6d415b85acef8100000000838161233a576123396132d3565b5b0492506020810190505b662386f26fc10000831061237357662386f26fc100008381612369576123686132d3565b5b0492506010810190505b6305f5e100831061239c576305f5e1008381612392576123916132d3565b5b0492506008810190505b61271083106123c15761271083816123b7576123b66132d3565b5b0492506004810190505b606483106123e457606483816123da576123d96132d3565b5b0492506002810190505b600a83106123f3576001810190505b80915050919050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6124418161240d565b811461244b575f80fd5b50565b5f8135905061245c81612438565b92915050565b5f6020828403121561247757612476612405565b5b5f6124848482850161244e565b91505092915050565b5f8115159050919050565b6124a18161248d565b82525050565b5f6020820190506124ba5f830184612498565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b838110156124f75780820151818401526020810190506124dc565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61251c826124c0565b61252681856124ca565b93506125368185602086016124da565b61253f81612502565b840191505092915050565b5f6020820190508181035f8301526125628184612512565b905092915050565b5f819050919050565b61257c8161256a565b8114612586575f80fd5b50565b5f8135905061259781612573565b92915050565b5f602082840312156125b2576125b1612405565b5b5f6125bf84828501612589565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6125f1826125c8565b9050919050565b612601816125e7565b82525050565b5f60208201905061261a5f8301846125f8565b92915050565b612629816125e7565b8114612633575f80fd5b50565b5f8135905061264481612620565b92915050565b5f80604083850312156126605761265f612405565b5b5f61266d85828601612636565b925050602061267e85828601612589565b9150509250929050565b5f805f6060848603121561269f5761269e612405565b5b5f6126ac86828701612636565b93505060206126bd86828701612636565b92505060406126ce86828701612589565b9150509250925092565b5f602082840312156126ed576126ec612405565b5b5f6126fa84828501612636565b91505092915050565b61270c8161256a565b82525050565b5f6020820190506127255f830184612703565b92915050565b6127348161248d565b811461273e575f80fd5b50565b5f8135905061274f8161272b565b92915050565b5f806040838503121561276b5761276a612405565b5b5f61277885828601612636565b925050602061278985828601612741565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6127d182612502565b810181811067ffffffffffffffff821117156127f0576127ef61279b565b5b80604052505050565b5f6128026123fc565b905061280e82826127c8565b919050565b5f67ffffffffffffffff82111561282d5761282c61279b565b5b61283682612502565b9050602081019050919050565b828183375f83830152505050565b5f61286361285e84612813565b6127f9565b90508281526020810184848401111561287f5761287e612797565b5b61288a848285612843565b509392505050565b5f82601f8301126128a6576128a5612793565b5b81356128b6848260208601612851565b91505092915050565b5f805f80608085870312156128d7576128d6612405565b5b5f6128e487828801612636565b94505060206128f587828801612636565b935050604061290687828801612589565b925050606085013567ffffffffffffffff81111561292757612926612409565b5b61293387828801612892565b91505092959194509250565b5f819050919050565b5f61296261295d612958846125c8565b61293f565b6125c8565b9050919050565b5f61297382612948565b9050919050565b5f61298482612969565b9050919050565b6129948161297a565b82525050565b5f6020820190506129ad5f83018461298b565b92915050565b5f6129bd82612969565b9050919050565b6129cd816129b3565b82525050565b5f6020820190506129e65f8301846129c4565b92915050565b5f8060408385031215612a0257612a01612405565b5b5f612a0f85828601612636565b9250506020612a2085828601612636565b9150509250929050565b5f612a3482612969565b9050919050565b612a4481612a2a565b82525050565b5f602082019050612a5d5f830184612a3b565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680612aa757607f821691505b602082108103612aba57612ab9612a63565b5b50919050565b5f819050815f5260205f209050919050565b5f8154612ade81612a90565b612ae881866124ca565b9450600182165f8114612b025760018114612b1857612b4a565b60ff198316865281151560200286019350612b4a565b612b2185612ac0565b5f5b83811015612b4257815481890152600182019150602081019050612b23565b808801955050505b50505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f612b7782612b53565b612b818185612b5d565b9350612b918185602086016124da565b612b9a81612502565b840191505092915050565b5f6040820190508181035f830152612bbd8185612ad2565b90508181036020830152612bd18184612b6d565b90509392505050565b5f612bec612be784612813565b6127f9565b905082815260208101848484011115612c0857612c07612797565b5b612c138482856124da565b509392505050565b5f82601f830112612c2f57612c2e612793565b5b8151612c3f848260208601612bda565b91505092915050565b5f60208284031215612c5d57612c5c612405565b5b5f82015167ffffffffffffffff811115612c7a57612c79612409565b5b612c8684828501612c1b565b91505092915050565b7f617070726f76616c7300000000000000000000000000000000000000000000005f82015250565b5f612cc36009836124ca565b9150612cce82612c8f565b602082019050919050565b5f6040820190508181035f830152612cf18184612b6d565b90508181036020830152612d0481612cb7565b905092915050565b5f67ffffffffffffffff821115612d2657612d2561279b565b5b602082029050602081019050919050565b5f80fd5b5f612d4d612d4884612d0c565b6127f9565b90508083825260208201905060208402830185811115612d7057612d6f612d37565b5b835b81811015612db757805167ffffffffffffffff811115612d9557612d94612793565b5b808601612da28982612c1b565b85526020850194505050602081019050612d72565b5050509392505050565b5f82601f830112612dd557612dd4612793565b5b8151612de5848260208601612d3b565b91505092915050565b5f60208284031215612e0357612e02612405565b5b5f82015167ffffffffffffffff811115612e2057612e1f612409565b5b612e2c84828501612dc1565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f7370656e646572000000000000000000000000000000000000000000000000005f82015250565b5f612e966007836124ca565b9150612ea182612e62565b602082019050919050565b5f6040820190508181035f830152612ec48184612b6d565b90508181036020830152612ed781612e8a565b905092915050565b5f81519050612eed81612620565b92915050565b5f60208284031215612f0857612f07612405565b5b5f612f1584828501612edf565b91505092915050565b5f67ffffffffffffffff821115612f3857612f3761279b565b5b612f4182612502565b9050602081019050919050565b5f612f60612f5b84612f1e565b6127f9565b905082815260208101848484011115612f7c57612f7b612797565b5b612f878482856124da565b509392505050565b5f82601f830112612fa357612fa2612793565b5b8151612fb3848260208601612f4e565b91505092915050565b5f60208284031215612fd157612fd0612405565b5b5f82015167ffffffffffffffff811115612fee57612fed612409565b5b612ffa84828501612f8f565b91505092915050565b7f6066726f6d60206d75737420626520746865206f776e657200000000000000005f82015250565b5f6130376018836124ca565b915061304282613003565b602082019050919050565b5f6020820190508181035f8301526130648161302b565b9050919050565b7f6f776e65720000000000000000000000000000000000000000000000000000005f82015250565b5f61309f6005836124ca565b91506130aa8261306b565b602082019050919050565b5f6040820190508181035f8301526130cd8184612b6d565b905081810360208301526130e081613093565b905092915050565b7f746f6b656e7300000000000000000000000000000000000000000000000000005f82015250565b5f61311c6006836124ca565b9150613127826130e8565b602082019050919050565b5f6040820190508181035f83015261314a8184612b6d565b9050818103602083015261315d81613110565b905092915050565b7f746f6b656e5f75726900000000000000000000000000000000000000000000005f82015250565b5f6131996009836124ca565b91506131a482613165565b602082019050919050565b5f6040820190508181035f8301526131c78184612b6d565b905081810360208301526131da8161318d565b905092915050565b7f6f70657261746f727300000000000000000000000000000000000000000000005f82015250565b5f6132166009836124ca565b9150613221826131e2565b602082019050919050565b5f6040820190508181035f8301526132448184612b6d565b905081810360208301526132578161320a565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6132968261256a565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036132c8576132c761325f565b5b600182019050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f81905092915050565b5f613314826124c0565b61331e8185613300565b935061332e8185602086016124da565b80840191505092915050565b7f2200000000000000000000000000000000000000000000000000000000000000815250565b5f61336b828461330a565b91506133768261333a565b60018201915081905092915050565b5f61338f8261333a565b60018201915061339f828461330a565b915081905092915050565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b5f6133db828461330a565b91506133e6826133aa565b60018201915081905092915050565b7f7b00000000000000000000000000000000000000000000000000000000000000815250565b5f613425826133f5565b600182019150613435828461330a565b915081905092915050565b5f61344b828561330a565b9150613457828461330a565b91508190509392505050565b5f6060820190508181035f83015261347b8186612ad2565b9050818103602083015261348f8185612b6d565b905081810360408301526134a38184612b6d565b9050949350505050565b5f81905092915050565b5f6134c182612b53565b6134cb81856134ad565b93506134db8185602086016124da565b80840191505092915050565b5f6134f282846134b7565b915081905092915050565b7f436f736d5761736d2065786563757465206661696c65640000000000000000005f82015250565b5f6135316017836124ca565b915061353c826134fd565b602082019050919050565b5f6020820190508181035f83015261355e81613525565b9050919050565b5f6080820190506135785f8301876125f8565b61358560208301866125f8565b6135926040830185612703565b81810360608301526135a48184612b6d565b905095945050505050565b5f815190506135bd81612438565b92915050565b5f602082840312156135d8576135d7612405565b5b5f6135e5848285016135af565b9150509291505056fea2646970667358221220a2c419c1e43b74d07c7e3f63d55af936cde414fdc186470d597ab1da5b53412e64736f6c63430008150033 \ No newline at end of file diff --git a/x/evm/artifacts/cw721/artifacts.go b/x/evm/artifacts/cw721/artifacts.go new file mode 100644 index 0000000000..18e5f812a3 --- /dev/null +++ b/x/evm/artifacts/cw721/artifacts.go @@ -0,0 +1,101 @@ +package cw721 + +import ( + "bytes" + "embed" + "encoding/hex" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +const CurrentVersion uint16 = 2 + +//go:embed CW721ERC721Pointer.abi +//go:embed CW721ERC721Pointer.bin +//go:embed legacy.bin +var f embed.FS + +var cachedBin []byte +var cachedLegacyBin []byte +var cachedABI *abi.ABI + +func GetABI() []byte { + bz, err := f.ReadFile("CW721ERC721Pointer.abi") + if err != nil { + panic("failed to read CW721ERC721Pointer contract ABI") + } + return bz +} + +func GetParsedABI() *abi.ABI { + if cachedABI != nil { + return cachedABI + } + parsedABI, err := abi.JSON(strings.NewReader(string(GetABI()))) + if err != nil { + panic(err) + } + cachedABI = &parsedABI + return cachedABI +} + +func GetBin() []byte { + if cachedBin != nil { + return cachedBin + } + code, err := f.ReadFile("CW721ERC721Pointer.bin") + if err != nil { + panic("failed to read CW721ERC721Pointer contract binary") + } + bz, err := hex.DecodeString(string(code)) + if err != nil { + panic("failed to decode CW721ERC721Pointer contract binary") + } + cachedBin = bz + return bz +} + +func GetLegacyBin() []byte { + if cachedLegacyBin != nil { + return cachedLegacyBin + } + code, err := f.ReadFile("legacy.bin") + if err != nil { + panic("failed to read CW721ERC721Pointer legacy contract binary") + } + bz, err := hex.DecodeString(string(code)) + if err != nil { + panic("failed to decode CW721ERC721Pointer legacy contract binary") + } + cachedLegacyBin = bz + return bz +} + +func IsCodeFromBin(code []byte) bool { + return isCodeFromBin(code, GetBin()) || isCodeFromBin(code, GetLegacyBin()) +} + +func isCodeFromBin(code []byte, bin []byte) bool { + binLen := len(bin) + if len(code) < binLen { + return false + } + if !bytes.Equal(code[:binLen], bin) { + return false + } + abi, err := Cw721MetaData.GetAbi() + if err != nil { + fmt.Printf("error getting metadata ABI: %s\n", err) + return false + } + args, err := abi.Constructor.Inputs.Unpack(code[binLen:]) + if err != nil || len(args) != 3 { + return false + } + _, isA0String := args[0].(string) + _, isA1String := args[1].(string) + _, isA2String := args[2].(string) + return isA0String && isA1String && isA2String +} diff --git a/x/evm/artifacts/cw721/cw721.go b/x/evm/artifacts/cw721/cw721.go new file mode 100644 index 0000000000..d7d3efcbcf --- /dev/null +++ b/x/evm/artifacts/cw721/cw721.go @@ -0,0 +1,1136 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package cw721 + +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 +) + +// 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\"}]", +} + +// Cw721ABI is the input ABI used to generate the binding from. +// Deprecated: Use Cw721MetaData.ABI instead. +var Cw721ABI = Cw721MetaData.ABI + +// Cw721 is an auto generated Go binding around an Ethereum contract. +type Cw721 struct { + Cw721Caller // Read-only binding to the contract + Cw721Transactor // Write-only binding to the contract + Cw721Filterer // Log filterer for contract events +} + +// Cw721Caller is an auto generated read-only Go binding around an Ethereum contract. +type Cw721Caller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Cw721Transactor is an auto generated write-only Go binding around an Ethereum contract. +type Cw721Transactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Cw721Filterer is an auto generated log filtering Go binding around an Ethereum contract events. +type Cw721Filterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// Cw721Session is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type Cw721Session struct { + Contract *Cw721 // 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 +} + +// Cw721CallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type Cw721CallerSession struct { + Contract *Cw721Caller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// Cw721TransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type Cw721TransactorSession struct { + Contract *Cw721Transactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// Cw721Raw is an auto generated low-level Go binding around an Ethereum contract. +type Cw721Raw struct { + Contract *Cw721 // Generic contract binding to access the raw methods on +} + +// Cw721CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type Cw721CallerRaw struct { + Contract *Cw721Caller // Generic read-only contract binding to access the raw methods on +} + +// Cw721TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type Cw721TransactorRaw struct { + Contract *Cw721Transactor // Generic write-only contract binding to access the raw methods on +} + +// NewCw721 creates a new instance of Cw721, bound to a specific deployed contract. +func NewCw721(address common.Address, backend bind.ContractBackend) (*Cw721, error) { + contract, err := bindCw721(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Cw721{Cw721Caller: Cw721Caller{contract: contract}, Cw721Transactor: Cw721Transactor{contract: contract}, Cw721Filterer: Cw721Filterer{contract: contract}}, nil +} + +// NewCw721Caller creates a new read-only instance of Cw721, bound to a specific deployed contract. +func NewCw721Caller(address common.Address, caller bind.ContractCaller) (*Cw721Caller, error) { + contract, err := bindCw721(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &Cw721Caller{contract: contract}, nil +} + +// NewCw721Transactor creates a new write-only instance of Cw721, bound to a specific deployed contract. +func NewCw721Transactor(address common.Address, transactor bind.ContractTransactor) (*Cw721Transactor, error) { + contract, err := bindCw721(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &Cw721Transactor{contract: contract}, nil +} + +// NewCw721Filterer creates a new log filterer instance of Cw721, bound to a specific deployed contract. +func NewCw721Filterer(address common.Address, filterer bind.ContractFilterer) (*Cw721Filterer, error) { + contract, err := bindCw721(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &Cw721Filterer{contract: contract}, nil +} + +// bindCw721 binds a generic wrapper to an already deployed contract. +func bindCw721(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := Cw721MetaData.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 (_Cw721 *Cw721Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Cw721.Contract.Cw721Caller.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 (_Cw721 *Cw721Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Cw721.Contract.Cw721Transactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Cw721 *Cw721Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Cw721.Contract.Cw721Transactor.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 (_Cw721 *Cw721CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Cw721.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 (_Cw721 *Cw721TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Cw721.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Cw721 *Cw721TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Cw721.Contract.contract.Transact(opts, method, params...) +} + +// AddrPrecompile is a free data retrieval call binding the contract method 0xc2aed302. +// +// Solidity: function AddrPrecompile() view returns(address) +func (_Cw721 *Cw721Caller) AddrPrecompile(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Cw721.contract.Call(opts, &out, "AddrPrecompile") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// AddrPrecompile is a free data retrieval call binding the contract method 0xc2aed302. +// +// Solidity: function AddrPrecompile() view returns(address) +func (_Cw721 *Cw721Session) AddrPrecompile() (common.Address, error) { + return _Cw721.Contract.AddrPrecompile(&_Cw721.CallOpts) +} + +// AddrPrecompile is a free data retrieval call binding the contract method 0xc2aed302. +// +// Solidity: function AddrPrecompile() view returns(address) +func (_Cw721 *Cw721CallerSession) AddrPrecompile() (common.Address, error) { + return _Cw721.Contract.AddrPrecompile(&_Cw721.CallOpts) +} + +// Cw721Address is a free data retrieval call binding the contract method 0x5c4aead7. +// +// Solidity: function Cw721Address() view returns(string) +func (_Cw721 *Cw721Caller) Cw721Address(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Cw721.contract.Call(opts, &out, "Cw721Address") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Cw721Address is a free data retrieval call binding the contract method 0x5c4aead7. +// +// Solidity: function Cw721Address() view returns(string) +func (_Cw721 *Cw721Session) Cw721Address() (string, error) { + return _Cw721.Contract.Cw721Address(&_Cw721.CallOpts) +} + +// Cw721Address is a free data retrieval call binding the contract method 0x5c4aead7. +// +// Solidity: function Cw721Address() view returns(string) +func (_Cw721 *Cw721CallerSession) Cw721Address() (string, error) { + return _Cw721.Contract.Cw721Address(&_Cw721.CallOpts) +} + +// JsonPrecompile is a free data retrieval call binding the contract method 0xde4725cc. +// +// Solidity: function JsonPrecompile() view returns(address) +func (_Cw721 *Cw721Caller) JsonPrecompile(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Cw721.contract.Call(opts, &out, "JsonPrecompile") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// JsonPrecompile is a free data retrieval call binding the contract method 0xde4725cc. +// +// Solidity: function JsonPrecompile() view returns(address) +func (_Cw721 *Cw721Session) JsonPrecompile() (common.Address, error) { + return _Cw721.Contract.JsonPrecompile(&_Cw721.CallOpts) +} + +// JsonPrecompile is a free data retrieval call binding the contract method 0xde4725cc. +// +// Solidity: function JsonPrecompile() view returns(address) +func (_Cw721 *Cw721CallerSession) JsonPrecompile() (common.Address, error) { + return _Cw721.Contract.JsonPrecompile(&_Cw721.CallOpts) +} + +// WasmdPrecompile is a free data retrieval call binding the contract method 0xf00b0255. +// +// Solidity: function WasmdPrecompile() view returns(address) +func (_Cw721 *Cw721Caller) WasmdPrecompile(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Cw721.contract.Call(opts, &out, "WasmdPrecompile") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// WasmdPrecompile is a free data retrieval call binding the contract method 0xf00b0255. +// +// Solidity: function WasmdPrecompile() view returns(address) +func (_Cw721 *Cw721Session) WasmdPrecompile() (common.Address, error) { + return _Cw721.Contract.WasmdPrecompile(&_Cw721.CallOpts) +} + +// WasmdPrecompile is a free data retrieval call binding the contract method 0xf00b0255. +// +// Solidity: function WasmdPrecompile() view returns(address) +func (_Cw721 *Cw721CallerSession) WasmdPrecompile() (common.Address, error) { + return _Cw721.Contract.WasmdPrecompile(&_Cw721.CallOpts) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address owner) view returns(uint256) +func (_Cw721 *Cw721Caller) BalanceOf(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { + var out []interface{} + err := _Cw721.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 (_Cw721 *Cw721Session) BalanceOf(owner common.Address) (*big.Int, error) { + return _Cw721.Contract.BalanceOf(&_Cw721.CallOpts, owner) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address owner) view returns(uint256) +func (_Cw721 *Cw721CallerSession) BalanceOf(owner common.Address) (*big.Int, error) { + return _Cw721.Contract.BalanceOf(&_Cw721.CallOpts, owner) +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 tokenId) view returns(address) +func (_Cw721 *Cw721Caller) GetApproved(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { + var out []interface{} + err := _Cw721.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 (_Cw721 *Cw721Session) GetApproved(tokenId *big.Int) (common.Address, error) { + return _Cw721.Contract.GetApproved(&_Cw721.CallOpts, tokenId) +} + +// GetApproved is a free data retrieval call binding the contract method 0x081812fc. +// +// Solidity: function getApproved(uint256 tokenId) view returns(address) +func (_Cw721 *Cw721CallerSession) GetApproved(tokenId *big.Int) (common.Address, error) { + return _Cw721.Contract.GetApproved(&_Cw721.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 (_Cw721 *Cw721Caller) IsApprovedForAll(opts *bind.CallOpts, owner common.Address, operator common.Address) (bool, error) { + var out []interface{} + err := _Cw721.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 (_Cw721 *Cw721Session) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { + return _Cw721.Contract.IsApprovedForAll(&_Cw721.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 (_Cw721 *Cw721CallerSession) IsApprovedForAll(owner common.Address, operator common.Address) (bool, error) { + return _Cw721.Contract.IsApprovedForAll(&_Cw721.CallOpts, owner, operator) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Cw721 *Cw721Caller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Cw721.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 (_Cw721 *Cw721Session) Name() (string, error) { + return _Cw721.Contract.Name(&_Cw721.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Cw721 *Cw721CallerSession) Name() (string, error) { + return _Cw721.Contract.Name(&_Cw721.CallOpts) +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 tokenId) view returns(address) +func (_Cw721 *Cw721Caller) OwnerOf(opts *bind.CallOpts, tokenId *big.Int) (common.Address, error) { + var out []interface{} + err := _Cw721.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 (_Cw721 *Cw721Session) OwnerOf(tokenId *big.Int) (common.Address, error) { + return _Cw721.Contract.OwnerOf(&_Cw721.CallOpts, tokenId) +} + +// OwnerOf is a free data retrieval call binding the contract method 0x6352211e. +// +// Solidity: function ownerOf(uint256 tokenId) view returns(address) +func (_Cw721 *Cw721CallerSession) OwnerOf(tokenId *big.Int) (common.Address, error) { + return _Cw721.Contract.OwnerOf(&_Cw721.CallOpts, tokenId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view 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) + + 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) view 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) +func (_Cw721 *Cw721CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Cw721.Contract.SupportsInterface(&_Cw721.CallOpts, interfaceId) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Cw721 *Cw721Caller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Cw721.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 (_Cw721 *Cw721Session) Symbol() (string, error) { + return _Cw721.Contract.Symbol(&_Cw721.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Cw721 *Cw721CallerSession) Symbol() (string, error) { + return _Cw721.Contract.Symbol(&_Cw721.CallOpts) +} + +// TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. +// +// Solidity: function tokenURI(uint256 tokenId) view returns(string) +func (_Cw721 *Cw721Caller) TokenURI(opts *bind.CallOpts, tokenId *big.Int) (string, error) { + var out []interface{} + err := _Cw721.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 (_Cw721 *Cw721Session) TokenURI(tokenId *big.Int) (string, error) { + return _Cw721.Contract.TokenURI(&_Cw721.CallOpts, tokenId) +} + +// TokenURI is a free data retrieval call binding the contract method 0xc87b56dd. +// +// Solidity: function tokenURI(uint256 tokenId) view returns(string) +func (_Cw721 *Cw721CallerSession) TokenURI(tokenId *big.Int) (string, error) { + return _Cw721.Contract.TokenURI(&_Cw721.CallOpts, tokenId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address approved, uint256 tokenId) returns() +func (_Cw721 *Cw721Transactor) Approve(opts *bind.TransactOpts, approved common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Cw721.contract.Transact(opts, "approve", approved, tokenId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address approved, uint256 tokenId) returns() +func (_Cw721 *Cw721Session) Approve(approved common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Cw721.Contract.Approve(&_Cw721.TransactOpts, approved, tokenId) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address approved, uint256 tokenId) returns() +func (_Cw721 *Cw721TransactorSession) Approve(approved common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Cw721.Contract.Approve(&_Cw721.TransactOpts, approved, tokenId) +} + +// SafeTransferFrom is a paid mutator transaction binding the contract method 0x42842e0e. +// +// Solidity: function safeTransferFrom(address from, address to, uint256 tokenId) returns() +func (_Cw721 *Cw721Transactor) SafeTransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Cw721.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 (_Cw721 *Cw721Session) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Cw721.Contract.SafeTransferFrom(&_Cw721.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 (_Cw721 *Cw721TransactorSession) SafeTransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Cw721.Contract.SafeTransferFrom(&_Cw721.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 (_Cw721 *Cw721Transactor) SafeTransferFrom0(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int, data []byte) (*types.Transaction, error) { + return _Cw721.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 (_Cw721 *Cw721Session) SafeTransferFrom0(from common.Address, to common.Address, tokenId *big.Int, data []byte) (*types.Transaction, error) { + return _Cw721.Contract.SafeTransferFrom0(&_Cw721.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 (_Cw721 *Cw721TransactorSession) SafeTransferFrom0(from common.Address, to common.Address, tokenId *big.Int, data []byte) (*types.Transaction, error) { + return _Cw721.Contract.SafeTransferFrom0(&_Cw721.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 (_Cw721 *Cw721Transactor) SetApprovalForAll(opts *bind.TransactOpts, operator common.Address, approved bool) (*types.Transaction, error) { + return _Cw721.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 (_Cw721 *Cw721Session) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _Cw721.Contract.SetApprovalForAll(&_Cw721.TransactOpts, operator, approved) +} + +// SetApprovalForAll is a paid mutator transaction binding the contract method 0xa22cb465. +// +// Solidity: function setApprovalForAll(address operator, bool approved) returns() +func (_Cw721 *Cw721TransactorSession) SetApprovalForAll(operator common.Address, approved bool) (*types.Transaction, error) { + return _Cw721.Contract.SetApprovalForAll(&_Cw721.TransactOpts, operator, approved) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 tokenId) returns() +func (_Cw721 *Cw721Transactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Cw721.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 (_Cw721 *Cw721Session) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Cw721.Contract.TransferFrom(&_Cw721.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 (_Cw721 *Cw721TransactorSession) TransferFrom(from common.Address, to common.Address, tokenId *big.Int) (*types.Transaction, error) { + return _Cw721.Contract.TransferFrom(&_Cw721.TransactOpts, from, to, tokenId) +} + +// Cw721ApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Cw721 contract. +type Cw721ApprovalIterator struct { + Event *Cw721Approval // 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 *Cw721ApprovalIterator) 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(Cw721Approval) + 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(Cw721Approval) + 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 *Cw721ApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Cw721ApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Cw721Approval represents a Approval event raised by the Cw721 contract. +type Cw721Approval 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 (_Cw721 *Cw721Filterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, approved []common.Address, tokenId []*big.Int) (*Cw721ApprovalIterator, 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 := _Cw721.contract.FilterLogs(opts, "Approval", ownerRule, approvedRule, tokenIdRule) + if err != nil { + return nil, err + } + return &Cw721ApprovalIterator{contract: _Cw721.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 (_Cw721 *Cw721Filterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *Cw721Approval, 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 := _Cw721.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(Cw721Approval) + if err := _Cw721.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 (_Cw721 *Cw721Filterer) ParseApproval(log types.Log) (*Cw721Approval, error) { + event := new(Cw721Approval) + if err := _Cw721.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// Cw721ApprovalForAllIterator is returned from FilterApprovalForAll and is used to iterate over the raw logs and unpacked data for ApprovalForAll events raised by the Cw721 contract. +type Cw721ApprovalForAllIterator struct { + Event *Cw721ApprovalForAll // 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 *Cw721ApprovalForAllIterator) 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(Cw721ApprovalForAll) + 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(Cw721ApprovalForAll) + 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 *Cw721ApprovalForAllIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Cw721ApprovalForAllIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Cw721ApprovalForAll represents a ApprovalForAll event raised by the Cw721 contract. +type Cw721ApprovalForAll 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 (_Cw721 *Cw721Filterer) FilterApprovalForAll(opts *bind.FilterOpts, owner []common.Address, operator []common.Address) (*Cw721ApprovalForAllIterator, 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 := _Cw721.contract.FilterLogs(opts, "ApprovalForAll", ownerRule, operatorRule) + if err != nil { + return nil, err + } + return &Cw721ApprovalForAllIterator{contract: _Cw721.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 (_Cw721 *Cw721Filterer) WatchApprovalForAll(opts *bind.WatchOpts, sink chan<- *Cw721ApprovalForAll, 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 := _Cw721.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(Cw721ApprovalForAll) + if err := _Cw721.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 (_Cw721 *Cw721Filterer) ParseApprovalForAll(log types.Log) (*Cw721ApprovalForAll, error) { + event := new(Cw721ApprovalForAll) + if err := _Cw721.contract.UnpackLog(event, "ApprovalForAll", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// Cw721TransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Cw721 contract. +type Cw721TransferIterator struct { + Event *Cw721Transfer // 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 *Cw721TransferIterator) 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(Cw721Transfer) + 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(Cw721Transfer) + 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 *Cw721TransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *Cw721TransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// Cw721Transfer represents a Transfer event raised by the Cw721 contract. +type Cw721Transfer 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 (_Cw721 *Cw721Filterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address, tokenId []*big.Int) (*Cw721TransferIterator, 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 := _Cw721.contract.FilterLogs(opts, "Transfer", fromRule, toRule, tokenIdRule) + if err != nil { + return nil, err + } + return &Cw721TransferIterator{contract: _Cw721.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 (_Cw721 *Cw721Filterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *Cw721Transfer, 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 := _Cw721.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(Cw721Transfer) + if err := _Cw721.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 (_Cw721 *Cw721Filterer) ParseTransfer(log types.Log) (*Cw721Transfer, error) { + event := new(Cw721Transfer) + if err := _Cw721.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/x/evm/artifacts/cw721/legacy.bin b/x/evm/artifacts/cw721/legacy.bin new file mode 100644 index 0000000000..a36e99b497 --- /dev/null +++ b/x/evm/artifacts/cw721/legacy.bin @@ -0,0 +1 @@ +608060405234801562000010575f80fd5b5060405162003be638038062003be68339818101604052810190620000369190620002c3565b8181815f9081620000489190620005b0565b5080600190816200005a9190620005b0565b50505061100260075f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100360085f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061100460095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508260069081620001349190620005b0565b5050505062000694565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200019f8262000157565b810181811067ffffffffffffffff82111715620001c157620001c062000167565b5b80604052505050565b5f620001d56200013e565b9050620001e3828262000194565b919050565b5f67ffffffffffffffff82111562000205576200020462000167565b5b620002108262000157565b9050602081019050919050565b5f5b838110156200023c5780820151818401526020810190506200021f565b5f8484015250505050565b5f6200025d6200025784620001e8565b620001ca565b9050828152602081018484840111156200027c576200027b62000153565b5b620002898482856200021d565b509392505050565b5f82601f830112620002a857620002a76200014f565b5b8151620002ba84826020860162000247565b91505092915050565b5f805f60608486031215620002dd57620002dc62000147565b5b5f84015167ffffffffffffffff811115620002fd57620002fc6200014b565b5b6200030b8682870162000291565b935050602084015167ffffffffffffffff8111156200032f576200032e6200014b565b5b6200033d8682870162000291565b925050604084015167ffffffffffffffff8111156200036157620003606200014b565b5b6200036f8682870162000291565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620003c857607f821691505b602082108103620003de57620003dd62000383565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004427fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000405565b6200044e868362000405565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000498620004926200048c8462000466565b6200046f565b62000466565b9050919050565b5f819050919050565b620004b38362000478565b620004cb620004c2826200049f565b84845462000411565b825550505050565b5f90565b620004e1620004d3565b620004ee818484620004a8565b505050565b5b818110156200051557620005095f82620004d7565b600181019050620004f4565b5050565b601f82111562000564576200052e81620003e4565b6200053984620003f6565b8101602085101562000549578190505b620005616200055885620003f6565b830182620004f3565b50505b505050565b5f82821c905092915050565b5f620005865f198460080262000569565b1980831691505092915050565b5f620005a0838362000575565b9150826002028217905092915050565b620005bb8262000379565b67ffffffffffffffff811115620005d757620005d662000167565b5b620005e38254620003b0565b620005f082828562000519565b5f60209050601f83116001811462000626575f841562000611578287015190505b6200061d858262000593565b8655506200068c565b601f1984166200063686620003e4565b5f5b828110156200065f5784890151825560018201915060208501945060208101905062000638565b868310156200067f57848901516200067b601f89168262000575565b8355505b6001600288020188555050505b505050505050565b61354480620006a25f395ff3fe608060405234801561000f575f80fd5b5060043610610109575f3560e01c806370a08231116100a0578063c2aed3021161006f578063c2aed302146102b3578063c87b56dd146102d1578063de4725cc14610301578063e985e9c51461031f578063f00b02551461034f57610109565b806370a082311461022d57806395d89b411461025d578063a22cb4651461027b578063b88d4fde1461029757610109565b806323b872dd116100dc57806323b872dd146101a757806342842e0e146101c35780635c4aead7146101df5780636352211e146101fd57610109565b806301ffc9a71461010d57806306fdde031461013d578063081812fc1461015b578063095ea7b31461018b575b5f80fd5b610127600480360381019061012291906123ea565b61036d565b604051610134919061242f565b60405180910390f35b61014561044e565b60405161015291906124d2565b60405180910390f35b61017560048036038101906101709190612525565b6104dd565b604051610182919061258f565b60405180910390f35b6101a560048036038101906101a091906125d2565b610837565b005b6101c160048036038101906101bc9190612610565b610a73565b005b6101dd60048036038101906101d89190612610565b610d18565b005b6101e7610d37565b6040516101f491906124d2565b60405180910390f35b61021760048036038101906102129190612525565b610dc3565b604051610224919061258f565b60405180910390f35b61024760048036038101906102429190612660565b61104d565b604051610254919061269a565b60405180910390f35b610265611343565b60405161027291906124d2565b60405180910390f35b610295600480360381019061029091906126dd565b6113d3565b005b6102b160048036038101906102ac9190612847565b6115d6565b005b6102bb6115f3565b6040516102c89190612922565b60405180910390f35b6102eb60048036038101906102e69190612525565b611618565b6040516102f891906124d2565b60405180910390f35b610309611815565b604051610316919061295b565b60405180910390f35b61033960048036038101906103349190612974565b61183a565b604051610346919061242f565b60405180910390f35b610357611c74565b60405161036491906129d2565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061043757507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80610447575061044682611c99565b5b9050919050565b60605f805461045c90612a18565b80601f016020809104026020016040519081016040528092919081815260200182805461048890612a18565b80156104d35780601f106104aa576101008083540402835291602001916104d3565b820191905f5260205f20905b8154815290600101906020018083116104b657829003601f168201915b5050505050905090565b5f8061052e6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061052961052486611d02565b611dcc565b611e14565b90505f61058061057b6040518060400160405280600981526020017f617070726f76616c73000000000000000000000000000000000000000000000081525061057685611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016105e0929190612b2d565b5f60405180830381865afa1580156105fa573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106229190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b815260040161067f9190612c61565b5f60405180830381865afa158015610699573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906106c19190612d76565b90505f8151111561082a575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5835f8151811061071d5761071c612dbd565b5b60200260200101516040518263ffffffff1660e01b81526004016107419190612e34565b5f60405180830381865afa15801561075b573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906107839190612bd0565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b81526004016107df91906124d2565b602060405180830381865afa1580156107fa573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061081e9190612e7b565b95505050505050610832565b5f9450505050505b919050565b5f61091a6040518060400160405280600781526020017f7370656e6465720000000000000000000000000000000000000000000000000081525061091560095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b81526004016108ce919061258f565b5f60405180830381865afa1580156108e8573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906109109190612f44565b611dcc565b611e14565b90505f61096c6040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061096761096286611d02565b611dcc565b611e14565b90505f6109fd6109f86040518060400160405280600781526020017f617070726f7665000000000000000000000000000000000000000000000000008152506109f36109ee87876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611eae565b611e66565b611e14565b611e66565b9050610a0881611efc565b50838573ffffffffffffffffffffffffffffffffffffffff16610a2a86610dc3565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610ae3575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ada919061258f565b60405180910390fd5b5f610bc66040518060400160405280600981526020017f726563697069656e740000000000000000000000000000000000000000000000815250610bc160095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401610b7a919061258f565b5f60405180830381865afa158015610b94573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610bbc9190612f44565b611dcc565b611e14565b90505f610c186040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610c13610c0e86611d02565b611dcc565b611e14565b90505f610ca9610ca46040518060400160405280600c81526020017f7472616e736665725f6e66740000000000000000000000000000000000000000815250610c9f610c9a87876040518060400160405280600181526020017f2c00000000000000000000000000000000000000000000000000000000000000815250611eae565b611e66565b611e14565b611e66565b9050610cb481611efc565b50838573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4505050505050565b610d3283838360405180602001604052805f8152506115d6565b505050565b60068054610d4490612a18565b80601f0160208091040260200160405190810160405280929190818152602001828054610d7090612a18565b8015610dbb5780601f10610d9257610100808354040283529160200191610dbb565b820191905f5260205f20905b815481529060010190602001808311610d9e57829003601f168201915b505050505081565b5f80610e146040518060400160405280600881526020017f746f6b656e5f6964000000000000000000000000000000000000000000000000815250610e0f610e0a86611d02565b611dcc565b611e14565b90505f610e66610e616040518060400160405280600881526020017f6f776e65725f6f66000000000000000000000000000000000000000000000000815250610e5c85611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401610ec6929190612b2d565b5f60405180830381865afa158015610ee0573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610f089190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b8152600401610f659190612fd5565b5f60405180830381865afa158015610f7f573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190610fa79190612bd0565b905060095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539826040518263ffffffff1660e01b815260040161100391906124d2565b602060405180830381865afa15801561101e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110429190612e7b565b945050505050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036110be575f6040517f89c62b640000000000000000000000000000000000000000000000000000000081526004016110b5919061258f565b60405180910390fd5b5f6111a16040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061119c60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed876040518263ffffffff1660e01b8152600401611155919061258f565b5f60405180830381865afa15801561116f573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906111979190612f44565b611dcc565b611e14565b90505f6111f36111ee6040518060400160405280600681526020017f746f6b656e7300000000000000000000000000000000000000000000000000008152506111e985611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401611253929190612b2d565b5f60405180830381865afa15801561126d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906112959190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b81526004016112f29190613052565b5f60405180830381865afa15801561130c573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906113349190612d76565b90508051945050505050919050565b60606001805461135290612a18565b80601f016020809104026020016040519081016040528092919081815260200182805461137e90612a18565b80156113c95780601f106113a0576101008083540402835291602001916113c9565b820191905f5260205f20905b8154815290600101906020018083116113ac57829003601f168201915b5050505050905090565b5f6114be6114b96040518060400160405280600881526020017f6f70657261746f720000000000000000000000000000000000000000000000008152506114b460095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b815260040161146d919061258f565b5f60405180830381865afa158015611487573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906114af9190612f44565b611dcc565b611e14565b611e66565b9050811561151b5761151561151061150b6040518060400160405280600b81526020017f617070726f76655f616c6c00000000000000000000000000000000000000000081525084611e14565b611e66565b611efc565b5061156c565b61156a6115656115606040518060400160405280600a81526020017f7265766f6b655f616c6c0000000000000000000000000000000000000000000081525084611e14565b611e66565b611efc565b505b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31846040516115c9919061242f565b60405180910390a3505050565b6115e1848484610a73565b6115ed8484848461207a565b50505050565b60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606061162382610dc3565b505f6116746040518060400160405280600881526020017f746f6b656e5f696400000000000000000000000000000000000000000000000081525061166f61166a86611d02565b611dcc565b611e14565b90505f6116c66116c16040518060400160405280600881526020017f6e66745f696e666f0000000000000000000000000000000000000000000000008152506116bc85611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b8152600401611726929190612b2d565b5f60405180830381865afa158015611740573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906117689190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5836040518263ffffffff1660e01b81526004016117c591906130cf565b5f60405180830381865afa1580156117df573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906118079190612bd0565b905080945050505050919050565b60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f8061191e6040518060400160405280600581526020017f6f776e657200000000000000000000000000000000000000000000000000000081525061191960095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630c3c20ed886040518263ffffffff1660e01b81526004016118d2919061258f565b5f60405180830381865afa1580156118ec573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906119149190612f44565b611dcc565b611e14565b90505f61197061196b6040518060400160405280600d81526020017f616c6c5f6f70657261746f72730000000000000000000000000000000000000081525061196685611e66565b611e14565b611e66565b90505f60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166306d81d296006846040518363ffffffff1660e01b81526004016119d0929190612b2d565b5f60405180830381865afa1580156119ea573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611a129190612bd0565b90505f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166387cdf621836040518263ffffffff1660e01b8152600401611a6f919061314c565b5f60405180830381865afa158015611a89573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611ab19190612d76565b90505f5b8151811015611c65575f60085f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166308d858e5848481518110611b0f57611b0e612dbd565b5b60200260200101516040518263ffffffff1660e01b8152600401611b339190612e34565b5f60405180830381865afa158015611b4d573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f82011682018060405250810190611b759190612bd0565b90508773ffffffffffffffffffffffffffffffffffffffff1660095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631778e539836040518263ffffffff1660e01b8152600401611be891906124d2565b602060405180830381865afa158015611c03573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c279190612e7b565b73ffffffffffffffffffffffffffffffffffffffff1603611c515760019650505050505050611c6e565b508080611c5d906131ac565b915050611ab5565b505f9450505050505b92915050565b60075f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b60605f6001611d108461222c565b0190505f8167ffffffffffffffff811115611d2e57611d2d612723565b5b6040519080825280601f01601f191660200182016040528015611d605781602001600182028036833780820191505090505b5090505f82602001820190505b600115611dc1578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8581611db657611db56131f3565b5b0494505f8503611d6d575b819350505050919050565b606081604051602001611ddf9190613280565b604051602081830303815290604052604051602001611dfe91906132a5565b6040516020818303038152906040529050919050565b6060611e5e611e2284611dcc565b836040518060400160405280600181526020017f3a00000000000000000000000000000000000000000000000000000000000000815250611eae565b905092915050565b606081604051602001611e7991906132f0565b604051602081830303815290604052604051602001611e98919061333b565b6040516020818303038152906040529050919050565b6060838284604051602001611ec4929190613360565b604051602081830303815290604052604051602001611ee4929190613360565b60405160208183030381529060405290509392505050565b60605f8061100273ffffffffffffffffffffffffffffffffffffffff166006856040518060400160405280600281526020017f5b5d000000000000000000000000000000000000000000000000000000000000815250604051602401611f6493929190613383565b6040516020818303038152906040527f44d227ae000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051611fee9190613407565b5f60405180830381855af49150503d805f8114612026576040519150601f19603f3d011682016040523d82523d5f602084013e61202b565b606091505b509150915081612070576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161206790613467565b60405180910390fd5b8092505050919050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b1115612226578273ffffffffffffffffffffffffffffffffffffffff1663150b7a026120bd61237d565b8685856040518563ffffffff1660e01b81526004016120df9493929190613485565b6020604051808303815f875af192505050801561211a57506040513d601f19601f8201168201806040525081019061211791906134e3565b60015b61219b573d805f8114612148576040519150601f19603f3d011682016040523d82523d5f602084013e61214d565b606091505b505f81510361219357836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161218a919061258f565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461222457836040517f64a0ae9200000000000000000000000000000000000000000000000000000000815260040161221b919061258f565b60405180910390fd5b505b50505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008310612288577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161227e5761227d6131f3565b5b0492506040810190505b6d04ee2d6d415b85acef810000000083106122c5576d04ee2d6d415b85acef810000000083816122bb576122ba6131f3565b5b0492506020810190505b662386f26fc1000083106122f457662386f26fc1000083816122ea576122e96131f3565b5b0492506010810190505b6305f5e100831061231d576305f5e1008381612313576123126131f3565b5b0492506008810190505b6127108310612342576127108381612338576123376131f3565b5b0492506004810190505b60648310612365576064838161235b5761235a6131f3565b5b0492506002810190505b600a8310612374576001810190505b80915050919050565b5f33905090565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6123c981612395565b81146123d3575f80fd5b50565b5f813590506123e4816123c0565b92915050565b5f602082840312156123ff576123fe61238d565b5b5f61240c848285016123d6565b91505092915050565b5f8115159050919050565b61242981612415565b82525050565b5f6020820190506124425f830184612420565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561247f578082015181840152602081019050612464565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6124a482612448565b6124ae8185612452565b93506124be818560208601612462565b6124c78161248a565b840191505092915050565b5f6020820190508181035f8301526124ea818461249a565b905092915050565b5f819050919050565b612504816124f2565b811461250e575f80fd5b50565b5f8135905061251f816124fb565b92915050565b5f6020828403121561253a5761253961238d565b5b5f61254784828501612511565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61257982612550565b9050919050565b6125898161256f565b82525050565b5f6020820190506125a25f830184612580565b92915050565b6125b18161256f565b81146125bb575f80fd5b50565b5f813590506125cc816125a8565b92915050565b5f80604083850312156125e8576125e761238d565b5b5f6125f5858286016125be565b925050602061260685828601612511565b9150509250929050565b5f805f606084860312156126275761262661238d565b5b5f612634868287016125be565b9350506020612645868287016125be565b925050604061265686828701612511565b9150509250925092565b5f602082840312156126755761267461238d565b5b5f612682848285016125be565b91505092915050565b612694816124f2565b82525050565b5f6020820190506126ad5f83018461268b565b92915050565b6126bc81612415565b81146126c6575f80fd5b50565b5f813590506126d7816126b3565b92915050565b5f80604083850312156126f3576126f261238d565b5b5f612700858286016125be565b9250506020612711858286016126c9565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6127598261248a565b810181811067ffffffffffffffff8211171561277857612777612723565b5b80604052505050565b5f61278a612384565b90506127968282612750565b919050565b5f67ffffffffffffffff8211156127b5576127b4612723565b5b6127be8261248a565b9050602081019050919050565b828183375f83830152505050565b5f6127eb6127e68461279b565b612781565b9050828152602081018484840111156128075761280661271f565b5b6128128482856127cb565b509392505050565b5f82601f83011261282e5761282d61271b565b5b813561283e8482602086016127d9565b91505092915050565b5f805f806080858703121561285f5761285e61238d565b5b5f61286c878288016125be565b945050602061287d878288016125be565b935050604061288e87828801612511565b925050606085013567ffffffffffffffff8111156128af576128ae612391565b5b6128bb8782880161281a565b91505092959194509250565b5f819050919050565b5f6128ea6128e56128e084612550565b6128c7565b612550565b9050919050565b5f6128fb826128d0565b9050919050565b5f61290c826128f1565b9050919050565b61291c81612902565b82525050565b5f6020820190506129355f830184612913565b92915050565b5f612945826128f1565b9050919050565b6129558161293b565b82525050565b5f60208201905061296e5f83018461294c565b92915050565b5f806040838503121561298a5761298961238d565b5b5f612997858286016125be565b92505060206129a8858286016125be565b9150509250929050565b5f6129bc826128f1565b9050919050565b6129cc816129b2565b82525050565b5f6020820190506129e55f8301846129c3565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680612a2f57607f821691505b602082108103612a4257612a416129eb565b5b50919050565b5f819050815f5260205f209050919050565b5f8154612a6681612a18565b612a708186612452565b9450600182165f8114612a8a5760018114612aa057612ad2565b60ff198316865281151560200286019350612ad2565b612aa985612a48565b5f5b83811015612aca57815481890152600182019150602081019050612aab565b808801955050505b50505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f612aff82612adb565b612b098185612ae5565b9350612b19818560208601612462565b612b228161248a565b840191505092915050565b5f6040820190508181035f830152612b458185612a5a565b90508181036020830152612b598184612af5565b90509392505050565b5f612b74612b6f8461279b565b612781565b905082815260208101848484011115612b9057612b8f61271f565b5b612b9b848285612462565b509392505050565b5f82601f830112612bb757612bb661271b565b5b8151612bc7848260208601612b62565b91505092915050565b5f60208284031215612be557612be461238d565b5b5f82015167ffffffffffffffff811115612c0257612c01612391565b5b612c0e84828501612ba3565b91505092915050565b7f617070726f76616c7300000000000000000000000000000000000000000000005f82015250565b5f612c4b600983612452565b9150612c5682612c17565b602082019050919050565b5f6040820190508181035f830152612c798184612af5565b90508181036020830152612c8c81612c3f565b905092915050565b5f67ffffffffffffffff821115612cae57612cad612723565b5b602082029050602081019050919050565b5f80fd5b5f612cd5612cd084612c94565b612781565b90508083825260208201905060208402830185811115612cf857612cf7612cbf565b5b835b81811015612d3f57805167ffffffffffffffff811115612d1d57612d1c61271b565b5b808601612d2a8982612ba3565b85526020850194505050602081019050612cfa565b5050509392505050565b5f82601f830112612d5d57612d5c61271b565b5b8151612d6d848260208601612cc3565b91505092915050565b5f60208284031215612d8b57612d8a61238d565b5b5f82015167ffffffffffffffff811115612da857612da7612391565b5b612db484828501612d49565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f7370656e646572000000000000000000000000000000000000000000000000005f82015250565b5f612e1e600783612452565b9150612e2982612dea565b602082019050919050565b5f6040820190508181035f830152612e4c8184612af5565b90508181036020830152612e5f81612e12565b905092915050565b5f81519050612e75816125a8565b92915050565b5f60208284031215612e9057612e8f61238d565b5b5f612e9d84828501612e67565b91505092915050565b5f67ffffffffffffffff821115612ec057612ebf612723565b5b612ec98261248a565b9050602081019050919050565b5f612ee8612ee384612ea6565b612781565b905082815260208101848484011115612f0457612f0361271f565b5b612f0f848285612462565b509392505050565b5f82601f830112612f2b57612f2a61271b565b5b8151612f3b848260208601612ed6565b91505092915050565b5f60208284031215612f5957612f5861238d565b5b5f82015167ffffffffffffffff811115612f7657612f75612391565b5b612f8284828501612f17565b91505092915050565b7f6f776e65720000000000000000000000000000000000000000000000000000005f82015250565b5f612fbf600583612452565b9150612fca82612f8b565b602082019050919050565b5f6040820190508181035f830152612fed8184612af5565b9050818103602083015261300081612fb3565b905092915050565b7f746f6b656e7300000000000000000000000000000000000000000000000000005f82015250565b5f61303c600683612452565b915061304782613008565b602082019050919050565b5f6040820190508181035f83015261306a8184612af5565b9050818103602083015261307d81613030565b905092915050565b7f746f6b656e5f75726900000000000000000000000000000000000000000000005f82015250565b5f6130b9600983612452565b91506130c482613085565b602082019050919050565b5f6040820190508181035f8301526130e78184612af5565b905081810360208301526130fa816130ad565b905092915050565b7f6f70657261746f727300000000000000000000000000000000000000000000005f82015250565b5f613136600983612452565b915061314182613102565b602082019050919050565b5f6040820190508181035f8301526131648184612af5565b905081810360208301526131778161312a565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6131b6826124f2565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036131e8576131e761317f565b5b600182019050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f81905092915050565b5f61323482612448565b61323e8185613220565b935061324e818560208601612462565b80840191505092915050565b7f2200000000000000000000000000000000000000000000000000000000000000815250565b5f61328b828461322a565b91506132968261325a565b60018201915081905092915050565b5f6132af8261325a565b6001820191506132bf828461322a565b915081905092915050565b7f7d00000000000000000000000000000000000000000000000000000000000000815250565b5f6132fb828461322a565b9150613306826132ca565b60018201915081905092915050565b7f7b00000000000000000000000000000000000000000000000000000000000000815250565b5f61334582613315565b600182019150613355828461322a565b915081905092915050565b5f61336b828561322a565b9150613377828461322a565b91508190509392505050565b5f6060820190508181035f83015261339b8186612a5a565b905081810360208301526133af8185612af5565b905081810360408301526133c38184612af5565b9050949350505050565b5f81905092915050565b5f6133e182612adb565b6133eb81856133cd565b93506133fb818560208601612462565b80840191505092915050565b5f61341282846133d7565b915081905092915050565b7f436f736d5761736d2065786563757465206661696c65640000000000000000005f82015250565b5f613451601783612452565b915061345c8261341d565b602082019050919050565b5f6020820190508181035f83015261347e81613445565b9050919050565b5f6080820190506134985f830187612580565b6134a56020830186612580565b6134b2604083018561268b565b81810360608301526134c48184612af5565b905095945050505050565b5f815190506134dd816123c0565b92915050565b5f602082840312156134f8576134f761238d565b5b5f613505848285016134cf565b9150509291505056fea2646970667358221220495112dee5946564e4698691b403b20ed33f5227eeb4c65f02a9f776f425467464736f6c63430008150033 \ No newline at end of file diff --git a/x/evm/artifacts/erc20/artifacts.go b/x/evm/artifacts/erc20/artifacts.go new file mode 100644 index 0000000000..9e964cbec0 --- /dev/null +++ b/x/evm/artifacts/erc20/artifacts.go @@ -0,0 +1,22 @@ +package erc20 + +import "embed" + +const CurrentVersion uint16 = 1 + +//go:embed cwerc20.wasm +var f embed.FS + +var cachedBin []byte + +func GetBin() []byte { + if cachedBin != nil { + return cachedBin + } + bz, err := f.ReadFile("cwerc20.wasm") + if err != nil { + panic("failed to read ERC20 wrapper contract wasm") + } + cachedBin = bz + return bz +} diff --git a/x/evm/artifacts/erc20/cwerc20.wasm b/x/evm/artifacts/erc20/cwerc20.wasm new file mode 100644 index 0000000000..aac641633a Binary files /dev/null and b/x/evm/artifacts/erc20/cwerc20.wasm differ diff --git a/x/evm/artifacts/erc721/artifacts.go b/x/evm/artifacts/erc721/artifacts.go new file mode 100644 index 0000000000..b542ee3b41 --- /dev/null +++ b/x/evm/artifacts/erc721/artifacts.go @@ -0,0 +1,22 @@ +package erc721 + +import "embed" + +const CurrentVersion uint16 = 1 + +//go:embed cwerc721.wasm +var f embed.FS + +var cachedBin []byte + +func GetBin() []byte { + if cachedBin != nil { + return cachedBin + } + bz, err := f.ReadFile("cwerc721.wasm") + if err != nil { + panic("failed to read ERC721 wrapper contract wasm") + } + cachedBin = bz + return bz +} diff --git a/x/evm/artifacts/erc721/cwerc721.wasm b/x/evm/artifacts/erc721/cwerc721.wasm new file mode 100644 index 0000000000..318ada77bc Binary files /dev/null and b/x/evm/artifacts/erc721/cwerc721.wasm differ diff --git a/x/evm/artifacts/native/NativeSeiTokensERC20.abi b/x/evm/artifacts/native/NativeSeiTokensERC20.abi new file mode 100644 index 0000000000..7406bac252 --- /dev/null +++ b/x/evm/artifacts/native/NativeSeiTokensERC20.abi @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"string","name":"denom_","type":"string"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BankPrecompile","outputs":[{"internalType":"contract IBank","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ddecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"denom","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nname","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ssymbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/x/evm/artifacts/native/NativeSeiTokensERC20.bin b/x/evm/artifacts/native/NativeSeiTokensERC20.bin new file mode 100644 index 0000000000..80a1d9ab58 --- /dev/null +++ b/x/evm/artifacts/native/NativeSeiTokensERC20.bin @@ -0,0 +1 @@ +608060405234801562000010575f80fd5b5060405162001a2d38038062001a2d8339818101604052810190620000369190620002d7565b60405180602001604052805f81525060405180602001604052805f8152508160039081620000659190620005da565b508060049081620000779190620005da565b505050611001600860016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360059081620000ce9190620005da565b508260069081620000e09190620005da565b508160079081620000f29190620005da565b508060085f6101000a81548160ff021916908360ff16021790555050505050620006be565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620001788262000130565b810181811067ffffffffffffffff821117156200019a576200019962000140565b5b80604052505050565b5f620001ae62000117565b9050620001bc82826200016d565b919050565b5f67ffffffffffffffff821115620001de57620001dd62000140565b5b620001e98262000130565b9050602081019050919050565b5f5b8381101562000215578082015181840152602081019050620001f8565b5f8484015250505050565b5f620002366200023084620001c1565b620001a3565b9050828152602081018484840111156200025557620002546200012c565b5b62000262848285620001f6565b509392505050565b5f82601f83011262000281576200028062000128565b5b81516200029384826020860162000220565b91505092915050565b5f60ff82169050919050565b620002b3816200029c565b8114620002be575f80fd5b50565b5f81519050620002d181620002a8565b92915050565b5f805f8060808587031215620002f257620002f162000120565b5b5f85015167ffffffffffffffff81111562000312576200031162000124565b5b62000320878288016200026a565b945050602085015167ffffffffffffffff81111562000344576200034362000124565b5b62000352878288016200026a565b935050604085015167ffffffffffffffff81111562000376576200037562000124565b5b62000384878288016200026a565b92505060606200039787828801620002c1565b91505092959194509250565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620003f257607f821691505b602082108103620004085762000407620003ad565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026200046c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200042f565b6200047886836200042f565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f620004c2620004bc620004b68462000490565b62000499565b62000490565b9050919050565b5f819050919050565b620004dd83620004a2565b620004f5620004ec82620004c9565b8484546200043b565b825550505050565b5f90565b6200050b620004fd565b62000518818484620004d2565b505050565b5b818110156200053f57620005335f8262000501565b6001810190506200051e565b5050565b601f8211156200058e5762000558816200040e565b620005638462000420565b8101602085101562000573578190505b6200058b620005828562000420565b8301826200051d565b50505b505050565b5f82821c905092915050565b5f620005b05f198460080262000593565b1980831691505092915050565b5f620005ca83836200059f565b9150826002028217905092915050565b620005e582620003a3565b67ffffffffffffffff81111562000601576200060062000140565b5b6200060d8254620003da565b6200061a82828562000543565b5f60209050601f83116001811462000650575f84156200063b578287015190505b620006478582620005bd565b865550620006b6565b601f19841662000660866200040e565b5f5b82811015620006895784890151825560018201915060208501945060208101905062000662565b86831015620006a95784890151620006a5601f8916826200059f565b8355505b6001600288020188555050505b505050505050565b61136180620006cc5f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c80638a0989f51161008a578063a8ad11e411610064578063a8ad11e41461024e578063a9059cbb1461026c578063c370b0421461029c578063dd62ed3e146102ba576100e8565b80638a0989f5146101f457806395d89b41146102125780639e10aa2414610230576100e8565b806323b872dd116100c657806323b872dd14610158578063313ce56714610188578063566732c1146101a657806370a08231146101c4576100e8565b806306fdde03146100ec578063095ea7b31461010a57806318160ddd1461013a575b5f80fd5b6100f46102ea565b6040516101019190610d79565b60405180910390f35b610124600480360381019061011f9190610e2a565b61037a565b6040516101319190610e82565b60405180910390f35b61014261039c565b60405161014f9190610eaa565b60405180910390f35b610172600480360381019061016d9190610ec3565b61043d565b60405161017f9190610e82565b60405180910390f35b61019061046b565b60405161019d9190610f2e565b60405180910390f35b6101ae610480565b6040516101bb9190610fa2565b60405180910390f35b6101de60048036038101906101d99190610fbb565b6104a6565b6040516101eb9190610eaa565b60405180910390f35b6101fc61054b565b6040516102099190610d79565b60405180910390f35b61021a6105d7565b6040516102279190610d79565b60405180910390f35b610238610667565b6040516102459190610d79565b60405180910390f35b6102566106f3565b6040516102639190610f2e565b60405180910390f35b61028660048036038101906102819190610e2a565b610705565b6040516102939190610e82565b60405180910390f35b6102a4610727565b6040516102b19190610d79565b60405180910390f35b6102d460048036038101906102cf9190610fe6565b6107b3565b6040516102e19190610eaa565b60405180910390f35b6060600680546102f990611051565b80601f016020809104026020016040519081016040528092919081815260200182805461032590611051565b80156103705780601f1061034757610100808354040283529160200191610370565b820191905f5260205f20905b81548152906001019060200180831161035357829003601f168201915b5050505050905090565b5f80610384610835565b905061039181858561083c565b600191505092915050565b5f600860019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636923a1fd60056040518263ffffffff1660e01b81526004016103f99190611114565b602060405180830381865afa158015610414573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104389190611148565b905090565b5f80610447610835565b905061045485828561084e565b61045f8585856108e0565b60019150509392505050565b5f60085f9054906101000a900460ff16905090565b600860019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f600860019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166316cadeab8360056040518363ffffffff1660e01b8152600401610505929190611182565b602060405180830381865afa158015610520573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105449190611148565b9050919050565b6006805461055890611051565b80601f016020809104026020016040519081016040528092919081815260200182805461058490611051565b80156105cf5780601f106105a6576101008083540402835291602001916105cf565b820191905f5260205f20905b8154815290600101906020018083116105b257829003601f168201915b505050505081565b6060600780546105e690611051565b80601f016020809104026020016040519081016040528092919081815260200182805461061290611051565b801561065d5780601f106106345761010080835404028352916020019161065d565b820191905f5260205f20905b81548152906001019060200180831161064057829003601f168201915b5050505050905090565b6007805461067490611051565b80601f01602080910402602001604051908101604052809291908181526020018280546106a090611051565b80156106eb5780601f106106c2576101008083540402835291602001916106eb565b820191905f5260205f20905b8154815290600101906020018083116106ce57829003601f168201915b505050505081565b60085f9054906101000a900460ff1681565b5f8061070f610835565b905061071c8185856108e0565b600191505092915050565b6005805461073490611051565b80601f016020809104026020016040519081016040528092919081815260200182805461076090611051565b80156107ab5780601f10610782576101008083540402835291602001916107ab565b820191905f5260205f20905b81548152906001019060200180831161078e57829003601f168201915b505050505081565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f33905090565b61084983838360016109d0565b505050565b5f61085984846107b3565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146108da57818110156108cb578281836040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526004016108c2939291906111b0565b60405180910390fd5b6108d984848484035f6109d0565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610950575f6040517f96c6fd1e00000000000000000000000000000000000000000000000000000000815260040161094791906111e5565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036109c0575f6040517fec442f050000000000000000000000000000000000000000000000000000000081526004016109b791906111e5565b60405180910390fd5b6109cb838383610b9f565b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610a40575f6040517fe602df05000000000000000000000000000000000000000000000000000000008152600401610a3791906111e5565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610ab0575f6040517f94280d62000000000000000000000000000000000000000000000000000000008152600401610aa791906111e5565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508015610b99578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610b909190610eaa565b60405180910390a35b50505050565b5f600860019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635c05961b85856005866040518563ffffffff1660e01b8152600401610c0294939291906111fe565b6020604051808303815f875af1158015610c1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c429190611272565b905080610c84576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7b9061130d565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610ce19190610eaa565b60405180910390a350505050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610d26578082015181840152602081019050610d0b565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610d4b82610cef565b610d558185610cf9565b9350610d65818560208601610d09565b610d6e81610d31565b840191505092915050565b5f6020820190508181035f830152610d918184610d41565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610dc682610d9d565b9050919050565b610dd681610dbc565b8114610de0575f80fd5b50565b5f81359050610df181610dcd565b92915050565b5f819050919050565b610e0981610df7565b8114610e13575f80fd5b50565b5f81359050610e2481610e00565b92915050565b5f8060408385031215610e4057610e3f610d99565b5b5f610e4d85828601610de3565b9250506020610e5e85828601610e16565b9150509250929050565b5f8115159050919050565b610e7c81610e68565b82525050565b5f602082019050610e955f830184610e73565b92915050565b610ea481610df7565b82525050565b5f602082019050610ebd5f830184610e9b565b92915050565b5f805f60608486031215610eda57610ed9610d99565b5b5f610ee786828701610de3565b9350506020610ef886828701610de3565b9250506040610f0986828701610e16565b9150509250925092565b5f60ff82169050919050565b610f2881610f13565b82525050565b5f602082019050610f415f830184610f1f565b92915050565b5f819050919050565b5f610f6a610f65610f6084610d9d565b610f47565b610d9d565b9050919050565b5f610f7b82610f50565b9050919050565b5f610f8c82610f71565b9050919050565b610f9c81610f82565b82525050565b5f602082019050610fb55f830184610f93565b92915050565b5f60208284031215610fd057610fcf610d99565b5b5f610fdd84828501610de3565b91505092915050565b5f8060408385031215610ffc57610ffb610d99565b5b5f61100985828601610de3565b925050602061101a85828601610de3565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061106857607f821691505b60208210810361107b5761107a611024565b5b50919050565b5f819050815f5260205f209050919050565b5f815461109f81611051565b6110a98186610cf9565b9450600182165f81146110c357600181146110d95761110b565b60ff19831686528115156020028601935061110b565b6110e285611081565b5f5b83811015611103578154818901526001820191506020810190506110e4565b808801955050505b50505092915050565b5f6020820190508181035f83015261112c8184611093565b905092915050565b5f8151905061114281610e00565b92915050565b5f6020828403121561115d5761115c610d99565b5b5f61116a84828501611134565b91505092915050565b61117c81610dbc565b82525050565b5f6040820190506111955f830185611173565b81810360208301526111a78184611093565b90509392505050565b5f6060820190506111c35f830186611173565b6111d06020830185610e9b565b6111dd6040830184610e9b565b949350505050565b5f6020820190506111f85f830184611173565b92915050565b5f6080820190506112115f830187611173565b61121e6020830186611173565b81810360408301526112308185611093565b905061123f6060830184610e9b565b95945050505050565b61125181610e68565b811461125b575f80fd5b50565b5f8151905061126c81611248565b92915050565b5f6020828403121561128757611286610d99565b5b5f6112948482850161125e565b91505092915050565b7f4e6174697665536569546f6b656e7345524332303a207472616e7366657220665f8201527f61696c6564000000000000000000000000000000000000000000000000000000602082015250565b5f6112f7602583610cf9565b91506113028261129d565b604082019050919050565b5f6020820190508181035f830152611324816112eb565b905091905056fea2646970667358221220a53e99f78dc222a4d23fb3791e957fee30742d09501be199c3b0134b6778160564736f6c63430008150033 \ No newline at end of file diff --git a/x/evm/artifacts/native/artifacts.go b/x/evm/artifacts/native/artifacts.go new file mode 100644 index 0000000000..801f66f45d --- /dev/null +++ b/x/evm/artifacts/native/artifacts.go @@ -0,0 +1,80 @@ +package native + +import ( + "bytes" + "embed" + "encoding/hex" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +const CurrentVersion uint16 = 1 + +//go:embed NativeSeiTokensERC20.abi +//go:embed NativeSeiTokensERC20.bin +var f embed.FS + +var cachedBin []byte +var cachedABI *abi.ABI + +func GetABI() []byte { + bz, err := f.ReadFile("NativeSeiTokensERC20.abi") + if err != nil { + panic("failed to read NativeSeiTokensERC20 contract ABI") + } + return bz +} + +func GetParsedABI() *abi.ABI { + if cachedABI != nil { + return cachedABI + } + parsedABI, err := abi.JSON(strings.NewReader(string(GetABI()))) + if err != nil { + panic(err) + } + cachedABI = &parsedABI + return cachedABI +} + +func GetBin() []byte { + if cachedBin != nil { + return cachedBin + } + code, err := f.ReadFile("NativeSeiTokensERC20.bin") + if err != nil { + panic("failed to read NativeSeiTokensERC20 contract binary") + } + bz, err := hex.DecodeString(string(code)) + if err != nil { + panic("failed to decode NativeSeiTokensERC20 contract binary") + } + cachedBin = bz + return bz +} + +func IsCodeFromBin(code []byte) bool { + binLen := len(GetBin()) + if len(code) < binLen { + return false + } + if !bytes.Equal(code[:binLen], GetBin()) { + return false + } + abi, err := NativeMetaData.GetAbi() + if err != nil { + fmt.Printf("error getting metadata ABI: %s\n", err) + return false + } + args, err := abi.Constructor.Inputs.Unpack(code[binLen:]) + if err != nil || len(args) != 4 { + return false + } + _, isString1 := args[0].(string) + _, isString2 := args[1].(string) + _, isString3 := args[2].(string) + _, isUint8 := args[3].(uint8) + return isString1 && isString2 && isString3 && isUint8 +} diff --git a/x/evm/artifacts/native/artifacts_test.go b/x/evm/artifacts/native/artifacts_test.go new file mode 100644 index 0000000000..e023def9b2 --- /dev/null +++ b/x/evm/artifacts/native/artifacts_test.go @@ -0,0 +1,103 @@ +package native_test + +import ( + "encoding/hex" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "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" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestSimple(t *testing.T) { + bytecode := native.GetBin() + abi, err := native.NativeMetaData.GetAbi() + require.Nil(t, err) + args, err := abi.Pack("", "test", "TST", "TST", uint8(6)) + require.Nil(t, err) + contractData := append(bytecode, args...) + + testApp := testkeeper.EVMTestApp + ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + k := &testApp.EvmKeeper + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + txData := ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 20000000, + To: nil, + Value: big.NewInt(0), + Data: contractData, + 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) + + seiAddr, evmAddr := testkeeper.PrivateKeyToAddresses(privKey) + k.SetAddressMapping(ctx, seiAddr, evmAddr) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) + require.Nil(t, k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, seiAddr, amt)) + require.Nil(t, k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, seiAddr, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(200000000))))) + + msgServer := keeper.NewMsgServerImpl(k) + + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) + + receipt, err := k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + require.NotNil(t, receipt) + require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) + k.SetERC20NativePointer(ctx, "test", common.HexToAddress(receipt.ContractAddress)) + _, found := k.GetSeiAddress(ctx, common.HexToAddress(receipt.ContractAddress)) + require.True(t, found) + + // send transaction to the contract + contractAddr := common.HexToAddress(receipt.ContractAddress) + to := common.HexToAddress("0x34b575c2eaae50b81375f077517e6490adbd9735") + k.SetAddressMapping(ctx, sdk.AccAddress(to[:]), to) + data, err := abi.Pack("transfer", to, big.NewInt(1)) + require.Nil(t, err) + txData = ethtypes.LegacyTx{ + GasPrice: big.NewInt(1000000000000), + Gas: 2000000, + To: &contractAddr, + Value: big.NewInt(0), + Data: data, + 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) + ante.Preprocess(ctx, req) + res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Empty(t, res.VmError) +} diff --git a/x/evm/artifacts/native/native.go b/x/evm/artifacts/native/native.go new file mode 100644 index 0000000000..d382e9c8bd --- /dev/null +++ b/x/evm/artifacts/native/native.go @@ -0,0 +1,893 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package native + +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 +) + +// NativeMetaData contains all meta data concerning the Native contract. +var NativeMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"denom_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"name_\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol_\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals_\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"allowance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientAllowance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"ERC20InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"approver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidApprover\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"ERC20InvalidReceiver\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSender\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"ERC20InvalidSpender\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BankPrecompile\",\"outputs\":[{\"internalType\":\"contractIBank\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ddecimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"denom\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nname\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"ssymbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// NativeABI is the input ABI used to generate the binding from. +// Deprecated: Use NativeMetaData.ABI instead. +var NativeABI = NativeMetaData.ABI + +// Native is an auto generated Go binding around an Ethereum contract. +type Native struct { + NativeCaller // Read-only binding to the contract + NativeTransactor // Write-only binding to the contract + NativeFilterer // Log filterer for contract events +} + +// NativeCaller is an auto generated read-only Go binding around an Ethereum contract. +type NativeCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NativeTransactor is an auto generated write-only Go binding around an Ethereum contract. +type NativeTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NativeFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type NativeFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// NativeSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type NativeSession struct { + Contract *Native // 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 +} + +// NativeCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type NativeCallerSession struct { + Contract *NativeCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// NativeTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type NativeTransactorSession struct { + Contract *NativeTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// NativeRaw is an auto generated low-level Go binding around an Ethereum contract. +type NativeRaw struct { + Contract *Native // Generic contract binding to access the raw methods on +} + +// NativeCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type NativeCallerRaw struct { + Contract *NativeCaller // Generic read-only contract binding to access the raw methods on +} + +// NativeTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type NativeTransactorRaw struct { + Contract *NativeTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewNative creates a new instance of Native, bound to a specific deployed contract. +func NewNative(address common.Address, backend bind.ContractBackend) (*Native, error) { + contract, err := bindNative(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &Native{NativeCaller: NativeCaller{contract: contract}, NativeTransactor: NativeTransactor{contract: contract}, NativeFilterer: NativeFilterer{contract: contract}}, nil +} + +// NewNativeCaller creates a new read-only instance of Native, bound to a specific deployed contract. +func NewNativeCaller(address common.Address, caller bind.ContractCaller) (*NativeCaller, error) { + contract, err := bindNative(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &NativeCaller{contract: contract}, nil +} + +// NewNativeTransactor creates a new write-only instance of Native, bound to a specific deployed contract. +func NewNativeTransactor(address common.Address, transactor bind.ContractTransactor) (*NativeTransactor, error) { + contract, err := bindNative(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &NativeTransactor{contract: contract}, nil +} + +// NewNativeFilterer creates a new log filterer instance of Native, bound to a specific deployed contract. +func NewNativeFilterer(address common.Address, filterer bind.ContractFilterer) (*NativeFilterer, error) { + contract, err := bindNative(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &NativeFilterer{contract: contract}, nil +} + +// bindNative binds a generic wrapper to an already deployed contract. +func bindNative(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := NativeMetaData.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 (_Native *NativeRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Native.Contract.NativeCaller.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 (_Native *NativeRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Native.Contract.NativeTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Native *NativeRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Native.Contract.NativeTransactor.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 (_Native *NativeCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _Native.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 (_Native *NativeTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _Native.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_Native *NativeTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _Native.Contract.contract.Transact(opts, method, params...) +} + +// BankPrecompile is a free data retrieval call binding the contract method 0x566732c1. +// +// Solidity: function BankPrecompile() view returns(address) +func (_Native *NativeCaller) BankPrecompile(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _Native.contract.Call(opts, &out, "BankPrecompile") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// BankPrecompile is a free data retrieval call binding the contract method 0x566732c1. +// +// Solidity: function BankPrecompile() view returns(address) +func (_Native *NativeSession) BankPrecompile() (common.Address, error) { + return _Native.Contract.BankPrecompile(&_Native.CallOpts) +} + +// BankPrecompile is a free data retrieval call binding the contract method 0x566732c1. +// +// Solidity: function BankPrecompile() view returns(address) +func (_Native *NativeCallerSession) BankPrecompile() (common.Address, error) { + return _Native.Contract.BankPrecompile(&_Native.CallOpts) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Native *NativeCaller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { + var out []interface{} + err := _Native.contract.Call(opts, &out, "allowance", owner, spender) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Native *NativeSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Native.Contract.Allowance(&_Native.CallOpts, owner, spender) +} + +// Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. +// +// Solidity: function allowance(address owner, address spender) view returns(uint256) +func (_Native *NativeCallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { + return _Native.Contract.Allowance(&_Native.CallOpts, owner, spender) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Native *NativeCaller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { + var out []interface{} + err := _Native.contract.Call(opts, &out, "balanceOf", account) + + 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 account) view returns(uint256) +func (_Native *NativeSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Native.Contract.BalanceOf(&_Native.CallOpts, account) +} + +// BalanceOf is a free data retrieval call binding the contract method 0x70a08231. +// +// Solidity: function balanceOf(address account) view returns(uint256) +func (_Native *NativeCallerSession) BalanceOf(account common.Address) (*big.Int, error) { + return _Native.Contract.BalanceOf(&_Native.CallOpts, account) +} + +// Ddecimals is a free data retrieval call binding the contract method 0xa8ad11e4. +// +// Solidity: function ddecimals() view returns(uint8) +func (_Native *NativeCaller) Ddecimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _Native.contract.Call(opts, &out, "ddecimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Ddecimals is a free data retrieval call binding the contract method 0xa8ad11e4. +// +// Solidity: function ddecimals() view returns(uint8) +func (_Native *NativeSession) Ddecimals() (uint8, error) { + return _Native.Contract.Ddecimals(&_Native.CallOpts) +} + +// Ddecimals is a free data retrieval call binding the contract method 0xa8ad11e4. +// +// Solidity: function ddecimals() view returns(uint8) +func (_Native *NativeCallerSession) Ddecimals() (uint8, error) { + return _Native.Contract.Ddecimals(&_Native.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Native *NativeCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _Native.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Native *NativeSession) Decimals() (uint8, error) { + return _Native.Contract.Decimals(&_Native.CallOpts) +} + +// Decimals is a free data retrieval call binding the contract method 0x313ce567. +// +// Solidity: function decimals() view returns(uint8) +func (_Native *NativeCallerSession) Decimals() (uint8, error) { + return _Native.Contract.Decimals(&_Native.CallOpts) +} + +// Denom is a free data retrieval call binding the contract method 0xc370b042. +// +// Solidity: function denom() view returns(string) +func (_Native *NativeCaller) Denom(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Native.contract.Call(opts, &out, "denom") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Denom is a free data retrieval call binding the contract method 0xc370b042. +// +// Solidity: function denom() view returns(string) +func (_Native *NativeSession) Denom() (string, error) { + return _Native.Contract.Denom(&_Native.CallOpts) +} + +// Denom is a free data retrieval call binding the contract method 0xc370b042. +// +// Solidity: function denom() view returns(string) +func (_Native *NativeCallerSession) Denom() (string, error) { + return _Native.Contract.Denom(&_Native.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Native *NativeCaller) Name(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Native.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 (_Native *NativeSession) Name() (string, error) { + return _Native.Contract.Name(&_Native.CallOpts) +} + +// Name is a free data retrieval call binding the contract method 0x06fdde03. +// +// Solidity: function name() view returns(string) +func (_Native *NativeCallerSession) Name() (string, error) { + return _Native.Contract.Name(&_Native.CallOpts) +} + +// Nname is a free data retrieval call binding the contract method 0x8a0989f5. +// +// Solidity: function nname() view returns(string) +func (_Native *NativeCaller) Nname(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Native.contract.Call(opts, &out, "nname") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Nname is a free data retrieval call binding the contract method 0x8a0989f5. +// +// Solidity: function nname() view returns(string) +func (_Native *NativeSession) Nname() (string, error) { + return _Native.Contract.Nname(&_Native.CallOpts) +} + +// Nname is a free data retrieval call binding the contract method 0x8a0989f5. +// +// Solidity: function nname() view returns(string) +func (_Native *NativeCallerSession) Nname() (string, error) { + return _Native.Contract.Nname(&_Native.CallOpts) +} + +// Ssymbol is a free data retrieval call binding the contract method 0x9e10aa24. +// +// Solidity: function ssymbol() view returns(string) +func (_Native *NativeCaller) Ssymbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Native.contract.Call(opts, &out, "ssymbol") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Ssymbol is a free data retrieval call binding the contract method 0x9e10aa24. +// +// Solidity: function ssymbol() view returns(string) +func (_Native *NativeSession) Ssymbol() (string, error) { + return _Native.Contract.Ssymbol(&_Native.CallOpts) +} + +// Ssymbol is a free data retrieval call binding the contract method 0x9e10aa24. +// +// Solidity: function ssymbol() view returns(string) +func (_Native *NativeCallerSession) Ssymbol() (string, error) { + return _Native.Contract.Ssymbol(&_Native.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Native *NativeCaller) Symbol(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _Native.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 (_Native *NativeSession) Symbol() (string, error) { + return _Native.Contract.Symbol(&_Native.CallOpts) +} + +// Symbol is a free data retrieval call binding the contract method 0x95d89b41. +// +// Solidity: function symbol() view returns(string) +func (_Native *NativeCallerSession) Symbol() (string, error) { + return _Native.Contract.Symbol(&_Native.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Native *NativeCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _Native.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 (_Native *NativeSession) TotalSupply() (*big.Int, error) { + return _Native.Contract.TotalSupply(&_Native.CallOpts) +} + +// TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. +// +// Solidity: function totalSupply() view returns(uint256) +func (_Native *NativeCallerSession) TotalSupply() (*big.Int, error) { + return _Native.Contract.TotalSupply(&_Native.CallOpts) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_Native *NativeTransactor) Approve(opts *bind.TransactOpts, spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Native.contract.Transact(opts, "approve", spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_Native *NativeSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Native.Contract.Approve(&_Native.TransactOpts, spender, value) +} + +// Approve is a paid mutator transaction binding the contract method 0x095ea7b3. +// +// Solidity: function approve(address spender, uint256 value) returns(bool) +func (_Native *NativeTransactorSession) Approve(spender common.Address, value *big.Int) (*types.Transaction, error) { + return _Native.Contract.Approve(&_Native.TransactOpts, spender, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_Native *NativeTransactor) Transfer(opts *bind.TransactOpts, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Native.contract.Transact(opts, "transfer", to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_Native *NativeSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _Native.Contract.Transfer(&_Native.TransactOpts, to, value) +} + +// Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. +// +// Solidity: function transfer(address to, uint256 value) returns(bool) +func (_Native *NativeTransactorSession) Transfer(to common.Address, value *big.Int) (*types.Transaction, error) { + return _Native.Contract.Transfer(&_Native.TransactOpts, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_Native *NativeTransactor) TransferFrom(opts *bind.TransactOpts, from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Native.contract.Transact(opts, "transferFrom", from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_Native *NativeSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Native.Contract.TransferFrom(&_Native.TransactOpts, from, to, value) +} + +// TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. +// +// Solidity: function transferFrom(address from, address to, uint256 value) returns(bool) +func (_Native *NativeTransactorSession) TransferFrom(from common.Address, to common.Address, value *big.Int) (*types.Transaction, error) { + return _Native.Contract.TransferFrom(&_Native.TransactOpts, from, to, value) +} + +// NativeApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Native contract. +type NativeApprovalIterator struct { + Event *NativeApproval // 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 *NativeApprovalIterator) 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(NativeApproval) + 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(NativeApproval) + 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 *NativeApprovalIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NativeApprovalIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NativeApproval represents a Approval event raised by the Native contract. +type NativeApproval struct { + Owner common.Address + Spender common.Address + Value *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 spender, uint256 value) +func (_Native *NativeFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*NativeApprovalIterator, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Native.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) + if err != nil { + return nil, err + } + return &NativeApprovalIterator{contract: _Native.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 spender, uint256 value) +func (_Native *NativeFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *NativeApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) { + + var ownerRule []interface{} + for _, ownerItem := range owner { + ownerRule = append(ownerRule, ownerItem) + } + var spenderRule []interface{} + for _, spenderItem := range spender { + spenderRule = append(spenderRule, spenderItem) + } + + logs, sub, err := _Native.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) + 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(NativeApproval) + if err := _Native.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 spender, uint256 value) +func (_Native *NativeFilterer) ParseApproval(log types.Log) (*NativeApproval, error) { + event := new(NativeApproval) + if err := _Native.contract.UnpackLog(event, "Approval", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// NativeTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Native contract. +type NativeTransferIterator struct { + Event *NativeTransfer // 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 *NativeTransferIterator) 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(NativeTransfer) + 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(NativeTransfer) + 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 *NativeTransferIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *NativeTransferIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// NativeTransfer represents a Transfer event raised by the Native contract. +type NativeTransfer struct { + From common.Address + To common.Address + Value *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 value) +func (_Native *NativeFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*NativeTransferIterator, error) { + + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _Native.contract.FilterLogs(opts, "Transfer", fromRule, toRule) + if err != nil { + return nil, err + } + return &NativeTransferIterator{contract: _Native.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 value) +func (_Native *NativeFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *NativeTransfer, from []common.Address, to []common.Address) (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) + } + + logs, sub, err := _Native.contract.WatchLogs(opts, "Transfer", fromRule, toRule) + 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(NativeTransfer) + if err := _Native.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 value) +func (_Native *NativeFilterer) ParseTransfer(log types.Log) (*NativeTransfer, error) { + event := new(NativeTransfer) + if err := _Native.contract.UnpackLog(event, "Transfer", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/x/evm/artifacts/utils/utils.go b/x/evm/artifacts/utils/utils.go new file mode 100644 index 0000000000..c75eeb8619 --- /dev/null +++ b/x/evm/artifacts/utils/utils.go @@ -0,0 +1,15 @@ +package utils + +import "encoding/binary" + +func GetVersionBz(version uint16) []byte { + res := make([]byte, 2) + binary.BigEndian.PutUint16(res, version) + return res +} + +func GetCodeIDBz(codeID uint64) []byte { + res := make([]byte, 8) + binary.BigEndian.PutUint64(res, codeID) + return res +} diff --git a/x/evm/artifacts/wsei/WSEI.abi b/x/evm/artifacts/wsei/WSEI.abi new file mode 100644 index 0000000000..e8a5861f22 --- /dev/null +++ b/x/evm/artifacts/wsei/WSEI.abi @@ -0,0 +1 @@ +[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guy","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}] \ No newline at end of file diff --git a/x/evm/artifacts/wsei/WSEI.bin b/x/evm/artifacts/wsei/WSEI.bin new file mode 100644 index 0000000000..471d4c80c7 --- /dev/null +++ b/x/evm/artifacts/wsei/WSEI.bin @@ -0,0 +1 @@ +60806040526040518060400160405280600b81526020017f57726170706564205365690000000000000000000000000000000000000000008152505f908162000049919062000323565b506040518060400160405280600481526020017f57534549000000000000000000000000000000000000000000000000000000008152506001908162000090919062000323565b50601260025f6101000a81548160ff021916908360ff160217905550348015620000b8575f80fd5b5062000407565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200013b57607f821691505b602082108103620001515762000150620000f6565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620001b57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000178565b620001c1868362000178565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200020b62000205620001ff84620001d9565b620001e2565b620001d9565b9050919050565b5f819050919050565b6200022683620001eb565b6200023e620002358262000212565b84845462000184565b825550505050565b5f90565b6200025462000246565b620002618184846200021b565b505050565b5b8181101562000288576200027c5f826200024a565b60018101905062000267565b5050565b601f821115620002d757620002a18162000157565b620002ac8462000169565b81016020851015620002bc578190505b620002d4620002cb8562000169565b83018262000266565b50505b505050565b5f82821c905092915050565b5f620002f95f1984600802620002dc565b1980831691505092915050565b5f620003138383620002e8565b9150826002028217905092915050565b6200032e82620000bf565b67ffffffffffffffff8111156200034a5762000349620000c9565b5b62000356825462000123565b620003638282856200028c565b5f60209050601f83116001811462000399575f841562000384578287015190505b62000390858262000306565b865550620003ff565b601f198416620003a98662000157565b5f5b82811015620003d257848901518255600182019150602085019450602081019050620003ab565b86831015620003f25784890151620003ee601f891682620002e8565b8355505b6001600288020188555050505b505050505050565b610e5680620004155f395ff3fe60806040526004361061009f575f3560e01c8063313ce56711610063578063313ce567146101ac57806370a08231146101d657806395d89b4114610212578063a9059cbb1461023c578063d0e30db014610278578063dd62ed3e14610282576100ae565b806306fdde03146100b8578063095ea7b3146100e257806318160ddd1461011e57806323b872dd146101485780632e1a7d4d14610184576100ae565b366100ae576100ac6102be565b005b6100b66102be565b005b3480156100c3575f80fd5b506100cc610361565b6040516100d99190610ace565b60405180910390f35b3480156100ed575f80fd5b5061010860048036038101906101039190610b7f565b6103ec565b6040516101159190610bd7565b60405180910390f35b348015610129575f80fd5b506101326104d9565b60405161013f9190610bff565b60405180910390f35b348015610153575f80fd5b5061016e60048036038101906101699190610c18565b6104e0565b60405161017b9190610bd7565b60405180910390f35b34801561018f575f80fd5b506101aa60048036038101906101a59190610c68565b61082c565b005b3480156101b7575f80fd5b506101c061095d565b6040516101cd9190610cae565b60405180910390f35b3480156101e1575f80fd5b506101fc60048036038101906101f79190610cc7565b61096f565b6040516102099190610bff565b60405180910390f35b34801561021d575f80fd5b50610226610984565b6040516102339190610ace565b60405180910390f35b348015610247575f80fd5b50610262600480360381019061025d9190610b7f565b610a10565b60405161026f9190610bd7565b60405180910390f35b6102806102be565b005b34801561028d575f80fd5b506102a860048036038101906102a39190610cf2565b610a24565b6040516102b59190610bff565b60405180910390f35b3460035f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461030a9190610d5d565b925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c346040516103579190610bff565b60405180910390a2565b5f805461036d90610dbd565b80601f016020809104026020016040519081016040528092919081815260200182805461039990610dbd565b80156103e45780601f106103bb576101008083540402835291602001916103e4565b820191905f5260205f20905b8154815290600101906020018083116103c757829003601f168201915b505050505081565b5f8160045f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516104c79190610bff565b60405180910390a36001905092915050565b5f47905090565b5f8160035f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054101561052a575f80fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141580156105fe57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60045f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205414155b15610716578160045f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541015610687575f80fd5b8160045f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461070e9190610ded565b925050819055505b8160035f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546107629190610ded565b925050819055508160035f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546107b59190610d5d565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516108199190610bff565b60405180910390a3600190509392505050565b8060035f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20541015610875575f80fd5b8060035f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546108c19190610ded565b925050819055503373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f1935050505015801561090b573d5f803e3d5ffd5b503373ffffffffffffffffffffffffffffffffffffffff167f7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65826040516109529190610bff565b60405180910390a250565b60025f9054906101000a900460ff1681565b6003602052805f5260405f205f915090505481565b6001805461099190610dbd565b80601f01602080910402602001604051908101604052809291908181526020018280546109bd90610dbd565b8015610a085780601f106109df57610100808354040283529160200191610a08565b820191905f5260205f20905b8154815290600101906020018083116109eb57829003601f168201915b505050505081565b5f610a1c3384846104e0565b905092915050565b6004602052815f5260405f20602052805f5260405f205f91509150505481565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610a7b578082015181840152602081019050610a60565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610aa082610a44565b610aaa8185610a4e565b9350610aba818560208601610a5e565b610ac381610a86565b840191505092915050565b5f6020820190508181035f830152610ae68184610a96565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610b1b82610af2565b9050919050565b610b2b81610b11565b8114610b35575f80fd5b50565b5f81359050610b4681610b22565b92915050565b5f819050919050565b610b5e81610b4c565b8114610b68575f80fd5b50565b5f81359050610b7981610b55565b92915050565b5f8060408385031215610b9557610b94610aee565b5b5f610ba285828601610b38565b9250506020610bb385828601610b6b565b9150509250929050565b5f8115159050919050565b610bd181610bbd565b82525050565b5f602082019050610bea5f830184610bc8565b92915050565b610bf981610b4c565b82525050565b5f602082019050610c125f830184610bf0565b92915050565b5f805f60608486031215610c2f57610c2e610aee565b5b5f610c3c86828701610b38565b9350506020610c4d86828701610b38565b9250506040610c5e86828701610b6b565b9150509250925092565b5f60208284031215610c7d57610c7c610aee565b5b5f610c8a84828501610b6b565b91505092915050565b5f60ff82169050919050565b610ca881610c93565b82525050565b5f602082019050610cc15f830184610c9f565b92915050565b5f60208284031215610cdc57610cdb610aee565b5b5f610ce984828501610b38565b91505092915050565b5f8060408385031215610d0857610d07610aee565b5b5f610d1585828601610b38565b9250506020610d2685828601610b38565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f610d6782610b4c565b9150610d7283610b4c565b9250828201905080821115610d8a57610d89610d30565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680610dd457607f821691505b602082108103610de757610de6610d90565b5b50919050565b5f610df782610b4c565b9150610e0283610b4c565b9250828203905081811115610e1a57610e19610d30565b5b9291505056fea26469706673582212209760e9f7136a7937f92559eee60462de4e4979de76e9753a09c73876151b049864736f6c63430008150033 \ No newline at end of file diff --git a/x/evm/artifacts/wsei/artifacts.go b/x/evm/artifacts/wsei/artifacts.go new file mode 100644 index 0000000000..fda3b85c48 --- /dev/null +++ b/x/evm/artifacts/wsei/artifacts.go @@ -0,0 +1,54 @@ +package wsei + +import ( + "embed" + "encoding/hex" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" +) + +const CurrentVersion uint16 = 1 + +//go:embed WSEI.abi +//go:embed WSEI.bin +var f embed.FS + +var cachedBin []byte +var cachedABI *abi.ABI + +func GetABI() []byte { + bz, err := f.ReadFile("WSEI.abi") + if err != nil { + panic("failed to read WSEI contract ABI") + } + return bz +} + +func GetParsedABI() *abi.ABI { + if cachedABI != nil { + return cachedABI + } + parsedABI, err := abi.JSON(strings.NewReader(string(GetABI()))) + if err != nil { + panic(err) + } + cachedABI = &parsedABI + return cachedABI +} + +func GetBin() []byte { + if cachedBin != nil { + return cachedBin + } + code, err := f.ReadFile("WSEI.bin") + if err != nil { + panic("failed to read WSEI contract binary") + } + bz, err := hex.DecodeString(string(code)) + if err != nil { + panic("failed to decode WSEI contract binary") + } + cachedBin = bz + return bz +} diff --git a/x/evm/blocktest/config.go b/x/evm/blocktest/config.go new file mode 100644 index 0000000000..96161360f0 --- /dev/null +++ b/x/evm/blocktest/config.go @@ -0,0 +1,37 @@ +package blocktest + +import ( + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/spf13/cast" +) + +type Config struct { + Enabled bool `mapstructure:"eth_blocktest_enabled"` + TestDataPath string `mapstructure:"eth_blocktest_test_data_path"` +} + +var DefaultConfig = Config{ + Enabled: false, + TestDataPath: "~/testdata/", +} + +const ( + flagEnabled = "eth_blocktest.eth_blocktest_enabled" + flagTestDataPath = "eth_blocktest.eth_blocktest_test_data_path" +) + +func ReadConfig(opts servertypes.AppOptions) (Config, error) { + cfg := DefaultConfig // copy + var err error + if v := opts.Get(flagEnabled); v != nil { + if cfg.Enabled, err = cast.ToBoolE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagTestDataPath); v != nil { + if cfg.TestDataPath, err = cast.ToStringE(v); err != nil { + return cfg, err + } + } + return cfg, nil +} diff --git a/x/evm/client/cli/gov_tx.go b/x/evm/client/cli/gov_tx.go new file mode 100644 index 0000000000..40b475768f --- /dev/null +++ b/x/evm/client/cli/gov_tx.go @@ -0,0 +1,175 @@ +package cli + +import ( + "strconv" + "strings" + + "github.com/sei-protocol/sei-chain/x/evm/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/spf13/cobra" +) + +func NewAddERCNativePointerProposalTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "add-erc-native-pointer title description token version deposit [pointer address]", + Args: cobra.RangeArgs(5, 6), + Short: "Submit an add ERC-native pointer proposal", + Long: strings.TrimSpace(` + Submit a proposal to register an ERC pointer contract address for a native token. + Not specifying the pointer address means a proposal that deletes the existing pointer. + `), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + version, err := strconv.ParseUint(args[3], 10, 16) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(args[4]) + if err != nil { + return err + } + var pointer string + if len(args) == 6 { + pointer = args[5] + } + + // Convert proposal to RegisterPairsProposal Type + from := clientCtx.GetFromAddress() + + content := types.AddERCNativePointerProposal{ + Title: args[0], + Description: args[1], + Token: args[2], + Version: uint32(version), + Pointer: pointer, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, from) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func NewAddERCCW20PointerProposalTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "add-erc-cw20-pointer title description cw20address version deposit [pointer address]", + Args: cobra.RangeArgs(5, 6), + Short: "Submit an add ERC-CW20 pointer proposal", + Long: strings.TrimSpace(` + Submit a proposal to register an ERC pointer contract address for a CW20 token. + Not specifying the pointer address means a proposal that deletes the existing pointer. + `), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + version, err := strconv.ParseUint(args[3], 10, 16) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(args[4]) + if err != nil { + return err + } + var pointer string + if len(args) == 6 { + pointer = args[5] + } + + // Convert proposal to RegisterPairsProposal Type + from := clientCtx.GetFromAddress() + + content := types.AddERCCW20PointerProposal{ + Title: args[0], + Description: args[1], + Pointee: args[2], + Version: uint32(version), + Pointer: pointer, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, from) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func NewAddERCCW721PointerProposalTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "add-erc-cw721-pointer title description cw721address version deposit [pointer address]", + Args: cobra.RangeArgs(5, 6), + Short: "Submit an add ERC-CW721 pointer proposal", + Long: strings.TrimSpace(` + Submit a proposal to register an ERC pointer contract address for a CW721 token. + Not specifying the pointer address means a proposal that deletes the existing pointer. + `), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + version, err := strconv.ParseUint(args[3], 10, 16) + if err != nil { + return err + } + deposit, err := sdk.ParseCoinsNormalized(args[4]) + if err != nil { + return err + } + var pointer string + if len(args) == 6 { + pointer = args[5] + } + + // Convert proposal to RegisterPairsProposal Type + from := clientCtx.GetFromAddress() + + content := types.AddERCCW721PointerProposal{ + Title: args[0], + Description: args[1], + Pointee: args[2], + Version: uint32(version), + Pointer: pointer, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, from) + if err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/evm/client/cli/native_tx.go b/x/evm/client/cli/native_tx.go new file mode 100644 index 0000000000..f61d9a5e8a --- /dev/null +++ b/x/evm/client/cli/native_tx.go @@ -0,0 +1,47 @@ +package cli + +import ( + "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/sei-protocol/sei-chain/x/evm/types" + "github.com/spf13/cobra" +) + +func NativeSendTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "native-send [from_key_or_address] [to_evm_address] [amount]", + Short: `Send funds from one account to an EVM address (e.g. 0x....). + Note, the '--from' flag is ignored as it is implied from [from_key_or_address]. + When using '--dry-run' a key name cannot be used, only a bech32 address.`, + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + _ = cmd.Flags().Set(flags.FlagFrom, args[0]) + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + coins, err := sdk.ParseCoinsNormalized(args[2]) + if err != nil { + return err + } + + msg := &types.MsgSend{ + FromAddress: clientCtx.GetFromAddress().String(), + ToAddress: args[1], + Amount: coins, + } + 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 new file mode 100644 index 0000000000..084f4a725c --- /dev/null +++ b/x/evm/client/cli/query.go @@ -0,0 +1,368 @@ +package cli + +import ( + "bytes" + "context" + "encoding/hex" + "errors" + "fmt" + "math/big" + "os" + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +const TrueStr = "true" +const FalseStr = "false" + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd(_ string) *cobra.Command { + // Group epoch queries under a subcommand + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(CmdQuerySeiAddress()) + cmd.AddCommand(CmdQueryEVMAddress()) + cmd.AddCommand(CmdQueryERC20Payload()) + cmd.AddCommand(CmdQueryERC721Payload()) + cmd.AddCommand(CmdQueryERC20()) + cmd.AddCommand(CmdQueryPayload()) + cmd.AddCommand(CmdQueryPointer()) + + return cmd +} + +func CmdQuerySeiAddress() *cobra.Command { + cmd := &cobra.Command{ + Use: "sei-addr", + 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) + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.SeiAddressByEVMAddress(context.Background(), &types.QuerySeiAddressByEVMAddressRequest{EvmAddress: args[0]}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func CmdQueryEVMAddress() *cobra.Command { + cmd := &cobra.Command{ + Use: "evm-addr", + 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) + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.EVMAddressBySeiAddress(context.Background(), &types.QueryEVMAddressBySeiAddressRequest{SeiAddress: args[0]}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func CmdQueryERC20() *cobra.Command { + cmd := &cobra.Command{ + Use: "erc20 [addr] [method] [arguments...]", + Short: "get hex payload for the given inputs", + Args: cobra.MinimumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + queryClient := types.NewQueryClient(clientCtx) + abi, err := native.NativeMetaData.GetAbi() + if err != nil { + return err + } + var bz []byte + switch args[1] { + case "name", "symbol", "decimals", "totalSupply": + bz, err = abi.Pack(args[1]) + case "balanceOf": + acc := common.HexToAddress(args[2]) + bz, err = abi.Pack(args[1], acc) + case "allowance": + owner := common.HexToAddress(args[2]) + spender := common.HexToAddress(args[3]) + bz, err = abi.Pack(args[1], owner, spender) + default: + return errors.New("unknown method") + } + if err != nil { + return err + } + res, err := queryClient.StaticCall(context.Background(), &types.QueryStaticCallRequest{ + To: args[0], + Data: bz, + }) + if err != nil { + return err + } + fields, err := abi.Unpack(args[1], res.Data) + if err != nil { + return err + } + var output string + switch args[1] { + case "name", "symbol": + output = fields[0].(string) + case "decimals": + output = fmt.Sprintf("%d", fields[0].(uint8)) + case "totalSupply", "balanceOf", "allowance": + output = fields[0].(*big.Int).String() + } + + return clientCtx.PrintString(output) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func CmdQueryPayload() *cobra.Command { + cmd := &cobra.Command{ + Use: "payload [abi-filepath] [method] [arguments...]", + Short: "get hex payload for the given inputs", + Args: cobra.MinimumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + dat, err := os.ReadFile(args[0]) + if err != nil { + return err + } + + newAbi, err := abi.JSON(bytes.NewReader(dat)) + if err != nil { + return err + } + method := newAbi.Methods[args[1]] + abiArgs := []interface{}{} + for i, input := range method.Inputs { + idx := i + 2 + if idx >= len(args) { + return errors.New("not enough arguments") + } + var arg interface{} + var err error + switch input.Type.T { + case abi.IntTy: + if input.Type.Size > 64 { + bi, success := new(big.Int).SetString(args[idx], 10) + if !success { + err = errors.New("invalid big.Int") + } else { + arg = bi + } + } else { + val, e := strconv.ParseInt(args[idx], 10, 64) + err = e + switch input.Type.Size { + case 8: + arg = int8(val) + case 16: + arg = int16(val) + case 32: + arg = int32(val) + case 64: + arg = val + } + } + case abi.UintTy: + if input.Type.Size > 64 { + bi, success := new(big.Int).SetString(args[idx], 10) + if !success { + err = errors.New("invalid big.Int") + } else { + arg = bi + } + } else { + val, e := strconv.ParseUint(args[idx], 10, 64) + err = e + switch input.Type.Size { + case 8: + arg = uint8(val) + case 16: + arg = uint16(val) + case 32: + arg = uint32(val) + case 64: + arg = val + } + } + case abi.BoolTy: + if args[idx] != TrueStr && args[idx] != FalseStr { + err = fmt.Errorf("boolean argument has to be either \"%s\" or \"%s\"", TrueStr, FalseStr) + } else { + arg = args[idx] == TrueStr + } + case abi.StringTy: + arg = args[idx] + case abi.AddressTy: + arg = common.HexToAddress(args[idx]) + default: + return errors.New("argument type not supported yet") + } + if err != nil { + return err + } + abiArgs = append(abiArgs, arg) + } + + bz, err := newAbi.Pack(args[1], abiArgs...) + if err != nil { + return err + } + + return clientCtx.PrintString(hex.EncodeToString(bz)) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func CmdQueryERC20Payload() *cobra.Command { + cmd := &cobra.Command{ + Use: "erc20-payload [method] [arguments...]", + Short: "get hex payload for the given inputs", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + abi, err := cw20.Cw20MetaData.GetAbi() + if err != nil { + return err + } + var bz []byte + switch args[0] { + case "transfer": + to := common.HexToAddress(args[1]) + amt, _ := sdk.NewIntFromString(args[2]) + bz, err = abi.Pack(args[0], to, amt.BigInt()) + case "approve": + spender := common.HexToAddress(args[1]) + amt, _ := sdk.NewIntFromString(args[2]) + bz, err = abi.Pack(args[0], spender, amt.BigInt()) + case "transferFrom": + from := common.HexToAddress(args[1]) + to := common.HexToAddress(args[2]) + amt, _ := sdk.NewIntFromString(args[3]) + bz, err = abi.Pack(args[0], from, to, amt.BigInt()) + } + if err != nil { + return err + } + + return clientCtx.PrintString(hex.EncodeToString(bz)) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func CmdQueryERC721Payload() *cobra.Command { + cmd := &cobra.Command{ + Use: "erc721-payload [method] [arguments...]", + Short: "get hex payload for the given inputs", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return err + } + var bz []byte + switch args[0] { + case "approve": + spender := common.HexToAddress(args[1]) + id, _ := sdk.NewIntFromString(args[2]) + bz, err = abi.Pack(args[0], spender, id.BigInt()) + case "transferFrom": + from := common.HexToAddress(args[1]) + to := common.HexToAddress(args[2]) + id, _ := sdk.NewIntFromString(args[3]) + bz, err = abi.Pack(args[0], from, to, id.BigInt()) + case "setApprovalForAll": + op := common.HexToAddress(args[1]) + approved := args[2] == "true" + bz, err = abi.Pack(args[0], op, approved) + } + if err != nil { + return err + } + + return clientCtx.PrintString(hex.EncodeToString(bz)) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func CmdQueryPointer() *cobra.Command { + cmd := &cobra.Command{ + Use: "pointer [type] [pointee]", + Short: "get pointer address of the specified type (one of [NATIVE, CW20, CW721, ERC20, ERC721]) and pointee", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Pointer(context.Background(), &types.QueryPointerRequest{ + PointerType: types.PointerType(types.PointerType_value[args[0]]), Pointee: args[1], + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/evm/client/cli/tx.go b/x/evm/client/cli/tx.go new file mode 100644 index 0000000000..0de934f06b --- /dev/null +++ b/x/evm/client/cli/tx.go @@ -0,0 +1,861 @@ +package cli + +import ( + "context" + "crypto/ecdsa" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io" + "math" + "math/big" + "net/http" + "strconv" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rlp" + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec/legacy" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/sei-protocol/sei-chain/evmrpc" + "github.com/sei-protocol/sei-chain/precompiles/staking" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/wsei" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" +) + +const ( + FlagGasFeeCap = "gas-fee-cap" + FlagGas = "gas-limit" + FlagValue = "value" + FlagRPC = "evm-rpc" + FlagNonce = "nonce" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(CmdAssociateAddress()) + cmd.AddCommand(CmdSend()) + cmd.AddCommand(CmdDeployErc20()) + cmd.AddCommand(CmdDeployErcCw20()) + cmd.AddCommand(CmdCallContract()) + cmd.AddCommand(CmdDeployErcCw721()) + cmd.AddCommand(CmdDeployWSEI()) + cmd.AddCommand(CmdERC20Send()) + cmd.AddCommand(CmdDelegate()) + cmd.AddCommand(NativeSendTxCmd()) + cmd.AddCommand(NewAddERCNativePointerProposalTxCmd()) + cmd.AddCommand(NewAddERCCW20PointerProposalTxCmd()) + cmd.AddCommand(NewAddERCCW721PointerProposalTxCmd()) + + return cmd +} + +func CmdAssociateAddress() *cobra.Command { + cmd := &cobra.Command{ + Use: "associate-address [optional priv key hex] --rpc= --from=", + Short: "associate EVM and Sei address for the sender", + Long: "", + Args: cobra.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + var privHex string + if len(args) == 1 { + privHex = args[0] + } else { + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + kb := txf.Keybase() + info, err := kb.Key(clientCtx.GetFromName()) + if err != nil { + return err + } + localInfo, ok := info.(keyring.LocalInfo) + if !ok { + return errors.New("can only associate address for local keys") + } + priv, err := legacy.PrivKeyFromBytes([]byte(localInfo.PrivKeyArmor)) + if err != nil { + return err + } + privHex = hex.EncodeToString(priv.Bytes()) + } + + emptyHash := crypto.Keccak256Hash([]byte{}) + key, err := crypto.HexToECDSA(privHex) + if err != nil { + return err + } + sig, err := crypto.Sign(emptyHash[:], key) + if err != nil { + return err + } + R, S, _, err := ethtx.DecodeSignature(sig) + if err != nil { + return err + } + V := big.NewInt(int64(sig[64])) + txData := evmrpc.AssociateRequest{V: hex.EncodeToString(V.Bytes()), R: hex.EncodeToString(R.Bytes()), S: hex.EncodeToString(S.Bytes())} + bz, err := json.Marshal(txData) + if err != nil { + return err + } + body := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"sei_associate\",\"params\":[%s],\"id\":\"associate_addr\"}", string(bz)) + rpc, err := cmd.Flags().GetString(FlagRPC) + if err != nil { + return err + } + req, err := http.NewRequest(http.MethodGet, rpc, strings.NewReader(body)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + resBody, err := io.ReadAll(res.Body) + if err != nil { + return err + } + fmt.Printf("Response: %s\n", string(resBody)) + + return nil + }, + } + + cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func CmdSend() *cobra.Command { + cmd := &cobra.Command{ + Use: "send [to EVM address] [amount in wei] --from= --gas-fee-cap= --gas-limit= --evm-rpc=", + Short: "send usei to EVM address", + Long: "", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) (err error) { + key, err := getPrivateKey(cmd) + if err != nil { + return err + } + + rpc, err := cmd.Flags().GetString(FlagRPC) + if err != nil { + return err + } + var nonce uint64 + if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { + nonce = uint64(n) + } else { + nonce, err = getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + } + + to := common.HexToAddress(args[0]) + val, success := new(big.Int).SetString(args[1], 10) + if !success { + return fmt.Errorf("%s is an invalid amount to send", args[1]) + } + txData, err := getTxData(cmd) + if err != nil { + return err + } + txData.Nonce = nonce + txData.Value = val + txData.Data = []byte("") + txData.To = &to + 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, 21000, "Gas limit for the transaction") + cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +type Response struct { + Jsonrpc string `json:"jsonrpc"` + ID string `json:"id"` + Result string `json:"result"` +} + +func CmdDeployErc20() *cobra.Command { + cmd := &cobra.Command{ + Use: "deploy-erc20 [denom] [name] [symbol] [decimal] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Short: "Deploy ERC20 contract for a native Sei token", + Long: "", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) (err error) { + err = sdk.ValidateDenom(args[0]) + if err != nil { + return err + } + denom := args[0] + name := args[1] + symbol := args[2] + decimal, err := strconv.ParseUint(args[3], 10, 64) + if err != nil { + return err + } + if decimal > math.MaxUint8 { + return fmt.Errorf("decimal cannot be larger than %d", math.MaxUint8) + } + + bytecode := native.GetBin() + constructorArguments := []interface{}{ + denom, name, symbol, uint8(decimal), + } + + packedArgs, err := native.GetParsedABI().Pack("", constructorArguments...) + if err != nil { + return err + } + contractData := append(bytecode, packedArgs...) + + key, err := getPrivateKey(cmd) + if err != nil { + return err + } + + rpc, err := cmd.Flags().GetString(FlagRPC) + if err != nil { + return err + } + var nonce uint64 + if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { + nonce = uint64(n) + } else { + nonce, err = getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + } + + txData, err := getTxData(cmd) + if err != nil { + return err + } + txData.Nonce = nonce + txData.Value = utils.Big0 + txData.Data = contractData + + resp, err := sendTx(txData, rpc, key) + if err != nil { + return err + } + + senderAddr := crypto.PubkeyToAddress(key.PublicKey) + data, err := rlp.EncodeToBytes([]interface{}{senderAddr, nonce}) + if err != nil { + return err + } + hash := crypto.Keccak256Hash(data) + contractAddress := hash.Bytes()[12:] + contractAddressHex := hex.EncodeToString(contractAddress) + + fmt.Println("Deployer:", senderAddr) + fmt.Println("Deployed to:", fmt.Sprintf("0x%s", contractAddressHex)) + fmt.Println("Transaction hash:", resp.Hex()) + return nil + }, + } + + cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") + cmd.Flags().Uint64(FlagGas, 5000000, "Gas limit for the transaction") + cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func CmdDeployErcCw20() *cobra.Command { + cmd := &cobra.Command{ + Use: "deploy-erccw20 [cw20addr] [name] [symbol] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Short: "Deploy ERC20 contract for a CW20 token", + Long: "", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) (err error) { + _, err = sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + bytecode := cw20.GetBin() + constructorArguments := []interface{}{ + args[0], args[1], args[2], + } + + packedArgs, err := cw20.GetParsedABI().Pack("", constructorArguments...) + if err != nil { + return err + } + contractData := append(bytecode, packedArgs...) + + key, err := getPrivateKey(cmd) + if err != nil { + return err + } + + rpc, err := cmd.Flags().GetString(FlagRPC) + if err != nil { + return err + } + var nonce uint64 + if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { + nonce = uint64(n) + } else { + nonce, err = getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + } + + txData, err := getTxData(cmd) + if err != nil { + return err + } + txData.Nonce = nonce + txData.Value = utils.Big0 + txData.Data = contractData + + resp, err := sendTx(txData, rpc, key) + if err != nil { + return err + } + + senderAddr := crypto.PubkeyToAddress(key.PublicKey) + data, err := rlp.EncodeToBytes([]interface{}{senderAddr, nonce}) + if err != nil { + return err + } + hash := crypto.Keccak256Hash(data) + contractAddress := hash.Bytes()[12:] + contractAddressHex := hex.EncodeToString(contractAddress) + + fmt.Println("Deployer:", senderAddr) + fmt.Println("Deployed to:", fmt.Sprintf("0x%s", contractAddressHex)) + fmt.Println("Transaction hash:", resp.Hex()) + return nil + }, + } + + cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") + cmd.Flags().Uint64(FlagGas, 7000000, "Gas limit for the transaction") + cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func CmdDeployErcCw721() *cobra.Command { + cmd := &cobra.Command{ + Use: "deploy-erccw721 [cw721addr] [name] [symbol] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Short: "Deploy ERC721 contract for a CW20 token", + Long: "", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) (err error) { + _, err = sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + bytecode := cw721.GetBin() + constructorArguments := []interface{}{ + args[0], args[1], args[2], + } + + packedArgs, err := cw721.GetParsedABI().Pack("", constructorArguments...) + if err != nil { + return err + } + contractData := append(bytecode, packedArgs...) + + key, err := getPrivateKey(cmd) + if err != nil { + return err + } + + rpc, err := cmd.Flags().GetString(FlagRPC) + if err != nil { + return err + } + var nonce uint64 + if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { + nonce = uint64(n) + } else { + nonce, err = getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + } + + txData, err := getTxData(cmd) + if err != nil { + return err + } + txData.Nonce = nonce + txData.Value = utils.Big0 + txData.Data = contractData + + resp, err := sendTx(txData, rpc, key) + if err != nil { + return err + } + + senderAddr := crypto.PubkeyToAddress(key.PublicKey) + data, err := rlp.EncodeToBytes([]interface{}{senderAddr, nonce}) + if err != nil { + return err + } + hash := crypto.Keccak256Hash(data) + contractAddress := hash.Bytes()[12:] + contractAddressHex := hex.EncodeToString(contractAddress) + + fmt.Println("Deployer:", senderAddr) + fmt.Println("Deployed to:", fmt.Sprintf("0x%s", contractAddressHex)) + fmt.Println("Transaction hash:", resp.Hex()) + return nil + }, + } + + cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") + cmd.Flags().Uint64(FlagGas, 7000000, "Gas limit for the transaction") + cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func CmdCallContract() *cobra.Command { + cmd := &cobra.Command{ + Use: "call-contract [addr] [payload hex] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Short: "Call EVM contract with a bytes payload in hex", + Long: "", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) (err error) { + contract := common.HexToAddress(args[0]) + payload, err := hex.DecodeString(args[1]) + 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 + } + var nonce uint64 + if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { + nonce = uint64(n) + } else { + nonce, err = getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + } + + value, err := cmd.Flags().GetUint64(FlagValue) + if err != nil { + return err + } + + txData, err := getTxData(cmd) + if err != nil { + return err + } + txData.Nonce = nonce + txData.Value = big.NewInt(int64(value)) + txData.Data = payload + txData.To = &contract + + 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().Uint64(FlagValue, 0, "Value for the transaction") + cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func CmdERC20Send() *cobra.Command { + cmd := &cobra.Command{ + Use: "erc20-send [addr] [recipient] [amount] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Short: "send recipient (in smallest unit) ERC20 tokens", + Long: "", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) (err error) { + contract := common.HexToAddress(args[0]) + recipient := common.HexToAddress(args[1]) + amt, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return err + } + abi, err := native.NativeMetaData.GetAbi() + if err != nil { + return err + } + payload, err := abi.Pack("transfer", recipient, new(big.Int).SetUint64(amt)) + 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 + } + var nonce uint64 + if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { + nonce = uint64(n) + } else { + nonce, err = getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + } + + txData, err := getTxData(cmd) + if err != nil { + return err + } + txData.Nonce = nonce + txData.Value = utils.Big0 + txData.Data = payload + txData.To = &contract + + 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(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func CmdDelegate() *cobra.Command { + cmd := &cobra.Command{ + Use: "delegate [val-addr] [amount] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Short: "delegate recipient usei", + Long: "", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) (err error) { + amt, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return err + } + abi := staking.GetABI() + payload, err := abi.Pack("delegate", args[0], new(big.Int).SetUint64(amt)) + 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 + } + var nonce uint64 + if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { + nonce = uint64(n) + } else { + nonce, err = getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + } + + txData, err := getTxData(cmd) + if err != nil { + return err + } + txData.Nonce = nonce + txData.Value = utils.Big0 + txData.Data = payload + to := common.HexToAddress(staking.StakingAddress) + txData.To = &to + + 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(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func CmdDeployWSEI() *cobra.Command { + cmd := &cobra.Command{ + Use: "deploy-wsei --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Short: "Deploy ERC20 contract for a native Sei token", + Long: "", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) (err error) { + contractData := wsei.GetBin() + + key, err := getPrivateKey(cmd) + if err != nil { + return err + } + + rpc, err := cmd.Flags().GetString(FlagRPC) + if err != nil { + return err + } + var nonce uint64 + if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { + nonce = uint64(n) + } else { + nonce, err = getNonce(rpc, key.PublicKey) + if err != nil { + return err + } + } + + txData, err := getTxData(cmd) + if err != nil { + return err + } + txData.Nonce = nonce + txData.Value = utils.Big0 + txData.Data = contractData + + resp, err := sendTx(txData, rpc, key) + if err != nil { + return err + } + + senderAddr := crypto.PubkeyToAddress(key.PublicKey) + data, err := rlp.EncodeToBytes([]interface{}{senderAddr, nonce}) + if err != nil { + return err + } + hash := crypto.Keccak256Hash(data) + contractAddress := hash.Bytes()[12:] + contractAddressHex := hex.EncodeToString(contractAddress) + + fmt.Println("Deployer:", senderAddr) + fmt.Println("Deployed to:", fmt.Sprintf("0x%s", contractAddressHex)) + fmt.Println("Transaction hash:", resp.Hex()) + return nil + }, + } + + cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") + cmd.Flags().Uint64(FlagGas, 5000000, "Gas limit for the transaction") + cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") + cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func getPrivateKey(cmd *cobra.Command) (*ecdsa.PrivateKey, error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return nil, err + } + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + kb := txf.Keybase() + info, err := kb.Key(clientCtx.GetFromName()) + if err != nil { + return nil, err + } + localInfo, ok := info.(keyring.LocalInfo) + if !ok { + return nil, errors.New("can only associate address for local keys") + } + priv, err := legacy.PrivKeyFromBytes([]byte(localInfo.PrivKeyArmor)) + if err != nil { + return nil, err + } + privHex := hex.EncodeToString(priv.Bytes()) + key, _ := crypto.HexToECDSA(privHex) + return key, nil +} + +func getNonce(rpc string, key ecdsa.PublicKey) (uint64, error) { + nonceQuery := fmt.Sprintf("{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionCount\",\"params\":[\"%s\",\"pending\"],\"id\":\"send-cli\"}", crypto.PubkeyToAddress(key).Hex()) + req, err := http.NewRequest(http.MethodGet, rpc, strings.NewReader(nonceQuery)) + if err != nil { + return 0, err + } + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + if err != nil { + return 0, err + } + defer res.Body.Close() + resBody, err := io.ReadAll(res.Body) + if err != nil { + return 0, err + } + resObj := map[string]interface{}{} + if err := json.Unmarshal(resBody, &resObj); err != nil { + return 0, err + } + nonce := new(hexutil.Uint64) + if err := nonce.UnmarshalText([]byte(resObj["result"].(string))); err != nil { + return 0, err + } + return uint64(*nonce), nil +} + +func getChainId(rpc string) (*big.Int, error) { + q := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_chainId\",\"params\":[],\"id\":\"send-cli\"}" + req, err := http.NewRequest(http.MethodGet, rpc, strings.NewReader(q)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + resBody, err := io.ReadAll(res.Body) + if err != nil { + return nil, err + } + resObj := map[string]interface{}{} + if err := json.Unmarshal(resBody, &resObj); err != nil { + return nil, err + } + chainId := new(hexutil.Big) + if err := chainId.UnmarshalText([]byte(resObj["result"].(string))); err != nil { + return nil, err + } + return chainId.ToInt(), nil +} + +func getTxData(cmd *cobra.Command) (*ethtypes.DynamicFeeTx, error) { + gasFeeCap, err := cmd.Flags().GetUint64(FlagGasFeeCap) + if err != nil { + return nil, err + } + gasLimit, err := cmd.Flags().GetUint64(FlagGas) + if err != nil { + return nil, err + } + rpc, err := cmd.Flags().GetString(FlagRPC) + if err != nil { + return nil, err + } + chainID, err := getChainId(rpc) + if err != nil { + return nil, err + } + return ðtypes.DynamicFeeTx{ + GasFeeCap: new(big.Int).SetUint64(gasFeeCap), + GasTipCap: new(big.Int).SetUint64(gasFeeCap), + Gas: gasLimit, + ChainID: chainID, + }, nil +} + +func sendTx(txData *ethtypes.DynamicFeeTx, rpcUrl string, key *ecdsa.PrivateKey) (common.Hash, error) { + ethCfg := types.DefaultChainConfig().EthereumConfig(txData.ChainID) + signer := ethtypes.MakeSigner(ethCfg, utils.Big1, 1) + signedTx, err := ethtypes.SignTx(ethtypes.NewTx(txData), signer, key) + if err != nil { + return common.Hash{}, err + } + + ethClient, err := ethclient.Dial(rpcUrl) + if err != nil { + return common.Hash{}, err + } + + if err := ethClient.SendTransaction(context.Background(), signedTx); err != nil { + return common.Hash{}, err + } + + return signedTx.Hash(), nil +} diff --git a/x/evm/client/wasm/bindings/queries.go b/x/evm/client/wasm/bindings/queries.go new file mode 100644 index 0000000000..15818b5947 --- /dev/null +++ b/x/evm/client/wasm/bindings/queries.go @@ -0,0 +1,167 @@ +package bindings + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type SeiEVMQuery struct { + StaticCall *StaticCallRequest `json:"static_call,omitempty"` + ERC20TransferPayload *ERC20TransferPayloadRequest `json:"erc20_transfer_payload,omitempty"` + ERC20TransferFromPayload *ERC20TransferFromPayloadRequest `json:"erc20_transfer_from_payload,omitempty"` + ERC20ApprovePayload *ERC20ApprovePayloadRequest `json:"erc20_approve_payload,omitempty"` + ERC20Allowance *ERC20AllowanceRequest `json:"erc20_allowance,omitempty"` + ERC20TokenInfo *ERC20TokenInfoRequest `json:"erc20_token_info,omitempty"` + ERC20Balance *ERC20BalanceRequest `json:"erc20_balance,omitempty"` + ERC721Owner *ERC721OwnerRequest `json:"erc721_owner,omitempty"` + ERC721TransferPayload *ERC721TransferPayloadRequest `json:"erc721_transfer_payload,omitempty"` + ERC721ApprovePayload *ERC721ApprovePayloadRequest `json:"erc721_approve_payload,omitempty"` + ERC721SetApprovalAllPayload *ERC721SetApprovalAllPayloadRequest `json:"erc721_set_approval_all_payload,omitempty"` + ERC721Approved *ERC721ApprovedRequest `json:"erc721_approved,omitempty"` + ERC721IsApprovedForAll *ERC721IsApprovedForAllRequest `json:"erc721_is_approved_for_all,omitempty"` + ERC721NameSymbol *ERC721NameSymbolRequest `json:"erc721_name_symbol,omitempty"` + ERC721Uri *ERC721UriRequest `json:"erc721_uri,omitempty"` + GetEvmAddress *GetEvmAddressRequest `json:"get_evm_address,omitempty"` + GetSeiAddress *GetSeiAddressRequest `json:"get_sei_address,omitempty"` +} + +type StaticCallRequest struct { + From string `json:"from"` + To string `json:"to"` + Data []byte `json:"data"` +} + +type ERC20TransferPayloadRequest struct { + Recipient string `json:"recipient"` + Amount *sdk.Int `json:"amount"` +} + +type ERC20TransferFromPayloadRequest struct { + Owner string `json:"owner"` + Recipient string `json:"recipient"` + Amount *sdk.Int `json:"amount"` +} + +type ERC20ApprovePayloadRequest struct { + Spender string `json:"spender"` + Amount *sdk.Int `json:"amount"` +} + +type ERC20AllowanceRequest struct { + ContractAddress string `json:"contract_address"` + Owner string `json:"owner"` + Spender string `json:"spender"` +} + +type ERC20TokenInfoRequest struct { + ContractAddress string `json:"contract_address"` + Caller string `json:"caller"` +} + +type ERC20BalanceRequest struct { + ContractAddress string `json:"contract_address"` + Account string `json:"account"` +} + +type ERC721OwnerRequest struct { + Caller string `json:"caller"` + ContractAddress string `json:"contract_address"` + TokenID string `json:"token_id"` +} + +type ERC721TransferPayloadRequest struct { + From string `json:"from"` + Recipient string `json:"recipient"` + TokenID string `json:"token_id"` +} + +type ERC721ApprovePayloadRequest struct { + Spender string `json:"spender"` + TokenID string `json:"token_id"` +} + +type ERC721SetApprovalAllPayloadRequest struct { + To string `json:"to"` + Approved bool `json:"approved"` +} + +type ERC721ApprovedRequest struct { + Caller string `json:"caller"` + ContractAddress string `json:"contract_address"` + TokenID string `json:"token_id"` +} + +type ERC721IsApprovedForAllRequest struct { + Caller string `json:"caller"` + ContractAddress string `json:"contract_address"` + Owner string `json:"owner"` + Operator string `json:"operator"` +} + +type ERC721NameSymbolRequest struct { + Caller string `json:"caller"` + ContractAddress string `json:"contract_address"` +} + +type ERC721UriRequest struct { + Caller string `json:"caller"` + ContractAddress string `json:"contract_address"` + TokenID string `json:"token_id"` +} + +type GetEvmAddressRequest struct { + SeiAddress string `json:"sei_address"` +} + +type GetSeiAddressRequest struct { + EvmAddress string `json:"evm_address"` +} + +type ERCPayloadResponse struct { + EncodedPayload string `json:"encoded_payload"` +} + +type ERC20AllowanceResponse struct { + Allowance *sdk.Int `json:"allowance"` +} + +type ERC721OwnerResponse struct { + Owner string `json:"owner"` +} + +type ERC20TokenInfoResponse struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals byte `json:"decimals"` + TotalSupply *sdk.Int `json:"total_supply"` +} + +type ERC20BalanceResponse struct { + Balance *sdk.Int `json:"balance"` +} + +type ERC721ApprovedResponse struct { + Approved string `json:"approved"` +} + +type ERC721IsApprovedForAllResponse struct { + IsApproved bool `json:"is_approved"` +} + +type ERC721NameSymbolResponse struct { + Name string `json:"name"` + Symbol string `json:"symbol"` +} + +type ERC721UriResponse struct { + Uri string `json:"uri"` +} + +type GetEvmAddressResponse struct { + EvmAddress string `json:"evm_address"` + Associated bool `json:"associated"` +} + +type GetSeiAddressResponse struct { + SeiAddress string `json:"sei_address"` + Associated bool `json:"associated"` +} diff --git a/x/evm/client/wasm/encoder.go b/x/evm/client/wasm/encoder.go new file mode 100644 index 0000000000..3d1015447c --- /dev/null +++ b/x/evm/client/wasm/encoder.go @@ -0,0 +1,53 @@ +package wasm + +import ( + "encoding/base64" + "encoding/json" + + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/wasmbinding/bindings" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func EncodeCallEVM(rawMsg json.RawMessage, sender sdk.AccAddress, info wasmvmtypes.MessageInfo) ([]sdk.Msg, error) { + encodedCallEVM := bindings.CallEVM{} + if err := json.Unmarshal(rawMsg, &encodedCallEVM); err != nil { + return []sdk.Msg{}, err + } + decodedData, err := base64.StdEncoding.DecodeString(encodedCallEVM.Data) + if err != nil { + return []sdk.Msg{}, err + } + internalCallEVMMsg := types.MsgInternalEVMCall{ + Sender: sender.String(), + To: encodedCallEVM.To, + Value: encodedCallEVM.Value, + Data: decodedData, + } + return []sdk.Msg{&internalCallEVMMsg}, nil +} + +func EncodeDelegateCallEVM(rawMsg json.RawMessage, sender sdk.AccAddress, info wasmvmtypes.MessageInfo, codeInfo wasmtypes.CodeInfo) ([]sdk.Msg, error) { + encodedCallEVM := bindings.DelegateCallEVM{} + if err := json.Unmarshal(rawMsg, &encodedCallEVM); err != nil { + return []sdk.Msg{}, err + } + decodedData, err := base64.StdEncoding.DecodeString(encodedCallEVM.Data) + if err != nil { + return []sdk.Msg{}, err + } + s := sender + if origSender, err := sdk.AccAddressFromBech32(info.Sender); err == nil { + s = origSender + } + internalCallEVMMsg := types.MsgInternalEVMDelegateCall{ + Sender: s.String(), + To: encodedCallEVM.To, + CodeHash: codeInfo.CodeHash, + Data: decodedData, + FromContract: sender.String(), + } + return []sdk.Msg{&internalCallEVMMsg}, nil +} diff --git a/x/evm/client/wasm/query.go b/x/evm/client/wasm/query.go new file mode 100644 index 0000000000..e823345996 --- /dev/null +++ b/x/evm/client/wasm/query.go @@ -0,0 +1,500 @@ +package wasm + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "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/client/wasm/bindings" + "github.com/sei-protocol/sei-chain/x/evm/keeper" +) + +type EVMQueryHandler struct { + k *keeper.Keeper +} + +func NewEVMQueryHandler(k *keeper.Keeper) *EVMQueryHandler { + return &EVMQueryHandler{k: k} +} + +func (h *EVMQueryHandler) HandleStaticCall(ctx sdk.Context, from string, to string, data []byte) ([]byte, error) { + fromAddr, err := sdk.AccAddressFromBech32(from) + if err != nil { + return nil, err + } + var toAddr *common.Address + if to != "" { + toSeiAddr := common.HexToAddress(to) + toAddr = &toSeiAddr + } + return h.k.StaticCallEVM(ctx, fromAddr, toAddr, data) +} + +func (h *EVMQueryHandler) HandleERC20TransferPayload(ctx sdk.Context, recipient string, amount *sdk.Int) ([]byte, error) { + abi, err := native.NativeMetaData.GetAbi() + if err != nil { + return nil, err + } + evmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(recipient)) + if !found { + return nil, fmt.Errorf("%s is not associated", recipient) + } + bz, err := abi.Pack("transfer", evmAddr, amount.BigInt()) + if err != nil { + return nil, err + } + res := bindings.ERCPayloadResponse{EncodedPayload: base64.StdEncoding.EncodeToString(bz)} + return json.Marshal(res) +} + +func (h *EVMQueryHandler) HandleERC20TokenInfo(ctx sdk.Context, contractAddress string, caller string) ([]byte, error) { + callerAddr, err := sdk.AccAddressFromBech32(caller) + if err != nil { + return nil, err + } + contract := common.HexToAddress(contractAddress) + abi, err := native.NativeMetaData.GetAbi() + if err != nil { + return nil, err + } + response := bindings.ERC20TokenInfoResponse{} + + 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 + } + unpacked, err := abi.Unpack("totalSupply", res) + if err != nil { + return nil, err + } + totalSupply := sdk.NewIntFromBigInt(unpacked[0].(*big.Int)) + response.TotalSupply = &totalSupply + + bz, err = abi.Pack("name") + if err != nil { + return nil, err + } + res, err = h.k.StaticCallEVM(ctx, callerAddr, &contract, bz) + if err != nil { + return nil, err + } + unpacked, err = abi.Unpack("name", res) + if err != nil { + return nil, err + } + response.Name = unpacked[0].(string) + + bz, err = abi.Pack("symbol") + if err != nil { + return nil, err + } + res, err = h.k.StaticCallEVM(ctx, callerAddr, &contract, bz) + if err != nil { + return nil, err + } + unpacked, err = abi.Unpack("symbol", res) + if err != nil { + return nil, err + } + response.Symbol = unpacked[0].(string) + + bz, err = abi.Pack("decimals") + if err != nil { + return nil, err + } + res, err = h.k.StaticCallEVM(ctx, callerAddr, &contract, bz) + if err != nil { + return nil, err + } + unpacked, err = abi.Unpack("decimals", res) + if err != nil { + return nil, err + } + response.Decimals = unpacked[0].(byte) + + return json.Marshal(response) +} + +func (h *EVMQueryHandler) HandleERC20Balance(ctx sdk.Context, contractAddress string, account string) ([]byte, error) { + addr, err := sdk.AccAddressFromBech32(account) + if err != nil { + return nil, err + } + evmAddr, found := h.k.GetEVMAddress(ctx, addr) + if !found { + return nil, fmt.Errorf("address %s is not associated", addr.String()) + } + contract := common.HexToAddress(contractAddress) + abi, err := native.NativeMetaData.GetAbi() + if err != nil { + return nil, err + } + + bz, err := abi.Pack("balanceOf", evmAddr) + if err != nil { + return nil, err + } + res, err := h.k.StaticCallEVM(ctx, addr, &contract, bz) + if err != nil { + return nil, err + } + unpacked, err := abi.Unpack("balanceOf", res) + if err != nil { + return nil, err + } + balance := sdk.NewIntFromBigInt(unpacked[0].(*big.Int)) + return json.Marshal(bindings.ERC20BalanceResponse{Balance: &balance}) +} + +func (h *EVMQueryHandler) HandleERC721Owner(ctx sdk.Context, caller string, contractAddress string, tokenId 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 + } + t, ok := sdk.NewIntFromString(tokenId) + if !ok { + return nil, errors.New("invalid token ID for ERC20, must be a big Int") + } + bz, err := abi.Pack("ownerOf", t.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("ownerOf", res) + if err != nil { + return nil, err + } + typedOwner := typed[0].(common.Address) + owner := "" + if (typedOwner != common.Address{}) { + owner = h.k.GetSeiAddressOrDefault(ctx, typedOwner).String() + } + response := bindings.ERC721OwnerResponse{Owner: owner} + return json.Marshal(response) +} + +func (h *EVMQueryHandler) HandleERC721TransferPayload(ctx sdk.Context, from string, recipient string, tokenId string) ([]byte, error) { + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return nil, err + } + fromEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(from)) + if !found { + return nil, fmt.Errorf("%s is not associated", from) + } + toEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(recipient)) + if !found { + return nil, fmt.Errorf("%s is not associated", recipient) + } + t, ok := sdk.NewIntFromString(tokenId) + if !ok { + return nil, errors.New("invalid token ID for ERC20, must be a big Int") + } + bz, err := abi.Pack("transferFrom", fromEvmAddr, toEvmAddr, t.BigInt()) + if err != nil { + return nil, err + } + res := bindings.ERCPayloadResponse{EncodedPayload: base64.StdEncoding.EncodeToString(bz)} + return json.Marshal(res) +} + +func (h *EVMQueryHandler) HandleERC721ApprovePayload(ctx sdk.Context, spender string, tokenId string) ([]byte, error) { + spenderEvmAddr := common.Address{} // empty address if approval should be revoked (i.e. spender string is empty) + var err error + if spender != "" { + evmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(spender)) + if !found { + return nil, fmt.Errorf("%s is not associated", spender) + } + spenderEvmAddr = evmAddr + } + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return nil, err + } + t, ok := sdk.NewIntFromString(tokenId) + if !ok { + return nil, errors.New("invalid token ID for ERC20, must be a big Int") + } + bz, err := abi.Pack("approve", spenderEvmAddr, t.BigInt()) + if err != nil { + return nil, err + } + res := bindings.ERCPayloadResponse{EncodedPayload: base64.StdEncoding.EncodeToString(bz)} + return json.Marshal(res) +} + +func (h *EVMQueryHandler) HandleERC721SetApprovalAllPayload(ctx sdk.Context, to string, approved bool) ([]byte, error) { + evmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(to)) + if !found { + return nil, fmt.Errorf("%s is not associated", to) + } + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return nil, err + } + bz, err := abi.Pack("setApprovalForAll", evmAddr, approved) + if err != nil { + return nil, err + } + res := bindings.ERCPayloadResponse{EncodedPayload: base64.StdEncoding.EncodeToString(bz)} + return json.Marshal(res) +} + +func (h *EVMQueryHandler) HandleERC20TransferFromPayload(ctx sdk.Context, owner string, recipient string, amount *sdk.Int) ([]byte, error) { + abi, err := native.NativeMetaData.GetAbi() + if err != nil { + return nil, err + } + ownerEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(owner)) + if !found { + return nil, fmt.Errorf("%s is not associated", owner) + } + recipientEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(recipient)) + if !found { + return nil, fmt.Errorf("%s is not associated", recipient) + } + bz, err := abi.Pack("transferFrom", ownerEvmAddr, recipientEvmAddr, amount.BigInt()) + if err != nil { + return nil, err + } + res := bindings.ERCPayloadResponse{EncodedPayload: base64.StdEncoding.EncodeToString(bz)} + return json.Marshal(res) +} + +func (h *EVMQueryHandler) HandleERC20ApprovePayload(ctx sdk.Context, spender string, amount *sdk.Int) ([]byte, error) { + abi, err := native.NativeMetaData.GetAbi() + if err != nil { + return nil, err + } + spenderEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(spender)) + if !found { + return nil, fmt.Errorf("%s is not associated", spender) + } + + bz, err := abi.Pack("approve", spenderEvmAddr, amount.BigInt()) + if err != nil { + return nil, err + } + res := bindings.ERCPayloadResponse{EncodedPayload: base64.StdEncoding.EncodeToString(bz)} + return json.Marshal(res) +} + +func (h *EVMQueryHandler) HandleERC20Allowance(ctx sdk.Context, contractAddress string, owner string, spender string) ([]byte, error) { + // Get the evm address of the owner + ownerAddr, err := sdk.AccAddressFromBech32(owner) + if err != nil { + return nil, err + } + ownerEvmAddr, found := h.k.GetEVMAddress(ctx, ownerAddr) + if !found { + return nil, fmt.Errorf("owner %s is not associated", ownerAddr.String()) + } + + // Get the evm address of spender + spenderEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(spender)) + if !found { + return nil, fmt.Errorf("%s is not associated", spender) + } + + // Fetch the contract ABI + contract := common.HexToAddress(contractAddress) + abi, err := native.NativeMetaData.GetAbi() + if err != nil { + return nil, err + } + + // Make the query to allowance(owner, spender) + bz, err := abi.Pack("allowance", ownerEvmAddr, spenderEvmAddr) + if err != nil { + return nil, err + } + res, err := h.k.StaticCallEVM(ctx, ownerAddr, &contract, bz) + if err != nil { + return nil, err + } + + // Parse the response (Should be of type uint256 if successful) + typed, err := abi.Unpack("allowance", res) + if err != nil { + return nil, err + } + allowance := typed[0].(*big.Int) + allowanceSdk := sdk.NewIntFromBigInt(allowance) + response := bindings.ERC20AllowanceResponse{Allowance: &allowanceSdk} + return json.Marshal(response) +} + +func (h *EVMQueryHandler) HandleERC721Approved(ctx sdk.Context, caller string, contractAddress string, tokenId 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 + } + t, ok := sdk.NewIntFromString(tokenId) + if !ok { + return nil, errors.New("invalid token ID for ERC20, must be a big Int") + } + bz, err := abi.Pack("getApproved", t.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("getApproved", res) + if err != nil { + return nil, err + } + approved := typed[0].(common.Address) + a := "" + if (approved != common.Address{}) { + a = h.k.GetSeiAddressOrDefault(ctx, approved).String() + } + response := bindings.ERC721ApprovedResponse{Approved: a} + return json.Marshal(response) +} + +func (h *EVMQueryHandler) HandleERC721IsApprovedForAll(ctx sdk.Context, caller string, contractAddress string, owner string, operator string) ([]byte, error) { + callerAddr, err := sdk.AccAddressFromBech32(caller) + if err != nil { + return nil, err + } + ownerEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(owner)) + if !found { + return nil, fmt.Errorf("%s is not associated", owner) + } + operatorEvmAddr, found := h.k.GetEVMAddress(ctx, sdk.MustAccAddressFromBech32(operator)) + if !found { + return nil, fmt.Errorf("%s is not associated", operator) + } + contract := common.HexToAddress(contractAddress) + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return nil, err + } + bz, err := abi.Pack("isApprovedForAll", ownerEvmAddr, operatorEvmAddr) + 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("isApprovedForAll", res) + if err != nil { + return nil, err + } + response := bindings.ERC721IsApprovedForAllResponse{IsApproved: typed[0].(bool)} + 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 { + return nil, err + } + contract := common.HexToAddress(contractAddress) + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return nil, err + } + bz, err := abi.Pack("name") + 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("name", res) + if err != nil { + return nil, err + } + name := typed[0].(string) + bz, err = abi.Pack("symbol") + 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("symbol", res) + if err != nil { + return nil, err + } + symbol := typed[0].(string) + response := bindings.ERC721NameSymbolResponse{Name: name, Symbol: symbol} + return json.Marshal(response) +} + +func (h *EVMQueryHandler) HandleERC721Uri(ctx sdk.Context, caller string, contractAddress string, tokenId string) ([]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 ERC20, must be a big Int") + } + contract := common.HexToAddress(contractAddress) + abi, err := cw721.Cw721MetaData.GetAbi() + if err != nil { + return nil, err + } + bz, err := abi.Pack("tokenURI", t.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("tokenURI", res) + if err != nil { + return nil, err + } + response := bindings.ERC721UriResponse{Uri: typed[0].(string)} + return json.Marshal(response) +} + +func (h *EVMQueryHandler) HandleGetEvmAddress(ctx sdk.Context, seiAddr string) ([]byte, error) { + addr, err := sdk.AccAddressFromBech32(seiAddr) + if err != nil { + return nil, err + } + evmAddr, associated := h.k.GetEVMAddress(ctx, addr) + response := bindings.GetEvmAddressResponse{EvmAddress: evmAddr.Hex(), Associated: associated} + return json.Marshal(response) +} + +func (h *EVMQueryHandler) HandleGetSeiAddress(ctx sdk.Context, evmAddr string) ([]byte, error) { + addr := common.HexToAddress(evmAddr) + seiAddr, associated := h.k.GetSeiAddress(ctx, addr) + response := bindings.GetSeiAddressResponse{SeiAddress: seiAddr.String(), Associated: associated} + return json.Marshal(response) +} diff --git a/x/evm/client/wasm/query_test.go b/x/evm/client/wasm/query_test.go new file mode 100644 index 0000000000..b13618592d --- /dev/null +++ b/x/evm/client/wasm/query_test.go @@ -0,0 +1,110 @@ +package wasm_test + +import ( + "encoding/json" + "testing" + + "github.com/cosmos/cosmos-sdk/types" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/client/wasm" + "github.com/sei-protocol/sei-chain/x/evm/client/wasm/bindings" + "github.com/stretchr/testify/require" +) + +func TestERC721TransferPayload(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + addr1, e1 := testkeeper.MockAddressPair() + addr2, e2 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + k.SetAddressMapping(ctx, addr2, e2) + h := wasm.NewEVMQueryHandler(k) + res, err := h.HandleERC721TransferPayload(ctx, addr1.String(), addr2.String(), "1") + require.Nil(t, err) + require.NotEmpty(t, res) +} + +func TestERC721ApprovePayload(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + h := wasm.NewEVMQueryHandler(k) + res, err := h.HandleERC721ApprovePayload(ctx, addr1.String(), "1") + require.Nil(t, err) + require.NotEmpty(t, res) +} + +func TestERC721ApproveAllPayload(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + h := wasm.NewEVMQueryHandler(k) + res, err := h.HandleERC721SetApprovalAllPayload(ctx, addr1.String(), true) + require.Nil(t, err) + require.NotEmpty(t, res) +} + +func TestERC20TransferPayload(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + h := wasm.NewEVMQueryHandler(k) + value := types.NewInt(500) + res, err := h.HandleERC20TransferPayload(ctx, addr1.String(), &value) + require.Nil(t, err) + require.NotEmpty(t, res) +} + +func TestERC20TransferFromPayload(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + addr1, e1 := testkeeper.MockAddressPair() + addr2, e2 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + k.SetAddressMapping(ctx, addr2, e2) + h := wasm.NewEVMQueryHandler(k) + value := types.NewInt(500) + res, err := h.HandleERC20TransferFromPayload(ctx, addr1.String(), addr2.String(), &value) + require.Nil(t, err) + require.NotEmpty(t, res) +} + +func TestERC20ApprovePayload(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + addr1, e1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, e1) + h := wasm.NewEVMQueryHandler(k) + value := types.NewInt(500) + res, err := h.HandleERC20ApprovePayload(ctx, addr1.String(), &value) + require.Nil(t, err) + require.NotEmpty(t, res) +} + +func TestGetAddress(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + seiAddr1, evmAddr1 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, seiAddr1, evmAddr1) + seiAddr2, evmAddr2 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, seiAddr2, evmAddr2) + h := wasm.NewEVMQueryHandler(k) + getEvmAddrResp := &bindings.GetEvmAddressResponse{} + res, err := h.HandleGetEvmAddress(ctx, seiAddr1.String()) + require.Nil(t, err) + require.Nil(t, json.Unmarshal(res, getEvmAddrResp)) + require.True(t, getEvmAddrResp.Associated) + require.Equal(t, evmAddr1.Hex(), getEvmAddrResp.EvmAddress) + getEvmAddrResp = &bindings.GetEvmAddressResponse{} + res, err = h.HandleGetEvmAddress(ctx, seiAddr2.String()) + require.Nil(t, err) + require.Nil(t, json.Unmarshal(res, getEvmAddrResp)) + require.True(t, getEvmAddrResp.Associated) + getSeiAddrResp := &bindings.GetSeiAddressResponse{} + res, err = h.HandleGetSeiAddress(ctx, evmAddr1.Hex()) + require.Nil(t, err) + require.Nil(t, json.Unmarshal(res, getSeiAddrResp)) + require.True(t, getSeiAddrResp.Associated) + require.Equal(t, seiAddr1.String(), getSeiAddrResp.SeiAddress) + getSeiAddrResp = &bindings.GetSeiAddressResponse{} + res, err = h.HandleGetSeiAddress(ctx, evmAddr2.Hex()) + require.Nil(t, err) + require.Nil(t, json.Unmarshal(res, getSeiAddrResp)) + require.True(t, getSeiAddrResp.Associated) +} diff --git a/x/evm/derived/derived.go b/x/evm/derived/derived.go new file mode 100644 index 0000000000..810df0b27c --- /dev/null +++ b/x/evm/derived/derived.go @@ -0,0 +1,32 @@ +package derived + +import ( + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" +) + +type SignerVersion int + +const ( + London SignerVersion = iota + Cancun +) + +type Derived struct { + SenderEVMAddr common.Address + SenderSeiAddr sdk.AccAddress + PubKey *secp256k1.PubKey + IsAssociate bool + Version SignerVersion +} + +// Derived should never come from deserialization or be transmitted after serialization, +// so all methods below would no-op. +func (d Derived) Marshal() ([]byte, error) { return []byte{}, nil } +func (d *Derived) MarshalTo([]byte) (n int, err error) { return } +func (d *Derived) Unmarshal([]byte) error { return nil } +func (d *Derived) Size() int { return 0 } + +func (d Derived) MarshalJSON() ([]byte, error) { return []byte{}, nil } +func (d *Derived) UnmarshalJSON([]byte) error { return nil } diff --git a/x/evm/genesis.go b/x/evm/genesis.go new file mode 100644 index 0000000000..54eacf22d6 --- /dev/null +++ b/x/evm/genesis.go @@ -0,0 +1,34 @@ +package evm + +import ( + "encoding/json" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func InitGenesis(ctx sdk.Context, k *keeper.Keeper, genState types.GenesisState) { + k.InitGenesis(ctx, genState) + k.SetParams(ctx, genState.Params) +} + +func ExportGenesis(ctx sdk.Context, k *keeper.Keeper) *types.GenesisState { + genesis := types.DefaultGenesis() + genesis.Params = k.GetParams(ctx) + + return genesis +} + +// GetGenesisStateFromAppState returns x/evm GenesisState given raw application +// genesis state. +func GetGenesisStateFromAppState(cdc codec.JSONCodec, appState map[string]json.RawMessage) *types.GenesisState { + var genesisState types.GenesisState + + if appState[types.ModuleName] != nil { + cdc.MustUnmarshalJSON(appState[types.ModuleName], &genesisState) + } + + return &genesisState +} diff --git a/x/evm/gov.go b/x/evm/gov.go new file mode 100644 index 0000000000..879f2fa5dd --- /dev/null +++ b/x/evm/gov.go @@ -0,0 +1,46 @@ +package evm + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func HandleAddERCNativePointerProposal(ctx sdk.Context, k *keeper.Keeper, p *types.AddERCNativePointerProposal) error { + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "native"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, p.Pointer), sdk.NewAttribute(types.AttributeKeyPointee, p.Token), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", p.Version)))) + if p.Pointer == "" { + k.DeleteERC20NativePointer(ctx, p.Token, uint16(p.Version)) + return nil + } + return k.SetERC20NativePointerWithVersion(ctx, p.Token, common.HexToAddress(p.Pointer), uint16(p.Version)) +} + +func HandleAddERCCW20PointerProposal(ctx sdk.Context, k *keeper.Keeper, p *types.AddERCCW20PointerProposal) error { + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "cw20"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, p.Pointer), sdk.NewAttribute(types.AttributeKeyPointee, p.Pointee), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", p.Version)))) + if p.Pointer == "" { + k.DeleteERC20CW20Pointer(ctx, p.Pointee, uint16(p.Version)) + return nil + } + return k.SetERC20CW20PointerWithVersion(ctx, p.Pointee, common.HexToAddress(p.Pointer), uint16(p.Version)) +} + +func HandleAddERCCW721PointerProposal(ctx sdk.Context, k *keeper.Keeper, p *types.AddERCCW721PointerProposal) error { + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "cw721"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, p.Pointer), sdk.NewAttribute(types.AttributeKeyPointee, p.Pointee), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", p.Version)))) + if p.Pointer == "" { + k.DeleteERC721CW721Pointer(ctx, p.Pointee, uint16(p.Version)) + return nil + } + return k.SetERC721CW721PointerWithVersion(ctx, p.Pointee, common.HexToAddress(p.Pointer), uint16(p.Version)) +} diff --git a/x/evm/gov_test.go b/x/evm/gov_test.go new file mode 100644 index 0000000000..355403742d --- /dev/null +++ b/x/evm/gov_test.go @@ -0,0 +1,106 @@ +package evm_test + +import ( + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestAddERCNativePointerProposals(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, pointer1 := testkeeper.MockAddressPair() + _, pointer2 := testkeeper.MockAddressPair() + require.Nil(t, evm.HandleAddERCNativePointerProposal(ctx, k, &types.AddERCNativePointerProposal{ + Token: "test", + Version: 1, + Pointer: pointer1.Hex(), + })) + addr, ver, exists := k.GetERC20NativePointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) + require.Nil(t, evm.HandleAddERCNativePointerProposal(ctx, k, &types.AddERCNativePointerProposal{ + Token: "test", + Version: 2, + Pointer: pointer2.Hex(), + })) + addr, ver, exists = k.GetERC20NativePointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(2), ver) + require.Equal(t, addr, pointer2) + require.Nil(t, evm.HandleAddERCNativePointerProposal(ctx, k, &types.AddERCNativePointerProposal{ + Token: "test", + Version: 2, + })) + addr, ver, exists = k.GetERC20NativePointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) +} + +func TestAddERCCW20PointerProposals(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, pointer1 := testkeeper.MockAddressPair() + _, pointer2 := testkeeper.MockAddressPair() + require.Nil(t, evm.HandleAddERCCW20PointerProposal(ctx, k, &types.AddERCCW20PointerProposal{ + Pointee: "test", + Version: 1, + Pointer: pointer1.Hex(), + })) + addr, ver, exists := k.GetERC20CW20Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) + require.Nil(t, evm.HandleAddERCCW20PointerProposal(ctx, k, &types.AddERCCW20PointerProposal{ + Pointee: "test", + Version: 2, + Pointer: pointer2.Hex(), + })) + addr, ver, exists = k.GetERC20CW20Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(2), ver) + require.Equal(t, addr, pointer2) + require.Nil(t, evm.HandleAddERCCW20PointerProposal(ctx, k, &types.AddERCCW20PointerProposal{ + Pointee: "test", + Version: 2, + })) + addr, ver, exists = k.GetERC20CW20Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) +} + +func TestAddERCCW721PointerProposals(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, pointer1 := testkeeper.MockAddressPair() + _, pointer2 := testkeeper.MockAddressPair() + require.Nil(t, evm.HandleAddERCCW721PointerProposal(ctx, k, &types.AddERCCW721PointerProposal{ + Pointee: "test", + Version: 1, + Pointer: pointer1.Hex(), + })) + addr, ver, exists := k.GetERC721CW721Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) + require.Nil(t, evm.HandleAddERCCW721PointerProposal(ctx, k, &types.AddERCCW721PointerProposal{ + Pointee: "test", + Version: 2, + Pointer: pointer2.Hex(), + })) + addr, ver, exists = k.GetERC721CW721Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(2), ver) + require.Equal(t, addr, pointer2) + require.Nil(t, evm.HandleAddERCCW721PointerProposal(ctx, k, &types.AddERCCW721PointerProposal{ + Pointee: "test", + Version: 2, + })) + addr, ver, exists = k.GetERC721CW721Pointer(ctx, "test") + require.True(t, exists) + require.Equal(t, uint16(1), ver) + require.Equal(t, addr, pointer1) +} diff --git a/x/evm/handler.go b/x/evm/handler.go new file mode 100644 index 0000000000..f610540ec0 --- /dev/null +++ b/x/evm/handler.go @@ -0,0 +1,47 @@ +package evm + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func NewHandler(k *keeper.Keeper) sdk.Handler { + msgServer := keeper.NewMsgServerImpl(k) + + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case *types.MsgEVMTransaction: + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgSend: + res, err := msgServer.Send(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) + } + } +} + +func NewProposalHandler(k keeper.Keeper) govtypes.Handler { + return func(ctx sdk.Context, content govtypes.Content) error { + switch c := content.(type) { + case *types.AddERCNativePointerProposal: + return HandleAddERCNativePointerProposal(ctx, &k, c) + case *types.AddERCCW20PointerProposal: + return HandleAddERCCW20PointerProposal(ctx, &k, c) + case *types.AddERCCW721PointerProposal: + return HandleAddERCCW721PointerProposal(ctx, &k, c) + default: + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized evm proposal content type: %T", c) + } + } +} diff --git a/x/evm/keeper/address.go b/x/evm/keeper/address.go new file mode 100644 index 0000000000..99f13cc1ce --- /dev/null +++ b/x/evm/keeper/address.go @@ -0,0 +1,63 @@ +package keeper + +import ( + 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) SetAddressMapping(ctx sdk.Context, seiAddress sdk.AccAddress, evmAddress common.Address) { + store := ctx.KVStore(k.storeKey) + store.Set(types.EVMAddressToSeiAddressKey(evmAddress), seiAddress) + store.Set(types.SeiAddressToEVMAddressKey(seiAddress), evmAddress[:]) + if !k.accountKeeper.HasAccount(ctx, seiAddress) { + k.accountKeeper.SetAccount(ctx, k.accountKeeper.NewAccountWithAddress(ctx, seiAddress)) + } + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeAddressAssociated, + sdk.NewAttribute(types.AttributeKeySeiAddress, seiAddress.String()), + sdk.NewAttribute(types.AttributeKeyEvmAddress, evmAddress.Hex()), + )) +} + +func (k *Keeper) DeleteAddressMapping(ctx sdk.Context, seiAddress sdk.AccAddress, evmAddress common.Address) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.EVMAddressToSeiAddressKey(evmAddress)) + store.Delete(types.SeiAddressToEVMAddressKey(seiAddress)) +} + +func (k *Keeper) GetEVMAddress(ctx sdk.Context, seiAddress sdk.AccAddress) (common.Address, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.SeiAddressToEVMAddressKey(seiAddress)) + addr := common.Address{} + if bz == nil { + return addr, false + } + copy(addr[:], bz) + return addr, true +} + +func (k *Keeper) GetEVMAddressOrDefault(ctx sdk.Context, seiAddress sdk.AccAddress) common.Address { + addr, ok := k.GetEVMAddress(ctx, seiAddress) + if ok { + return addr + } + return common.BytesToAddress(seiAddress) +} + +func (k *Keeper) GetSeiAddress(ctx sdk.Context, evmAddress common.Address) (sdk.AccAddress, bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.EVMAddressToSeiAddressKey(evmAddress)) + if bz == nil { + return []byte{}, false + } + return bz, true +} + +func (k *Keeper) GetSeiAddressOrDefault(ctx sdk.Context, evmAddress common.Address) sdk.AccAddress { + addr, ok := k.GetSeiAddress(ctx, evmAddress) + if ok { + return addr + } + return sdk.AccAddress(evmAddress[:]) +} diff --git a/x/evm/keeper/address_test.go b/x/evm/keeper/address_test.go new file mode 100644 index 0000000000..6c511fcc84 --- /dev/null +++ b/x/evm/keeper/address_test.go @@ -0,0 +1,42 @@ +package keeper_test + +import ( + "testing" + + "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/stretchr/testify/require" +) + +func TestSetGetAddressMapping(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + seiAddr, evmAddr := keeper.MockAddressPair() + foundEVM, ok := k.GetEVMAddress(ctx, seiAddr) + require.False(t, ok) + foundSei, ok := k.GetSeiAddress(ctx, evmAddr) + require.False(t, ok) + k.SetAddressMapping(ctx, seiAddr, evmAddr) + foundEVM, ok = k.GetEVMAddress(ctx, seiAddr) + require.True(t, ok) + require.Equal(t, evmAddr, foundEVM) + foundSei, ok = k.GetSeiAddress(ctx, evmAddr) + require.True(t, ok) + require.Equal(t, seiAddr, foundSei) + require.Equal(t, seiAddr, k.AccountKeeper().GetAccount(ctx, seiAddr).GetAddress()) +} + +func TestDeleteAddressMapping(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + seiAddr, evmAddr := keeper.MockAddressPair() + k.SetAddressMapping(ctx, seiAddr, evmAddr) + foundEVM, ok := k.GetEVMAddress(ctx, seiAddr) + require.True(t, ok) + require.Equal(t, evmAddr, foundEVM) + foundSei, ok := k.GetSeiAddress(ctx, evmAddr) + require.True(t, ok) + require.Equal(t, seiAddr, foundSei) + k.DeleteAddressMapping(ctx, seiAddr, evmAddr) + foundEVM, ok = k.GetEVMAddress(ctx, seiAddr) + require.False(t, ok) + foundSei, ok = k.GetSeiAddress(ctx, evmAddr) + require.False(t, ok) +} diff --git a/x/evm/keeper/code.go b/x/evm/keeper/code.go new file mode 100644 index 0000000000..d2412f26d7 --- /dev/null +++ b/x/evm/keeper/code.go @@ -0,0 +1,50 @@ +package keeper + +import ( + "encoding/binary" + + sdk "github.com/cosmos/cosmos-sdk/types" + "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/x/evm/types" +) + +func (k *Keeper) GetCode(ctx sdk.Context, addr common.Address) []byte { + code := k.PrefixStore(ctx, types.CodeKeyPrefix).Get(addr[:]) + if len(code) == 0 { + return nil + } + return code +} + +func (k *Keeper) SetCode(ctx sdk.Context, addr common.Address, code []byte) { + if code == nil { + code = []byte{} + } + k.PrefixStore(ctx, types.CodeKeyPrefix).Set(addr[:], code) + length := make([]byte, 8) + binary.BigEndian.PutUint64(length, uint64(len(code))) + k.PrefixStore(ctx, types.CodeSizeKeyPrefix).Set(addr[:], length) + h := crypto.Keccak256Hash(code) + k.PrefixStore(ctx, types.CodeHashKeyPrefix).Set(addr[:], h[:]) + // set association with direct cast Sei address for the contract address + k.SetAddressMapping(ctx, k.GetSeiAddressOrDefault(ctx, addr), addr) +} + +func (k *Keeper) GetCodeHash(ctx sdk.Context, addr common.Address) common.Hash { + store := k.PrefixStore(ctx, types.CodeHashKeyPrefix) + bz := store.Get(addr[:]) + if bz == nil { + return ethtypes.EmptyCodeHash + } + return common.BytesToHash(bz) +} + +func (k *Keeper) GetCodeSize(ctx sdk.Context, addr common.Address) int { + bz := k.PrefixStore(ctx, types.CodeSizeKeyPrefix).Get(addr[:]) + if bz == nil { + return 0 + } + return int(binary.BigEndian.Uint64(bz)) +} diff --git a/x/evm/keeper/code_test.go b/x/evm/keeper/code_test.go new file mode 100644 index 0000000000..e3563ea175 --- /dev/null +++ b/x/evm/keeper/code_test.go @@ -0,0 +1,37 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/stretchr/testify/require" +) + +func TestCode(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + _, addr := keeper.MockAddressPair() + + require.Equal(t, ethtypes.EmptyCodeHash, k.GetCodeHash(ctx, addr)) + require.Nil(t, k.GetCode(ctx, addr)) + require.Equal(t, 0, k.GetCodeSize(ctx, addr)) + + code := []byte{1, 2, 3, 4, 5} + k.SetCode(ctx, addr, code) + require.Equal(t, crypto.Keccak256Hash(code), k.GetCodeHash(ctx, addr)) + require.Equal(t, code, k.GetCode(ctx, addr)) + require.Equal(t, 5, k.GetCodeSize(ctx, addr)) + require.Equal(t, sdk.AccAddress(addr[:]), k.AccountKeeper().GetAccount(ctx, k.GetSeiAddressOrDefault(ctx, addr)).GetAddress()) +} + +func TestNilCode(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + _, addr := keeper.MockAddressPair() + + k.SetCode(ctx, addr, nil) + require.Nil(t, k.GetCode(ctx, addr)) + require.Equal(t, 0, k.GetCodeSize(ctx, addr)) + require.Equal(t, ethtypes.EmptyCodeHash, k.GetCodeHash(ctx, addr)) +} diff --git a/x/evm/keeper/coinbase.go b/x/evm/keeper/coinbase.go new file mode 100644 index 0000000000..378f4b9ca8 --- /dev/null +++ b/x/evm/keeper/coinbase.go @@ -0,0 +1,36 @@ +package keeper + +import ( + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +const CoinbaseSeedAddress = "0000000000000000000000000000000000000001" +const CoinbaseNonce = 42 + +func (k *Keeper) GetFeeCollectorAddress(ctx sdk.Context) (common.Address, error) { + k.cachedFeeCollectorAddressMtx.RLock() + cache := k.cachedFeeCollectorAddress + k.cachedFeeCollectorAddressMtx.RUnlock() + if cache != nil { + return *cache, nil + } + moduleAddr := k.accountKeeper.GetModuleAddress(authtypes.FeeCollectorName) + evmAddr, ok := k.GetEVMAddress(ctx, moduleAddr) + if !ok { + return common.Address{}, errors.New("fee collector's EVM address not found") + } + k.cachedFeeCollectorAddressMtx.Lock() + // ok to write multiple times since it's idempotent + k.cachedFeeCollectorAddress = &evmAddr + k.cachedFeeCollectorAddressMtx.Unlock() + return evmAddr, nil +} + +func GetCoinbaseAddress() common.Address { + return crypto.CreateAddress(common.HexToAddress(CoinbaseSeedAddress), CoinbaseNonce) +} diff --git a/x/evm/keeper/evm.go b/x/evm/keeper/evm.go new file mode 100644 index 0000000000..6df3dc9ce7 --- /dev/null +++ b/x/evm/keeper/evm.go @@ -0,0 +1,147 @@ +package keeper + +import ( + "errors" + "fmt" + "math" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +type EVMCallFunc func(caller vm.ContractRef, addr *common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) + +var MaxUint64BigInt = new(big.Int).SetUint64(math.MaxUint64) + +func (k *Keeper) HandleInternalEVMCall(ctx sdk.Context, req *types.MsgInternalEVMCall) (*sdk.Result, error) { + var to *common.Address + if req.To != "" { + addr := common.HexToAddress(req.To) + to = &addr + } + senderAddr, err := sdk.AccAddressFromBech32(req.Sender) + if err != nil { + return nil, err + } + ret, err := k.CallEVM(ctx, senderAddr, to, req.Value, req.Data) + if err != nil { + return nil, err + } + return &sdk.Result{Data: ret}, nil +} + +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 + } + zeroInt := sdk.ZeroInt() + senderAddr, err := sdk.AccAddressFromBech32(req.Sender) + if err != nil { + return nil, err + } + // delegatecall caller must be associated; otherwise any state change on EVM contract will be lost + // after they asssociate. + _, found := k.GetEVMAddress(ctx, senderAddr) + if !found { + return nil, fmt.Errorf("sender %s is not associated", req.Sender) + } + ret, err := k.CallEVM(ctx, senderAddr, to, &zeroInt, req.Data) + if err != nil { + return nil, err + } + return &sdk.Result{Data: ret}, nil +} + +func (k *Keeper) CallEVM(ctx sdk.Context, from sdk.AccAddress, to *common.Address, val *sdk.Int, data []byte) (retdata []byte, reterr error) { + evm, finalizer, err := k.getOrCreateEVM(ctx, from) + if err != nil { + return nil, err + } + defer func() { + if finalizer != nil { + if err := finalizer(); err != nil { + reterr = err + return + } + } + }() + 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) + } + } + return k.callEVM(ctx, from, to, val, data, f) +} + +func (k *Keeper) StaticCallEVM(ctx sdk.Context, from sdk.AccAddress, to *common.Address, data []byte) ([]byte, error) { + evm, _, err := k.getOrCreateEVM(ctx, from) + if err != nil { + return nil, err + } + return k.callEVM(ctx, from, to, nil, data, func(caller vm.ContractRef, addr *common.Address, input []byte, gas uint64, _ *big.Int) ([]byte, uint64, error) { + return evm.StaticCall(caller, *addr, input, gas) + }) +} + +func (k *Keeper) callEVM(ctx sdk.Context, from sdk.AccAddress, to *common.Address, val *sdk.Int, data []byte, f EVMCallFunc) ([]byte, error) { + sender := k.GetEVMAddressOrDefault(ctx, from) + seiGasRemaining := ctx.GasMeter().Limit() - ctx.GasMeter().GasConsumedToLimit() + if ctx.GasMeter().Limit() <= 0 { + // infinite gas meter (used in queries) + seiGasRemaining = math.MaxUint64 + } + multiplier := k.GetPriorityNormalizer(ctx) + evmGasRemaining := sdk.NewDecFromInt(sdk.NewIntFromUint64(seiGasRemaining)).Quo(multiplier).TruncateInt().BigInt() + if evmGasRemaining.Cmp(MaxUint64BigInt) > 0 { + evmGasRemaining = MaxUint64BigInt + } + value := utils.Big0 + if val != nil { + value = val.BigInt() + } + ret, leftoverGas, err := f(vm.AccountRef(sender), to, data, evmGasRemaining.Uint64(), value) + ctx.GasMeter().ConsumeGas(ctx.GasMeter().Limit()-sdk.NewDecFromInt(sdk.NewIntFromUint64(leftoverGas)).Mul(multiplier).TruncateInt().Uint64(), "call EVM") + if err != nil { + return nil, err + } + return ret, nil +} + +func (k *Keeper) getOrCreateEVM(ctx sdk.Context, from sdk.AccAddress) (*vm.EVM, func() error, error) { + evm := types.GetCtxEVM(ctx) + if evm != nil { + return evm, nil, nil + } + executionCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) + stateDB := state.NewDBImpl(executionCtx, k, false) + executionCtx, gp := k.getGasPool(executionCtx) + blockCtx, err := k.GetVMBlockContext(executionCtx, gp) + if err != nil { + return nil, nil, err + } + cfg := types.DefaultChainConfig().EthereumConfig(k.ChainID(executionCtx)) + txCtx := vm.TxContext{Origin: k.GetEVMAddressOrDefault(ctx, from)} + evm = vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) + stateDB.SetEVM(evm) + return evm, func() error { + _, err := stateDB.Finalize() + return err + }, nil +} diff --git a/x/evm/keeper/evm_test.go b/x/evm/keeper/evm_test.go new file mode 100644 index 0000000000..940e246ec7 --- /dev/null +++ b/x/evm/keeper/evm_test.go @@ -0,0 +1,117 @@ +package keeper_test + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/crypto" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestInternalCallCreateContract(t *testing.T) { + bytecode := native.GetBin() + abi, err := native.NativeMetaData.GetAbi() + require.Nil(t, err) + args, err := abi.Pack("", "test", "TST", "TST", uint8(6)) + require.Nil(t, err) + contractData := append(bytecode, args...) + + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + testAddr, _ := testkeeper.MockAddressPair() + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) + require.Nil(t, k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, testAddr, amt)) + req := &types.MsgInternalEVMCall{ + Sender: testAddr.String(), + Data: contractData, + } + _, err = k.HandleInternalEVMCall(ctx, req) + require.Nil(t, err) +} + +func TestInternalCall(t *testing.T) { + bytecode := native.GetBin() + abi, err := native.NativeMetaData.GetAbi() + require.Nil(t, err) + args, err := abi.Pack("", "test", "TST", "TST", uint8(6)) + require.Nil(t, err) + contractData := append(bytecode, args...) + + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + testAddr, senderEvmAddr := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, testAddr, senderEvmAddr) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))) + require.Nil(t, k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, testAddr, amt)) + req := &types.MsgInternalEVMCall{ + Sender: testAddr.String(), + Data: contractData, + } + ret, err := k.HandleInternalEVMCall(ctx, req) + require.Nil(t, err) + contractAddr := crypto.CreateAddress(senderEvmAddr, 0) + require.NotEmpty(t, k.GetCode(ctx, contractAddr)) + require.Equal(t, ret.Data, k.GetCode(ctx, contractAddr)) + k.SetERC20NativePointer(ctx, "test", contractAddr) + + receiverAddr, evmAddr := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, receiverAddr, evmAddr) + args, err = abi.Pack("transfer", evmAddr, big.NewInt(1000)) + require.Nil(t, err) + require.Nil(t, k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(200000000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, testAddr, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(200000000))))) + val := sdk.NewInt(0) + req = &types.MsgInternalEVMCall{ + Sender: testAddr.String(), + To: contractAddr.Hex(), + Data: args, + Value: &val, + } + _, err = k.HandleInternalEVMCall(ctx, req) + require.Nil(t, err) + require.Equal(t, int64(1000), testkeeper.EVMTestApp.BankKeeper.GetBalance(ctx, receiverAddr, "test").Amount.Int64()) +} + +func TestStaticCall(t *testing.T) { + bytecode := native.GetBin() + abi, err := native.NativeMetaData.GetAbi() + require.Nil(t, err) + args, err := abi.Pack("", "test", "TST", "TST", uint8(6)) + require.Nil(t, err) + contractData := append(bytecode, args...) + + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) + testAddr, senderEvmAddr := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, testAddr, senderEvmAddr) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(2000))) + require.Nil(t, k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(2000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, testAddr, amt)) + req := &types.MsgInternalEVMCall{ + Sender: testAddr.String(), + Data: contractData, + } + ret, err := k.HandleInternalEVMCall(ctx, req) + require.Nil(t, err) + contractAddr := crypto.CreateAddress(senderEvmAddr, 0) + require.NotEmpty(t, k.GetCode(ctx, contractAddr)) + require.Equal(t, ret.Data, k.GetCode(ctx, contractAddr)) + require.Nil(t, k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(2000))))) + require.Nil(t, k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, testAddr, sdk.NewCoins(sdk.NewCoin("test", sdk.NewInt(2000))))) + + args, err = abi.Pack("balanceOf", senderEvmAddr) + require.Nil(t, err) + res, err := k.StaticCallEVM(ctx, testAddr, &contractAddr, args) + require.Nil(t, err) + decoded, err := abi.Unpack("balanceOf", res) + require.Nil(t, err) + require.Equal(t, 1, len(decoded)) + require.Equal(t, big.NewInt(int64(2000)), decoded[0].(*big.Int)) +} diff --git a/x/evm/keeper/genesis.go b/x/evm/keeper/genesis.go new file mode 100644 index 0000000000..dc46d5ac71 --- /dev/null +++ b/x/evm/keeper/genesis.go @@ -0,0 +1,105 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/trie/triedb/hashdb" + "github.com/ethereum/go-ethereum/trie/triedb/pathdb" + + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + artifactsutils "github.com/sei-protocol/sei-chain/x/evm/artifacts/utils" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +var ethReplayInitialied = false + +func (k *Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { + moduleAcc := authtypes.NewEmptyModuleAccount(types.ModuleName, authtypes.Minter, authtypes.Burner) + k.accountKeeper.SetModuleAccount(ctx, moduleAcc) + + k.SetParams(ctx, genState.Params) + + seiAddrFc := k.accountKeeper.GetModuleAddress(authtypes.FeeCollectorName) // feeCollector == coinbase + k.SetAddressMapping(ctx, seiAddrFc, GetCoinbaseAddress()) + + for _, addr := range genState.AddressAssociations { + k.SetAddressMapping(ctx, sdk.MustAccAddressFromBech32(addr.SeiAddress), common.HexToAddress(addr.EthAddress)) + } + + erc20CodeID, err := k.wasmKeeper.Create(ctx, k.accountKeeper.GetModuleAddress(types.ModuleName), erc20.GetBin(), nil) + if err != nil { + panic(err) + } + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW20ERC20Prefix).Set( + artifactsutils.GetVersionBz(erc20.CurrentVersion), + artifactsutils.GetCodeIDBz(erc20CodeID), + ) + + erc721CodeID, err := k.wasmKeeper.Create(ctx, k.accountKeeper.GetModuleAddress(types.ModuleName), erc721.GetBin(), nil) + if err != nil { + panic(err) + } + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW721ERC721Prefix).Set( + artifactsutils.GetVersionBz(erc721.CurrentVersion), + artifactsutils.GetCodeIDBz(erc721CodeID), + ) + + if k.EthReplayConfig.Enabled && !ethReplayInitialied { + header := k.OpenEthDatabase() + params := k.GetParams(ctx) + params.ChainId = sdk.OneInt() + k.SetParams(ctx, params) + k.SetReplayInitialHeight(ctx, header.Number.Int64()) + ethReplayInitialied = true + } +} + +func (k *Keeper) OpenEthDatabase() *ethtypes.Header { + db, err := rawdb.Open(rawdb.OpenOptions{ + Type: "pebble", + Directory: k.EthReplayConfig.EthDataDir, + AncientsDirectory: fmt.Sprintf("%s/ancient", k.EthReplayConfig.EthDataDir), + Namespace: "", + Cache: 256, + Handles: 256, + ReadOnly: true, + }) + if err != nil { + panic(err) + } + config := &trie.Config{ + Preimages: true, + IsVerkle: false, + } + scheme, err := rawdb.ParseStateScheme(rawdb.ReadStateScheme(db), db) + if err != nil { + panic(err) + } + var triedb *trie.Database + if scheme == rawdb.HashScheme { + config.HashDB = hashdb.Defaults + triedb = trie.NewDatabase(db, config) + } else { + config.PathDB = pathdb.ReadOnly + triedb = trie.NewDatabase(db, config) + } + header := rawdb.ReadHeadHeader(db) + sdb := state.NewDatabaseWithNodeDB(db, triedb) + tr, err := sdb.OpenTrie(header.Root) + if err != nil { + panic(err) + } + k.Root = header.Root + k.DB = sdb + k.Trie = tr + return header +} diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go new file mode 100644 index 0000000000..3c0905ef0e --- /dev/null +++ b/x/evm/keeper/grpc_query.go @@ -0,0 +1,113 @@ +package keeper + +import ( + "context" + "errors" + + 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/types" +) + +var _ types.QueryServer = Querier{} + +// Querier defines a wrapper around the x/mint keeper providing gRPC method +// handlers. +type Querier struct { + *Keeper +} + +func NewQuerier(k *Keeper) Querier { + return Querier{Keeper: k} +} + +func (q Querier) SeiAddressByEVMAddress(c context.Context, req *types.QuerySeiAddressByEVMAddressRequest) (*types.QuerySeiAddressByEVMAddressResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + if req.EvmAddress == "" { + return nil, sdkerrors.ErrInvalidRequest + } + evmAddr := common.HexToAddress(req.EvmAddress) + addr, found := q.Keeper.GetSeiAddress(ctx, evmAddr) + if !found { + return &types.QuerySeiAddressByEVMAddressResponse{Associated: false}, nil + } + + return &types.QuerySeiAddressByEVMAddressResponse{SeiAddress: addr.String(), Associated: true}, nil +} + +func (q Querier) EVMAddressBySeiAddress(c context.Context, req *types.QueryEVMAddressBySeiAddressRequest) (*types.QueryEVMAddressBySeiAddressResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + if req.SeiAddress == "" { + return nil, sdkerrors.ErrInvalidRequest + } + seiAddr, err := sdk.AccAddressFromBech32(req.SeiAddress) + if err != nil { + return nil, err + } + addr, found := q.Keeper.GetEVMAddress(ctx, seiAddr) + if !found { + return &types.QueryEVMAddressBySeiAddressResponse{Associated: false}, nil + } + + return &types.QueryEVMAddressBySeiAddressResponse{EvmAddress: addr.Hex(), Associated: true}, nil +} + +func (q Querier) StaticCall(c context.Context, req *types.QueryStaticCallRequest) (*types.QueryStaticCallResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + if req.To == "" { + return nil, errors.New("cannot use static call to create contracts") + } + if ctx.GasMeter().Limit() == 0 { + ctx = ctx.WithGasMeter(sdk.NewGasMeter(q.QueryConfig.GasLimit)) + } + to := common.HexToAddress(req.To) + res, err := q.Keeper.StaticCallEVM(ctx, q.Keeper.AccountKeeper().GetModuleAddress(types.ModuleName), &to, req.Data) + if err != nil { + return nil, err + } + return &types.QueryStaticCallResponse{Data: res}, nil +} + +func (q Querier) Pointer(c context.Context, req *types.QueryPointerRequest) (*types.QueryPointerResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + switch req.PointerType { + case types.PointerType_NATIVE: + p, v, e := q.Keeper.GetERC20NativePointer(ctx, req.Pointee) + return &types.QueryPointerResponse{ + Pointer: p.Hex(), + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_CW20: + p, v, e := q.Keeper.GetERC20CW20Pointer(ctx, req.Pointee) + return &types.QueryPointerResponse{ + Pointer: p.Hex(), + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_CW721: + p, v, e := q.Keeper.GetERC721CW721Pointer(ctx, req.Pointee) + return &types.QueryPointerResponse{ + Pointer: p.Hex(), + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_ERC20: + p, v, e := q.Keeper.GetCW20ERC20Pointer(ctx, common.HexToAddress(req.Pointee)) + return &types.QueryPointerResponse{ + Pointer: p.String(), + Version: uint32(v), + Exists: e, + }, nil + case types.PointerType_ERC721: + p, v, e := q.Keeper.GetCW721ERC721Pointer(ctx, common.HexToAddress(req.Pointee)) + return &types.QueryPointerResponse{ + Pointer: p.String(), + Version: uint32(v), + Exists: e, + }, nil + default: + return nil, errors.ErrUnsupported + } +} diff --git a/x/evm/keeper/grpc_query_test.go b/x/evm/keeper/grpc_query_test.go new file mode 100644 index 0000000000..5df0480431 --- /dev/null +++ b/x/evm/keeper/grpc_query_test.go @@ -0,0 +1,47 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestQueryPointer(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + seiAddr1, evmAddr1 := testkeeper.MockAddressPair() + seiAddr2, evmAddr2 := testkeeper.MockAddressPair() + seiAddr3, evmAddr3 := testkeeper.MockAddressPair() + seiAddr4, evmAddr4 := testkeeper.MockAddressPair() + seiAddr5, evmAddr5 := testkeeper.MockAddressPair() + goCtx := sdk.WrapSDKContext(ctx) + k.SetERC20NativePointer(ctx, seiAddr1.String(), evmAddr1) + k.SetERC20CW20Pointer(ctx, seiAddr2.String(), evmAddr2) + k.SetERC721CW721Pointer(ctx, seiAddr3.String(), evmAddr3) + k.SetCW20ERC20Pointer(ctx, evmAddr4, seiAddr4.String()) + k.SetCW721ERC721Pointer(ctx, evmAddr5, seiAddr5.String()) + q := keeper.Querier{k} + res, err := q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_NATIVE, Pointee: seiAddr1.String()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: evmAddr1.Hex(), Version: uint32(native.CurrentVersion), Exists: true}, *res) + res, err = q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_CW20, Pointee: seiAddr2.String()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: evmAddr2.Hex(), Version: uint32(cw20.CurrentVersion), Exists: true}, *res) + res, err = q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_CW721, Pointee: seiAddr3.String()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: evmAddr3.Hex(), Version: uint32(cw721.CurrentVersion), Exists: true}, *res) + res, err = q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_ERC20, Pointee: evmAddr4.Hex()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: seiAddr4.String(), Version: uint32(erc20.CurrentVersion), Exists: true}, *res) + res, err = q.Pointer(goCtx, &types.QueryPointerRequest{PointerType: types.PointerType_ERC721, Pointee: evmAddr5.Hex()}) + require.Nil(t, err) + require.Equal(t, types.QueryPointerResponse{Pointer: seiAddr5.String(), Version: uint32(erc721.CurrentVersion), Exists: true}, *res) +} diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go new file mode 100644 index 0000000000..92f98af7cd --- /dev/null +++ b/x/evm/keeper/keeper.go @@ -0,0 +1,570 @@ +package keeper + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "math" + "math/big" + "slices" + "sort" + "sync" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" + "github.com/ethereum/go-ethereum/core" + ethstate "github.com/ethereum/go-ethereum/core/state" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/tests" + abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/blocktest" + "github.com/sei-protocol/sei-chain/x/evm/querier" + "github.com/sei-protocol/sei-chain/x/evm/replay" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +type Keeper struct { + storeKey sdk.StoreKey + memStoreKey sdk.StoreKey + Paramstore paramtypes.Subspace + + deferredInfo *sync.Map + txResults []*abci.ExecTxResult + + bankKeeper bankkeeper.Keeper + accountKeeper *authkeeper.AccountKeeper + stakingKeeper *stakingkeeper.Keeper + transferKeeper ibctransferkeeper.Keeper + wasmKeeper *wasmkeeper.PermissionedKeeper + + cachedFeeCollectorAddressMtx *sync.RWMutex + cachedFeeCollectorAddress *common.Address + nonceMx *sync.RWMutex + pendingTxs map[string][]*PendingTx + keyToNonce map[tmtypes.TxKey]*AddressNoncePair + + QueryConfig *querier.Config + + // only used during ETH replay. Not used in chain critical path. + EthClient *ethclient.Client + EthReplayConfig replay.Config + + // only used during blocktest. Not used in chain critical path. + EthBlockTestConfig blocktest.Config + BlockTest *tests.BlockTest + + // used for both ETH replay and block tests. Not used in chain critical path. + Trie ethstate.Trie + DB ethstate.Database + Root common.Hash + ReplayBlock *ethtypes.Block +} + +type EvmTxDeferredInfo struct { + TxIndx int + TxHash common.Hash + TxBloom ethtypes.Bloom + Surplus sdk.Int + Error string +} + +type AddressNoncePair struct { + Address common.Address + Nonce uint64 +} + +type PendingTx struct { + Key tmtypes.TxKey + Nonce uint64 + Priority int64 +} + +// only used during ETH replay +type ReplayChainContext struct { + ethClient *ethclient.Client +} + +func (ctx *ReplayChainContext) Engine() consensus.Engine { + return nil +} + +func (ctx *ReplayChainContext) GetHeader(hash common.Hash, number uint64) *ethtypes.Header { + res, err := ctx.ethClient.BlockByNumber(context.Background(), big.NewInt(int64(number))) + if err != nil || res.Header_.Hash() != hash { + return nil + } + return res.Header_ +} + +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 { + if !paramstore.HasKeyTable() { + paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) + } + k := &Keeper{ + storeKey: storeKey, + memStoreKey: memStoreKey, + Paramstore: paramstore, + bankKeeper: bankKeeper, + accountKeeper: accountKeeper, + stakingKeeper: stakingKeeper, + transferKeeper: transferKeeper, + wasmKeeper: wasmKeeper, + pendingTxs: make(map[string][]*PendingTx), + nonceMx: &sync.RWMutex{}, + cachedFeeCollectorAddressMtx: &sync.RWMutex{}, + keyToNonce: make(map[tmtypes.TxKey]*AddressNoncePair), + deferredInfo: &sync.Map{}, + } + return k +} + +func (k *Keeper) AccountKeeper() *authkeeper.AccountKeeper { + return k.accountKeeper +} + +func (k *Keeper) BankKeeper() bankkeeper.Keeper { + return k.bankKeeper +} + +func (k *Keeper) WasmKeeper() *wasmkeeper.PermissionedKeeper { + return k.wasmKeeper +} + +func (k *Keeper) GetStoreKey() sdk.StoreKey { + return k.storeKey +} + +func (k *Keeper) PrefixStore(ctx sdk.Context, pref []byte) sdk.KVStore { + store := ctx.KVStore(k.GetStoreKey()) + return prefix.NewStore(store, pref) +} + +func (k *Keeper) PurgePrefix(ctx sdk.Context, pref []byte) { + store := k.PrefixStore(ctx, pref) + if err := store.DeleteAll(nil, nil); err != nil { + panic(err) + } +} + +func (k *Keeper) GetVMBlockContext(ctx sdk.Context, gp core.GasPool) (*vm.BlockContext, error) { + if k.EthBlockTestConfig.Enabled { + return k.getBlockTestBlockCtx(ctx) + } + if k.EthReplayConfig.Enabled { + return k.getReplayBlockCtx(ctx) + } + coinbase, err := k.GetFeeCollectorAddress(ctx) + if err != nil { + return nil, err + } + r, err := ctx.BlockHeader().Time.MarshalBinary() + if err != nil { + return nil, err + } + rh := common.BytesToHash(r) + + txfer := func(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { + if IsPayablePrecompile(&recipient) { + state.TransferWithoutEvents(db, sender, recipient, amount) + } else { + core.Transfer(db, sender, recipient, amount) + } + } + + return &vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: txfer, + GetHash: k.GetHashFn(ctx), + Coinbase: coinbase, + GasLimit: gp.Gas(), + BlockNumber: big.NewInt(ctx.BlockHeight()), + Time: uint64(ctx.BlockHeader().Time.Unix()), + Difficulty: utils.Big0, // only needed for PoW + BaseFee: k.GetBaseFeePerGas(ctx).TruncateInt().BigInt(), // feemarket not enabled + Random: &rh, + }, nil +} + +// returns a function that provides block header hash based on block number +func (k *Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc { + return func(height uint64) common.Hash { + if height > math.MaxInt64 { + ctx.Logger().Error("Sei block height is bounded by int64 range") + return common.Hash{} + } + h := int64(height) + if ctx.BlockHeight() == h { + // current header hash is in the context already + return common.BytesToHash(ctx.HeaderHash()) + } + if ctx.BlockHeight() < h { + // future block doesn't have a hash yet + return common.Hash{} + } + // fetch historical hash from historical info + return k.getHistoricalHash(ctx, h) + } +} + +func (k *Keeper) GetEVMTxDeferredInfo(ctx sdk.Context) (res []EvmTxDeferredInfo) { + k.deferredInfo.Range(func(key, value any) bool { + txIdx := key.(int) + if txIdx < 0 || txIdx >= len(k.txResults) { + ctx.Logger().Error(fmt.Sprintf("getting invalid tx index in EVM deferred info: %d, num of txs: %d", txIdx, len(k.txResults))) + return true + } + if k.txResults[txIdx].Code == 0 || value.(*EvmTxDeferredInfo).Error != "" { + res = append(res, *(value.(*EvmTxDeferredInfo))) + } + return true + }) + sort.SliceStable(res, func(i, j int) bool { return res[i].TxIndx < res[j].TxIndx }) + return +} + +func (k *Keeper) AppendToEvmTxDeferredInfo(ctx sdk.Context, bloom ethtypes.Bloom, txHash common.Hash, surplus sdk.Int) { + k.deferredInfo.Store(ctx.TxIndex(), &EvmTxDeferredInfo{ + TxIndx: ctx.TxIndex(), + TxBloom: bloom, + TxHash: txHash, + Surplus: surplus, + }) +} + +func (k *Keeper) AppendErrorToEvmTxDeferredInfo(ctx sdk.Context, txHash common.Hash, err string) { + k.deferredInfo.Store(ctx.TxIndex(), &EvmTxDeferredInfo{ + TxIndx: ctx.TxIndex(), + TxHash: txHash, + Error: err, + }) +} + +func (k *Keeper) ClearEVMTxDeferredInfo() { + k.deferredInfo = &sync.Map{} +} + +func (k *Keeper) getHistoricalHash(ctx sdk.Context, h int64) common.Hash { + histInfo, found := k.stakingKeeper.GetHistoricalInfo(ctx, h) + if !found { + // too old, already pruned + return common.Hash{} + } + header, _ := tmtypes.HeaderFromProto(&histInfo.Header) + + return common.BytesToHash(header.Hash()) +} + +// CalculateNextNonce calculates the next nonce for an address +// If includePending is true, it will consider pending nonces +// If includePending is false, it will only return the next nonce from GetNonce +func (k *Keeper) CalculateNextNonce(ctx sdk.Context, addr common.Address, includePending bool) uint64 { + k.nonceMx.Lock() + defer k.nonceMx.Unlock() + + nextNonce := k.GetNonce(ctx, addr) + + // we only want the latest nonce if we're not including pending + if !includePending { + return nextNonce + } + + // get the pending nonces (nil is fine) + pending := k.pendingTxs[addr.Hex()] + + // Check each nonce starting from latest until we find a gap + // That gap is the next nonce we should use. + for ; ; nextNonce++ { + // if it's not in pending, then it's the next nonce + if _, found := sort.Find(len(pending), func(i int) int { return uint64Cmp(nextNonce, pending[i].Nonce) }); !found { + return nextNonce + } + } +} + +// AddPendingNonce adds a pending nonce to the keeper +func (k *Keeper) AddPendingNonce(key tmtypes.TxKey, addr common.Address, nonce uint64, priority int64) { + k.nonceMx.Lock() + defer k.nonceMx.Unlock() + + addrStr := addr.Hex() + if existing, ok := k.keyToNonce[key]; ok { + if existing.Nonce != nonce { + fmt.Printf("Seeing transactions with the same hash %X but different nonces (%d vs. %d), which should be impossible\n", key, nonce, existing.Nonce) + } + if existing.Address != addr { + fmt.Printf("Seeing transactions with the same hash %X but different addresses (%s vs. %s), which should be impossible\n", key, addr.Hex(), existing.Address.Hex()) + } + // we want to no-op whether it's a genuine duplicate or not + return + } + for _, pendingTx := range k.pendingTxs[addrStr] { + if pendingTx.Nonce == nonce { + if priority > pendingTx.Priority { + // replace existing tx + delete(k.keyToNonce, pendingTx.Key) + pendingTx.Priority = priority + pendingTx.Key = key + k.keyToNonce[key] = &AddressNoncePair{ + Address: addr, + Nonce: nonce, + } + } + // we don't need to return error here if priority is lower. + // Tendermint will take care of rejecting the tx from mempool + return + } + } + k.keyToNonce[key] = &AddressNoncePair{ + Address: addr, + Nonce: nonce, + } + k.pendingTxs[addrStr] = append(k.pendingTxs[addrStr], &PendingTx{ + Key: key, + Nonce: nonce, + Priority: priority, + }) + slices.SortStableFunc(k.pendingTxs[addrStr], func(a, b *PendingTx) int { + if a.Nonce < b.Nonce { + return -1 + } else if a.Nonce > b.Nonce { + return 1 + } + return 0 + }) +} + +// RemovePendingNonce removes a pending nonce from the keeper but leaves a hole +// so that a future transaction must use this nonce. +func (k *Keeper) RemovePendingNonce(key tmtypes.TxKey) { + k.nonceMx.Lock() + defer k.nonceMx.Unlock() + tx, ok := k.keyToNonce[key] + + if !ok { + return + } + + delete(k.keyToNonce, key) + + addr := tx.Address.Hex() + pendings := k.pendingTxs[addr] + firstMatch, found := sort.Find(len(pendings), func(i int) int { return uint64Cmp(tx.Nonce, pendings[i].Nonce) }) + if !found { + fmt.Printf("Removing tx %X without a corresponding pending nonce, which should not happen\n", key) + return + } + k.pendingTxs[addr] = append(k.pendingTxs[addr][:firstMatch], k.pendingTxs[addr][firstMatch+1:]...) + if len(k.pendingTxs[addr]) == 0 { + delete(k.pendingTxs, addr) + } +} + +func (k *Keeper) SetTxResults(txResults []*abci.ExecTxResult) { + k.txResults = txResults +} + +// Test use only +func (k *Keeper) GetPendingTxs() map[string][]*PendingTx { + return k.pendingTxs +} + +// Test use only +func (k *Keeper) GetKeysToNonces() map[tmtypes.TxKey]*AddressNoncePair { + return k.keyToNonce +} + +// Only used in ETH replay +func (k *Keeper) PrepareReplayedAddr(ctx sdk.Context, addr common.Address) { + if !k.EthReplayConfig.Enabled { + return + } + store := k.PrefixStore(ctx, types.ReplaySeenAddrPrefix) + bz := store.Get(addr[:]) + if len(bz) > 0 { + return + } + a, err := k.Trie.GetAccount(addr) + if err != nil || a == nil { + return + } + store.Set(addr[:], a.Root[:]) + if a.Balance != nil && a.Balance.Cmp(utils.Big0) != 0 { + usei, wei := state.SplitUseiWeiAmount(a.Balance) + err = k.BankKeeper().AddCoins(ctx, k.GetSeiAddressOrDefault(ctx, addr), sdk.NewCoins(sdk.NewCoin("usei", usei)), true) + if err != nil { + panic(err) + } + err = k.BankKeeper().AddWei(ctx, k.GetSeiAddressOrDefault(ctx, addr), wei) + if err != nil { + panic(err) + } + } + k.SetNonce(ctx, addr, a.Nonce) + if !bytes.Equal(a.CodeHash, ethtypes.EmptyCodeHash.Bytes()) { + k.PrefixStore(ctx, types.CodeHashKeyPrefix).Set(addr[:], a.CodeHash) + code, err := k.DB.ContractCode(addr, common.BytesToHash(a.CodeHash)) + if err != nil { + panic(err) + } + if len(code) > 0 { + k.PrefixStore(ctx, types.CodeKeyPrefix).Set(addr[:], code) + length := make([]byte, 8) + binary.BigEndian.PutUint64(length, uint64(len(code))) + k.PrefixStore(ctx, types.CodeSizeKeyPrefix).Set(addr[:], length) + } + } +} + +func (k *Keeper) GetBaseFee(ctx sdk.Context) *big.Int { + if k.EthReplayConfig.Enabled { + return k.ReplayBlock.Header_.BaseFee + } + if k.EthBlockTestConfig.Enabled { + bb := k.BlockTest.Json.Blocks[ctx.BlockHeight()-1] + b, err := bb.Decode() + if err != nil { + panic(err) + } + return b.Header_.BaseFee + } + return nil +} + +func (k *Keeper) GetReplayedHeight(ctx sdk.Context) int64 { + return k.getInt64State(ctx, types.ReplayedHeight) +} + +func (k *Keeper) SetReplayedHeight(ctx sdk.Context) { + k.setInt64State(ctx, types.ReplayedHeight, ctx.BlockHeight()) +} + +func (k *Keeper) GetReplayInitialHeight(ctx sdk.Context) int64 { + return k.getInt64State(ctx, types.ReplayInitialHeight) +} + +func (k *Keeper) SetReplayInitialHeight(ctx sdk.Context, h int64) { + k.setInt64State(ctx, types.ReplayInitialHeight, h) +} + +func (k *Keeper) setInt64State(ctx sdk.Context, key []byte, val int64) { + store := ctx.KVStore(k.storeKey) + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, uint64(val)) + store.Set(key, bz) +} + +func (k *Keeper) getInt64State(ctx sdk.Context, key []byte) int64 { + store := ctx.KVStore(k.storeKey) + bz := store.Get(key) + if bz == nil { + return 0 + } + return int64(binary.BigEndian.Uint64(bz)) +} + +func (k *Keeper) getBlockTestBlockCtx(ctx sdk.Context) (*vm.BlockContext, error) { + bb := k.BlockTest.Json.Blocks[ctx.BlockHeight()-1] + b, err := bb.Decode() + if err != nil { + return nil, err + } + header := b.Header_ + getHash := func(height uint64) common.Hash { + height = height + 1 + for i := 0; i < len(k.BlockTest.Json.Blocks); i++ { + if k.BlockTest.Json.Blocks[i].BlockHeader.Number.Uint64() == height { + return k.BlockTest.Json.Blocks[i].BlockHeader.Hash + } + } + panic(fmt.Sprintf("block hash not found for height %d", height)) + } + var ( + baseFee *big.Int + blobBaseFee *big.Int + random *common.Hash + ) + if header.BaseFee != nil { + baseFee = new(big.Int).Set(header.BaseFee) + } + if header.ExcessBlobGas != nil { + blobBaseFee = eip4844.CalcBlobFee(*header.ExcessBlobGas) + } else { + blobBaseFee = eip4844.CalcBlobFee(0) + } + if header.Difficulty.Cmp(common.Big0) == 0 { + random = &header.MixDigest + } + return &vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + GetHash: getHash, + Coinbase: header.Coinbase, + GasLimit: header.GasLimit, + BlockNumber: new(big.Int).Set(header.Number), + Time: header.Time, + Difficulty: new(big.Int).Set(header.Difficulty), + BaseFee: baseFee, + BlobBaseFee: blobBaseFee, + Random: random, + }, nil +} + +func (k *Keeper) getReplayBlockCtx(ctx sdk.Context) (*vm.BlockContext, error) { + header := k.ReplayBlock.Header_ + getHash := core.GetHashFn(header, &ReplayChainContext{ethClient: k.EthClient}) + var ( + baseFee *big.Int + blobBaseFee *big.Int + random *common.Hash + ) + if header.BaseFee != nil { + baseFee = new(big.Int).Set(header.BaseFee) + } + if header.ExcessBlobGas != nil { + blobBaseFee = eip4844.CalcBlobFee(*header.ExcessBlobGas) + } + if header.Difficulty.Cmp(common.Big0) == 0 { + random = &header.MixDigest + } + return &vm.BlockContext{ + CanTransfer: core.CanTransfer, + Transfer: core.Transfer, + GetHash: getHash, + Coinbase: header.Coinbase, + GasLimit: header.GasLimit, + BlockNumber: new(big.Int).Set(header.Number), + Time: header.Time, + Difficulty: new(big.Int).Set(header.Difficulty), + BaseFee: baseFee, + BlobBaseFee: blobBaseFee, + Random: random, + }, nil +} + +func uint64Cmp(a, b uint64) int { + if a < b { + return -1 + } else if a == b { + return 0 + } + return 1 +} diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go new file mode 100644 index 0000000000..9da18560ff --- /dev/null +++ b/x/evm/keeper/keeper_test.go @@ -0,0 +1,234 @@ +package keeper_test + +import ( + "math" + "sync" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/sei-protocol/sei-chain/testutil/keeper" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/rand" + tmtypes "github.com/tendermint/tendermint/types" +) + +func TestPurgePrefixNotHang(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + _, evmAddr := keeper.MockAddressPair() + for i := 0; i < 50; i++ { + ctx = ctx.WithMultiStore(ctx.MultiStore().CacheMultiStore()) + store := k.PrefixStore(ctx, types.StateKey(evmAddr)) + store.Set([]byte{0x03}, []byte("test")) + } + require.NotPanics(t, func() { k.PurgePrefix(ctx, types.StateKey(evmAddr)) }) +} + +func TestGetChainID(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + require.Equal(t, types.DefaultChainID.Int64(), k.ChainID(ctx).Int64()) +} + +func TestGetVMBlockContext(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + moduleAddr := k.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName) + evmAddr, _ := k.GetEVMAddress(ctx, moduleAddr) + k.DeleteAddressMapping(ctx, moduleAddr, evmAddr) + _, err := k.GetVMBlockContext(ctx, 0) + require.NotNil(t, err) +} + +func TestGetHashFn(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + f := k.GetHashFn(ctx) + require.Equal(t, common.Hash{}, f(math.MaxInt64+1)) + require.Equal(t, common.BytesToHash(ctx.HeaderHash()), f(uint64(ctx.BlockHeight()))) + require.Equal(t, common.Hash{}, f(uint64(ctx.BlockHeight())+1)) + require.Equal(t, common.Hash{}, f(uint64(ctx.BlockHeight())-1)) +} + +func TestKeeper_CalculateNextNonce(t *testing.T) { + address1 := common.BytesToAddress([]byte("addr1")) + key1 := tmtypes.TxKey(rand.NewRand().Bytes(32)) + key2 := tmtypes.TxKey(rand.NewRand().Bytes(32)) + tests := []struct { + name string + address common.Address + pending bool + setup func(ctx sdk.Context, k *evmkeeper.Keeper) + expectedNonce uint64 + }{ + { + name: "latest block, no latest stored", + address: address1, + pending: false, + expectedNonce: 0, + }, + { + name: "latest block, latest stored", + address: address1, + pending: false, + setup: func(ctx sdk.Context, k *evmkeeper.Keeper) { + k.SetNonce(ctx, address1, 50) + }, + expectedNonce: 50, + }, + { + name: "latest block, latest stored with pending nonces", + address: address1, + pending: false, + setup: func(ctx sdk.Context, k *evmkeeper.Keeper) { + k.SetNonce(ctx, address1, 50) + // because pending:false, these won't matter + k.AddPendingNonce(key1, address1, 50, 0) + k.AddPendingNonce(key2, address1, 51, 0) + }, + expectedNonce: 50, + }, + { + name: "pending block, nonce should follow the last pending", + address: address1, + pending: true, + setup: func(ctx sdk.Context, k *evmkeeper.Keeper) { + k.SetNonce(ctx, address1, 50) + k.AddPendingNonce(key1, address1, 50, 0) + k.AddPendingNonce(key2, address1, 51, 0) + }, + expectedNonce: 52, + }, + { + name: "pending block, nonce should be the value of hole", + address: address1, + pending: true, + setup: func(ctx sdk.Context, k *evmkeeper.Keeper) { + k.SetNonce(ctx, address1, 50) + k.AddPendingNonce(key1, address1, 50, 0) + // missing 51, so nonce = 51 + k.AddPendingNonce(key2, address1, 52, 0) + }, + expectedNonce: 51, + }, + { + name: "pending block, completed nonces should also be skipped", + address: address1, + pending: true, + setup: func(ctx sdk.Context, k *evmkeeper.Keeper) { + k.SetNonce(ctx, address1, 50) + k.AddPendingNonce(key1, address1, 50, 0) + k.AddPendingNonce(key2, address1, 51, 0) + k.SetNonce(ctx, address1, 52) + k.RemovePendingNonce(key1) + k.RemovePendingNonce(key2) + }, + expectedNonce: 52, + }, + { + name: "pending block, hole created by expiration", + address: address1, + pending: true, + setup: func(ctx sdk.Context, k *evmkeeper.Keeper) { + k.SetNonce(ctx, address1, 50) + k.AddPendingNonce(key1, address1, 50, 0) + k.AddPendingNonce(key2, address1, 51, 0) + k.RemovePendingNonce(key1) + }, + expectedNonce: 50, + }, + { + name: "pending block, skipped nonces all in pending", + address: address1, + pending: true, + setup: func(ctx sdk.Context, k *evmkeeper.Keeper) { + // next expected for latest is 50, but 51,52 were sent + k.SetNonce(ctx, address1, 50) + k.AddPendingNonce(key1, address1, 51, 0) + k.AddPendingNonce(key2, address1, 52, 0) + }, + expectedNonce: 50, + }, + { + name: "try 1000 nonces concurrently", + address: address1, + pending: true, + setup: func(ctx sdk.Context, k *evmkeeper.Keeper) { + // next expected for latest is 50, but 51,52 were sent + k.SetNonce(ctx, address1, 50) + wg := sync.WaitGroup{} + for i := 50; i < 1000; i++ { + wg.Add(1) + go func(nonce int) { + defer wg.Done() + key := tmtypes.TxKey(rand.NewRand().Bytes(32)) + // call this just to exercise locks + k.CalculateNextNonce(ctx, address1, true) + k.AddPendingNonce(key, address1, uint64(nonce), 0) + }(i) + } + wg.Wait() + }, + expectedNonce: 1000, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + if test.setup != nil { + test.setup(ctx, k) + } + next := k.CalculateNextNonce(ctx, test.address, test.pending) + require.Equal(t, test.expectedNonce, next) + }) + } +} + +func TestDeferredInfo(t *testing.T) { + k, ctx := keeper.MockEVMKeeper() + ctx = ctx.WithTxIndex(1) + k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{1, 2, 3}, common.Hash{4, 5, 6}, sdk.NewInt(1)) + ctx = ctx.WithTxIndex(2) + k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{7, 8}, common.Hash{9, 0}, sdk.NewInt(1)) + ctx = ctx.WithTxIndex(3) // should be ignored because txResult has non-zero code + k.AppendToEvmTxDeferredInfo(ctx, ethtypes.Bloom{11, 12}, common.Hash{13, 14}, sdk.NewInt(1)) + k.SetTxResults([]*abci.ExecTxResult{{Code: 0}, {Code: 0}, {Code: 0}, {Code: 1}}) + infoList := k.GetEVMTxDeferredInfo(ctx) + require.Equal(t, 2, len(infoList)) + require.Equal(t, 1, infoList[0].TxIndx) + require.Equal(t, ethtypes.Bloom{1, 2, 3}, infoList[0].TxBloom) + require.Equal(t, common.Hash{4, 5, 6}, infoList[0].TxHash) + require.Equal(t, sdk.NewInt(1), infoList[0].Surplus) + require.Equal(t, 2, infoList[1].TxIndx) + require.Equal(t, ethtypes.Bloom{7, 8}, infoList[1].TxBloom) + require.Equal(t, common.Hash{9, 0}, infoList[1].TxHash) + require.Equal(t, sdk.NewInt(1), infoList[1].Surplus) + // test clear tx deferred info + k.ClearEVMTxDeferredInfo() + infoList = k.GetEVMTxDeferredInfo(ctx) + require.Empty(t, len(infoList)) +} + +func TestAddPendingNonce(t *testing.T) { + k, _ := keeper.MockEVMKeeper() + k.AddPendingNonce(tmtypes.TxKey{1}, common.HexToAddress("123"), 1, 1) + k.AddPendingNonce(tmtypes.TxKey{2}, common.HexToAddress("123"), 2, 1) + k.AddPendingNonce(tmtypes.TxKey{3}, common.HexToAddress("123"), 2, 2) // should replace the one above + pendingTxs := k.GetPendingTxs()[common.HexToAddress("123").Hex()] + require.Equal(t, 2, len(pendingTxs)) + require.Equal(t, tmtypes.TxKey{1}, pendingTxs[0].Key) + require.Equal(t, uint64(1), pendingTxs[0].Nonce) + require.Equal(t, int64(1), pendingTxs[0].Priority) + require.Equal(t, tmtypes.TxKey{3}, pendingTxs[1].Key) + require.Equal(t, uint64(2), pendingTxs[1].Nonce) + require.Equal(t, int64(2), pendingTxs[1].Priority) + keyToNonce := k.GetKeysToNonces() + require.Equal(t, common.HexToAddress("123"), keyToNonce[tmtypes.TxKey{1}].Address) + require.Equal(t, uint64(1), keyToNonce[tmtypes.TxKey{1}].Nonce) + require.Equal(t, common.HexToAddress("123"), keyToNonce[tmtypes.TxKey{3}].Address) + require.Equal(t, uint64(2), keyToNonce[tmtypes.TxKey{3}].Nonce) + require.NotContains(t, keyToNonce, tmtypes.TxKey{2}) +} diff --git a/x/evm/keeper/log.go b/x/evm/keeper/log.go new file mode 100644 index 0000000000..c7012780c8 --- /dev/null +++ b/x/evm/keeper/log.go @@ -0,0 +1,60 @@ +package keeper + +import ( + "bytes" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/bitutil" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func (k *Keeper) GetBlockBloom(ctx sdk.Context, height int64) (res ethtypes.Bloom) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.BlockBloomKey(height)) + if bz != nil { + res.SetBytes(bz) + } + return +} + +func (k *Keeper) SetBlockBloom(ctx sdk.Context, height int64, blooms []ethtypes.Bloom) { + blockBloom := make([]byte, ethtypes.BloomByteLength) + for _, bloom := range blooms { + or := make([]byte, ethtypes.BloomByteLength) + bitutil.ORBytes(or, blockBloom, bloom[:]) + blockBloom = or + } + if bytes.Equal(blockBloom, make([]byte, ethtypes.BloomByteLength)) { + // early return if bloom is empty + return + } + store := ctx.KVStore(k.storeKey) + store.Set(types.BlockBloomKey(height), blockBloom) +} + +func GetLogsForTx(receipt *types.Receipt) []*ethtypes.Log { + return utils.Map(receipt.Logs, func(l *types.Log) *ethtypes.Log { return convertLog(l, receipt) }) +} + +func convertLog(l *types.Log, receipt *types.Receipt) *ethtypes.Log { + return ðtypes.Log{ + Address: common.HexToAddress(l.Address), + Topics: utils.Map(l.Topics, common.HexToHash), + Data: l.Data, + BlockNumber: receipt.BlockNumber, + TxHash: common.HexToHash(receipt.TxHashHex), + TxIndex: uint(receipt.TransactionIndex), + Index: uint(l.Index)} +} + +func ConvertEthLog(l *ethtypes.Log) *types.Log { + return &types.Log{ + Address: l.Address.Hex(), + Topics: utils.Map(l.Topics, func(h common.Hash) string { return h.Hex() }), + Data: l.Data, + Index: uint32(l.Index), + } +} diff --git a/x/evm/keeper/log_test.go b/x/evm/keeper/log_test.go new file mode 100644 index 0000000000..8f3644d00d --- /dev/null +++ b/x/evm/keeper/log_test.go @@ -0,0 +1,83 @@ +package keeper + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" + + evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func TestConvertEthLog(t *testing.T) { + // Create a sample ethtypes.Log object + ethLog := &types.Log{ + Address: common.HexToAddress("0x123"), + Topics: []common.Hash{ + common.HexToHash("0x456"), + common.HexToHash("0x789"), + }, + Data: []byte("data"), + BlockNumber: 1, + TxHash: common.HexToHash("0xabc"), + TxIndex: 2, + Index: 3, + } + + // Convert the ethtypes.Log to a types.Log + log := ConvertEthLog(ethLog) + + // Check that the fields match + require.Equal(t, ethLog.Address.Hex(), log.Address) + require.Equal(t, len(ethLog.Topics), len(log.Topics)) + for i, topic := range ethLog.Topics { + require.Equal(t, topic.Hex(), log.Topics[i]) + } + require.Equal(t, ethLog.Data, log.Data) + require.Equal(t, uint32(ethLog.Index), log.Index) +} + +func TestGetLogsForTx(t *testing.T) { + // Create a sample types.Receipt object with a list of types.Log objects + receipt := &evmtypes.Receipt{ + Logs: []*evmtypes.Log{ + { + Address: common.HexToAddress("0x123").Hex(), + Topics: []string{ + "0x0000000000000000000000000000000000000000000000000000000000000456", + "0x0000000000000000000000000000000000000000000000000000000000000789", + }, + Data: []byte("data"), + Index: 3, + }, + { + Address: common.HexToAddress("0x123").Hex(), + Topics: []string{ + "0x0000000000000000000000000000000000000000000000000000000000000def", + "0x0000000000000000000000000000000000000000000000000000000000000123", + }, + Data: []byte("data2"), + Index: 4, + }, + }, + BlockNumber: 1, + TransactionIndex: 2, + TxHashHex: "0xabc", + } + + // Convert the types.Receipt to a list of ethtypes.Log objects + logs := GetLogsForTx(receipt) + + // Check that the fields match + require.Equal(t, len(receipt.Logs), len(logs)) + for i, log := range logs { + require.Equal(t, receipt.Logs[i].Address, log.Address.Hex()) + require.Equal(t, len(receipt.Logs[i].Topics), len(log.Topics)) + for j, topic := range log.Topics { + require.Equal(t, receipt.Logs[i].Topics[j], topic.Hex()) + } + require.Equal(t, receipt.Logs[i].Data, log.Data) + require.Equal(t, uint(receipt.Logs[i].Index), log.Index) + } +} diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go new file mode 100644 index 0000000000..d589273acd --- /dev/null +++ b/x/evm/keeper/msg_server.go @@ -0,0 +1,315 @@ +package keeper + +import ( + "context" + "encoding/binary" + "encoding/json" + "fmt" + "math" + "math/big" + "runtime/debug" + + "github.com/armon/go-metrics" + "github.com/cosmos/cosmos-sdk/store/prefix" + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/common" + cmath "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + artifactsutils "github.com/sei-protocol/sei-chain/x/evm/artifacts/utils" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +type msgServer struct { + *Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper *Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +func (server msgServer) EVMTransaction(goCtx context.Context, msg *types.MsgEVMTransaction) (serverRes *types.MsgEVMTransactionResponse, err error) { + if msg.IsAssociateTx() { + // no-op in msg server for associate tx; all the work have been done in ante handler + return &types.MsgEVMTransactionResponse{}, nil + } + ctx := sdk.UnwrapSDKContext(goCtx) + // EVM has a special case here, mainly because for an EVM transaction the gas limit is set on EVM payload level, not on top-level GasWanted field + // as normal transactions (because existing eth client can't). As a result EVM has its own dedicated ante handler chain. The full sequence is: + + // 1. At the beginning of the ante handler chain, gas meter is set to infinite so that the ante processing itself won't run out of gas (EVM ante is pretty light but it does read a parameter or two) + // 2. At the end of the ante handler chain, gas meter is set based on the gas limit specified in the EVM payload; this is only to provide a GasWanted return value to tendermint mempool when CheckTx returns, and not used for anything else. + // 3. At the beginning of message server (here), gas meter is set to infinite again, because EVM internal logic will then take over and manage out-of-gas scenarios. + // 4. At the end of message server, gas consumed by EVM is adjusted to Sei's unit and counted in the original gas meter, because that original gas meter will be used to count towards block gas after message server returns + originalGasMeter := ctx.GasMeter() + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) + + stateDB := state.NewDBImpl(ctx, &server, false) + tx, _ := msg.AsTransaction() + ctx, gp := server.getGasPool(ctx) + emsg := server.getEVMMessage(ctx, tx, msg.Derived.SenderEVMAddr) + + defer func() { + if pe := recover(); pe != nil { + // there is not supposed to be any panic + debug.PrintStack() + ctx.Logger().Error(fmt.Sprintf("EVM PANIC: %s", pe)) + telemetry.IncrCounter(1, types.ModuleName, "panics") + server.AppendErrorToEvmTxDeferredInfo(ctx, tx.Hash(), fmt.Sprintf("%s", pe)) + + panic(pe) + } + if err != nil { + ctx.Logger().Error(fmt.Sprintf("Got EVM state transition error (not VM error): %s", err)) + + telemetry.IncrCounterWithLabels( + []string{types.ModuleName, "errors", "state_transition"}, + 1, + []metrics.Label{ + telemetry.NewLabel("type", err.Error()), + }, + ) + return + } + receipt, err := server.writeReceipt(ctx, msg, tx, emsg, serverRes, stateDB) + if err != nil { + ctx.Logger().Error(fmt.Sprintf("failed to write EVM receipt: %s", err)) + + telemetry.IncrCounterWithLabels( + []string{types.ModuleName, "errors", "write_receipt"}, + 1, + []metrics.Label{ + telemetry.NewLabel("type", err.Error()), + }, + ) + return + } + surplus, ferr := stateDB.Finalize() + if ferr != nil { + err = ferr + ctx.Logger().Error(fmt.Sprintf("failed to finalize EVM stateDB: %s", err)) + + telemetry.IncrCounterWithLabels( + []string{types.ModuleName, "errors", "stateDB_finalize"}, + 1, + []metrics.Label{ + telemetry.NewLabel("type", err.Error()), + }, + ) + + return + } + bloom := ethtypes.Bloom{} + bloom.SetBytes(receipt.LogsBloom) + server.AppendToEvmTxDeferredInfo(ctx, bloom, tx.Hash(), surplus) + + // GasUsed in serverRes is in EVM's gas unit, not Sei's gas unit. + // PriorityNormalizer is the coefficient that's used to adjust EVM + // transactions' priority, which is based on gas limit in EVM unit, + // to Sei transactions' priority, which is based on gas limit in + // Sei unit, so we use the same coefficient to convert gas unit here. + adjustedGasUsed := server.GetPriorityNormalizer(ctx).MulInt64(int64(serverRes.GasUsed)) + originalGasMeter.ConsumeGas(adjustedGasUsed.TruncateInt().Uint64(), "evm transaction") + }() + + res, applyErr := server.applyEVMMessage(ctx, emsg, stateDB, gp) + serverRes = &types.MsgEVMTransactionResponse{ + Hash: tx.Hash().Hex(), + } + if applyErr != nil { + // This should not happen, as anything that could cause applyErr is supposed to + // be checked in CheckTx first + err = applyErr + + telemetry.IncrCounterWithLabels( + []string{types.ModuleName, "errors", "apply_message"}, + 1, + []metrics.Label{ + telemetry.NewLabel("type", err.Error()), + }, + ) + + } else { + // if applyErr is nil then res must be non-nil + if res.Err != nil { + serverRes.VmError = res.Err.Error() + + telemetry.IncrCounterWithLabels( + []string{types.ModuleName, "errors", "vm_execution"}, + 1, + []metrics.Label{ + telemetry.NewLabel("type", serverRes.VmError), + }, + ) + } + serverRes.GasUsed = res.UsedGas + serverRes.ReturnData = res.ReturnData + } + + return +} + +func (k *Keeper) getGasPool(ctx sdk.Context) (sdk.Context, core.GasPool) { + return ctx, math.MaxUint64 +} + +func (server msgServer) getEVMMessage(ctx sdk.Context, tx *ethtypes.Transaction, sender common.Address) *core.Message { + msg := &core.Message{ + Nonce: tx.Nonce(), + GasLimit: tx.Gas(), + GasPrice: new(big.Int).Set(tx.GasPrice()), + GasFeeCap: new(big.Int).Set(tx.GasFeeCap()), + GasTipCap: new(big.Int).Set(tx.GasTipCap()), + To: tx.To(), + Value: tx.Value(), + Data: tx.Data(), + AccessList: tx.AccessList(), + SkipAccountChecks: false, + BlobHashes: tx.BlobHashes(), + BlobGasFeeCap: tx.BlobGasFeeCap(), + From: sender, + } + // If baseFee provided, set gasPrice to effectiveGasPrice. + baseFee := server.GetBaseFee(ctx) + if baseFee != nil { + msg.GasPrice = cmath.BigMin(msg.GasPrice.Add(msg.GasTipCap, baseFee), msg.GasFeeCap) + } + return msg +} + +func (server msgServer) applyEVMMessage(ctx sdk.Context, msg *core.Message, stateDB *state.DBImpl, gp core.GasPool) (*core.ExecutionResult, error) { + blockCtx, err := server.GetVMBlockContext(ctx, gp) + if err != nil { + return nil, err + } + cfg := types.DefaultChainConfig().EthereumConfig(server.ChainID(ctx)) + txCtx := core.NewEVMTxContext(msg) + evmInstance := vm.NewEVM(*blockCtx, txCtx, stateDB, cfg, vm.Config{}) + stateDB.SetEVM(evmInstance) + st := core.NewStateTransition(evmInstance, msg, &gp) + res, err := st.TransitionDb() + return res, err +} + +func (server msgServer) writeReceipt(ctx sdk.Context, origMsg *types.MsgEVMTransaction, tx *ethtypes.Transaction, msg *core.Message, response *types.MsgEVMTransactionResponse, stateDB *state.DBImpl) (*types.Receipt, error) { + ethLogs := stateDB.GetAllLogs() + bloom := ethtypes.CreateBloom(ethtypes.Receipts{ðtypes.Receipt{Logs: ethLogs}}) + receipt := &types.Receipt{ + TxType: uint32(tx.Type()), + CumulativeGasUsed: uint64(0), + TxHashHex: tx.Hash().Hex(), + GasUsed: response.GasUsed, + BlockNumber: uint64(ctx.BlockHeight()), + TransactionIndex: uint32(ctx.TxIndex()), + EffectiveGasPrice: tx.GasPrice().Uint64(), + VmError: response.VmError, + Logs: utils.Map(ethLogs, ConvertEthLog), + LogsBloom: bloom[:], + } + + if msg.To == nil { + receipt.ContractAddress = crypto.CreateAddress(msg.From, msg.Nonce).Hex() + } else { + receipt.To = msg.To.Hex() + if len(msg.Data) > 0 { + receipt.ContractAddress = msg.To.Hex() + } + } + + if response.VmError == "" { + receipt.Status = uint32(ethtypes.ReceiptStatusSuccessful) + } else { + receipt.Status = uint32(ethtypes.ReceiptStatusFailed) + } + + receipt.From = origMsg.Derived.SenderEVMAddr.Hex() + + return receipt, server.SetReceipt(ctx, tx.Hash(), receipt) +} + +func (server msgServer) Send(goCtx context.Context, msg *types.MsgSend) (*types.MsgSendResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + recipient := server.GetSeiAddressOrDefault(ctx, common.HexToAddress(msg.ToAddress)) + _, err := bankkeeper.NewMsgServerImpl(server.BankKeeper()).Send(goCtx, &banktypes.MsgSend{ + FromAddress: msg.FromAddress, + ToAddress: recipient.String(), + Amount: msg.Amount, + }) + if err != nil { + return nil, err + } + return &types.MsgSendResponse{}, nil +} + +func (server msgServer) RegisterPointer(goCtx context.Context, msg *types.MsgRegisterPointer) (*types.MsgRegisterPointerResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + var existingPointer sdk.AccAddress + var existingVersion uint16 + var currentVersion uint16 + var exists bool + switch msg.PointerType { + case types.PointerType_ERC20: + currentVersion = erc20.CurrentVersion + existingPointer, existingVersion, exists = server.GetCW20ERC20Pointer(ctx, common.HexToAddress(msg.ErcAddress)) + case types.PointerType_ERC721: + currentVersion = erc721.CurrentVersion + existingPointer, existingVersion, exists = server.GetCW721ERC721Pointer(ctx, common.HexToAddress(msg.ErcAddress)) + default: + panic("unknown pointer type") + } + if exists && existingVersion >= currentVersion { + return nil, fmt.Errorf("pointer %s already registered at version %d", existingPointer.String(), existingVersion) + } + store := server.PrefixStore(ctx, types.PointerCWCodePrefix) + payload := map[string]interface{}{} + switch msg.PointerType { + case types.PointerType_ERC20: + store = prefix.NewStore(store, types.PointerCW20ERC20Prefix) + payload["erc20_address"] = msg.ErcAddress + case types.PointerType_ERC721: + store = prefix.NewStore(store, types.PointerCW721ERC721Prefix) + payload["erc721_address"] = msg.ErcAddress + default: + panic("unknown pointer type") + } + codeID := binary.BigEndian.Uint64(store.Get(artifactsutils.GetVersionBz(currentVersion))) + bz, err := json.Marshal(payload) + if err != nil { + return nil, err + } + moduleAcct := server.accountKeeper.GetModuleAddress(types.ModuleName) + pointerAddr, _, err := server.wasmKeeper.Instantiate(ctx, codeID, moduleAcct, moduleAcct, bz, fmt.Sprintf("Pointer of %s", msg.ErcAddress), sdk.NewCoins()) + if err != nil { + return nil, err + } + switch msg.PointerType { + case types.PointerType_ERC20: + err = server.SetCW20ERC20Pointer(ctx, common.HexToAddress(msg.ErcAddress), pointerAddr.String()) + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "erc20"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, pointerAddr.String()), sdk.NewAttribute(types.AttributeKeyPointee, msg.ErcAddress), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", erc20.CurrentVersion)))) + case types.PointerType_ERC721: + err = server.SetCW721ERC721Pointer(ctx, common.HexToAddress(msg.ErcAddress), pointerAddr.String()) + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePointerRegistered, sdk.NewAttribute(types.AttributeKeyPointerType, "erc721"), + sdk.NewAttribute(types.AttributeKeyPointerAddress, pointerAddr.String()), sdk.NewAttribute(types.AttributeKeyPointee, msg.ErcAddress), + sdk.NewAttribute(types.AttributeKeyPointerVersion, fmt.Sprintf("%d", erc721.CurrentVersion)))) + default: + panic("unknown pointer type") + } + return &types.MsgRegisterPointerResponse{PointerAddress: pointerAddr.String()}, err +} diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go new file mode 100644 index 0000000000..6dfc666053 --- /dev/null +++ b/x/evm/keeper/msg_server_test.go @@ -0,0 +1,541 @@ +package keeper_test + +import ( + "bytes" + "encoding/hex" + "math/big" + "os" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "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/example/contracts/echo" + "github.com/sei-protocol/sei-chain/example/contracts/sendall" + "github.com/sei-protocol/sei-chain/example/contracts/simplestorage" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/ante" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" +) + +func TestEVMTransaction(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + 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) + + msgServer := keeper.NewMsgServerImpl(k) + + // Deploy Simple Storage contract + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.LessOrEqual(t, res.GasUsed, uint64(200000)) + require.Empty(t, res.VmError) + require.NotEmpty(t, res.ReturnData) + require.NotEmpty(t, res.Hash) + require.Equal(t, uint64(1000000)-res.GasUsed, k.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), "usei").Amount.Uint64()) + require.Equal(t, res.GasUsed, k.BankKeeper().GetBalance(ctx, state.GetCoinbaseAddress(ctx.TxIndex()), k.GetBaseDenom(ctx)).Amount.Uint64()) + receipt, err := k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + require.NotNil(t, receipt) + require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) + + // send transaction to the contract + contractAddr := common.HexToAddress(receipt.ContractAddress) + abi, err := simplestorage.SimplestorageMetaData.GetAbi() + require.Nil(t, err) + bz, err = abi.Pack("set", big.NewInt(20)) + 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) + ante.Preprocess(ctx, req) + res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.LessOrEqual(t, res.GasUsed, uint64(200000)) + require.Empty(t, res.VmError) + receipt, err = k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + require.NotNil(t, receipt) + require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) + stateDB := state.NewDBImpl(ctx, k, false) + val := hex.EncodeToString(bytes.Trim(stateDB.GetState(contractAddr, common.Hash{}).Bytes(), "\x00")) // key is 0x0 since the contract only has one variable + require.Equal(t, "14", val) // value is 0x14 = 20 +} + +func TestEVMTransactionError(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + 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: []byte("123090321920390920123"), // gibberish data + 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) + + msgServer := keeper.NewMsgServerImpl(k) + + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) // there should only be VM error, no msg-level error + require.NotEmpty(t, res.VmError) + // gas should be charged and receipt should be created + require.Equal(t, uint64(800000), k.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), "usei").Amount.Uint64()) + receipt, err := k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + require.Equal(t, uint32(ethtypes.ReceiptStatusFailed), receipt.Status) + // yet there should be no contract state + stateDB := state.NewDBImpl(ctx, k, false) + require.Empty(t, stateDB.GetState(common.HexToAddress(receipt.ContractAddress), common.Hash{})) +} + +func TestEVMTransactionInsufficientGas(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + 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: 1000, + 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(1000))) + k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(1000)))) + k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, evmAddr[:], amt) + + msgServer := keeper.NewMsgServerImpl(k) + + // Deploy Simple Storage contract with insufficient gas + ante.Preprocess(ctx, req) + _, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.NotNil(t, err) + require.Contains(t, err.Error(), "intrinsic gas too low") // this can only happen in test because we didn't call CheckTx in this test +} + +func TestEVMDynamicFeeTransaction(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + 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.DynamicFeeTx{ + GasFeeCap: 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.NewDynamicFeeTx(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) + + msgServer := keeper.NewMsgServerImpl(k) + + // Deploy Simple Storage contract + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.LessOrEqual(t, res.GasUsed, uint64(200000)) + require.Empty(t, res.VmError) + require.NotEmpty(t, res.ReturnData) + require.NotEmpty(t, res.Hash) + require.LessOrEqual(t, k.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), "usei").Amount.Uint64(), uint64(1000000)-res.GasUsed) + receipt, err := k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + require.NotNil(t, receipt) + require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) // value is 0x14 = 20 +} + +func TestEVMPrecompiles(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeperWithPrecompiles() + params := k.GetParams(ctx) + k.SetParams(ctx, params) + code, err := os.ReadFile("../../../example/contracts/sendall/SendAll.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: 500000, + 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) + + msgServer := keeper.NewMsgServerImpl(k) + + // Deploy SendAll contract + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.LessOrEqual(t, res.GasUsed, uint64(500000)) + require.Empty(t, res.VmError) + require.NotEmpty(t, res.ReturnData) + require.NotEmpty(t, res.Hash) + require.Equal(t, uint64(1000000)-res.GasUsed, k.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), "usei").Amount.Uint64()) + require.Equal(t, res.GasUsed, k.BankKeeper().GetBalance(ctx, state.GetCoinbaseAddress(ctx.TxIndex()), k.GetBaseDenom(ctx)).Amount.Uint64()) + receipt, err := k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + require.NotNil(t, receipt) + require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) + k.SetERC20NativePointer(ctx, k.GetBaseDenom(ctx), common.HexToAddress(receipt.ContractAddress)) + + // call sendall + addr1, evmAddr1 := testkeeper.MockAddressPair() + addr2, evmAddr2 := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, addr1, evmAddr1) + k.SetAddressMapping(ctx, addr2, evmAddr2) + err = k.BankKeeper().MintCoins(ctx, types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(100000)))) + require.Nil(t, err) + err = k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr1, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(100000)))) + require.Nil(t, err) + contractAddr := common.HexToAddress(receipt.ContractAddress) + abi, err := sendall.SendallMetaData.GetAbi() + require.Nil(t, err) + bz, err = abi.Pack("sendAll", evmAddr1, evmAddr2, k.GetBaseDenom(ctx)) + 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) + ante.Preprocess(ctx, req) + res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.LessOrEqual(t, res.GasUsed, uint64(200000)) + require.Empty(t, res.VmError) + receipt, err = k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + require.NotNil(t, receipt) + require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) + addr1Balance := k.BankKeeper().GetBalance(ctx, addr1, k.GetBaseDenom(ctx)).Amount.Uint64() + require.Equal(t, uint64(0), addr1Balance) + addr2Balance := k.BankKeeper().GetBalance(ctx, addr2, k.GetBaseDenom(ctx)).Amount.Uint64() + require.Equal(t, uint64(100000), addr2Balance) +} + +func TestEVMAssociateTx(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + req, err := types.NewMsgEVMTransaction(ðtx.AssociateTx{}) + require.Nil(t, err) + msgServer := keeper.NewMsgServerImpl(k) + + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.Equal(t, types.MsgEVMTransactionResponse{}, *res) +} + +func TestEVMBlockEnv(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + code, err := os.ReadFile("../../../example/contracts/echo/Echo.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) + + msgServer := keeper.NewMsgServerImpl(k) + + // Deploy Simple Storage contract + ante.Preprocess(ctx, req) + res, err := msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.LessOrEqual(t, res.GasUsed, uint64(200000)) + require.Empty(t, res.VmError) + require.NotEmpty(t, res.ReturnData) + require.NotEmpty(t, res.Hash) + require.Equal(t, uint64(1000000)-res.GasUsed, k.BankKeeper().GetBalance(ctx, sdk.AccAddress(evmAddr[:]), "usei").Amount.Uint64()) + require.Equal(t, res.GasUsed, k.BankKeeper().GetBalance(ctx, state.GetCoinbaseAddress(ctx.TxIndex()), k.GetBaseDenom(ctx)).Amount.Uint64()) + receipt, err := k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + require.NotNil(t, receipt) + require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) + + // send transaction to the contract + contractAddr := common.HexToAddress(receipt.ContractAddress) + abi, err := echo.EchoMetaData.GetAbi() + require.Nil(t, err) + bz, err = abi.Pack("setTime", big.NewInt(1)) + 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) + ante.Preprocess(ctx, req) + res, err = msgServer.EVMTransaction(sdk.WrapSDKContext(ctx), req) + require.Nil(t, err) + require.LessOrEqual(t, res.GasUsed, uint64(200000)) + require.Empty(t, res.VmError) + receipt, err = k.GetReceipt(ctx, common.HexToHash(res.Hash)) + require.Nil(t, err) + require.NotNil(t, receipt) + require.Equal(t, uint32(ethtypes.ReceiptStatusSuccessful), receipt.Status) +} + +func TestSend(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + seiFrom, evmFrom := testkeeper.MockAddressPair() + seiTo, evmTo := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, seiFrom, evmFrom) + k.SetAddressMapping(ctx, seiTo, evmTo) + k.BankKeeper().AddCoins(ctx, seiFrom, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(1000000))), true) + _, err := keeper.NewMsgServerImpl(k).Send(sdk.WrapSDKContext(ctx), &types.MsgSend{ + FromAddress: seiFrom.String(), + ToAddress: evmTo.Hex(), + Amount: sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(500000))), + }) + require.Nil(t, err) + require.Equal(t, sdk.NewInt(500000), k.BankKeeper().GetBalance(ctx, seiFrom, "usei").Amount) + require.Equal(t, sdk.NewInt(500000), k.BankKeeper().GetBalance(ctx, seiTo, "usei").Amount) +} + +func TestRegisterPointer(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + sender, _ := testkeeper.MockAddressPair() + _, pointee := testkeeper.MockAddressPair() + res, err := keeper.NewMsgServerImpl(k).RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: sender.String(), + PointerType: types.PointerType_ERC20, + ErcAddress: pointee.Hex(), + }) + require.Nil(t, err) + pointer, version, exists := k.GetCW20ERC20Pointer(ctx, pointee) + require.True(t, exists) + require.Equal(t, erc20.CurrentVersion, version) + require.Equal(t, pointer.String(), res.PointerAddress) + hasRegisteredEvent := false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + require.Equal(t, types.EventTypePointerRegistered, e.Type) + require.Equal(t, "erc20", string(e.Attributes[0].Value)) + } + require.True(t, hasRegisteredEvent) + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + // already exists + _, err = keeper.NewMsgServerImpl(k).RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: sender.String(), + PointerType: types.PointerType_ERC20, + ErcAddress: pointee.Hex(), + }) + require.NotNil(t, err) + hasRegisteredEvent = false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + } + require.False(t, hasRegisteredEvent) + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + res, err = keeper.NewMsgServerImpl(k).RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: sender.String(), + PointerType: types.PointerType_ERC721, + ErcAddress: pointee.Hex(), + }) + require.Nil(t, err) + pointer, version, exists = k.GetCW721ERC721Pointer(ctx, pointee) + require.True(t, exists) + require.Equal(t, erc721.CurrentVersion, version) + require.Equal(t, pointer.String(), res.PointerAddress) + hasRegisteredEvent = false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + require.Equal(t, types.EventTypePointerRegistered, e.Type) + require.Equal(t, "erc721", string(e.Attributes[0].Value)) + } + require.True(t, hasRegisteredEvent) + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + // already exists + _, err = keeper.NewMsgServerImpl(k).RegisterPointer(sdk.WrapSDKContext(ctx), &types.MsgRegisterPointer{ + Sender: sender.String(), + PointerType: types.PointerType_ERC721, + ErcAddress: pointee.Hex(), + }) + require.NotNil(t, err) + hasRegisteredEvent = false + for _, e := range ctx.EventManager().Events() { + if e.Type != types.EventTypePointerRegistered { + continue + } + hasRegisteredEvent = true + } + require.False(t, hasRegisteredEvent) +} diff --git a/x/evm/keeper/nonce.go b/x/evm/keeper/nonce.go new file mode 100644 index 0000000000..27e937ee45 --- /dev/null +++ b/x/evm/keeper/nonce.go @@ -0,0 +1,23 @@ +package keeper + +import ( + "encoding/binary" + + 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) GetNonce(ctx sdk.Context, addr common.Address) uint64 { + bz := k.PrefixStore(ctx, types.NonceKeyPrefix).Get(addr[:]) + if bz == nil { + return 0 + } + return binary.BigEndian.Uint64(bz) +} + +func (k *Keeper) SetNonce(ctx sdk.Context, addr common.Address, nonce uint64) { + length := make([]byte, 8) + binary.BigEndian.PutUint64(length, nonce) + k.PrefixStore(ctx, types.NonceKeyPrefix).Set(addr[:], length) +} diff --git a/x/evm/keeper/params.go b/x/evm/keeper/params.go new file mode 100644 index 0000000000..81c821f0c2 --- /dev/null +++ b/x/evm/keeper/params.go @@ -0,0 +1,49 @@ +package keeper + +import ( + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +const BaseDenom = "usei" + +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.Paramstore.SetParamSet(ctx, ¶ms) +} + +func (k *Keeper) GetParams(ctx sdk.Context) types.Params { + params := types.Params{} + k.Paramstore.GetParamSet(ctx, ¶ms) + return params +} + +func (k *Keeper) GetBaseDenom(ctx sdk.Context) string { + return BaseDenom +} + +func (k *Keeper) GetPriorityNormalizer(ctx sdk.Context) sdk.Dec { + return k.GetParams(ctx).PriorityNormalizer +} + +func (k *Keeper) GetBaseFeePerGas(ctx sdk.Context) sdk.Dec { + return k.GetParams(ctx).BaseFeePerGas +} + +func (k *Keeper) GetMinimumFeePerGas(ctx sdk.Context) sdk.Dec { + return k.GetParams(ctx).MinimumFeePerGas +} + +func (k *Keeper) ChainID(ctx sdk.Context) *big.Int { + if k.EthReplayConfig.Enabled || k.EthBlockTestConfig.Enabled { + // replay is for eth mainnet so always return 1 + return utils.Big1 + } + return k.GetParams(ctx).ChainId.BigInt() +} + +func (k *Keeper) WhitelistedCwCodeHashesForDelegateCall(ctx sdk.Context) [][]byte { + return k.GetParams(ctx).WhitelistedCwCodeHashesForDelegateCall +} diff --git a/x/evm/keeper/params_test.go b/x/evm/keeper/params_test.go new file mode 100644 index 0000000000..39bcc9f750 --- /dev/null +++ b/x/evm/keeper/params_test.go @@ -0,0 +1,19 @@ +package keeper_test + +import ( + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestParams(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + require.Equal(t, "usei", k.GetBaseDenom(ctx)) + require.Equal(t, types.DefaultPriorityNormalizer, k.GetPriorityNormalizer(ctx)) + require.Equal(t, types.DefaultBaseFeePerGas, k.GetBaseFeePerGas(ctx)) + require.Equal(t, types.DefaultMinFeePerGas, k.GetMinimumFeePerGas(ctx)) + + require.Nil(t, k.GetParams(ctx).Validate()) +} diff --git a/x/evm/keeper/pointer.go b/x/evm/keeper/pointer.go new file mode 100644 index 0000000000..e871928346 --- /dev/null +++ b/x/evm/keeper/pointer.go @@ -0,0 +1,132 @@ +package keeper + +import ( + "encoding/binary" + "fmt" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func (k *Keeper) SetERC20NativePointer(ctx sdk.Context, token string, addr common.Address) error { + return k.SetPointerInfo(ctx, types.PointerERC20NativeKey(token), addr[:], native.CurrentVersion) +} + +func (k *Keeper) SetERC20NativePointerWithVersion(ctx sdk.Context, token string, addr common.Address, version uint16) error { + return k.SetPointerInfo(ctx, types.PointerERC20NativeKey(token), addr[:], version) +} + +func (k *Keeper) GetERC20NativePointer(ctx sdk.Context, token string) (addr common.Address, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerERC20NativeKey(token)) + if exists { + addr = common.BytesToAddress(addrBz) + } + return +} + +func (k *Keeper) DeleteERC20NativePointer(ctx sdk.Context, token string, version uint16) { + k.DeletePointerInfo(ctx, types.PointerERC20NativeKey(token), version) +} + +func (k *Keeper) SetERC20CW20Pointer(ctx sdk.Context, cw20Address string, addr common.Address) error { + return k.SetPointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), addr[:], cw20.CurrentVersion) +} + +func (k *Keeper) SetERC20CW20PointerWithVersion(ctx sdk.Context, cw20Address string, addr common.Address, version uint16) error { + return k.SetPointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), addr[:], version) +} + +func (k *Keeper) GetERC20CW20Pointer(ctx sdk.Context, cw20Address string) (addr common.Address, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerERC20CW20Key(cw20Address)) + if exists { + addr = common.BytesToAddress(addrBz) + } + return +} + +func (k *Keeper) DeleteERC20CW20Pointer(ctx sdk.Context, cw20Address string, version uint16) { + k.DeletePointerInfo(ctx, types.PointerERC20CW20Key(cw20Address), version) +} + +func (k *Keeper) SetERC721CW721Pointer(ctx sdk.Context, cw721Address string, addr common.Address) error { + return k.SetPointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), addr[:], cw721.CurrentVersion) +} + +func (k *Keeper) SetERC721CW721PointerWithVersion(ctx sdk.Context, cw721Address string, addr common.Address, version uint16) error { + return k.SetPointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), addr[:], version) +} + +func (k *Keeper) GetERC721CW721Pointer(ctx sdk.Context, cw721Address string) (addr common.Address, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerERC721CW721Key(cw721Address)) + if exists { + addr = common.BytesToAddress(addrBz) + } + return +} + +func (k *Keeper) DeleteERC721CW721Pointer(ctx sdk.Context, cw721Address string, version uint16) { + k.DeletePointerInfo(ctx, types.PointerERC721CW721Key(cw721Address), version) +} + +func (k *Keeper) SetCW20ERC20Pointer(ctx sdk.Context, erc20Address common.Address, addr string) error { + return k.SetPointerInfo(ctx, types.PointerCW20ERC20Key(erc20Address), []byte(addr), erc20.CurrentVersion) +} + +func (k *Keeper) GetCW20ERC20Pointer(ctx sdk.Context, erc20Address common.Address) (addr sdk.AccAddress, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerCW20ERC20Key(erc20Address)) + if exists { + addr = sdk.MustAccAddressFromBech32(string(addrBz)) + } + return +} + +func (k *Keeper) SetCW721ERC721Pointer(ctx sdk.Context, erc721Address common.Address, addr string) error { + return k.SetPointerInfo(ctx, types.PointerCW721ERC721Key(erc721Address), []byte(addr), erc721.CurrentVersion) +} + +func (k *Keeper) GetCW721ERC721Pointer(ctx sdk.Context, erc721Address common.Address) (addr sdk.AccAddress, version uint16, exists bool) { + addrBz, version, exists := k.GetPointerInfo(ctx, types.PointerCW721ERC721Key(erc721Address)) + if exists { + addr = sdk.MustAccAddressFromBech32(string(addrBz)) + } + return +} + +func (k *Keeper) GetPointerInfo(ctx sdk.Context, pref []byte) (addr []byte, version uint16, exists bool) { + store := prefix.NewStore(ctx.KVStore(k.GetStoreKey()), pref) + iter := store.ReverseIterator(nil, nil) + defer iter.Close() + exists = iter.Valid() + if !exists { + return + } + version = binary.BigEndian.Uint16(iter.Key()) + addr = iter.Value() + return +} + +func (k *Keeper) SetPointerInfo(ctx sdk.Context, pref []byte, addr []byte, version uint16) error { + existingAddr, existingVersion, exists := k.GetPointerInfo(ctx, pref) + if exists && existingVersion >= version { + return fmt.Errorf("pointer at %s with version %d exists when trying to set pointer for version %d", string(existingAddr), existingVersion, version) + } + store := prefix.NewStore(ctx.KVStore(k.GetStoreKey()), pref) + versionBz := make([]byte, 2) + binary.BigEndian.PutUint16(versionBz, version) + store.Set(versionBz, addr) + return nil +} + +func (k *Keeper) DeletePointerInfo(ctx sdk.Context, pref []byte, version uint16) { + store := prefix.NewStore(ctx.KVStore(k.GetStoreKey()), pref) + versionBz := make([]byte, 2) + binary.BigEndian.PutUint16(versionBz, version) + store.Delete(versionBz) +} diff --git a/x/evm/keeper/pointer_test.go b/x/evm/keeper/pointer_test.go new file mode 100644 index 0000000000..e4048af692 --- /dev/null +++ b/x/evm/keeper/pointer_test.go @@ -0,0 +1,21 @@ +package keeper_test + +import ( + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/stretchr/testify/require" +) + +func TestSetPointer(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, pointer := testkeeper.MockAddressPair() + cw20, _ := testkeeper.MockAddressPair() + cw721, _ := testkeeper.MockAddressPair() + require.Nil(t, k.SetERC20NativePointer(ctx, "test", pointer)) + require.NotNil(t, k.SetERC20NativePointer(ctx, "test", pointer)) // already set + require.Nil(t, k.SetERC20CW20Pointer(ctx, cw20.String(), pointer)) + require.NotNil(t, k.SetERC20CW20Pointer(ctx, cw20.String(), pointer)) // already set + require.Nil(t, k.SetERC721CW721Pointer(ctx, cw721.String(), pointer)) + require.NotNil(t, k.SetERC721CW721Pointer(ctx, cw721.String(), pointer)) // already set +} diff --git a/x/evm/keeper/precompile.go b/x/evm/keeper/precompile.go new file mode 100644 index 0000000000..c2a8b51191 --- /dev/null +++ b/x/evm/keeper/precompile.go @@ -0,0 +1,24 @@ +package keeper + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/precompiles/bank" + "github.com/sei-protocol/sei-chain/precompiles/gov" + "github.com/sei-protocol/sei-chain/precompiles/staking" +) + +// add any payable precompiles here +// these will suppress transfer events to/from the precompile address +var payablePrecompiles = map[string]struct{}{ + bank.BankAddress: {}, + staking.StakingAddress: {}, + gov.GovAddress: {}, +} + +func IsPayablePrecompile(addr *common.Address) bool { + if addr == nil { + return false + } + _, ok := payablePrecompiles[addr.Hex()] + return ok +} diff --git a/x/evm/keeper/precompile_test.go b/x/evm/keeper/precompile_test.go new file mode 100644 index 0000000000..956f5cb959 --- /dev/null +++ b/x/evm/keeper/precompile_test.go @@ -0,0 +1,29 @@ +package keeper_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + "github.com/sei-protocol/sei-chain/precompiles/bank" + "github.com/sei-protocol/sei-chain/precompiles/gov" + "github.com/sei-protocol/sei-chain/precompiles/staking" + "github.com/sei-protocol/sei-chain/testutil/keeper" + evmkeeper "github.com/sei-protocol/sei-chain/x/evm/keeper" +) + +func toAddr(addr string) *common.Address { + ca := common.HexToAddress(addr) + return &ca +} + +func TestIsPayablePrecompile(t *testing.T) { + _, evmAddr := keeper.MockAddressPair() + require.False(t, evmkeeper.IsPayablePrecompile(&evmAddr)) + require.False(t, evmkeeper.IsPayablePrecompile(nil)) + + require.True(t, evmkeeper.IsPayablePrecompile(toAddr(bank.BankAddress))) + require.True(t, evmkeeper.IsPayablePrecompile(toAddr(staking.StakingAddress))) + require.True(t, evmkeeper.IsPayablePrecompile(toAddr(gov.GovAddress))) +} diff --git a/x/evm/keeper/receipt.go b/x/evm/keeper/receipt.go new file mode 100644 index 0000000000..43e6c93880 --- /dev/null +++ b/x/evm/keeper/receipt.go @@ -0,0 +1,35 @@ +package keeper + +import ( + "errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +// Receipt is a data structure that stores EVM specific transaction metadata. +// Many EVM applications (e.g. MetaMask) relies on being on able to query receipt +// by EVM transaction hash (not Sei transaction hash) to function properly. +func (k *Keeper) GetReceipt(ctx sdk.Context, txHash common.Hash) (*types.Receipt, error) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ReceiptKey(txHash)) + if bz == nil { + return nil, errors.New("not found") + } + r := types.Receipt{} + if err := r.Unmarshal(bz); err != nil { + return nil, err + } + return &r, nil +} + +func (k *Keeper) SetReceipt(ctx sdk.Context, txHash common.Hash, receipt *types.Receipt) error { + store := ctx.KVStore(k.storeKey) + bz, err := receipt.Marshal() + if err != nil { + return err + } + store.Set(types.ReceiptKey(txHash), bz) + return nil +} diff --git a/x/evm/keeper/replay.go b/x/evm/keeper/replay.go new file mode 100644 index 0000000000..c202b38edc --- /dev/null +++ b/x/evm/keeper/replay.go @@ -0,0 +1,106 @@ +package keeper + +import ( + "bytes" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func (k *Keeper) VerifyBalance(ctx sdk.Context, addr common.Address) { + useiBalance := k.BankKeeper().GetBalance(ctx, k.GetSeiAddressOrDefault(ctx, addr), "usei").Amount + weiBalance := k.bankKeeper.GetWeiBalance(ctx, k.GetSeiAddressOrDefault(ctx, addr)) + totalSeiBalance := useiBalance.Mul(sdk.NewInt(1_000_000_000_000)).Add(weiBalance).BigInt() + ethBalance, err := k.EthClient.BalanceAt(ctx.Context(), addr, big.NewInt(k.GetReplayInitialHeight(ctx)+ctx.BlockHeight())) + if err != nil { + panic(err) + } + if totalSeiBalance.Cmp(ethBalance) != 0 { + panic(fmt.Sprintf("difference for addr %s: sei balance is %s, eth balance is %s", addr.Hex(), totalSeiBalance, ethBalance)) + } +} + +func (k *Keeper) VerifyTxResult(ctx sdk.Context, hash common.Hash) { + localReceipt, err := k.GetReceipt(ctx, hash) + if err != nil { + // it's okay if remote also doesn't have receipt + _, err = k.EthClient.TransactionReceipt(ctx.Context(), hash) + if err == ethereum.NotFound { + return + } + panic(fmt.Sprintf("missing local receipt for %s", hash.Hex())) + } + remoteReceipt, err := k.EthClient.TransactionReceipt(ctx.Context(), hash) + if err != nil { + panic(err) + } + if localReceipt.Status != uint32(remoteReceipt.Status) { + panic(fmt.Sprintf("remote transaction has status %d while local has status %d", remoteReceipt.Status, localReceipt.Status)) + } + if len(localReceipt.Logs) != len(remoteReceipt.Logs) { + panic(fmt.Sprintf("remote transaction has %d logs while local has %d logs", len(remoteReceipt.Logs), len(localReceipt.Logs))) + } + for i, log := range localReceipt.Logs { + rlog := remoteReceipt.Logs[i] + if log.Address != rlog.Address.Hex() { + panic(fmt.Sprintf("%d-th log has address %s on local but %s on remote", i, log.Address, rlog.Address.Hex())) + } + if !bytes.Equal(log.Data, rlog.Data) { + panic(fmt.Sprintf("%d-th log has data %X on local but %X on remote", i, log.Data, rlog.Data)) + } + if len(log.Topics) != len(rlog.Topics) { + panic(fmt.Sprintf("%d-th log has %d topics on local but %d on remote", i, len(log.Topics), len(rlog.Topics))) + } + for j, topic := range log.Topics { + rtopic := rlog.Topics[j] + if topic != rtopic.Hex() { + panic(fmt.Sprintf("%d-th log %d-th topic is %s on local but %s on remote", i, j, topic, rtopic.Hex())) + } + } + } +} + +func (k *Keeper) VerifyAccount(ctx sdk.Context, addr common.Address, accountData core.GenesisAccount) { + code := accountData.Code + for key, expectedState := range accountData.Storage { + actualState := k.GetState(ctx, addr, key) + if !bytes.Equal(actualState.Bytes(), expectedState.Bytes()) { + panic(fmt.Sprintf("storage mismatch for address %s: expected %X, got %X", addr.Hex(), expectedState, actualState)) + } + } + balance := accountData.Balance + nonce := accountData.Nonce + if !bytes.Equal(code, k.GetCode(ctx, addr)) { + panic(fmt.Sprintf("code mismatch for address %s", addr)) + } + useiBalance := k.BankKeeper().GetBalance(ctx, k.GetSeiAddressOrDefault(ctx, addr), "usei").Amount + weiBalance := k.bankKeeper.GetWeiBalance(ctx, k.GetSeiAddressOrDefault(ctx, addr)) + totalSeiBalance := useiBalance.Mul(sdk.NewInt(1_000_000_000_000)).Add(weiBalance).BigInt() + if balance.Cmp(totalSeiBalance) != 0 { + panic(fmt.Sprintf("balance mismatch for address %s: expected %s, got %s", addr.Hex(), balance, totalSeiBalance)) + } + if nonce != k.GetNonce(ctx, addr) { + panic(fmt.Sprintf("nonce mismatch for address %s: expected %d, got %d", addr.Hex(), nonce, k.GetNonce(ctx, addr))) + } +} + +func (k *Keeper) VerifyState(ctx sdk.Context, addr common.Address) { + store := k.PrefixStore(ctx, types.StateKey(addr)) + iter := store.Iterator(nil, nil) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + key := common.BytesToHash(iter.Key()) + ethVal, err := k.EthClient.StorageAt(ctx.Context(), addr, key, k.ReplayBlock.Number()) + if err != nil { + panic(err) + } + if !bytes.Equal(iter.Value(), ethVal) { + panic(fmt.Sprintf("state mismatch for address %s hash %s: expected %X but got %X", addr.Hex(), key.Hex(), ethVal, iter.Value())) + } + } +} diff --git a/x/evm/keeper/state.go b/x/evm/keeper/state.go new file mode 100644 index 0000000000..2cd0ab722e --- /dev/null +++ b/x/evm/keeper/state.go @@ -0,0 +1,31 @@ +package keeper + +import ( + 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) GetState(ctx sdk.Context, addr common.Address, hash common.Hash) common.Hash { + val := k.PrefixStore(ctx, types.StateKey(addr)).Get(hash[:]) + if val == nil { + if k.EthReplayConfig.Enabled { + // try to get from eth DB + tr, err := k.DB.OpenStorageTrie(k.Root, addr, common.BytesToHash(k.PrefixStore(ctx, types.ReplaySeenAddrPrefix).Get(addr[:])), k.Trie) + if err != nil { + panic(err) + } + val, err := tr.GetStorage(addr, hash.Bytes()) + if err != nil { + return common.Hash{} + } + return common.BytesToHash(val) + } + return common.Hash{} + } + return common.BytesToHash(val) +} + +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[:]) +} diff --git a/x/evm/keeper/state_test.go b/x/evm/keeper/state_test.go new file mode 100644 index 0000000000..f8d0be2cf2 --- /dev/null +++ b/x/evm/keeper/state_test.go @@ -0,0 +1,21 @@ +package keeper_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/stretchr/testify/require" +) + +func TestState(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, addr := testkeeper.MockAddressPair() + + initialState := k.GetState(ctx, addr, common.HexToHash("0xabc")) + require.Equal(t, common.Hash{}, initialState) + k.SetState(ctx, addr, common.HexToHash("0xabc"), common.HexToHash("0xdef")) + + got := k.GetState(ctx, addr, common.HexToHash("0xabc")) + require.Equal(t, common.HexToHash("0xdef"), got) +} diff --git a/x/evm/keeper/tx.go b/x/evm/keeper/tx.go new file mode 100644 index 0000000000..1c086d565e --- /dev/null +++ b/x/evm/keeper/tx.go @@ -0,0 +1,31 @@ +package keeper + +import ( + 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) GetTxHashesOnHeight(ctx sdk.Context, height int64) (res []common.Hash) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.TxHashesKey(height)) + if bz == nil { + return + } + for i := 0; i <= len(bz)-common.HashLength; i += common.HashLength { + res = append(res, common.Hash(bz[i:i+common.HashLength])) + } + return +} + +func (k *Keeper) SetTxHashesOnHeight(ctx sdk.Context, height int64, hashes []common.Hash) { + if len(hashes) == 0 { + return + } + store := ctx.KVStore(k.storeKey) + bz := []byte{} + for _, hash := range hashes { + bz = append(bz, hash[:]...) + } + store.Set(types.TxHashesKey(height), bz) +} diff --git a/x/evm/keeper/whitelist.go b/x/evm/keeper/whitelist.go new file mode 100644 index 0000000000..5e85bfbf43 --- /dev/null +++ b/x/evm/keeper/whitelist.go @@ -0,0 +1,16 @@ +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/migrations/add_new_param_migration.go b/x/evm/migrations/add_new_param_migration.go new file mode 100644 index 0000000000..8ac3df08a9 --- /dev/null +++ b/x/evm/migrations/add_new_param_migration.go @@ -0,0 +1,16 @@ +package migrations + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +// Note that such migration would nuke any param changes that deviate +// from the defaults. If such changes need to be preserved, a fine-grained +// migration handler should be used instead +func AddNewParamsAndSetAllToDefaults(ctx sdk.Context, k *keeper.Keeper) error { + defaultParams := types.DefaultParams() + k.SetParams(ctx, defaultParams) + return nil +} diff --git a/x/evm/migrations/add_new_param_migration_test.go b/x/evm/migrations/add_new_param_migration_test.go new file mode 100644 index 0000000000..981ab5d1e8 --- /dev/null +++ b/x/evm/migrations/add_new_param_migration_test.go @@ -0,0 +1,17 @@ +package migrations_test + +import ( + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/migrations" + "github.com/stretchr/testify/require" + tmtypes "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestAddNewParamsAndSetAllToDefaults(t *testing.T) { + k := testkeeper.EVMTestApp.EvmKeeper + ctx := testkeeper.EVMTestApp.NewContext(false, tmtypes.Header{}) + migrations.AddNewParamsAndSetAllToDefaults(ctx, &k) + require.NotPanics(t, func() { k.GetParams(ctx) }) +} diff --git a/x/evm/migrations/store_cw_pointer_code.go b/x/evm/migrations/store_cw_pointer_code.go new file mode 100644 index 0000000000..2e188ec24d --- /dev/null +++ b/x/evm/migrations/store_cw_pointer_code.go @@ -0,0 +1,32 @@ +package migrations + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc20" + "github.com/sei-protocol/sei-chain/x/evm/artifacts/erc721" + artifactsutils "github.com/sei-protocol/sei-chain/x/evm/artifacts/utils" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func StoreCWPointerCode(ctx sdk.Context, k *keeper.Keeper) error { + erc20CodeID, err := k.WasmKeeper().Create(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), erc20.GetBin(), nil) + if err != nil { + panic(err) + } + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW20ERC20Prefix).Set( + artifactsutils.GetVersionBz(erc20.CurrentVersion), + artifactsutils.GetCodeIDBz(erc20CodeID), + ) + + erc721CodeID, err := k.WasmKeeper().Create(ctx, k.AccountKeeper().GetModuleAddress(types.ModuleName), erc721.GetBin(), nil) + if err != nil { + panic(err) + } + prefix.NewStore(k.PrefixStore(ctx, types.PointerCWCodePrefix), types.PointerCW721ERC721Prefix).Set( + artifactsutils.GetVersionBz(erc721.CurrentVersion), + artifactsutils.GetCodeIDBz(erc721CodeID), + ) + return nil +} diff --git a/x/evm/module.go b/x/evm/module.go new file mode 100644 index 0000000000..208038fdba --- /dev/null +++ b/x/evm/module.go @@ -0,0 +1,251 @@ +package evm + +import ( + "encoding/json" + "fmt" + "math" + + // this line is used by starport scaffolding # 1 + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/client/cli" + "github.com/sei-protocol/sei-chain/x/evm/keeper" + "github.com/sei-protocol/sei-chain/x/evm/migrations" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the capability module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterCodec(*codec.LegacyAmino) {} + +func (AppModuleBasic) RegisterLegacyAminoCodec(*codec.LegacyAmino) {} + +// RegisterInterfaces registers the module's interface types +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the capability module's default genesis state. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the capability module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// RegisterRESTRoutes registers the capability module's REST service handlers. +func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(_ client.Context, _ *runtime.ServeMux) {} + +// GetTxCmd returns the capability module's root tx command. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the capability module's root query command. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd(types.StoreKey) +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for the capability module. +type AppModule struct { + AppModuleBasic + + keeper *keeper.Keeper +} + +func NewAppModule( + cdc codec.Codec, + keeper *keeper.Keeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + } +} + +// Name returns the capability module's name. +func (am AppModule) Name() string { + return am.AppModuleBasic.Name() +} + +// Route returns the capability module's message routing key. +func (am AppModule) Route() sdk.Route { + return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper)) +} + +// QuerierRoute returns the capability module's query routing key. +func (AppModule) QuerierRoute() string { return types.QuerierRoute } + +// LegacyQuerierHandler returns the capability module's Querier. +func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers a GRPC query service to respond to the +// module-specific GRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) + + _ = cfg.RegisterMigration(types.ModuleName, 2, func(ctx sdk.Context) error { + return migrations.AddNewParamsAndSetAllToDefaults(ctx, am.keeper) + }) + + _ = cfg.RegisterMigration(types.ModuleName, 3, func(ctx sdk.Context) error { + return migrations.AddNewParamsAndSetAllToDefaults(ctx, am.keeper) + }) + + _ = cfg.RegisterMigration(types.ModuleName, 4, func(ctx sdk.Context) error { + return migrations.StoreCWPointerCode(ctx, am.keeper) + }) +} + +// RegisterInvariants registers the capability module's invariants. +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the capability module's genesis initialization It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + InitGenesis(ctx, am.keeper, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the capability module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion implements ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 5 } + +// BeginBlock executes all ABCI BeginBlock logic respective to the capability module. +func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { + // clear tx responses from last block + am.keeper.SetTxResults([]*abci.ExecTxResult{}) + // clear the TxDeferredInfo + am.keeper.ClearEVMTxDeferredInfo() + // mock beacon root if replaying + if am.keeper.EthReplayConfig.Enabled { + if beaconRoot := am.keeper.ReplayBlock.BeaconRoot(); beaconRoot != nil { + blockCtx, err := am.keeper.GetVMBlockContext(ctx, core.GasPool(math.MaxUint64)) + if err != nil { + panic(err) + } + statedb := state.NewDBImpl(ctx, am.keeper, false) + vmenv := vm.NewEVM(*blockCtx, vm.TxContext{}, statedb, types.DefaultChainConfig().EthereumConfig(am.keeper.ChainID(ctx)), vm.Config{}) + core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) + _, err = statedb.Finalize() + if err != nil { + panic(err) + } + } + } +} + +// EndBlock executes all ABCI EndBlock logic respective to the evm module. It +// returns no validator updates. +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + var coinbase sdk.AccAddress + if am.keeper.EthBlockTestConfig.Enabled { + blocks := am.keeper.BlockTest.Json.Blocks + block, err := blocks[ctx.BlockHeight()-1].Decode() + if err != nil { + panic(err) + } + coinbase = am.keeper.GetSeiAddressOrDefault(ctx, block.Header_.Coinbase) + } else if am.keeper.EthReplayConfig.Enabled { + coinbase = am.keeper.GetSeiAddressOrDefault(ctx, am.keeper.ReplayBlock.Header_.Coinbase) + am.keeper.SetReplayedHeight(ctx) + } else { + coinbase = am.keeper.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName) + } + evmTxDeferredInfoList := am.keeper.GetEVMTxDeferredInfo(ctx) + denom := am.keeper.GetBaseDenom(ctx) + surplus := utils.Sdk0 + for _, deferredInfo := range evmTxDeferredInfoList { + if deferredInfo.Error != "" { + _ = am.keeper.SetReceipt(ctx, deferredInfo.TxHash, &types.Receipt{ + TxHashHex: deferredInfo.TxHash.Hex(), + TransactionIndex: uint32(deferredInfo.TxIndx), + VmError: deferredInfo.Error, + }) + continue + } + idx := deferredInfo.TxIndx + coinbaseAddress := state.GetCoinbaseAddress(idx) + balance := am.keeper.BankKeeper().GetBalance(ctx, coinbaseAddress, denom) + weiBalance := am.keeper.BankKeeper().GetWeiBalance(ctx, coinbaseAddress) + if !balance.Amount.IsZero() || !weiBalance.IsZero() { + if err := am.keeper.BankKeeper().SendCoinsAndWei(ctx, coinbaseAddress, coinbase, balance.Amount, weiBalance); err != nil { + panic(err) + } + } + 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 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) + } + } + am.keeper.SetTxHashesOnHeight(ctx, ctx.BlockHeight(), utils.Map(evmTxDeferredInfoList, func(i keeper.EvmTxDeferredInfo) common.Hash { return i.TxHash })) + am.keeper.SetBlockBloom(ctx, ctx.BlockHeight(), utils.Map(evmTxDeferredInfoList, func(i keeper.EvmTxDeferredInfo) ethtypes.Bloom { return i.TxBloom })) + return []abci.ValidatorUpdate{} +} diff --git a/x/evm/module_test.go b/x/evm/module_test.go new file mode 100644 index 0000000000..108603d854 --- /dev/null +++ b/x/evm/module_test.go @@ -0,0 +1,77 @@ +package evm_test + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + 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/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" +) + +func TestABCI(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, evmAddr1 := testkeeper.MockAddressPair() + _, evmAddr2 := testkeeper.MockAddressPair() + amt := sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10))) + k.BankKeeper().MintCoins(ctx, types.ModuleName, amt) + k.BankKeeper().SendCoinsFromModuleToAccount(ctx, types.ModuleName, sdk.AccAddress(evmAddr1[:]), amt) + m := evm.NewAppModule(nil, k) + // first block + m.BeginBlock(ctx, abci.RequestBeginBlock{}) + // 1st tx + s := state.NewDBImpl(ctx.WithTxIndex(1), k, false) + s.SubBalance(evmAddr1, big.NewInt(10000000000000), tracing.BalanceChangeUnspecified) + s.AddBalance(evmAddr2, big.NewInt(8000000000000), tracing.BalanceChangeUnspecified) + feeCollectorAddr, err := k.GetFeeCollectorAddress(ctx) + require.Nil(t, err) + s.AddBalance(feeCollectorAddr, big.NewInt(2000000000000), tracing.BalanceChangeUnspecified) + surplus, err := s.Finalize() + require.Nil(t, err) + require.Equal(t, sdk.ZeroInt(), surplus) + k.AppendToEvmTxDeferredInfo(ctx.WithTxIndex(1), ethtypes.Bloom{}, common.Hash{}, surplus) + // 3rd tx + s = state.NewDBImpl(ctx.WithTxIndex(3), k, false) + s.SubBalance(evmAddr2, big.NewInt(5000000000000), tracing.BalanceChangeUnspecified) + s.AddBalance(evmAddr1, big.NewInt(5000000000000), tracing.BalanceChangeUnspecified) + 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.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()) + require.Equal(t, uint64(2), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName), "usei").Amount.Uint64()) + + // second block + m.BeginBlock(ctx, abci.RequestBeginBlock{}) + // 2nd tx + s = state.NewDBImpl(ctx.WithTxIndex(2), k, false) + s.SubBalance(evmAddr2, big.NewInt(3000000000000), tracing.BalanceChangeUnspecified) + s.AddBalance(evmAddr1, big.NewInt(2000000000000), tracing.BalanceChangeUnspecified) + 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.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()) + require.Equal(t, uint64(2), k.BankKeeper().GetBalance(ctx, k.AccountKeeper().GetModuleAddress(authtypes.FeeCollectorName), "usei").Amount.Uint64()) + + // third block + m.BeginBlock(ctx, abci.RequestBeginBlock{}) + k.AppendErrorToEvmTxDeferredInfo(ctx.WithTxIndex(0), common.Hash{1}, "test error") + k.SetTxResults([]*abci.ExecTxResult{{Code: 1}}) + m.EndBlock(ctx, abci.RequestEndBlock{}) + receipt, err := k.GetReceipt(ctx, common.Hash{1}) + require.Nil(t, err) + require.Equal(t, receipt.VmError, "test error") +} diff --git a/x/evm/querier/config.go b/x/evm/querier/config.go new file mode 100644 index 0000000000..8997594e23 --- /dev/null +++ b/x/evm/querier/config.go @@ -0,0 +1,29 @@ +package querier + +import ( + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/spf13/cast" +) + +type Config struct { + GasLimit uint64 `mapstructure:"evm_query_gas_limit"` +} + +var DefaultConfig = Config{ + GasLimit: 300000, +} + +const ( + flagGasLimit = "evm_query.evm_query_gas_limit" +) + +func ReadConfig(opts servertypes.AppOptions) (Config, error) { + cfg := DefaultConfig // copy + var err error + if v := opts.Get(flagGasLimit); v != nil { + if cfg.GasLimit, err = cast.ToUint64E(v); err != nil { + return cfg, err + } + } + return cfg, nil +} diff --git a/x/evm/replay/config.go b/x/evm/replay/config.go new file mode 100644 index 0000000000..638c868adf --- /dev/null +++ b/x/evm/replay/config.go @@ -0,0 +1,45 @@ +package replay + +import ( + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/spf13/cast" +) + +type Config struct { + Enabled bool `mapstructure:"eth_replay_enabled"` + EthRPC string `mapstructure:"eth_rpc"` + EthDataDir string `mapstructure:"eth_data_dir"` +} + +var DefaultConfig = Config{ + Enabled: false, + EthRPC: "http://44.234.105.54:18545", + EthDataDir: "/root/.ethereum/chaindata", +} + +const ( + flagEnabled = "eth_replay.eth_replay_enabled" + flagEthRPC = "eth_replay.eth_rpc" + flagEthDataDir = "eth_replay.eth_data_dir" +) + +func ReadConfig(opts servertypes.AppOptions) (Config, error) { + cfg := DefaultConfig // copy + var err error + if v := opts.Get(flagEnabled); v != nil { + if cfg.Enabled, err = cast.ToBoolE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagEthRPC); v != nil { + if cfg.EthRPC, err = cast.ToStringE(v); err != nil { + return cfg, err + } + } + if v := opts.Get(flagEthDataDir); v != nil { + if cfg.EthDataDir, err = cast.ToStringE(v); err != nil { + return cfg, err + } + } + return cfg, nil +} diff --git a/x/evm/state/accesslist.go b/x/evm/state/accesslist.go new file mode 100644 index 0000000000..21b98fd3aa --- /dev/null +++ b/x/evm/state/accesslist.go @@ -0,0 +1,106 @@ +package state + +import ( + "encoding/json" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +// Forked from go-ethereum, except journaling logic which is unnecessary with cacheKV + +type accessList struct { + Addresses map[common.Address]int `json:"addresses"` + Slots []map[common.Hash]struct{} `json:"slots"` +} + +func (s *DBImpl) AddressInAccessList(addr common.Address) bool { + s.k.PrepareReplayedAddr(s.ctx, addr) + _, ok := s.getAccessList().Addresses[addr] + return ok +} + +func (s *DBImpl) SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) { + s.k.PrepareReplayedAddr(s.ctx, addr) + al := s.getAccessList() + idx, ok := al.Addresses[addr] + if ok && idx != -1 { + _, slotOk := al.Slots[idx][slot] + return ok, slotOk + } + return ok, false +} + +func (s *DBImpl) AddAddressToAccessList(addr common.Address) { + s.k.PrepareReplayedAddr(s.ctx, addr) + al := s.getAccessList() + defer s.saveAccessList(al) + if _, present := al.Addresses[addr]; present { + return + } + al.Addresses[addr] = -1 +} + +func (s *DBImpl) AddSlotToAccessList(addr common.Address, slot common.Hash) { + s.k.PrepareReplayedAddr(s.ctx, addr) + al := s.getAccessList() + defer s.saveAccessList(al) + idx, addrPresent := al.Addresses[addr] + if !addrPresent || idx == -1 { + // Address not present, or addr present but no slots there + al.Addresses[addr] = len(al.Slots) + slotmap := map[common.Hash]struct{}{slot: {}} + al.Slots = append(al.Slots, slotmap) + return + } + // There is already an (address,slot) mapping + slotmap := al.Slots[idx] + if _, ok := slotmap[slot]; !ok { + slotmap[slot] = struct{}{} + } +} + +func (s *DBImpl) Prepare(_ params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses ethtypes.AccessList) { + s.k.PrepareReplayedAddr(s.ctx, sender) + s.k.PrepareReplayedAddr(s.ctx, coinbase) + if dest != nil { + s.k.PrepareReplayedAddr(s.ctx, *dest) + } + s.Snapshot() + s.AddAddressToAccessList(sender) + if dest != nil { + s.AddAddressToAccessList(*dest) + // If it's a create-tx, the destination will be added inside evm.create + } + for _, addr := range precompiles { + s.AddAddressToAccessList(addr) + } + for _, el := range txAccesses { + s.AddAddressToAccessList(el.Address) + for _, key := range el.StorageKeys { + s.AddSlotToAccessList(el.Address, key) + } + } + s.AddAddressToAccessList(coinbase) +} + +func (s *DBImpl) getAccessList() *accessList { + bz, found := s.getTransientModule(AccessListKey) + al := accessList{Addresses: make(map[common.Address]int)} + if !found || bz == nil { + return &al + } + if err := json.Unmarshal(bz, &al); err != nil { + panic(err) + } + return &al +} + +func (s *DBImpl) saveAccessList(al *accessList) { + albz, err := json.Marshal(al) + if err != nil { + panic(err) + } + s.tempStateCurrent.transientModuleStates[string(AccessListKey)] = albz +} diff --git a/x/evm/state/accesslist_test.go b/x/evm/state/accesslist_test.go new file mode 100644 index 0000000000..9b6fe1e476 --- /dev/null +++ b/x/evm/state/accesslist_test.go @@ -0,0 +1,112 @@ +package state_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" +) + +func TestAddAddressToAccessList(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + statedb := state.NewDBImpl(ctx, k, false) + + _, addr := testkeeper.MockAddressPair() + require.False(t, statedb.AddressInAccessList(addr)) + statedb.AddAddressToAccessList(addr) + require.Nil(t, statedb.Err()) + require.True(t, statedb.AddressInAccessList(addr)) + + // add same address again + statedb.AddAddressToAccessList(addr) + require.Nil(t, statedb.Err()) + require.True(t, statedb.AddressInAccessList(addr)) +} + +func TestAddSlotToAccessList(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + statedb := state.NewDBImpl(ctx, k, false) + + _, addr := testkeeper.MockAddressPair() + statedb.AddAddressToAccessList(addr) + + slot := common.BytesToHash([]byte("abc")) + addAndCheckSlot(t, statedb, addr, true, slot, false) + + slot2 := common.BytesToHash([]byte("def")) + addAndCheckSlot(t, statedb, addr, true, slot2, false) + + existingSlot := slot + addAndCheckSlot(t, statedb, addr, true, existingSlot, true) +} + +func TestAddSlotToAccessListWithNonExistentAddress(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + statedb := state.NewDBImpl(ctx, k, false) + + _, addr := testkeeper.MockAddressPair() + + slot := common.BytesToHash([]byte("abc")) + addAndCheckSlot(t, statedb, addr, false, slot, false) +} + +func TestPrepare(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + statedb := state.NewDBImpl(ctx, k, false) + + _, sender := testkeeper.MockAddressPair() + _, coinbase := testkeeper.MockAddressPair() + _, dest := testkeeper.MockAddressPair() + p1 := common.BytesToAddress([]byte{1}) + p2 := common.BytesToAddress([]byte{2}) + p3 := common.BytesToAddress([]byte{3}) + precompiles := []common.Address{p1, p2, p3} + _, access1 := testkeeper.MockAddressPair() + _, access2 := testkeeper.MockAddressPair() + txaccesses := []ethtypes.AccessTuple{ + {Address: access1, StorageKeys: []common.Hash{common.BytesToHash([]byte("abc"))}}, + { + Address: access2, + StorageKeys: []common.Hash{ + common.BytesToHash([]byte("def")), + common.BytesToHash([]byte("ghi")), + }, + }, + } + shanghai := params.Rules{ChainID: k.ChainID(ctx), IsShanghai: true} + statedb.Prepare( + shanghai, sender, coinbase, &dest, precompiles, txaccesses, + ) + inAccessList := []common.Address{sender, dest, p1, p2, p3, access1, access2, coinbase} + for _, addr := range inAccessList { + require.True(t, statedb.AddressInAccessList(addr)) + } + slotInAccessList := []struct { + addr common.Address + slot common.Hash + }{ + {access1, common.BytesToHash([]byte("abc"))}, + {access2, common.BytesToHash([]byte("def"))}, + {access2, common.BytesToHash([]byte("ghi"))}, + } + for _, el := range slotInAccessList { + addrOk, slotOk := statedb.SlotInAccessList(el.addr, el.slot) + require.True(t, addrOk) + require.True(t, slotOk) + } +} + +func addAndCheckSlot(t *testing.T, statedb *state.DBImpl, addr common.Address, addrInAl bool, slot common.Hash, slotInAl bool) { + addrOk, slotOk := statedb.SlotInAccessList(addr, slot) + require.Equal(t, addrOk, addrInAl) + require.Equal(t, slotOk, slotInAl) + statedb.AddSlotToAccessList(addr, slot) + addrOk, slotOk = statedb.SlotInAccessList(addr, slot) + require.True(t, addrOk) + require.Nil(t, statedb.Err()) + require.True(t, slotOk) +} diff --git a/x/evm/state/balance.go b/x/evm/state/balance.go new file mode 100644 index 0000000000..493c8e4956 --- /dev/null +++ b/x/evm/state/balance.go @@ -0,0 +1,128 @@ +package state + +import ( + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func (s *DBImpl) SubBalance(evmAddr common.Address, amt *big.Int, reason tracing.BalanceChangeReason) { + s.k.PrepareReplayedAddr(s.ctx, evmAddr) + if amt.Sign() == 0 { + return + } + if amt.Sign() < 0 { + s.AddBalance(evmAddr, new(big.Int).Neg(amt), reason) + return + } + + ctx := s.ctx + + // this avoids emitting cosmos events for ephemeral bookkeeping transfers like send_native + if s.eventsSuppressed { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + } + + usei, wei := SplitUseiWeiAmount(amt) + addr := s.getSeiAddress(evmAddr) + s.err = s.k.BankKeeper().SubUnlockedCoins(ctx, addr, sdk.NewCoins(sdk.NewCoin(s.k.GetBaseDenom(s.ctx), usei)), true) + if s.err != nil { + return + } + s.err = s.k.BankKeeper().SubWei(ctx, addr, wei) + if s.err != nil { + return + } + + if s.logger != nil && s.logger.OnBalanceChange != nil { + // We could modify AddWei instead so it returns us the old/new balance directly. + newBalance := s.GetBalance(evmAddr) + oldBalance := new(big.Int).Add(newBalance, amt) + + s.logger.OnBalanceChange(evmAddr, oldBalance, newBalance, reason) + } + + s.tempStateCurrent.surplus = s.tempStateCurrent.surplus.Add(sdk.NewIntFromBigInt(amt)) +} + +func (s *DBImpl) AddBalance(evmAddr common.Address, amt *big.Int, reason tracing.BalanceChangeReason) { + s.k.PrepareReplayedAddr(s.ctx, evmAddr) + if amt.Sign() == 0 { + return + } + if amt.Sign() < 0 { + s.SubBalance(evmAddr, new(big.Int).Neg(amt), reason) + return + } + + ctx := s.ctx + // this avoids emitting cosmos events for ephemeral bookkeeping transfers like send_native + if s.eventsSuppressed { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + } + + usei, wei := SplitUseiWeiAmount(amt) + addr := s.getSeiAddress(evmAddr) + s.err = s.k.BankKeeper().AddCoins(ctx, addr, sdk.NewCoins(sdk.NewCoin(s.k.GetBaseDenom(s.ctx), usei)), true) + if s.err != nil { + return + } + s.err = s.k.BankKeeper().AddWei(ctx, addr, wei) + if s.err != nil { + return + } + + if s.logger != nil && s.logger.OnBalanceChange != nil { + // We could modify AddWei instead so it returns us the old/new balance directly. + newBalance := s.GetBalance(evmAddr) + oldBalance := new(big.Int).Sub(newBalance, amt) + + s.logger.OnBalanceChange(evmAddr, oldBalance, newBalance, reason) + } + + s.tempStateCurrent.surplus = s.tempStateCurrent.surplus.Sub(sdk.NewIntFromBigInt(amt)) +} + +func (s *DBImpl) GetBalance(evmAddr common.Address) *big.Int { + s.k.PrepareReplayedAddr(s.ctx, evmAddr) + usei := s.k.BankKeeper().GetBalance(s.ctx, s.getSeiAddress(evmAddr), s.k.GetBaseDenom(s.ctx)).Amount + wei := s.k.BankKeeper().GetWeiBalance(s.ctx, s.getSeiAddress(evmAddr)) + return usei.Mul(SdkUseiToSweiMultiplier).Add(wei).BigInt() +} + +// should only be called during simulation +func (s *DBImpl) SetBalance(evmAddr common.Address, amt *big.Int, reason tracing.BalanceChangeReason) { + if !s.simulation { + panic("should never call SetBalance in a non-simulation setting") + } + seiAddr := s.getSeiAddress(evmAddr) + moduleAddr := s.k.AccountKeeper().GetModuleAddress(types.ModuleName) + s.send(seiAddr, moduleAddr, s.GetBalance(evmAddr)) + if s.err != nil { + panic(s.err) + } + usei, _ := SplitUseiWeiAmount(amt) + coinsAmt := sdk.NewCoins(sdk.NewCoin(s.k.GetBaseDenom(s.ctx), usei.Add(sdk.OneInt()))) + if err := s.k.BankKeeper().MintCoins(s.ctx, types.ModuleName, coinsAmt); err != nil { + panic(err) + } + s.send(moduleAddr, seiAddr, amt) + if s.err != nil { + panic(s.err) + } +} + +func (s *DBImpl) getSeiAddress(evmAddr common.Address) sdk.AccAddress { + if s.coinbaseEvmAddress.Cmp(evmAddr) == 0 { + return s.coinbaseAddress + } + return s.k.GetSeiAddressOrDefault(s.ctx, evmAddr) +} + +func (s *DBImpl) send(from sdk.AccAddress, to sdk.AccAddress, amt *big.Int) { + usei, wei := SplitUseiWeiAmount(amt) + s.err = s.k.BankKeeper().SendCoinsAndWei(s.ctx, from, to, usei, wei) +} diff --git a/x/evm/state/balance_test.go b/x/evm/state/balance_test.go new file mode 100644 index 0000000000..d732b2fb30 --- /dev/null +++ b/x/evm/state/balance_test.go @@ -0,0 +1,150 @@ +package state_test + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/core/tracing" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestAddBalance(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + db := state.NewDBImpl(ctx, k, false) + seiAddr, evmAddr := testkeeper.MockAddressPair() + require.Equal(t, big.NewInt(0), db.GetBalance(evmAddr)) + db.AddBalance(evmAddr, big.NewInt(0), tracing.BalanceChangeUnspecified) + + // set association + k.SetAddressMapping(db.Ctx(), seiAddr, evmAddr) + require.Equal(t, big.NewInt(0), db.GetBalance(evmAddr)) + db.AddBalance(evmAddr, big.NewInt(10000000000000), tracing.BalanceChangeUnspecified) + require.Nil(t, db.Err()) + require.Equal(t, db.GetBalance(evmAddr), big.NewInt(10000000000000)) + + _, evmAddr2 := testkeeper.MockAddressPair() + db.SubBalance(evmAddr2, big.NewInt(-5000000000000), tracing.BalanceChangeUnspecified) // should redirect to AddBalance + require.Nil(t, db.Err()) + require.Equal(t, db.GetBalance(evmAddr), big.NewInt(10000000000000)) + require.Equal(t, db.GetBalance(evmAddr2), big.NewInt(5000000000000)) + + _, evmAddr3 := testkeeper.MockAddressPair() + db.SelfDestruct(evmAddr3) + db.AddBalance(evmAddr2, big.NewInt(5000000000000), tracing.BalanceChangeUnspecified) + require.Nil(t, db.Err()) + require.Equal(t, db.GetBalance(evmAddr3), big.NewInt(0)) +} + +func TestSubBalance(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + db := state.NewDBImpl(ctx, k, false) + seiAddr, evmAddr := testkeeper.MockAddressPair() + require.Equal(t, big.NewInt(0), db.GetBalance(evmAddr)) + db.SubBalance(evmAddr, big.NewInt(0), tracing.BalanceChangeUnspecified) + + // set association + k.SetAddressMapping(db.Ctx(), seiAddr, evmAddr) + require.Equal(t, big.NewInt(0), db.GetBalance(evmAddr)) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(20))) + k.BankKeeper().MintCoins(db.Ctx(), types.ModuleName, amt) + k.BankKeeper().SendCoinsFromModuleToAccount(db.Ctx(), types.ModuleName, seiAddr, amt) + db.SubBalance(evmAddr, big.NewInt(10000000000000), tracing.BalanceChangeUnspecified) + require.Nil(t, db.Err()) + require.Equal(t, db.GetBalance(evmAddr), big.NewInt(10000000000000)) + + _, evmAddr2 := testkeeper.MockAddressPair() + amt = sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(10))) + k.BankKeeper().MintCoins(db.Ctx(), types.ModuleName, amt) + k.BankKeeper().SendCoinsFromModuleToAccount(db.Ctx(), types.ModuleName, sdk.AccAddress(evmAddr2[:]), amt) + db.AddBalance(evmAddr2, big.NewInt(-5000000000000), tracing.BalanceChangeUnspecified) // should redirect to SubBalance + require.Nil(t, db.Err()) + require.Equal(t, db.GetBalance(evmAddr), big.NewInt(10000000000000)) + require.Equal(t, db.GetBalance(evmAddr2), big.NewInt(5000000000000)) + + // insufficient balance + db.SubBalance(evmAddr2, big.NewInt(10000000000000), tracing.BalanceChangeUnspecified) + require.NotNil(t, db.Err()) + + _, evmAddr3 := testkeeper.MockAddressPair() + db.SelfDestruct(evmAddr3) + db.SubBalance(evmAddr2, big.NewInt(5000000000000), tracing.BalanceChangeUnspecified) + require.Nil(t, db.Err()) + require.Equal(t, db.GetBalance(evmAddr3), big.NewInt(0)) +} + +func TestSetBalance(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + db := state.NewDBImpl(ctx, k, true) + _, evmAddr := testkeeper.MockAddressPair() + db.SetBalance(evmAddr, big.NewInt(10000000000000), tracing.BalanceChangeUnspecified) + require.Equal(t, big.NewInt(10000000000000), db.GetBalance(evmAddr)) + + seiAddr2, evmAddr2 := testkeeper.MockAddressPair() + k.SetAddressMapping(db.Ctx(), seiAddr2, evmAddr2) + db.SetBalance(evmAddr2, big.NewInt(10000000000000), tracing.BalanceChangeUnspecified) + require.Equal(t, big.NewInt(10000000000000), db.GetBalance(evmAddr2)) +} + +func TestSurplus(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, evmAddr := testkeeper.MockAddressPair() + + // test negative usei surplus negative wei surplus + 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") + + // 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") + + // test negative usei surplus positive wei surplus (positive total) + db = state.NewDBImpl(ctx, k, false) + db.AddBalance(evmAddr, big.NewInt(1_000_000_000_000), tracing.BalanceChangeUnspecified) + db.SubBalance(evmAddr, big.NewInt(2), tracing.BalanceChangeUnspecified) + db.SubBalance(evmAddr, big.NewInt(999_999_999_999), tracing.BalanceChangeUnspecified) + surplus, err := db.Finalize() + require.Nil(t, err) + require.Equal(t, sdk.OneInt(), surplus) + + // test positive usei surplus negative wei surplus (negative total) + db = state.NewDBImpl(ctx, k, false) + db.SubBalance(evmAddr, big.NewInt(1_000_000_000_000), tracing.BalanceChangeUnspecified) + 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") + + // test positive usei surplus negative wei surplus (positive total) + db = state.NewDBImpl(ctx, k, false) + db.SubBalance(evmAddr, big.NewInt(1_000_000_000_000), tracing.BalanceChangeUnspecified) + db.AddBalance(evmAddr, big.NewInt(999_999_999_999), tracing.BalanceChangeUnspecified) + surplus, err = db.Finalize() + require.Nil(t, err) + require.Equal(t, sdk.OneInt(), surplus) + + // test snapshots + db = state.NewDBImpl(ctx, k, false) + db.SubBalance(evmAddr, big.NewInt(1_000_000_000_000), tracing.BalanceChangeUnspecified) + db.AddBalance(evmAddr, big.NewInt(999_999_999_999), tracing.BalanceChangeUnspecified) + db.Snapshot() + db.SubBalance(evmAddr, big.NewInt(1_000_000_000_000), tracing.BalanceChangeUnspecified) + db.AddBalance(evmAddr, big.NewInt(999_999_999_999), tracing.BalanceChangeUnspecified) + db.Snapshot() + db.SubBalance(evmAddr, big.NewInt(1_000_000_000_000), tracing.BalanceChangeUnspecified) + db.AddBalance(evmAddr, big.NewInt(999_999_999_999), tracing.BalanceChangeUnspecified) + surplus, err = db.Finalize() + require.Nil(t, err) + require.Equal(t, sdk.NewInt(3), surplus) +} diff --git a/x/evm/state/check.go b/x/evm/state/check.go new file mode 100644 index 0000000000..3b3a6b606b --- /dev/null +++ b/x/evm/state/check.go @@ -0,0 +1,40 @@ +package state + +import ( + "bytes" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/sei-protocol/sei-chain/utils" +) + +// Exist reports whether the given account exists in state. +// Notably this should also return true for self-destructed accounts. +func (s *DBImpl) Exist(addr common.Address) bool { + s.k.PrepareReplayedAddr(s.ctx, addr) + // check if the address exists as a contract + codeHash := s.GetCodeHash(addr) + if codeHash.Cmp(ethtypes.EmptyCodeHash) != 0 && s.GetCodeHash(addr).Cmp(common.Hash{}) != 0 { + return true + } + + // check if the address exists as an EOA + if s.GetNonce(addr) > 0 { + return true + } + + // check if account has a balance + if s.GetBalance(addr).Cmp(utils.Big0) > 0 { + return true + } + + // go-ethereum impl considers just-deleted accounts as "exist" as well + return s.HasSelfDestructed(addr) +} + +// Empty returns whether the given account is empty. Empty +// is defined according to EIP161 (balance = nonce = code = 0). +func (s *DBImpl) Empty(addr common.Address) bool { + s.k.PrepareReplayedAddr(s.ctx, addr) + return s.GetBalance(addr).Cmp(utils.Big0) == 0 && s.GetNonce(addr) == 0 && bytes.Equal(s.GetCodeHash(addr).Bytes(), ethtypes.EmptyCodeHash.Bytes()) +} diff --git a/x/evm/state/check_test.go b/x/evm/state/check_test.go new file mode 100644 index 0000000000..6c631bd1be --- /dev/null +++ b/x/evm/state/check_test.go @@ -0,0 +1,56 @@ +package state_test + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/core/tracing" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" +) + +func TestExist(t *testing.T) { + // not exist + k, ctx := testkeeper.MockEVMKeeper() + _, addr := testkeeper.MockAddressPair() + statedb := state.NewDBImpl(ctx, k, false) + require.False(t, statedb.Exist(addr)) + + // has code + _, addr2 := testkeeper.MockAddressPair() + statedb.SetCode(addr2, []byte{3}) + require.True(t, statedb.Exist(addr2)) + + // has balance + _, addr3 := testkeeper.MockAddressPair() + statedb.AddBalance(addr3, big.NewInt(1000000000000), tracing.BalanceChangeUnspecified) + require.True(t, statedb.Exist(addr3)) + + // destructed + _, addr4 := testkeeper.MockAddressPair() + statedb.SelfDestruct(addr4) + require.True(t, statedb.Exist(addr4)) +} + +func TestEmpty(t *testing.T) { + // empty + k, ctx := testkeeper.MockEVMKeeper() + _, addr := testkeeper.MockAddressPair() + statedb := state.NewDBImpl(ctx, k, false) + require.True(t, statedb.Empty(addr)) + + // has balance + statedb.AddBalance(addr, big.NewInt(1000000000000), tracing.BalanceChangeUnspecified) + require.False(t, statedb.Empty(addr)) + + // has non-zero nonce + statedb.SubBalance(addr, big.NewInt(1000000000000), tracing.BalanceChangeUnspecified) + statedb.SetNonce(addr, 1) + require.False(t, statedb.Empty(addr)) + + // has code + statedb.SetNonce(addr, 0) + statedb.SetCode(addr, []byte{1}) + require.False(t, statedb.Empty(addr)) +} diff --git a/x/evm/state/code.go b/x/evm/state/code.go new file mode 100644 index 0000000000..f7596db075 --- /dev/null +++ b/x/evm/state/code.go @@ -0,0 +1,35 @@ +package state + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +func (s *DBImpl) GetCodeHash(addr common.Address) common.Hash { + s.k.PrepareReplayedAddr(s.ctx, addr) + return s.k.GetCodeHash(s.ctx, addr) +} + +func (s *DBImpl) GetCode(addr common.Address) []byte { + s.k.PrepareReplayedAddr(s.ctx, addr) + return s.k.GetCode(s.ctx, addr) +} + +func (s *DBImpl) SetCode(addr common.Address, code []byte) { + s.k.PrepareReplayedAddr(s.ctx, addr) + + if s.logger != nil && s.logger.OnCodeChange != nil { + // The SetCode method could be modified to return the old code/hash directly. + oldCode := s.GetCode(addr) + oldHash := s.GetCodeHash(addr) + + s.logger.OnCodeChange(addr, oldHash, oldCode, common.Hash(crypto.Keccak256(code)), code) + } + + s.k.SetCode(s.ctx, addr, code) +} + +func (s *DBImpl) GetCodeSize(addr common.Address) int { + s.k.PrepareReplayedAddr(s.ctx, addr) + return s.k.GetCodeSize(s.ctx, addr) +} diff --git a/x/evm/state/code_test.go b/x/evm/state/code_test.go new file mode 100644 index 0000000000..8930770452 --- /dev/null +++ b/x/evm/state/code_test.go @@ -0,0 +1,27 @@ +package state_test + +import ( + "testing" + + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" +) + +func TestCode(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, addr := testkeeper.MockAddressPair() + statedb := state.NewDBImpl(ctx, k, false) + + require.Equal(t, ethtypes.EmptyCodeHash, statedb.GetCodeHash(addr)) + require.Nil(t, statedb.GetCode(addr)) + require.Equal(t, 0, statedb.GetCodeSize(addr)) + + code := []byte{1, 2, 3, 4, 5} + statedb.SetCode(addr, code) + require.Equal(t, crypto.Keccak256Hash(code), statedb.GetCodeHash(addr)) + require.Equal(t, code, statedb.GetCode(addr)) + require.Equal(t, 5, statedb.GetCodeSize(addr)) +} diff --git a/x/evm/state/expected_keepers.go b/x/evm/state/expected_keepers.go new file mode 100644 index 0000000000..b84137e8f0 --- /dev/null +++ b/x/evm/state/expected_keepers.go @@ -0,0 +1,29 @@ +package state + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/ethereum/go-ethereum/common" +) + +type EVMKeeper interface { + PrefixStore(sdk.Context, []byte) sdk.KVStore + PurgePrefix(sdk.Context, []byte) + GetSeiAddress(sdk.Context, common.Address) (sdk.AccAddress, bool) + GetSeiAddressOrDefault(ctx sdk.Context, evmAddress common.Address) sdk.AccAddress + BankKeeper() bankkeeper.Keeper + GetBaseDenom(sdk.Context) string + DeleteAddressMapping(sdk.Context, sdk.AccAddress, common.Address) + GetCode(sdk.Context, common.Address) []byte + SetCode(sdk.Context, common.Address, []byte) + GetCodeHash(sdk.Context, common.Address) common.Hash + GetCodeSize(sdk.Context, common.Address) int + GetState(sdk.Context, common.Address, common.Hash) common.Hash + SetState(sdk.Context, common.Address, common.Hash, common.Hash) + AccountKeeper() *authkeeper.AccountKeeper + GetFeeCollectorAddress(sdk.Context) (common.Address, error) + GetNonce(sdk.Context, common.Address) uint64 + SetNonce(sdk.Context, common.Address, uint64) + PrepareReplayedAddr(ctx sdk.Context, addr common.Address) +} diff --git a/x/evm/state/keys.go b/x/evm/state/keys.go new file mode 100644 index 0000000000..f99ec0769e --- /dev/null +++ b/x/evm/state/keys.go @@ -0,0 +1,24 @@ +package state + +/* +* +Transient Module State Keys +*/ +var ( + // Represents the sum of all unassociated evm account balances + // If evm module balance is higher than this value at the end of + // the transaction, we need to burn from module balance in order + // for this number to align. + GasRefundKey = []byte{0x01} + LogsKey = []byte{0x02} + AccessListKey = []byte{0x03} +) + +/* +* +Transient Account State Keys +*/ +var ( + AccountCreated = []byte{0x01} + AccountDeleted = []byte{0x02} +) diff --git a/x/evm/state/log.go b/x/evm/state/log.go new file mode 100644 index 0000000000..682bca0dbe --- /dev/null +++ b/x/evm/state/log.go @@ -0,0 +1,32 @@ +package state + +import ( + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +type Logs struct { + Ls []*ethtypes.Log `json:"logs"` +} + +func (s *DBImpl) AddLog(l *ethtypes.Log) { + l.Index = uint(len(s.GetAllLogs())) + s.tempStateCurrent.logs = append(s.tempStateCurrent.logs, l) + + if s.logger != nil && s.logger.OnLog != nil { + s.logger.OnLog(l) + } +} + +func (s *DBImpl) GetAllLogs() []*ethtypes.Log { + res := []*ethtypes.Log{} + for _, st := range s.tempStatesHist { + res = append(res, st.logs...) + } + res = append(res, s.tempStateCurrent.logs...) + return res +} + +func (s *DBImpl) GetLogs(common.Hash, uint64, common.Hash) []*ethtypes.Log { + return s.GetAllLogs() +} diff --git a/x/evm/state/log_test.go b/x/evm/state/log_test.go new file mode 100644 index 0000000000..afbbf83a87 --- /dev/null +++ b/x/evm/state/log_test.go @@ -0,0 +1,49 @@ +package state_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/state" + "github.com/stretchr/testify/require" +) + +func TestAddLog(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + statedb := state.NewDBImpl(ctx, k, false) + + logs := statedb.GetAllLogs() + require.Empty(t, logs) + + log1 := ethtypes.Log{Address: common.BytesToAddress([]byte{1}), Topics: []common.Hash{}, Data: []byte{}} + statedb.AddLog(&log1) + require.Nil(t, statedb.Err()) + logs = statedb.GetAllLogs() + require.Equal(t, 1, len(logs)) + require.Equal(t, log1, *logs[0]) + + log2 := ethtypes.Log{Address: common.BytesToAddress([]byte{2}), Topics: []common.Hash{}, Data: []byte{3}} + statedb.AddLog(&log2) + require.Nil(t, statedb.Err()) + logs = statedb.GetAllLogs() + require.Equal(t, 2, len(logs)) + require.Equal(t, log1, *logs[0]) + require.Equal(t, log2, *logs[1]) + + logs = statedb.GetLogs(common.Hash{}, 0, common.Hash{}) + require.Equal(t, 2, len(logs)) +} + +func TestLogIndex(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + statedb := state.NewDBImpl(ctx, k, false) + statedb.AddLog(ðtypes.Log{}) + statedb.Snapshot() + statedb.AddLog(ðtypes.Log{}) + logs := statedb.GetAllLogs() + require.Equal(t, 2, len(logs)) + require.Equal(t, uint(0), logs[0].Index) + require.Equal(t, uint(1), logs[1].Index) +} diff --git a/x/evm/state/nonce.go b/x/evm/state/nonce.go new file mode 100644 index 0000000000..d6eaef234f --- /dev/null +++ b/x/evm/state/nonce.go @@ -0,0 +1,21 @@ +package state + +import ( + "github.com/ethereum/go-ethereum/common" +) + +func (s *DBImpl) GetNonce(addr common.Address) uint64 { + s.k.PrepareReplayedAddr(s.ctx, addr) + return s.k.GetNonce(s.ctx, addr) +} + +func (s *DBImpl) SetNonce(addr common.Address, nonce uint64) { + s.k.PrepareReplayedAddr(s.ctx, addr) + + if s.logger != nil && s.logger.OnNonceChange != nil { + // The SetCode method could be modified to return the old code/hash directly. + s.logger.OnNonceChange(addr, s.GetNonce(addr), nonce) + } + + s.k.SetNonce(s.ctx, addr, nonce) +} diff --git a/x/evm/state/nonce_test.go b/x/evm/state/nonce_test.go new file mode 100644 index 0000000000..ed8b579f0a --- /dev/null +++ b/x/evm/state/nonce_test.go @@ -0,0 +1,21 @@ +package state_test + +import ( + "github.com/stretchr/testify/require" + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" +) + +func TestNonce(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + stateDB := state.NewDBImpl(ctx, k, false) + _, addr := testkeeper.MockAddressPair() + stateDB.SetNonce(addr, 1) + nonce := stateDB.GetNonce(addr) + require.Equal(t, nonce, uint64(1)) + stateDB.SetNonce(addr, 2) + nonce = stateDB.GetNonce(addr) + require.Equal(t, nonce, uint64(2)) +} diff --git a/x/evm/state/refund.go b/x/evm/state/refund.go new file mode 100644 index 0000000000..c403b4d21b --- /dev/null +++ b/x/evm/state/refund.go @@ -0,0 +1,33 @@ +package state + +import ( + "encoding/binary" + "fmt" +) + +func (s *DBImpl) AddRefund(gas uint64) { + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, s.GetRefund()+gas) + s.tempStateCurrent.transientModuleStates[string(GasRefundKey)] = bz +} + +// Copied from go-ethereum as-is +// SubRefund removes gas from the refund counter. +// This method will panic if the refund counter goes below zero +func (s *DBImpl) SubRefund(gas uint64) { + refund := s.GetRefund() + if gas > refund { + panic(fmt.Sprintf("Refund counter below zero (gas: %d > refund: %d)", gas, refund)) + } + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, refund-gas) + s.tempStateCurrent.transientModuleStates[string(GasRefundKey)] = bz +} + +func (s *DBImpl) GetRefund() uint64 { + bz, found := s.getTransientModule(GasRefundKey) + if !found || bz == nil { + return 0 + } + return binary.BigEndian.Uint64(bz) +} diff --git a/x/evm/state/refund_test.go b/x/evm/state/refund_test.go new file mode 100644 index 0000000000..a2810f3e60 --- /dev/null +++ b/x/evm/state/refund_test.go @@ -0,0 +1,21 @@ +package state_test + +import ( + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" +) + +func TestGasRefund(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + statedb := state.NewDBImpl(ctx, k, false) + + require.Equal(t, uint64(0), statedb.GetRefund()) + statedb.AddRefund(2) + require.Equal(t, uint64(2), statedb.GetRefund()) + statedb.SubRefund(1) + require.Equal(t, uint64(1), statedb.GetRefund()) + require.Panics(t, func() { statedb.SubRefund(2) }) +} diff --git a/x/evm/state/state.go b/x/evm/state/state.go new file mode 100644 index 0000000000..7d88551767 --- /dev/null +++ b/x/evm/state/state.go @@ -0,0 +1,202 @@ +package state + +import ( + "bytes" + + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/sei-protocol/sei-chain/utils" + "github.com/sei-protocol/sei-chain/x/evm/types" +) + +func (s *DBImpl) CreateAccount(acc common.Address) { + s.k.PrepareReplayedAddr(s.ctx, acc) + // clear any existing state but keep balance untouched + s.clearAccountState(acc) + s.MarkAccount(acc, AccountCreated) +} + +func (s *DBImpl) GetCommittedState(addr common.Address, hash common.Hash) common.Hash { + return s.getState(s.snapshottedCtxs[0], addr, hash) +} + +func (s *DBImpl) GetState(addr common.Address, hash common.Hash) common.Hash { + return s.getState(s.ctx, addr, hash) +} + +func (s *DBImpl) getState(ctx sdk.Context, addr common.Address, hash common.Hash) common.Hash { + s.k.PrepareReplayedAddr(ctx, addr) + return s.k.GetState(ctx, addr, hash) +} + +func (s *DBImpl) SetState(addr common.Address, key common.Hash, val common.Hash) { + s.k.PrepareReplayedAddr(s.ctx, addr) + + if s.logger != nil && s.logger.OnStorageChange != nil { + s.logger.OnStorageChange(addr, key, s.GetState(addr, key), val) + } + + s.k.SetState(s.ctx, addr, key, val) +} + +func (s *DBImpl) GetTransientState(addr common.Address, key common.Hash) common.Hash { + val, found := s.getTransientState(addr, key) + if !found { + return common.Hash{} + } + return val +} + +func (s *DBImpl) SetTransientState(addr common.Address, key, val common.Hash) { + st, ok := s.tempStateCurrent.transientStates[addr.Hex()] + if !ok { + st = make(map[string]common.Hash) + s.tempStateCurrent.transientStates[addr.Hex()] = st + } + st[key.Hex()] = val +} + +// debits account's balance. The corresponding credit happens here: +// https://github.com/sei-protocol/go-ethereum/blob/master/core/vm/instructions.go#L825 +// clear account's state except the transient state (in Ethereum transient states are +// still available even after self destruction in the same tx) +func (s *DBImpl) SelfDestruct(acc common.Address) { + s.k.PrepareReplayedAddr(s.ctx, acc) + if seiAddr, ok := s.k.GetSeiAddress(s.ctx, acc); ok { + // remove the association + s.k.DeleteAddressMapping(s.ctx, seiAddr, acc) + } + + s.SubBalance(acc, s.GetBalance(acc), tracing.BalanceDecreaseSelfdestruct) + + // mark account as self-destructed + s.MarkAccount(acc, AccountDeleted) +} + +func (s *DBImpl) Selfdestruct6780(acc common.Address) { + // only self-destruct if acc is newly created in the same block + if s.Created(acc) { + s.SelfDestruct(acc) + } +} + +// the Ethereum semantics of HasSelfDestructed checks if the account is self destructed in the +// **CURRENT** block +func (s *DBImpl) HasSelfDestructed(acc common.Address) bool { + val, found := s.getTransientAccount(acc) + if !found || val == nil { + return false + } + return bytes.Equal(val, AccountDeleted) +} + +func (s *DBImpl) Snapshot() int { + newCtx := s.ctx.WithMultiStore(s.ctx.MultiStore().CacheMultiStore()) + s.snapshottedCtxs = append(s.snapshottedCtxs, s.ctx) + s.ctx = newCtx + s.tempStatesHist = append(s.tempStatesHist, s.tempStateCurrent) + s.tempStateCurrent = NewTemporaryState() + return len(s.snapshottedCtxs) - 1 +} + +func (s *DBImpl) RevertToSnapshot(rev int) { + s.ctx = s.snapshottedCtxs[rev] + s.snapshottedCtxs = s.snapshottedCtxs[:rev] + s.tempStateCurrent = s.tempStatesHist[rev] + s.tempStatesHist = s.tempStatesHist[:rev] + s.Snapshot() +} + +func (s *DBImpl) handleResidualFundsInDestructedAccounts(st *TemporaryState) { + for a, status := range st.transientAccounts { + if !bytes.Equal(status, AccountDeleted) { + continue + } + acc := common.HexToAddress(a) + residual := s.GetBalance(acc) + if residual.Cmp(utils.Big0) == 0 { + continue + } + s.SubBalance(acc, residual, tracing.BalanceDecreaseSelfdestructBurn) + // we don't want to really "burn" the token since it will mess up + // total supply calculation, so we send them to fee collector instead + s.AddBalance(s.coinbaseEvmAddress, residual, tracing.BalanceDecreaseSelfdestructBurn) + } +} + +func (s *DBImpl) clearAccountStateIfDestructed(st *TemporaryState) { + for acc, status := range st.transientAccounts { + if !bytes.Equal(status, AccountDeleted) { + continue + } + s.clearAccountState(common.HexToAddress(acc)) + } +} + +func (s *DBImpl) clearAccountState(acc common.Address) { + s.k.PrepareReplayedAddr(s.ctx, acc) + s.k.PurgePrefix(s.ctx, types.StateKey(acc)) + deleteIfExists(s.k.PrefixStore(s.ctx, types.CodeKeyPrefix), acc[:]) + deleteIfExists(s.k.PrefixStore(s.ctx, types.CodeSizeKeyPrefix), acc[:]) + deleteIfExists(s.k.PrefixStore(s.ctx, types.CodeHashKeyPrefix), acc[:]) + deleteIfExists(s.k.PrefixStore(s.ctx, types.NonceKeyPrefix), acc[:]) +} + +func (s *DBImpl) MarkAccount(acc common.Address, status []byte) { + // val being nil means it's deleted + s.tempStateCurrent.transientAccounts[acc.Hex()] = status +} + +func (s *DBImpl) Created(acc common.Address) bool { + val, found := s.getTransientAccount(acc) + if !found || val == nil { + return false + } + return bytes.Equal(val, AccountCreated) +} + +func (s *DBImpl) SetStorage(addr common.Address, states map[common.Hash]common.Hash) { + s.clearAccountState(addr) + for key, val := range states { + s.SetState(addr, key, val) + } +} + +func (s *DBImpl) getTransientAccount(acc common.Address) ([]byte, bool) { + val, found := s.tempStateCurrent.transientAccounts[acc.Hex()] + for i := len(s.tempStatesHist) - 1; !found && i >= 0; i-- { + val, found = s.tempStatesHist[i].transientAccounts[acc.Hex()] + } + return val, found +} + +func (s *DBImpl) getTransientModule(key []byte) ([]byte, bool) { + val, found := s.tempStateCurrent.transientModuleStates[string(key)] + for i := len(s.tempStatesHist) - 1; !found && i >= 0; i-- { + val, found = s.tempStatesHist[i].transientModuleStates[string(key)] + } + return val, found +} + +func (s *DBImpl) getTransientState(acc common.Address, key common.Hash) (common.Hash, bool) { + var val common.Hash + m, found := s.tempStateCurrent.transientStates[acc.Hex()] + if found { + val, found = m[key.Hex()] + } + for i := len(s.tempStatesHist) - 1; !found && i >= 0; i-- { + m, found = s.tempStatesHist[i].transientStates[acc.Hex()] + if found { + val, found = m[key.Hex()] + } + } + return val, found +} + +func deleteIfExists(store storetypes.KVStore, key []byte) { + if store.Has(key) { + store.Delete(key) + } +} diff --git a/x/evm/state/state_test.go b/x/evm/state/state_test.go new file mode 100644 index 0000000000..1b165d63ff --- /dev/null +++ b/x/evm/state/state_test.go @@ -0,0 +1,168 @@ +package state_test + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestState(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, evmAddr := testkeeper.MockAddressPair() + statedb := state.NewDBImpl(ctx, k, false) + statedb.CreateAccount(evmAddr) + require.True(t, statedb.Created(evmAddr)) + require.False(t, statedb.HasSelfDestructed(evmAddr)) + statedb.AddBalance(evmAddr, big.NewInt(10), tracing.BalanceChangeUnspecified) + k.BankKeeper().MintCoins(statedb.Ctx(), types.ModuleName, sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(10)))) + key := common.BytesToHash([]byte("abc")) + val := common.BytesToHash([]byte("def")) + statedb.SetState(evmAddr, key, val) + require.Equal(t, val, statedb.GetState(evmAddr, key)) + require.Equal(t, common.Hash{}, statedb.GetCommittedState(evmAddr, key)) + // fork the store and overwrite the key + statedb.Snapshot() + newVal := common.BytesToHash([]byte("ghi")) + statedb.SetState(evmAddr, key, newVal) + require.Equal(t, newVal, statedb.GetState(evmAddr, key)) + require.Equal(t, common.Hash{}, statedb.GetCommittedState(evmAddr, key)) + tkey := common.BytesToHash([]byte("jkl")) + tval := common.BytesToHash([]byte("mno")) + statedb.SetTransientState(evmAddr, tkey, tval) + require.Equal(t, tval, statedb.GetTransientState(evmAddr, tkey)) + // destruct should clear balance, but keep state. Committed state should also be accessible + // state would be cleared after finalize + statedb.SelfDestruct(evmAddr) + require.Equal(t, tval, statedb.GetTransientState(evmAddr, tkey)) + require.NotEqual(t, common.Hash{}, statedb.GetState(evmAddr, key)) + require.Equal(t, common.Hash{}, statedb.GetCommittedState(evmAddr, key)) + require.Equal(t, big.NewInt(0), statedb.GetBalance(evmAddr)) + require.True(t, statedb.HasSelfDestructed(evmAddr)) + statedb.Finalize() + require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, key)) + // set storage + statedb.SetStorage(evmAddr, map[common.Hash]common.Hash{{}: {}}) + require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, common.Hash{})) +} + +func TestCreate(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + _, evmAddr := testkeeper.MockAddressPair() + statedb := state.NewDBImpl(ctx, k, false) + statedb.CreateAccount(evmAddr) + require.False(t, statedb.HasSelfDestructed(evmAddr)) + key := common.BytesToHash([]byte("abc")) + val := common.BytesToHash([]byte("def")) + tkey := common.BytesToHash([]byte("jkl")) + tval := common.BytesToHash([]byte("mno")) + statedb.SetState(evmAddr, key, val) + statedb.SetTransientState(evmAddr, tkey, tval) + statedb.AddBalance(evmAddr, big.NewInt(10000000000000), tracing.BalanceChangeUnspecified) + // recreate an account should clear its state, but keep its balance and transient state + statedb.CreateAccount(evmAddr) + require.Equal(t, tval, statedb.GetTransientState(evmAddr, tkey)) + require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, key)) + require.Equal(t, big.NewInt(10000000000000), statedb.GetBalance(evmAddr)) + require.True(t, statedb.Created(evmAddr)) + require.False(t, statedb.HasSelfDestructed(evmAddr)) + // recreate a destructed (in the same tx) account should clear its selfDestructed flag + statedb.SelfDestruct(evmAddr) + require.Nil(t, statedb.Err()) + require.True(t, statedb.HasSelfDestructed(evmAddr)) + require.Equal(t, big.NewInt(0), statedb.GetBalance(evmAddr)) + statedb.CreateAccount(evmAddr) + require.Equal(t, tval, statedb.GetTransientState(evmAddr, tkey)) + require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, key)) + require.Equal(t, big.NewInt(0), statedb.GetBalance(evmAddr)) // cleared during SelfDestruct + require.True(t, statedb.Created(evmAddr)) + require.False(t, statedb.HasSelfDestructed(evmAddr)) +} + +func TestSelfDestructAssociated(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + seiAddr, evmAddr := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, seiAddr, evmAddr) + statedb := state.NewDBImpl(ctx, k, false) + statedb.CreateAccount(evmAddr) + key := common.BytesToHash([]byte("abc")) + val := common.BytesToHash([]byte("def")) + tkey := common.BytesToHash([]byte("jkl")) + tval := common.BytesToHash([]byte("mno")) + statedb.SetState(evmAddr, key, val) + statedb.SetTransientState(evmAddr, tkey, tval) + amt := sdk.NewCoins(sdk.NewCoin(k.GetBaseDenom(ctx), sdk.NewInt(10))) + k.BankKeeper().MintCoins(statedb.Ctx(), types.ModuleName, amt) + k.BankKeeper().SendCoinsFromModuleToAccount(statedb.Ctx(), types.ModuleName, seiAddr, amt) + + // Selfdestruct6780 should only act if the account is created in the same block + statedb.MarkAccount(evmAddr, nil) + statedb.Selfdestruct6780(evmAddr) + require.Equal(t, val, statedb.GetState(evmAddr, key)) + statedb.MarkAccount(evmAddr, state.AccountCreated) + require.False(t, statedb.HasSelfDestructed(evmAddr)) + + // Selfdestruct6780 is equivalent to SelfDestruct if account is created in the same block + statedb.Selfdestruct6780(evmAddr) + require.Equal(t, tval, statedb.GetTransientState(evmAddr, tkey)) + require.NotEqual(t, common.Hash{}, statedb.GetState(evmAddr, key)) + require.Equal(t, big.NewInt(0), statedb.GetBalance(evmAddr)) + require.Equal(t, big.NewInt(0), k.BankKeeper().GetBalance(ctx, seiAddr, k.GetBaseDenom(ctx)).Amount.BigInt()) + require.True(t, statedb.HasSelfDestructed(evmAddr)) + require.False(t, statedb.Created(evmAddr)) + statedb.AddBalance(evmAddr, big.NewInt(1), tracing.BalanceChangeUnspecified) + require.Equal(t, big.NewInt(1), statedb.GetBalance(evmAddr)) + statedb.Finalize() + require.Equal(t, common.Hash{}, statedb.GetState(evmAddr, key)) + // association should also be removed + _, ok := k.GetSeiAddress(statedb.Ctx(), evmAddr) + require.False(t, ok) + // balance in destructed account should be cleared and transferred to coinbase + require.Equal(t, big.NewInt(0), statedb.GetBalance(evmAddr)) + fc, _ := k.GetFeeCollectorAddress(statedb.Ctx()) + require.Equal(t, big.NewInt(1), statedb.GetBalance(fc)) +} + +func TestSnapshot(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + seiAddr, evmAddr := testkeeper.MockAddressPair() + k.SetAddressMapping(ctx, seiAddr, evmAddr) + statedb := state.NewDBImpl(ctx, k, false) + statedb.CreateAccount(evmAddr) + key := common.BytesToHash([]byte("abc")) + val := common.BytesToHash([]byte("def")) + tkey := common.BytesToHash([]byte("jkl")) + tval := common.BytesToHash([]byte("mno")) + statedb.SetState(evmAddr, key, val) + statedb.SetTransientState(evmAddr, tkey, tval) + + rev := statedb.Snapshot() + + newVal := common.BytesToHash([]byte("x")) + newTVal := common.BytesToHash([]byte("y")) + statedb.SetState(evmAddr, key, newVal) + statedb.SetTransientState(evmAddr, tkey, newTVal) + + statedb.RevertToSnapshot(rev) + + require.Equal(t, tval, statedb.GetTransientState(evmAddr, tkey)) + require.Equal(t, val, statedb.GetState(evmAddr, key)) + + newStateDB := state.NewDBImpl(ctx, k, false) + // prev state DB not committed yet + require.Equal(t, common.Hash{}, newStateDB.GetTransientState(evmAddr, tkey)) + require.Equal(t, common.Hash{}, newStateDB.GetState(evmAddr, key)) + + _, err := statedb.Finalize() + require.Nil(t, err) + newStateDB = state.NewDBImpl(ctx, k, false) + // prev state DB committed except for transient states + require.Equal(t, common.Hash{}, newStateDB.GetTransientState(evmAddr, tkey)) + require.Equal(t, val, newStateDB.GetState(evmAddr, key)) +} diff --git a/x/evm/state/statedb.go b/x/evm/state/statedb.go new file mode 100644 index 0000000000..4988b3e9b1 --- /dev/null +++ b/x/evm/state/statedb.go @@ -0,0 +1,202 @@ +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 +type DBImpl struct { + ctx sdk.Context + snapshottedCtxs []sdk.Context + + tempStateCurrent *TemporaryState + tempStatesHist []*TemporaryState + // If err is not nil at the end of the execution, the transaction will be rolled + // back. + err 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 + // before the block commits + coinbaseAddress sdk.AccAddress + coinbaseEvmAddress common.Address + + k EVMKeeper + simulation bool + + // for cases like bank.send_native, we want to suppress transfer events + eventsSuppressed bool + + logger *tracing.Hooks +} + +func NewDBImpl(ctx sdk.Context, k EVMKeeper, simulation bool) *DBImpl { + feeCollector, _ := k.GetFeeCollectorAddress(ctx) + s := &DBImpl{ + ctx: ctx, + k: k, + snapshottedCtxs: []sdk.Context{}, + coinbaseAddress: GetCoinbaseAddress(ctx.TxIndex()), + simulation: simulation, + tempStateCurrent: NewTemporaryState(), + coinbaseEvmAddress: feeCollector, + } + s.Snapshot() // take an initial snapshot for GetCommitted + return s +} + +func (s *DBImpl) DisableEvents() { + s.eventsSuppressed = true +} + +func (s *DBImpl) EnableEvents() { + s.eventsSuppressed = false +} + +func (s *DBImpl) SetLogger(logger *tracing.Hooks) { + s.logger = logger +} + +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) }) +} + +// AddPreimage records a SHA3 preimage seen by the VM. +// AddPreimage performs a no-op since the EnablePreimageRecording flag is disabled +// on the vm.Config during state transitions. No store trie preimages are written +// to the database. +func (s *DBImpl) AddPreimage(_ common.Hash, _ []byte) {} + +func (s *DBImpl) Finalize() (surplus sdk.Int, err error) { + if s.simulation { + panic("should never call finalize on a simulation DB") + } + if s.err != nil { + err = s.err + return + } + + // delete state of self-destructed accounts + s.handleResidualFundsInDestructedAccounts(s.tempStateCurrent) + s.clearAccountStateIfDestructed(s.tempStateCurrent) + for _, ts := range s.tempStatesHist { + s.handleResidualFundsInDestructedAccounts(ts) + s.clearAccountStateIfDestructed(ts) + } + + // remove transient states + // write cache to underlying + s.flushCtx(s.ctx) + // write all snapshotted caches in reverse order, except the very first one (base) which will be written by baseapp::runTx + for i := len(s.snapshottedCtxs) - 1; i > 0; i-- { + s.flushCtx(s.snapshottedCtxs[i]) + } + + surplus = s.tempStateCurrent.surplus + for _, ts := range s.tempStatesHist { + surplus = surplus.Add(ts.surplus) + } + if surplus.IsNegative() { + err = fmt.Errorf("negative surplus value: %s", surplus.String()) + } + return +} + +func (s *DBImpl) flushCtx(ctx sdk.Context) { + ctx.MultiStore().(sdk.CacheMultiStore).Write() +} + +// Backward-compatibility functions +func (s *DBImpl) Error() error { + return s.Err() +} + +func (s *DBImpl) GetStorageRoot(common.Address) common.Hash { + panic("GetStorageRoot is not implemented and called unexpectedly") +} + +func (s *DBImpl) Copy() vm.StateDB { + newCtx := s.ctx.WithMultiStore(s.ctx.MultiStore().CacheMultiStore()) + return &DBImpl{ + ctx: newCtx, + snapshottedCtxs: append(s.snapshottedCtxs, s.ctx), + tempStateCurrent: NewTemporaryState(), + tempStatesHist: append(s.tempStatesHist, s.tempStateCurrent), + k: s.k, + coinbaseAddress: s.coinbaseAddress, + coinbaseEvmAddress: s.coinbaseEvmAddress, + simulation: s.simulation, + err: s.err, + logger: s.logger, + } +} + +func (s *DBImpl) Finalise(bool) { + s.ctx.Logger().Info("Finalise should only be called during simulation and will no-op") +} + +func (s *DBImpl) Commit(uint64, bool) (common.Hash, error) { + panic("Commit is not implemented and called unexpectedly") +} + +func (s *DBImpl) SetTxContext(common.Hash, int) { + //noop +} + +func (s *DBImpl) IntermediateRoot(bool) common.Hash { + panic("IntermediateRoot is not implemented and called unexpectedly") +} + +func (s *DBImpl) TxIndex() int { + return s.ctx.TxIndex() +} + +func (s *DBImpl) Preimages() map[common.Hash][]byte { + return map[common.Hash][]byte{} +} + +// ** TEST ONLY FUNCTIONS **// +func (s *DBImpl) Err() error { + return s.err +} + +func (s *DBImpl) WithErr(err error) { + s.err = err +} + +func (s *DBImpl) Ctx() sdk.Context { + return s.ctx +} + +func (s *DBImpl) WithCtx(ctx sdk.Context) { + s.ctx = ctx +} + +// in-memory state that's generated by a specific +// EVM snapshot in a single transaction +type TemporaryState struct { + logs []*ethtypes.Log + transientStates map[string]map[string]common.Hash + transientAccounts map[string][]byte + transientModuleStates map[string][]byte + surplus sdk.Int // in wei +} + +func NewTemporaryState() *TemporaryState { + return &TemporaryState{ + logs: []*ethtypes.Log{}, + transientStates: make(map[string]map[string]common.Hash), + transientAccounts: make(map[string][]byte), + transientModuleStates: make(map[string][]byte), + surplus: utils.Sdk0, + } +} diff --git a/x/evm/state/transfer.go b/x/evm/state/transfer.go new file mode 100644 index 0000000000..9a75be9e7a --- /dev/null +++ b/x/evm/state/transfer.go @@ -0,0 +1,21 @@ +package state + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/vm" +) + +func TransferWithoutEvents(db vm.StateDB, sender, recipient common.Address, amount *big.Int) { + sdb, ok := db.(*DBImpl) + if !ok { + panic("EventlessTransfer only works with DBImpl") + } + sdb.DisableEvents() + defer sdb.EnableEvents() + + sdb.SubBalance(sender, amount, tracing.BalanceChangeTransfer) + sdb.AddBalance(recipient, amount, tracing.BalanceChangeTransfer) +} diff --git a/x/evm/state/transfer_test.go b/x/evm/state/transfer_test.go new file mode 100644 index 0000000000..f633dc8792 --- /dev/null +++ b/x/evm/state/transfer_test.go @@ -0,0 +1,24 @@ +package state_test + +import ( + "math/big" + "testing" + + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" +) + +func TestEventlessTransfer(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + db := state.NewDBImpl(ctx, k, false) + _, fromAddr := testkeeper.MockAddressPair() + _, toAddr := testkeeper.MockAddressPair() + + beforeLen := len(ctx.EventManager().ABCIEvents()) + + state.TransferWithoutEvents(db, fromAddr, toAddr, big.NewInt(100)) + + // should be unchanged + require.Len(t, ctx.EventManager().ABCIEvents(), beforeLen) +} diff --git a/x/evm/state/utils.go b/x/evm/state/utils.go new file mode 100644 index 0000000000..5ad268b39a --- /dev/null +++ b/x/evm/state/utils.go @@ -0,0 +1,27 @@ +package state + +import ( + "encoding/binary" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// UseiToSweiMultiplier Fields that were denominated in usei will be converted to swei (1usei = 10^12swei) +// for existing Ethereum application (which assumes 18 decimal points) to display properly. +var UseiToSweiMultiplier = big.NewInt(1_000_000_000_000) +var SdkUseiToSweiMultiplier = sdk.NewIntFromBigInt(UseiToSweiMultiplier) + +var CoinbaseAddressPrefix = []byte("evm_coinbase") + +func GetCoinbaseAddress(txIdx int) sdk.AccAddress { + txIndexBz := make([]byte, 8) + binary.BigEndian.PutUint64(txIndexBz, uint64(txIdx)) + return append(CoinbaseAddressPrefix, txIndexBz...) +} + +func SplitUseiWeiAmount(amt *big.Int) (sdk.Int, sdk.Int) { + wei := new(big.Int).Mod(amt, UseiToSweiMultiplier) + usei := new(big.Int).Quo(amt, UseiToSweiMultiplier) + return sdk.NewIntFromBigInt(usei), sdk.NewIntFromBigInt(wei) +} diff --git a/x/evm/state/utils_test.go b/x/evm/state/utils_test.go new file mode 100644 index 0000000000..3b01ea1510 --- /dev/null +++ b/x/evm/state/utils_test.go @@ -0,0 +1,52 @@ +package state_test + +import ( + "math/big" + "testing" + + "github.com/sei-protocol/sei-chain/x/evm/state" + "github.com/stretchr/testify/require" +) + +func TestGetCoinbaseAddress(t *testing.T) { + coinbaseAddr := state.GetCoinbaseAddress(1).String() + require.Equal(t, coinbaseAddr, "sei1v4mx6hmrda5kucnpwdjsqqqqqqqqqqqpz6djs7") +} + +func TestSplitUseiWeiAmount(t *testing.T) { + for _, test := range []struct { + amt *big.Int + expectedSei *big.Int + expectedWei *big.Int + }{ + { + amt: big.NewInt(0), + expectedSei: big.NewInt(0), + expectedWei: big.NewInt(0), + }, { + amt: big.NewInt(1), + expectedSei: big.NewInt(0), + expectedWei: big.NewInt(1), + }, { + amt: big.NewInt(999_999_999_999), + expectedSei: big.NewInt(0), + expectedWei: big.NewInt(999_999_999_999), + }, { + amt: big.NewInt(1_000_000_000_000), + expectedSei: big.NewInt(1), + expectedWei: big.NewInt(0), + }, { + amt: big.NewInt(1_000_000_000_001), + expectedSei: big.NewInt(1), + expectedWei: big.NewInt(1), + }, { + amt: big.NewInt(123_456_789_123_456_789), + expectedSei: big.NewInt(123456), + expectedWei: big.NewInt(789_123_456_789), + }, + } { + usei, wei := state.SplitUseiWeiAmount(test.amt) + require.Equal(t, test.expectedSei, usei.BigInt()) + require.Equal(t, test.expectedWei, wei.BigInt()) + } +} diff --git a/x/evm/types/NativeSeiTokensERC20.bin b/x/evm/types/NativeSeiTokensERC20.bin new file mode 100644 index 0000000000..4c372396a7 --- /dev/null +++ b/x/evm/types/NativeSeiTokensERC20.bin @@ -0,0 +1 @@ +60806040523480156200001157600080fd5b5060405162000e6a38038062000e6a8339810160408190526200003491620000b0565b6040805160208082018352600080835283519182019093529182529060036200005e838262000216565b5060046200006d828262000216565b5050600680546001600160a01b03191661100117905550600562000092828262000216565b5050620002e2565b634e487b7160e01b600052604160045260246000fd5b60006020808385031215620000c457600080fd5b82516001600160401b0380821115620000dc57600080fd5b818501915085601f830112620000f157600080fd5b8151818111156200010657620001066200009a565b604051601f8201601f19908116603f011681019083821181831017156200013157620001316200009a565b8160405282815288868487010111156200014a57600080fd5b600093505b828410156200016e57848401860151818501870152928501926200014f565b600086848301015280965050505050505092915050565b600181811c908216806200019a57607f821691505b602082108103620001bb57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000211576000816000526020600020601f850160051c81016020861015620001ec5750805b601f850160051c820191505b818110156200020d57828155600101620001f8565b5050505b505050565b81516001600160401b038111156200023257620002326200009a565b6200024a8162000243845462000185565b84620001c1565b602080601f831160018114620002825760008415620002695750858301515b600019600386901b1c1916600185901b1785556200020d565b600085815260208120601f198616915b82811015620002b35788860151825594840194600190910190840162000292565b5085821015620002d25787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b610b7880620002f26000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063566732c111610071578063566732c11461013257806370a082311461015d57806395d89b4114610170578063a9059cbb14610178578063c370b0421461018b578063dd62ed3e1461019357600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610105578063313ce56714610118575b600080fd5b6100b66101cc565b6040516100c391906107bd565b60405180910390f35b6100df6100da36600461080c565b610248565b60405190151581526020016100c3565b6100f7610260565b6040519081526020016100c3565b6100df610113366004610836565b6102d3565b6101206102f7565b60405160ff90911681526020016100c3565b600654610145906001600160a01b031681565b6040516001600160a01b0390911681526020016100c3565b6100f761016b366004610872565b61036a565b6100b66103e5565b6100df61018636600461080c565b610417565b6100b6610425565b6100f76101a1366004610894565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600654604051635b43bc9960e01b81526060916001600160a01b031690635b43bc99906101fe906005906004016109a5565b600060405180830381865afa15801561021b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261024391908101906109ce565b905090565b6000336102568185856104b3565b5060019392505050565b600654604051636923a1fd60e01b81526000916001600160a01b031690636923a1fd90610292906005906004016109a5565b602060405180830381865afa1580156102af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102439190610a7b565b6000336102e18582856104c5565b6102ec858585610548565b506001949350505050565b600654604051630ecacc8160e21b81526000916001600160a01b031690633b2b320490610329906005906004016109a5565b602060405180830381865afa158015610346573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102439190610a94565b6006546040516316cadeab60e01b81526000916001600160a01b0316906316cadeab9061039e908590600590600401610ab7565b602060405180830381865afa1580156103bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103df9190610a7b565b92915050565b6006546040516341bb055960e01b81526060916001600160a01b0316906341bb0559906101fe906005906004016109a5565b600033610256818585610548565b60058054610432906108c7565b80601f016020809104026020016040519081016040528092919081815260200182805461045e906108c7565b80156104ab5780601f10610480576101008083540402835291602001916104ab565b820191906000526020600020905b81548152906001019060200180831161048e57829003601f168201915b505050505081565b6104c083838360016105a7565b505050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198114610542578181101561053357604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064015b60405180910390fd5b610542848484840360006105a7565b50505050565b6001600160a01b03831661057257604051634b637e8f60e11b81526000600482015260240161052a565b6001600160a01b03821661059c5760405163ec442f0560e01b81526000600482015260240161052a565b6104c083838361067c565b6001600160a01b0384166105d15760405163e602df0560e01b81526000600482015260240161052a565b6001600160a01b0383166105fb57604051634a1406b160e11b81526000600482015260240161052a565b6001600160a01b038085166000908152600160209081526040808320938716835292905220829055801561054257826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161066e91815260200190565b60405180910390a350505050565b600654604051635c05961b60e01b81526000916001600160a01b031690635c05961b906106b490879087906005908890600401610ae3565b6020604051808303816000875af11580156106d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f79190610b20565b9050806107545760405162461bcd60e51b815260206004820152602560248201527f4e6174697665536569546f6b656e7345524332303a207472616e736665722066604482015264185a5b195960da1b606482015260840161052a565b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161066e91815260200190565b60005b838110156107b457818101518382015260200161079c565b50506000910152565b60208152600082518060208401526107dc816040850160208701610799565b601f01601f19169190910160400192915050565b80356001600160a01b038116811461080757600080fd5b919050565b6000806040838503121561081f57600080fd5b610828836107f0565b946020939093013593505050565b60008060006060848603121561084b57600080fd5b610854846107f0565b9250610862602085016107f0565b9150604084013590509250925092565b60006020828403121561088457600080fd5b61088d826107f0565b9392505050565b600080604083850312156108a757600080fd5b6108b0836107f0565b91506108be602084016107f0565b90509250929050565b600181811c908216806108db57607f821691505b6020821081036108fb57634e487b7160e01b600052602260045260246000fd5b50919050565b8054600090600181811c908083168061091b57607f831692505b6020808410820361093c57634e487b7160e01b600052602260045260246000fd5b83885260208801828015610957576001811461096d57610998565b60ff198716825285151560051b82019750610998565b60008981526020902060005b8781101561099257815484820152908601908401610979565b83019850505b5050505050505092915050565b60208152600061088d6020830184610901565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156109e057600080fd5b815167ffffffffffffffff808211156109f857600080fd5b818401915084601f830112610a0c57600080fd5b815181811115610a1e57610a1e6109b8565b604051601f8201601f19908116603f01168101908382118183101715610a4657610a466109b8565b81604052828152876020848701011115610a5f57600080fd5b610a70836020830160208801610799565b979650505050505050565b600060208284031215610a8d57600080fd5b5051919050565b600060208284031215610aa657600080fd5b815160ff8116811461088d57600080fd5b6001600160a01b0383168152604060208201819052600090610adb90830184610901565b949350505050565b6001600160a01b03858116825284166020820152608060408201819052600090610b0f90830185610901565b905082606083015295945050505050565b600060208284031215610b3257600080fd5b8151801515811461088d57600080fdfea264697066735822122035de7dd0a7c0231cf9ea33df619d77f03e363c21dcba228344173e332cb7b6e064736f6c63430008170033 \ No newline at end of file diff --git a/x/evm/types/codec.go b/x/evm/types/codec.go new file mode 100644 index 0000000000..a092de6e0d --- /dev/null +++ b/x/evm/types/codec.go @@ -0,0 +1,103 @@ +package types + +//nolint:typecheck +import ( + "errors" + fmt "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + + "github.com/gogo/protobuf/proto" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" +) + +var ( + amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + AminoCdc = codec.NewAminoCodec(amino) +) + +func init() { + cryptocodec.RegisterCrypto(amino) + amino.Seal() +} + +func GetAmino() *codec.LegacyAmino { + return amino +} + +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgEVMTransaction{}, + &MsgSend{}, + &MsgRegisterPointer{}, + ) + registry.RegisterInterface( + "seiprotocol.seichain.evm.TxData", + (*ethtx.TxData)(nil), + ðtx.DynamicFeeTx{}, + ðtx.AccessListTx{}, + ðtx.LegacyTx{}, + ðtx.BlobTx{}, + ðtx.AssociateTx{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +func PackTxData(txData ethtx.TxData) (*codectypes.Any, error) { + msg, ok := txData.(proto.Message) + if !ok { + return nil, fmt.Errorf("cannot proto marshal %T", txData) + } + + anyTxData, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return nil, errors.New(err.Error()) + } + + return anyTxData, nil +} + +func UnpackTxData(any *codectypes.Any) (ethtx.TxData, error) { + if any == nil { + return nil, errors.New("protobuf Any message cannot be nil") + } + + txData, ok := any.GetCachedValue().(ethtx.TxData) + if !ok { + ltx := ethtx.LegacyTx{} + if proto.Unmarshal(any.Value, <x) == nil { + // value is a legacy tx + return <x, nil + } + atx := ethtx.AccessListTx{} + if proto.Unmarshal(any.Value, &atx) == nil { + // value is a accesslist tx + return &atx, nil + } + dtx := ethtx.DynamicFeeTx{} + if proto.Unmarshal(any.Value, &dtx) == nil { + // value is a dynamic fee tx + return &dtx, nil + } + btx := ethtx.BlobTx{} + if proto.Unmarshal(any.Value, &btx) == nil { + // value is a blob tx + return &btx, nil + } + astx := ethtx.AssociateTx{} + if proto.Unmarshal(any.Value, &astx) == nil { + // value is an associate tx + return &astx, nil + } + return nil, fmt.Errorf("cannot unpack Any into TxData %T", any) + } + + return txData, nil +} diff --git a/x/evm/types/config.go b/x/evm/types/config.go new file mode 100644 index 0000000000..ef235ae6b7 --- /dev/null +++ b/x/evm/types/config.go @@ -0,0 +1,67 @@ +package types + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/params" + "github.com/sei-protocol/sei-chain/utils" +) + +/* +* +XXBlock/Time fields indicate upgrade heights/timestamps. For example, a BerlinBlock +of 123 means the chain upgraded to the Berlin version at height 123; a ShanghaiTime +of 42198537129 means the chain upgraded to the Shanghai version at timestamp 42198537129. +A value of 0 means the upgrade is included in the genesis of the EVM, which will be the +case on Sei for all versions up to Cancun. Still, we want to keep these fields in the +config for backward compatibility with the official EVM lib. +*/ +func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig { + return ¶ms.ChainConfig{ + ChainID: chainID, + HomesteadBlock: utils.Big0, + DAOForkBlock: utils.Big0, + DAOForkSupport: false, // fork of Sei is supported outside EVM + EIP150Block: utils.Big0, + EIP155Block: utils.Big0, + EIP158Block: utils.Big0, + ByzantiumBlock: utils.Big0, + ConstantinopleBlock: utils.Big0, + PetersburgBlock: utils.Big0, + IstanbulBlock: utils.Big0, + MuirGlacierBlock: utils.Big0, + BerlinBlock: utils.Big0, + LondonBlock: utils.Big0, + ArrowGlacierBlock: utils.Big0, + GrayGlacierBlock: utils.Big0, + MergeNetsplitBlock: utils.Big0, + ShanghaiTime: getUpgradeTimestamp(0), + CancunTime: getUpgradeTimestamp(cc.CancunTime), + PragueTime: getUpgradeTimestamp(cc.PragueTime), + VerkleTime: getUpgradeTimestamp(cc.VerkleTime), + } +} + +func DefaultChainConfig() ChainConfig { + return ChainConfig{ + CancunTime: 0, + PragueTime: -1, + VerkleTime: -1, + } +} + +func getUpgradeTimestamp(i int64) *uint64 { + if i < 0 { + return nil + } + res := uint64(i) + return &res +} + +func (cc ChainConfig) Validate() error { + if err := cc.EthereumConfig(nil).CheckConfigForkOrder(); err != nil { + return errors.New("invalid config fork order") + } + return nil +} diff --git a/x/evm/types/config.pb.go b/x/evm/types/config.pb.go new file mode 100644 index 0000000000..aa5657a185 --- /dev/null +++ b/x/evm/types/config.pb.go @@ -0,0 +1,378 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/config.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// XXTime fields indicate upgrade timestamps. For example, a ShanghaiTime +// of 42198537129 means the chain upgraded to the Shanghai version at timestamp 42198537129. +// A value of 0 means the upgrade is included in the genesis of the EVM on Sei. +// -1 means upgrade not reached yet. +type ChainConfig struct { + CancunTime int64 `protobuf:"varint,1,opt,name=cancun_time,json=cancunTime,proto3" json:"cancun_time,omitempty" yaml:"cancun_time"` + PragueTime int64 `protobuf:"varint,2,opt,name=prague_time,json=pragueTime,proto3" json:"prague_time,omitempty" yaml:"prague_time"` + VerkleTime int64 `protobuf:"varint,3,opt,name=verkle_time,json=verkleTime,proto3" json:"verkle_time,omitempty" yaml:"verkle_time"` +} + +func (m *ChainConfig) Reset() { *m = ChainConfig{} } +func (m *ChainConfig) String() string { return proto.CompactTextString(m) } +func (*ChainConfig) ProtoMessage() {} +func (*ChainConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_95b591dca6bd862e, []int{0} +} +func (m *ChainConfig) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ChainConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ChainConfig.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ChainConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChainConfig.Merge(m, src) +} +func (m *ChainConfig) XXX_Size() int { + return m.Size() +} +func (m *ChainConfig) XXX_DiscardUnknown() { + xxx_messageInfo_ChainConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_ChainConfig proto.InternalMessageInfo + +func (m *ChainConfig) GetCancunTime() int64 { + if m != nil { + return m.CancunTime + } + return 0 +} + +func (m *ChainConfig) GetPragueTime() int64 { + if m != nil { + return m.PragueTime + } + return 0 +} + +func (m *ChainConfig) GetVerkleTime() int64 { + if m != nil { + return m.VerkleTime + } + return 0 +} + +func init() { + proto.RegisterType((*ChainConfig)(nil), "seiprotocol.seichain.evm.ChainConfig") +} + +func init() { proto.RegisterFile("evm/config.proto", fileDescriptor_95b591dca6bd862e) } + +var fileDescriptor_95b591dca6bd862e = []byte{ + // 240 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x48, 0x2d, 0xcb, 0xd5, + 0x4f, 0xce, 0xcf, 0x4b, 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x28, 0x4e, + 0xcd, 0x04, 0xb3, 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, 0x33, 0xf3, 0xf4, + 0x52, 0xcb, 0x72, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x52, 0xfa, 0x20, 0x16, 0x44, 0xbd, + 0xd2, 0x0e, 0x46, 0x2e, 0x6e, 0x67, 0x90, 0x1a, 0x67, 0xb0, 0x29, 0x42, 0xe6, 0x5c, 0xdc, 0xc9, + 0x89, 0x79, 0xc9, 0xa5, 0x79, 0xf1, 0x25, 0x99, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, + 0x4e, 0x62, 0x9f, 0xee, 0xc9, 0x0b, 0x55, 0x26, 0xe6, 0xe6, 0x58, 0x29, 0x21, 0x49, 0x2a, 0x05, + 0x71, 0x41, 0x78, 0x21, 0x99, 0xb9, 0xa9, 0x20, 0x8d, 0x05, 0x45, 0x89, 0xe9, 0xa5, 0xa9, 0x10, + 0x8d, 0x4c, 0xe8, 0x1a, 0x91, 0x24, 0x95, 0x82, 0xb8, 0x20, 0x3c, 0x98, 0xc6, 0xb2, 0xd4, 0xa2, + 0xec, 0x1c, 0xa8, 0x46, 0x66, 0x74, 0x8d, 0x48, 0x92, 0x4a, 0x41, 0x5c, 0x10, 0x1e, 0x48, 0xa3, + 0x93, 0xfb, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, + 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xe9, 0xa6, 0x67, 0x96, + 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x17, 0xa7, 0x66, 0xea, 0xc2, 0x02, 0x04, 0xcc, + 0x01, 0x87, 0x88, 0x7e, 0x85, 0x3e, 0x28, 0xe8, 0x4a, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, + 0xf2, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xef, 0xb3, 0x8f, 0x62, 0x4e, 0x01, 0x00, 0x00, +} + +func (m *ChainConfig) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ChainConfig) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ChainConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.VerkleTime != 0 { + i = encodeVarintConfig(dAtA, i, uint64(m.VerkleTime)) + i-- + dAtA[i] = 0x18 + } + if m.PragueTime != 0 { + i = encodeVarintConfig(dAtA, i, uint64(m.PragueTime)) + i-- + dAtA[i] = 0x10 + } + if m.CancunTime != 0 { + i = encodeVarintConfig(dAtA, i, uint64(m.CancunTime)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintConfig(dAtA []byte, offset int, v uint64) int { + offset -= sovConfig(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ChainConfig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CancunTime != 0 { + n += 1 + sovConfig(uint64(m.CancunTime)) + } + if m.PragueTime != 0 { + n += 1 + sovConfig(uint64(m.PragueTime)) + } + if m.VerkleTime != 0 { + n += 1 + sovConfig(uint64(m.VerkleTime)) + } + return n +} + +func sovConfig(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozConfig(x uint64) (n int) { + return sovConfig(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ChainConfig) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConfig + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ChainConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ChainConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CancunTime", wireType) + } + m.CancunTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConfig + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CancunTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PragueTime", wireType) + } + m.PragueTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConfig + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PragueTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VerkleTime", wireType) + } + m.VerkleTime = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowConfig + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VerkleTime |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipConfig(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthConfig + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipConfig(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowConfig + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowConfig + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowConfig + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthConfig + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupConfig + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthConfig + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthConfig = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowConfig = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupConfig = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/context.go b/x/evm/types/context.go new file mode 100644 index 0000000000..e3a30f7a74 --- /dev/null +++ b/x/evm/types/context.go @@ -0,0 +1,28 @@ +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/enums.pb.go b/x/evm/types/enums.pb.go new file mode 100644 index 0000000000..d5f2e56420 --- /dev/null +++ b/x/evm/types/enums.pb.go @@ -0,0 +1,78 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/enums.proto + +package types + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type PointerType int32 + +const ( + PointerType_ERC20 PointerType = 0 + PointerType_ERC721 PointerType = 1 + PointerType_NATIVE PointerType = 2 + PointerType_CW20 PointerType = 3 + PointerType_CW721 PointerType = 4 +) + +var PointerType_name = map[int32]string{ + 0: "ERC20", + 1: "ERC721", + 2: "NATIVE", + 3: "CW20", + 4: "CW721", +} + +var PointerType_value = map[string]int32{ + "ERC20": 0, + "ERC721": 1, + "NATIVE": 2, + "CW20": 3, + "CW721": 4, +} + +func (x PointerType) String() string { + return proto.EnumName(PointerType_name, int32(x)) +} + +func (PointerType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_9ba0923a26222f98, []int{0} +} + +func init() { + proto.RegisterEnum("seiprotocol.seichain.evm.PointerType", PointerType_name, PointerType_value) +} + +func init() { proto.RegisterFile("evm/enums.proto", fileDescriptor_9ba0923a26222f98) } + +var fileDescriptor_9ba0923a26222f98 = []byte{ + // 194 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4f, 0x2d, 0xcb, 0xd5, + 0x4f, 0xcd, 0x2b, 0xcd, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x28, 0x4e, 0xcd, + 0x04, 0xb3, 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, 0x33, 0xf3, 0xf4, 0x52, + 0xcb, 0x72, 0xb5, 0x5c, 0xb9, 0xb8, 0x03, 0xf2, 0x33, 0xf3, 0x4a, 0x52, 0x8b, 0x42, 0x2a, 0x0b, + 0x52, 0x85, 0x38, 0xb9, 0x58, 0x5d, 0x83, 0x9c, 0x8d, 0x0c, 0x04, 0x18, 0x84, 0xb8, 0xb8, 0xd8, + 0x5c, 0x83, 0x9c, 0xcd, 0x8d, 0x0c, 0x05, 0x18, 0x41, 0x6c, 0x3f, 0xc7, 0x10, 0xcf, 0x30, 0x57, + 0x01, 0x26, 0x21, 0x0e, 0x2e, 0x16, 0xe7, 0x70, 0x23, 0x03, 0x01, 0x66, 0x90, 0x62, 0xe7, 0x70, + 0x90, 0x02, 0x16, 0x27, 0xf7, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, + 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, + 0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x2f, 0x4e, 0xcd, 0xd4, 0x85, + 0x39, 0x03, 0xcc, 0x01, 0xbb, 0x43, 0xbf, 0x42, 0x1f, 0xe4, 0xde, 0x92, 0xca, 0x82, 0xd4, 0xe2, + 0x24, 0x36, 0xb0, 0xbc, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x3c, 0xe6, 0x84, 0x48, 0xc3, 0x00, + 0x00, 0x00, +} diff --git a/x/evm/types/ethtx/access_list.go b/x/evm/types/ethtx/access_list.go new file mode 100644 index 0000000000..ea9cad0cb7 --- /dev/null +++ b/x/evm/types/ethtx/access_list.go @@ -0,0 +1,49 @@ +package ethtx + +import ( + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +type AccessList []AccessTuple + +func NewAccessList(ethAccessList *ethtypes.AccessList) AccessList { + if ethAccessList == nil { + return nil + } + + al := AccessList{} + for _, tuple := range *ethAccessList { + storageKeys := make([]string, len(tuple.StorageKeys)) + + for i := range tuple.StorageKeys { + storageKeys[i] = tuple.StorageKeys[i].String() + } + + al = append(al, AccessTuple{ + Address: tuple.Address.String(), + StorageKeys: storageKeys, + }) + } + + return al +} + +func (al AccessList) ToEthAccessList() *ethtypes.AccessList { + var ethAccessList ethtypes.AccessList + + for _, tuple := range al { + storageKeys := make([]common.Hash, len(tuple.StorageKeys)) + + for i := range tuple.StorageKeys { + storageKeys[i] = common.HexToHash(tuple.StorageKeys[i]) + } + + ethAccessList = append(ethAccessList, ethtypes.AccessTuple{ + Address: common.HexToAddress(tuple.Address), + StorageKeys: storageKeys, + }) + } + + return ðAccessList +} diff --git a/x/evm/types/ethtx/access_list_test.go b/x/evm/types/ethtx/access_list_test.go new file mode 100644 index 0000000000..62e1a95542 --- /dev/null +++ b/x/evm/types/ethtx/access_list_test.go @@ -0,0 +1,24 @@ +package ethtx + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" +) + +func TestAccessList(t *testing.T) { + require.Nil(t, NewAccessList(nil)) + ethAccessList := mockAccessList() + require.Equal(t, ethAccessList, *NewAccessList(ðAccessList).ToEthAccessList()) +} + +func mockAccessList() ethtypes.AccessList { + return ethtypes.AccessList{ + ethtypes.AccessTuple{ + Address: common.Address{'a'}, + StorageKeys: []common.Hash{{'b'}}, + }, + } +} diff --git a/x/evm/types/ethtx/access_list_tx.go b/x/evm/types/ethtx/access_list_tx.go new file mode 100644 index 0000000000..06f4306a22 --- /dev/null +++ b/x/evm/types/ethtx/access_list_tx.go @@ -0,0 +1,210 @@ +package ethtx + +import ( + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +func NewAccessListTx(tx *ethtypes.Transaction) (*AccessListTx, error) { + if err := ValidateEthTx(tx); err != nil { + return nil, err + } + txData := &AccessListTx{ + Nonce: tx.Nonce(), + Data: tx.Data(), + GasLimit: tx.Gas(), + } + + v, r, s := tx.RawSignatureValues() + + SetConvertIfPresent(tx.To(), func(to *common.Address) string { return to.Hex() }, txData.SetTo) + SetConvertIfPresent(tx.Value(), sdk.NewIntFromBigInt, txData.SetAmount) + SetConvertIfPresent(tx.GasPrice(), sdk.NewIntFromBigInt, txData.SetGasPrice) + al := tx.AccessList() + SetConvertIfPresent(&al, NewAccessList, txData.SetAccesses) + + txData.SetSignatureValues(tx.ChainId(), v, r, s) + + return txData, txData.Validate() +} + +func (tx *AccessListTx) TxType() uint8 { + return ethtypes.AccessListTxType +} + +func (tx *AccessListTx) Copy() TxData { + return &AccessListTx{ + ChainID: tx.ChainID, + Nonce: tx.Nonce, + GasPrice: tx.GasPrice, + GasLimit: tx.GasLimit, + To: tx.To, + Amount: tx.Amount, + Data: common.CopyBytes(tx.Data), + Accesses: tx.Accesses, + V: common.CopyBytes(tx.V), + R: common.CopyBytes(tx.R), + S: common.CopyBytes(tx.S), + } +} + +func (tx *AccessListTx) GetChainID() *big.Int { + if tx.ChainID == nil { + return nil + } + + return tx.ChainID.BigInt() +} + +func (tx *AccessListTx) GetAccessList() ethtypes.AccessList { + if tx.Accesses == nil { + return nil + } + return *tx.Accesses.ToEthAccessList() +} + +func (tx *AccessListTx) GetData() []byte { + return common.CopyBytes(tx.Data) +} + +func (tx *AccessListTx) GetGas() uint64 { + return tx.GasLimit +} + +func (tx *AccessListTx) GetGasPrice() *big.Int { + if tx.GasPrice == nil { + return nil + } + return tx.GasPrice.BigInt() +} + +func (tx *AccessListTx) GetGasTipCap() *big.Int { + return tx.GetGasPrice() +} + +func (tx *AccessListTx) GetGasFeeCap() *big.Int { + return tx.GetGasPrice() +} + +func (tx *AccessListTx) GetValue() *big.Int { + if tx.Amount == nil { + return nil + } + + return tx.Amount.BigInt() +} + +func (tx *AccessListTx) GetNonce() uint64 { return tx.Nonce } + +func (tx *AccessListTx) GetTo() *common.Address { + if tx.To == "" { + return nil + } + to := common.HexToAddress(tx.To) + return &to +} + +func (tx *AccessListTx) AsEthereumData() ethtypes.TxData { + v, r, s := tx.GetRawSignatureValues() + return ðtypes.AccessListTx{ + ChainID: tx.GetChainID(), + Nonce: tx.GetNonce(), + GasPrice: tx.GetGasPrice(), + Gas: tx.GetGas(), + To: tx.GetTo(), + Value: tx.GetValue(), + Data: tx.GetData(), + AccessList: tx.GetAccessList(), + V: v, + R: r, + S: s, + } +} + +func (tx *AccessListTx) GetRawSignatureValues() (v, r, s *big.Int) { + return rawSignatureValues(tx.V, tx.R, tx.S) +} + +func (tx *AccessListTx) SetSignatureValues(chainID, v, r, s *big.Int) { + if v != nil { + tx.V = v.Bytes() + } + if r != nil { + tx.R = r.Bytes() + } + if s != nil { + tx.S = s.Bytes() + } + if chainID != nil { + chainIDInt := sdk.NewIntFromBigInt(chainID) + tx.ChainID = &chainIDInt + } +} + +func (tx *AccessListTx) GetBlobFeeCap() *big.Int { + return nil +} + +func (tx *AccessListTx) GetBlobHashes() []common.Hash { + return nil +} + +func (tx AccessListTx) Validate() error { + gasPrice := tx.GetGasPrice() + if gasPrice == nil { + return errors.New("gas price cannot be nil") + } + if gasPrice.Sign() == -1 { + return fmt.Errorf("gas price cannot be negative %s", gasPrice) + } + + amount := tx.GetValue() + // Amount can be 0 + if amount != nil && amount.Sign() == -1 { + return fmt.Errorf("amount cannot be negative %s", amount) + } + + if !IsValidInt256(tx.Fee()) { + return errors.New("fee out of bound") + } + + if tx.To != "" { + if err := ValidateAddress(tx.To); err != nil { + return errors.New("invalid to address") + } + } + + chainID := tx.GetChainID() + + if chainID == nil { + return errors.New("chain ID must be present on AccessList txs") + } + + return nil +} + +func (tx AccessListTx) Fee() *big.Int { + return fee(tx.GetGasPrice(), tx.GetGas()) +} + +func (tx AccessListTx) Cost() *big.Int { + return cost(tx.Fee(), tx.GetValue()) +} + +func (tx AccessListTx) EffectiveGasPrice(_ *big.Int) *big.Int { + return tx.GetGasPrice() +} + +func (tx AccessListTx) EffectiveFee(_ *big.Int) *big.Int { + return tx.Fee() +} + +func (tx AccessListTx) EffectiveCost(_ *big.Int) *big.Int { + return tx.Cost() +} diff --git a/x/evm/types/ethtx/access_list_tx_setter.go b/x/evm/types/ethtx/access_list_tx_setter.go new file mode 100644 index 0000000000..a532518d58 --- /dev/null +++ b/x/evm/types/ethtx/access_list_tx_setter.go @@ -0,0 +1,19 @@ +package ethtx + +import sdk "github.com/cosmos/cosmos-sdk/types" + +func (tx *AccessListTx) SetTo(v string) { + tx.To = v +} + +func (tx *AccessListTx) SetAmount(v sdk.Int) { + tx.Amount = &v +} + +func (tx *AccessListTx) SetGasPrice(v sdk.Int) { + tx.GasPrice = &v +} + +func (tx *AccessListTx) SetAccesses(v AccessList) { + tx.Accesses = v +} diff --git a/x/evm/types/ethtx/access_list_tx_test.go b/x/evm/types/ethtx/access_list_tx_test.go new file mode 100644 index 0000000000..b9dd1b62e9 --- /dev/null +++ b/x/evm/types/ethtx/access_list_tx_test.go @@ -0,0 +1,123 @@ +package ethtx + +import ( + "math" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" +) + +func mockAccessListTransaction(value *big.Int) *ethtypes.Transaction { + inner := ðtypes.AccessListTx{ + ChainID: big.NewInt(1), + GasPrice: big.NewInt(100), + Gas: 1000, + To: &common.Address{'a'}, + Value: value, + Data: []byte{'b'}, + AccessList: mockAccessList(), + V: big.NewInt(3), + R: big.NewInt(5), + S: big.NewInt(7), + } + return ethtypes.NewTx(inner) +} + +func TestAccessListTransaction(t *testing.T) { + ethTx := mockAccessListTransaction(big.NewInt(20)) + tx, err := NewAccessListTx(ethTx) + require.Nil(t, err) + + require.Equal(t, uint8(ethtypes.AccessListTxType), tx.TxType()) + copy := tx.Copy() + require.Equal(t, tx, copy) + cached := tx.ChainID + tx.ChainID = nil + require.Nil(t, tx.GetChainID()) + tx.ChainID = cached + require.Equal(t, cached.BigInt(), tx.GetChainID()) + al := tx.Accesses + tx.Accesses = nil + require.Nil(t, tx.GetAccessList()) + tx.Accesses = al + require.Equal(t, *al.ToEthAccessList(), tx.GetAccessList()) + require.Equal(t, common.CopyBytes(tx.Data), tx.GetData()) + require.Equal(t, tx.GasLimit, tx.GetGas()) + gp := tx.GasPrice + tx.GasPrice = nil + require.Nil(t, tx.GetGasPrice()) + tx.GasPrice = gp + require.Equal(t, gp.BigInt(), tx.GetGasPrice()) + require.Equal(t, gp.BigInt(), tx.GetGasTipCap()) + require.Equal(t, gp.BigInt(), tx.GetGasFeeCap()) + amt := tx.Amount + tx.Amount = nil + require.Nil(t, tx.GetValue()) + tx.Amount = amt + require.Equal(t, amt.BigInt(), tx.GetValue()) + require.Equal(t, tx.Nonce, tx.GetNonce()) + to := tx.To + tx.To = "" + require.Nil(t, tx.GetTo()) + tx.To = to + require.Equal(t, common.HexToAddress(to), *tx.GetTo()) + require.Equal(t, ethTx.Hash(), ethtypes.NewTx(tx.AsEthereumData()).Hash()) + v, s, r := tx.GetRawSignatureValues() + V, S, R := ethTx.RawSignatureValues() + require.Equal(t, *v, *V) + require.Equal(t, *s, *S) + require.Equal(t, *r, *R) + tx.SetSignatureValues(cached.BigInt(), v, s, r) + require.Equal(t, fee(tx.GasPrice.BigInt(), tx.GasLimit), tx.Fee()) + require.Equal(t, cost(fee(tx.GasPrice.BigInt(), tx.GasLimit), tx.Amount.BigInt()), tx.Cost()) + require.Equal(t, tx.GasPrice.BigInt(), tx.EffectiveGasPrice(nil)) + require.Equal(t, fee(tx.GasPrice.BigInt(), tx.GasLimit), tx.EffectiveFee(nil)) + require.Equal(t, cost(fee(tx.GasPrice.BigInt(), tx.GasLimit), tx.Amount.BigInt()), tx.EffectiveCost(nil)) + + require.Nil(t, tx.GetBlobFeeCap()) + require.Nil(t, tx.GetBlobHashes()) +} + +func TestInvalidAccessListTransaction(t *testing.T) { + maxInt64 := big.NewInt(math.MaxInt64) + overflowed := &big.Int{} + // (2^64)^5 > 2^256 + ethTx := mockAccessListTransaction(overflowed.Exp(maxInt64, big.NewInt(5), nil)) + _, err := NewAccessListTx(ethTx) + require.NotNil(t, err) +} + +func TestValidateAccessListTransaction(t *testing.T) { + ethTx := mockAccessListTransaction(big.NewInt(20)) + tx, err := NewAccessListTx(ethTx) + require.Nil(t, err) + gp := tx.GasPrice + tx.GasPrice = nil + require.NotNil(t, tx.Validate()) + ngp := gp.Neg() + tx.GasPrice = &ngp + require.NotNil(t, tx.Validate()) + tx.GasPrice = gp + amt := tx.Amount + namt := amt.Neg() + tx.Amount = &namt + require.NotNil(t, tx.Validate()) + tx.Amount = amt + overflowed := &big.Int{} + sdkOverflowed := sdk.NewIntFromBigInt(overflowed.Exp(big.NewInt(math.MaxInt64), big.NewInt(4), nil)) + tx.GasPrice = &sdkOverflowed + require.NotNil(t, tx.Validate()) + tx.GasPrice = gp + to := tx.To + tx.To = "xyz" + require.NotNil(t, tx.Validate()) + tx.To = to + chainID := tx.ChainID + tx.ChainID = nil + require.NotNil(t, tx.Validate()) + tx.ChainID = chainID +} diff --git a/x/evm/types/ethtx/associate_tx.go b/x/evm/types/ethtx/associate_tx.go new file mode 100644 index 0000000000..c1b2099365 --- /dev/null +++ b/x/evm/types/ethtx/associate_tx.go @@ -0,0 +1,50 @@ +package ethtx + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +func NewAssociateTx(tx *ethtypes.Transaction, customMessage string) (*AssociateTx, error) { + v, r, s := tx.RawSignatureValues() + txData := &AssociateTx{ + V: v.Bytes(), + R: r.Bytes(), + S: s.Bytes(), + CustomMessage: customMessage, + } + return txData, nil +} + +func (tx *AssociateTx) TxType() byte { panic("not implemented") } +func (tx *AssociateTx) Copy() TxData { panic("not implemented") } +func (tx *AssociateTx) GetChainID() *big.Int { panic("not implemented") } +func (tx *AssociateTx) GetAccessList() ethtypes.AccessList { panic("not implemented") } +func (tx *AssociateTx) GetData() []byte { panic("not implemented") } +func (tx *AssociateTx) GetNonce() uint64 { panic("not implemented") } +func (tx *AssociateTx) GetGas() uint64 { panic("not implemented") } +func (tx *AssociateTx) GetGasPrice() *big.Int { panic("not implemented") } +func (tx *AssociateTx) GetGasTipCap() *big.Int { panic("not implemented") } +func (tx *AssociateTx) GetGasFeeCap() *big.Int { panic("not implemented") } +func (tx *AssociateTx) GetValue() *big.Int { panic("not implemented") } +func (tx *AssociateTx) GetTo() *common.Address { panic("not implemented") } + +func (tx *AssociateTx) GetRawSignatureValues() (v, r, s *big.Int) { + return rawSignatureValues(tx.V, tx.R, tx.S) +} +func (tx *AssociateTx) SetSignatureValues(_, _, _, _ *big.Int) { panic("not implemented") } + +func (tx *AssociateTx) AsEthereumData() ethtypes.TxData { panic("not implemented") } +func (tx *AssociateTx) Validate() error { panic("not implemented") } + +func (tx *AssociateTx) Fee() *big.Int { panic("not implemented") } +func (tx *AssociateTx) Cost() *big.Int { panic("not implemented") } + +func (tx *AssociateTx) EffectiveGasPrice(_ *big.Int) *big.Int { panic("not implemented") } +func (tx *AssociateTx) EffectiveFee(_ *big.Int) *big.Int { panic("not implemented") } +func (tx *AssociateTx) EffectiveCost(_ *big.Int) *big.Int { panic("not implemented") } + +func (tx *AssociateTx) GetBlobHashes() []common.Hash { panic("not implemented") } +func (tx *AssociateTx) GetBlobFeeCap() *big.Int { panic("not implemented") } diff --git a/x/evm/types/ethtx/blob_tx.go b/x/evm/types/ethtx/blob_tx.go new file mode 100644 index 0000000000..b024fa7a89 --- /dev/null +++ b/x/evm/types/ethtx/blob_tx.go @@ -0,0 +1,287 @@ +package ethtx + +import ( + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" + "github.com/sei-protocol/sei-chain/utils" +) + +func NewBlobTx(tx *ethtypes.Transaction) (*BlobTx, error) { + if err := ValidateEthTx(tx); err != nil { + return nil, err + } + txData := &BlobTx{ + Nonce: tx.Nonce(), + Data: tx.Data(), + GasLimit: tx.Gas(), + } + + v, r, s := tx.RawSignatureValues() + + SetConvertIfPresent(tx.To(), func(to *common.Address) string { return to.Hex() }, txData.SetTo) + // internally BlobTx uses uint256 which is guaranteed to not have overflow, so using NewIntFromBigInt directly here + SetConvertIfPresent(tx.Value(), sdk.NewIntFromBigInt, txData.SetAmount) + SetConvertIfPresent(tx.GasFeeCap(), sdk.NewIntFromBigInt, txData.SetGasFeeCap) + SetConvertIfPresent(tx.GasTipCap(), sdk.NewIntFromBigInt, txData.SetGasTipCap) + al := tx.AccessList() + SetConvertIfPresent(&al, NewAccessList, txData.SetAccesses) + SetConvertIfPresent(tx.BlobGasFeeCap(), sdk.NewIntFromBigInt, txData.SetBlobFeeCap) + bh := tx.BlobHashes() + SetConvertIfPresent(&bh, func(hs *[]common.Hash) [][]byte { return utils.Map(*hs, func(h common.Hash) []byte { return h[:] }) }, txData.SetBlobHashes) + SetConvertIfPresent(tx.BlobTxSidecar(), sidecarConverter, txData.SetBlobSidecar) + + txData.SetSignatureValues(tx.ChainId(), v, r, s) + return txData, txData.Validate() +} + +func (tx *BlobTx) TxType() uint8 { + return ethtypes.BlobTxType +} + +func (tx *BlobTx) Copy() TxData { + return &BlobTx{ + ChainID: tx.ChainID, + Nonce: tx.Nonce, + GasTipCap: tx.GasTipCap, + GasFeeCap: tx.GasFeeCap, + GasLimit: tx.GasLimit, + To: tx.To, + Amount: tx.Amount, + Data: common.CopyBytes(tx.Data), + Accesses: tx.Accesses, + BlobFeeCap: tx.BlobFeeCap, + BlobHashes: tx.BlobHashes, + Sidecar: tx.Sidecar, + V: common.CopyBytes(tx.V), + R: common.CopyBytes(tx.R), + S: common.CopyBytes(tx.S), + } +} + +func (tx *BlobTx) GetChainID() *big.Int { + if tx.ChainID == nil { + return nil + } + + return tx.ChainID.BigInt() +} + +func (tx *BlobTx) GetAccessList() ethtypes.AccessList { + if tx.Accesses == nil { + return nil + } + return *tx.Accesses.ToEthAccessList() +} + +func (tx *BlobTx) GetData() []byte { + return common.CopyBytes(tx.Data) +} + +func (tx *BlobTx) GetGas() uint64 { + return tx.GasLimit +} + +func (tx *BlobTx) BlobGas() uint64 { + return params.BlobTxBlobGasPerBlob * uint64(len(tx.BlobHashes)) +} + +func (tx *BlobTx) GetGasPrice() *big.Int { + return tx.GetGasFeeCap() +} + +func (tx *BlobTx) GetGasTipCap() *big.Int { + if tx.GasTipCap == nil { + return nil + } + return tx.GasTipCap.BigInt() +} + +func (tx *BlobTx) GetGasFeeCap() *big.Int { + if tx.GasFeeCap == nil { + return nil + } + return tx.GasFeeCap.BigInt() +} + +func (tx *BlobTx) GetValue() *big.Int { + if tx.Amount == nil { + return nil + } + + return tx.Amount.BigInt() +} + +func (tx *BlobTx) GetNonce() uint64 { return tx.Nonce } + +func (tx *BlobTx) GetTo() *common.Address { + if tx.To == "" { + return &common.Address{} + } + to := common.HexToAddress(tx.To) + return &to +} + +func (tx *BlobTx) GetBlobFeeCap() *big.Int { + if tx.BlobFeeCap == nil { + return nil + } + + return tx.BlobFeeCap.BigInt() +} + +func (tx *BlobTx) GetBlobHashes() []common.Hash { + if tx.BlobHashes == nil { + return nil + } + + return utils.Map(tx.BlobHashes, func(hash []byte) common.Hash { + commonHash := [common.HashLength]byte{} + copy(commonHash[:], hash) + return commonHash + }) +} + +func (tx *BlobTx) AsEthereumData() ethtypes.TxData { + v, r, s := tx.GetRawSignatureValues() + return ðtypes.BlobTx{ + ChainID: uint256.MustFromBig(tx.GetChainID()), + Nonce: tx.GetNonce(), + GasTipCap: uint256.MustFromBig(tx.GetGasTipCap()), + GasFeeCap: uint256.MustFromBig(tx.GetGasFeeCap()), + Gas: tx.GetGas(), + To: *tx.GetTo(), + Value: uint256.MustFromBig(tx.GetValue()), + Data: tx.GetData(), + AccessList: tx.GetAccessList(), + BlobFeeCap: uint256.MustFromBig(tx.GetBlobFeeCap()), + BlobHashes: tx.GetBlobHashes(), + Sidecar: sidecarToEthSidecar(tx.Sidecar), + V: uint256.MustFromBig(v), + R: uint256.MustFromBig(r), + S: uint256.MustFromBig(s), + } +} + +func (tx *BlobTx) GetRawSignatureValues() (v, r, s *big.Int) { + return rawSignatureValues(tx.V, tx.R, tx.S) +} + +func (tx *BlobTx) SetSignatureValues(chainID, v, r, s *big.Int) { + if v != nil { + tx.V = v.Bytes() + } + if r != nil { + tx.R = r.Bytes() + } + if s != nil { + tx.S = s.Bytes() + } + if chainID != nil { + chainIDInt := sdk.NewIntFromBigInt(chainID) + tx.ChainID = &chainIDInt + } +} + +func (tx BlobTx) Validate() error { + if tx.GasTipCap == nil { + return errors.New("gas tip cap cannot nil") + } + + if tx.GasFeeCap == nil { + return errors.New("gas fee cap cannot nil") + } + + if tx.GasTipCap.IsNegative() { + return fmt.Errorf("gas tip cap cannot be negative %s", tx.GasTipCap) + } + + if tx.GasFeeCap.IsNegative() { + return fmt.Errorf("gas fee cap cannot be negative %s", tx.GasFeeCap) + } + + if tx.GasFeeCap.LT(*tx.GasTipCap) { + return fmt.Errorf("max priority fee per gas higher than max fee per gas (%s > %s)", + tx.GasTipCap, tx.GasFeeCap, + ) + } + + if !IsValidInt256(tx.Fee()) { + return errors.New("fee out of bound") + } + + amount := tx.GetValue() + // Amount can be 0 + if amount != nil && amount.Sign() == -1 { + return fmt.Errorf("amount cannot be negative %s", amount) + } + + if tx.To != "" { + if err := ValidateAddress(tx.To); err != nil { + return errors.New("invalid to address") + } + } + + chainID := tx.GetChainID() + + if chainID == nil { + return errors.New( + "chain ID must be present on AccessList txs", + ) + } + + return nil +} + +func (tx BlobTx) Fee() *big.Int { + return new(big.Int).Add(fee(tx.GetGasFeeCap(), tx.GasLimit), tx.blobFee()) +} + +func (tx BlobTx) blobFee() *big.Int { + return fee(tx.GetBlobFeeCap(), tx.BlobGas()) +} + +func (tx BlobTx) Cost() *big.Int { + return cost(tx.Fee(), tx.GetValue()) +} + +func (tx *BlobTx) EffectiveGasPrice(baseFee *big.Int) *big.Int { + return EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()) +} + +func (tx BlobTx) EffectiveFee(baseFee *big.Int) *big.Int { + return new(big.Int).Add(fee(tx.EffectiveGasPrice(baseFee), tx.GasLimit), tx.blobFee()) +} + +func (tx BlobTx) EffectiveCost(baseFee *big.Int) *big.Int { + return cost(tx.EffectiveFee(baseFee), tx.GetValue()) +} + +func sidecarConverter(ethSidecar *ethtypes.BlobTxSidecar) *BlobTxSidecar { + if ethSidecar == nil { + return nil + } + return &BlobTxSidecar{ + Blobs: utils.Map(ethSidecar.Blobs, func(b kzg4844.Blob) []byte { return b[:] }), + Commitments: utils.Map(ethSidecar.Commitments, func(c kzg4844.Commitment) []byte { return c[:] }), + Proofs: utils.Map(ethSidecar.Proofs, func(p kzg4844.Proof) []byte { return p[:] }), + } +} + +func sidecarToEthSidecar(sidecar *BlobTxSidecar) *ethtypes.BlobTxSidecar { + if sidecar == nil { + return nil + } + return ðtypes.BlobTxSidecar{ + Blobs: utils.Map(sidecar.Blobs, func(b []byte) kzg4844.Blob { return kzg4844.Blob(b) }), + Commitments: utils.Map(sidecar.Commitments, func(b []byte) kzg4844.Commitment { return kzg4844.Commitment(b) }), + Proofs: utils.Map(sidecar.Proofs, func(p []byte) kzg4844.Proof { return kzg4844.Proof(p) }), + } +} diff --git a/x/evm/types/ethtx/blob_tx_setter.go b/x/evm/types/ethtx/blob_tx_setter.go new file mode 100644 index 0000000000..7d5449cd52 --- /dev/null +++ b/x/evm/types/ethtx/blob_tx_setter.go @@ -0,0 +1,35 @@ +package ethtx + +import sdk "github.com/cosmos/cosmos-sdk/types" + +func (tx *BlobTx) SetTo(v string) { + tx.To = v +} + +func (tx *BlobTx) SetAmount(v sdk.Int) { + tx.Amount = &v +} + +func (tx *BlobTx) SetGasFeeCap(v sdk.Int) { + tx.GasFeeCap = &v +} + +func (tx *BlobTx) SetGasTipCap(v sdk.Int) { + tx.GasTipCap = &v +} + +func (tx *BlobTx) SetAccesses(v AccessList) { + tx.Accesses = v +} + +func (tx *BlobTx) SetBlobFeeCap(v sdk.Int) { + tx.BlobFeeCap = &v +} + +func (tx *BlobTx) SetBlobHashes(v [][]byte) { + tx.BlobHashes = v +} + +func (tx *BlobTx) SetBlobSidecar(v *BlobTxSidecar) { + tx.Sidecar = v +} diff --git a/x/evm/types/ethtx/blob_tx_test.go b/x/evm/types/ethtx/blob_tx_test.go new file mode 100644 index 0000000000..53ab9ec4ed --- /dev/null +++ b/x/evm/types/ethtx/blob_tx_test.go @@ -0,0 +1,140 @@ +package ethtx + +import ( + "math" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/holiman/uint256" + "github.com/stretchr/testify/require" +) + +func mockBlobTransaction(value *uint256.Int) *ethtypes.Transaction { + inner := ðtypes.BlobTx{ + ChainID: uint256.NewInt(1), + GasTipCap: uint256.NewInt(50), + GasFeeCap: uint256.NewInt(100), + Gas: 1000, + To: common.Address{'a'}, + Value: value, + Data: []byte{'b'}, + AccessList: mockAccessList(), + BlobFeeCap: uint256.NewInt(30), + BlobHashes: []common.Hash{{'c', 'd'}}, + Sidecar: ðtypes.BlobTxSidecar{ + Blobs: []kzg4844.Blob{{'e', 'f'}}, + Commitments: []kzg4844.Commitment{{'g', 'h'}}, + Proofs: []kzg4844.Proof{{'i', 'j'}}, + }, + V: uint256.NewInt(3), + R: uint256.NewInt(5), + S: uint256.NewInt(7), + } + return ethtypes.NewTx(inner) +} + +func TestBlobTransaction(t *testing.T) { + ethTx := mockBlobTransaction(uint256.NewInt(20)) + tx, err := NewBlobTx(ethTx) + require.Nil(t, err) + require.Nil(t, tx.Validate()) + + require.Equal(t, uint8(ethtypes.BlobTxType), tx.TxType()) + copy := tx.Copy() + require.Equal(t, tx, copy) + cached := tx.ChainID + tx.ChainID = nil + require.Nil(t, tx.GetChainID()) + tx.ChainID = cached + require.Equal(t, cached.BigInt(), tx.GetChainID()) + al := tx.Accesses + tx.Accesses = nil + require.Nil(t, tx.GetAccessList()) + tx.Accesses = al + require.Equal(t, *al.ToEthAccessList(), tx.GetAccessList()) + require.Equal(t, common.CopyBytes(tx.Data), tx.GetData()) + require.Equal(t, tx.GasLimit, tx.GetGas()) + gfc := tx.GasFeeCap + tx.GasFeeCap = nil + require.Nil(t, tx.GetGasPrice()) + tx.GasFeeCap = gfc + require.Equal(t, gfc.BigInt(), tx.GetGasPrice()) + gtc := tx.GasTipCap + tx.GasTipCap = nil + require.Nil(t, tx.GetGasTipCap()) + tx.GasTipCap = gtc + require.Equal(t, gtc.BigInt(), tx.GetGasTipCap()) + require.Equal(t, gfc.BigInt(), tx.GetGasFeeCap()) + amt := tx.Amount + tx.Amount = nil + require.Nil(t, tx.GetValue()) + tx.Amount = amt + require.Equal(t, amt.BigInt(), tx.GetValue()) + require.Equal(t, tx.Nonce, tx.GetNonce()) + to := tx.To + tx.To = "" + require.Equal(t, &common.Address{}, tx.GetTo()) + tx.To = to + require.Equal(t, common.HexToAddress(to), *tx.GetTo()) + require.Equal(t, ethTx.Hash(), ethtypes.NewTx(tx.AsEthereumData()).Hash()) + v, s, r := tx.GetRawSignatureValues() + V, S, R := ethTx.RawSignatureValues() + require.Equal(t, *v, *V) + require.Equal(t, *s, *S) + require.Equal(t, *r, *R) + tx.SetSignatureValues(cached.BigInt(), v, s, r) + require.Equal(t, new(big.Int).Add(fee(tx.GasFeeCap.BigInt(), tx.GasLimit), fee(tx.BlobFeeCap.BigInt(), tx.BlobGas())), tx.Fee()) + require.Equal(t, cost(new(big.Int).Add(fee(tx.GasFeeCap.BigInt(), tx.GasLimit), fee(tx.BlobFeeCap.BigInt(), tx.BlobGas())), tx.Amount.BigInt()), tx.Cost()) + baseFee := big.NewInt(2) + require.Equal(t, EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()), tx.EffectiveGasPrice(baseFee)) + require.Equal(t, new(big.Int).Add(fee(EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()), tx.GasLimit), fee(tx.BlobFeeCap.BigInt(), tx.BlobGas())), tx.EffectiveFee(baseFee)) + require.Equal(t, cost(new(big.Int).Add(fee(EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()), tx.GasLimit), fee(tx.BlobFeeCap.BigInt(), tx.BlobGas())), tx.Amount.BigInt()), tx.EffectiveCost(baseFee)) + + require.Equal(t, big.NewInt(30), tx.GetBlobFeeCap()) + require.Equal(t, []common.Hash{{'c', 'd'}}, tx.GetBlobHashes()) +} + +func TestValidateBlobTransaction(t *testing.T) { + ethTx := mockBlobTransaction(uint256.NewInt(20)) + tx, err := NewBlobTx(ethTx) + require.Nil(t, err) + gtc := tx.GasTipCap + tx.GasTipCap = nil + require.NotNil(t, tx.Validate()) + ngtc := gtc.Neg() + tx.GasTipCap = &ngtc + require.NotNil(t, tx.Validate()) + tx.GasTipCap = gtc + gfc := tx.GasFeeCap + tx.GasFeeCap = nil + require.NotNil(t, tx.Validate()) + ngfc := gfc.Neg() + tx.GasFeeCap = &ngfc + require.NotNil(t, tx.Validate()) + sgfc := tx.GasTipCap.Sub(sdk.OneInt()) + tx.GasFeeCap = &sgfc + require.NotNil(t, tx.Validate()) + tx.GasFeeCap = gfc + amt := tx.Amount + namt := amt.Neg() + tx.Amount = &namt + require.NotNil(t, tx.Validate()) + tx.Amount = amt + overflowed := &big.Int{} + sdkOverflowed := sdk.NewIntFromBigInt(overflowed.Exp(big.NewInt(math.MaxInt64), big.NewInt(4), nil)) + tx.GasFeeCap = &sdkOverflowed + require.NotNil(t, tx.Validate()) + tx.GasFeeCap = gfc + to := tx.To + tx.To = "xyz" + require.NotNil(t, tx.Validate()) + tx.To = to + chainID := tx.ChainID + tx.ChainID = nil + require.NotNil(t, tx.Validate()) + tx.ChainID = chainID +} diff --git a/x/evm/types/ethtx/dynamic_fee_tx.go b/x/evm/types/ethtx/dynamic_fee_tx.go new file mode 100644 index 0000000000..e118ab4566 --- /dev/null +++ b/x/evm/types/ethtx/dynamic_fee_tx.go @@ -0,0 +1,229 @@ +package ethtx + +import ( + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +func NewDynamicFeeTx(tx *ethtypes.Transaction) (*DynamicFeeTx, error) { + if err := ValidateEthTx(tx); err != nil { + return nil, err + } + txData := &DynamicFeeTx{ + Nonce: tx.Nonce(), + Data: tx.Data(), + GasLimit: tx.Gas(), + } + + v, r, s := tx.RawSignatureValues() + SetConvertIfPresent(tx.To(), func(to *common.Address) string { return to.Hex() }, txData.SetTo) + SetConvertIfPresent(tx.Value(), sdk.NewIntFromBigInt, txData.SetAmount) + SetConvertIfPresent(tx.GasFeeCap(), sdk.NewIntFromBigInt, txData.SetGasFeeCap) + SetConvertIfPresent(tx.GasTipCap(), sdk.NewIntFromBigInt, txData.SetGasTipCap) + al := tx.AccessList() + SetConvertIfPresent(&al, NewAccessList, txData.SetAccesses) + + txData.SetSignatureValues(tx.ChainId(), v, r, s) + return txData, txData.Validate() +} + +func (tx *DynamicFeeTx) TxType() uint8 { + return ethtypes.DynamicFeeTxType +} + +func (tx *DynamicFeeTx) Copy() TxData { + return &DynamicFeeTx{ + ChainID: tx.ChainID, + Nonce: tx.Nonce, + GasTipCap: tx.GasTipCap, + GasFeeCap: tx.GasFeeCap, + GasLimit: tx.GasLimit, + To: tx.To, + Amount: tx.Amount, + Data: common.CopyBytes(tx.Data), + Accesses: tx.Accesses, + V: common.CopyBytes(tx.V), + R: common.CopyBytes(tx.R), + S: common.CopyBytes(tx.S), + } +} + +func (tx *DynamicFeeTx) GetChainID() *big.Int { + if tx.ChainID == nil { + return nil + } + + return tx.ChainID.BigInt() +} + +func (tx *DynamicFeeTx) GetAccessList() ethtypes.AccessList { + if tx.Accesses == nil { + return nil + } + return *tx.Accesses.ToEthAccessList() +} + +func (tx *DynamicFeeTx) GetData() []byte { + return common.CopyBytes(tx.Data) +} + +func (tx *DynamicFeeTx) GetGas() uint64 { + return tx.GasLimit +} + +func (tx *DynamicFeeTx) GetGasPrice() *big.Int { + return tx.GetGasFeeCap() +} + +func (tx *DynamicFeeTx) GetGasTipCap() *big.Int { + if tx.GasTipCap == nil { + return nil + } + return tx.GasTipCap.BigInt() +} + +func (tx *DynamicFeeTx) GetGasFeeCap() *big.Int { + if tx.GasFeeCap == nil { + return nil + } + return tx.GasFeeCap.BigInt() +} + +func (tx *DynamicFeeTx) GetValue() *big.Int { + if tx.Amount == nil { + return nil + } + + return tx.Amount.BigInt() +} + +func (tx *DynamicFeeTx) GetNonce() uint64 { return tx.Nonce } + +func (tx *DynamicFeeTx) GetTo() *common.Address { + if tx.To == "" { + return nil + } + to := common.HexToAddress(tx.To) + return &to +} + +func (tx *DynamicFeeTx) AsEthereumData() ethtypes.TxData { + v, r, s := tx.GetRawSignatureValues() + return ðtypes.DynamicFeeTx{ + ChainID: tx.GetChainID(), + Nonce: tx.GetNonce(), + GasTipCap: tx.GetGasTipCap(), + GasFeeCap: tx.GetGasFeeCap(), + Gas: tx.GetGas(), + To: tx.GetTo(), + Value: tx.GetValue(), + Data: tx.GetData(), + AccessList: tx.GetAccessList(), + V: v, + R: r, + S: s, + } +} + +func (tx *DynamicFeeTx) GetRawSignatureValues() (v, r, s *big.Int) { + return rawSignatureValues(tx.V, tx.R, tx.S) +} + +func (tx *DynamicFeeTx) SetSignatureValues(chainID, v, r, s *big.Int) { + if v != nil { + tx.V = v.Bytes() + } + if r != nil { + tx.R = r.Bytes() + } + if s != nil { + tx.S = s.Bytes() + } + if chainID != nil { + chainIDInt := sdk.NewIntFromBigInt(chainID) + tx.ChainID = &chainIDInt + } +} + +func (tx *DynamicFeeTx) GetBlobFeeCap() *big.Int { + return nil +} + +func (tx *DynamicFeeTx) GetBlobHashes() []common.Hash { + return nil +} + +func (tx DynamicFeeTx) Validate() error { + if tx.GasTipCap == nil { + return errors.New("gas tip cap cannot nil") + } + + if tx.GasFeeCap == nil { + return errors.New("gas fee cap cannot nil") + } + + if tx.GasTipCap.IsNegative() { + return fmt.Errorf("gas tip cap cannot be negative %s", tx.GasTipCap) + } + + if tx.GasFeeCap.IsNegative() { + return fmt.Errorf("gas fee cap cannot be negative %s", tx.GasFeeCap) + } + + if tx.GasFeeCap.LT(*tx.GasTipCap) { + return fmt.Errorf("max priority fee per gas higher than max fee per gas (%s > %s)", + tx.GasTipCap, tx.GasFeeCap, + ) + } + + if !IsValidInt256(tx.Fee()) { + return errors.New("fee out of bound") + } + + amount := tx.GetValue() + // Amount can be 0 + if amount != nil && amount.Sign() == -1 { + return fmt.Errorf("amount cannot be negative %s", amount) + } + + if tx.To != "" { + if err := ValidateAddress(tx.To); err != nil { + return errors.New("invalid to address") + } + } + + chainID := tx.GetChainID() + + if chainID == nil { + return errors.New( + "chain ID must be present on AccessList txs", + ) + } + + return nil +} + +func (tx DynamicFeeTx) Fee() *big.Int { + return fee(tx.GetGasFeeCap(), tx.GasLimit) +} + +func (tx DynamicFeeTx) Cost() *big.Int { + return cost(tx.Fee(), tx.GetValue()) +} + +func (tx *DynamicFeeTx) EffectiveGasPrice(baseFee *big.Int) *big.Int { + return EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()) +} + +func (tx DynamicFeeTx) EffectiveFee(baseFee *big.Int) *big.Int { + return fee(tx.EffectiveGasPrice(baseFee), tx.GasLimit) +} + +func (tx DynamicFeeTx) EffectiveCost(baseFee *big.Int) *big.Int { + return cost(tx.EffectiveFee(baseFee), tx.GetValue()) +} diff --git a/x/evm/types/ethtx/dynamic_fee_tx_setter.go b/x/evm/types/ethtx/dynamic_fee_tx_setter.go new file mode 100644 index 0000000000..2b173345f3 --- /dev/null +++ b/x/evm/types/ethtx/dynamic_fee_tx_setter.go @@ -0,0 +1,23 @@ +package ethtx + +import sdk "github.com/cosmos/cosmos-sdk/types" + +func (tx *DynamicFeeTx) SetTo(v string) { + tx.To = v +} + +func (tx *DynamicFeeTx) SetAmount(v sdk.Int) { + tx.Amount = &v +} + +func (tx *DynamicFeeTx) SetGasFeeCap(v sdk.Int) { + tx.GasFeeCap = &v +} + +func (tx *DynamicFeeTx) SetGasTipCap(v sdk.Int) { + tx.GasTipCap = &v +} + +func (tx *DynamicFeeTx) SetAccesses(v AccessList) { + tx.Accesses = v +} diff --git a/x/evm/types/ethtx/dynamic_fee_tx_test.go b/x/evm/types/ethtx/dynamic_fee_tx_test.go new file mode 100644 index 0000000000..1031907f34 --- /dev/null +++ b/x/evm/types/ethtx/dynamic_fee_tx_test.go @@ -0,0 +1,140 @@ +package ethtx + +import ( + "math" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" +) + +func mockDynamicFeeTransaction(value *big.Int) *ethtypes.Transaction { + inner := ðtypes.DynamicFeeTx{ + ChainID: big.NewInt(1), + GasTipCap: big.NewInt(50), + GasFeeCap: big.NewInt(100), + Gas: 1000, + To: &common.Address{'a'}, + Value: value, + Data: []byte{'b'}, + AccessList: mockAccessList(), + V: big.NewInt(3), + R: big.NewInt(5), + S: big.NewInt(7), + } + return ethtypes.NewTx(inner) +} + +func TestDynamicFeeTransaction(t *testing.T) { + ethTx := mockDynamicFeeTransaction(big.NewInt(20)) + tx, err := NewDynamicFeeTx(ethTx) + require.Nil(t, err) + require.Nil(t, tx.Validate()) + + require.Equal(t, uint8(ethtypes.DynamicFeeTxType), tx.TxType()) + copy := tx.Copy() + require.Equal(t, tx, copy) + cached := tx.ChainID + tx.ChainID = nil + require.Nil(t, tx.GetChainID()) + tx.ChainID = cached + require.Equal(t, cached.BigInt(), tx.GetChainID()) + al := tx.Accesses + tx.Accesses = nil + require.Nil(t, tx.GetAccessList()) + tx.Accesses = al + require.Equal(t, *al.ToEthAccessList(), tx.GetAccessList()) + require.Equal(t, common.CopyBytes(tx.Data), tx.GetData()) + require.Equal(t, tx.GasLimit, tx.GetGas()) + gfc := tx.GasFeeCap + tx.GasFeeCap = nil + require.Nil(t, tx.GetGasPrice()) + tx.GasFeeCap = gfc + require.Equal(t, gfc.BigInt(), tx.GetGasPrice()) + gtc := tx.GasTipCap + tx.GasTipCap = nil + require.Nil(t, tx.GetGasTipCap()) + tx.GasTipCap = gtc + require.Equal(t, gtc.BigInt(), tx.GetGasTipCap()) + require.Equal(t, gfc.BigInt(), tx.GetGasFeeCap()) + amt := tx.Amount + tx.Amount = nil + require.Nil(t, tx.GetValue()) + tx.Amount = amt + require.Equal(t, amt.BigInt(), tx.GetValue()) + require.Equal(t, tx.Nonce, tx.GetNonce()) + to := tx.To + tx.To = "" + require.Nil(t, tx.GetTo()) + tx.To = to + require.Equal(t, common.HexToAddress(to), *tx.GetTo()) + require.Equal(t, ethTx.Hash(), ethtypes.NewTx(tx.AsEthereumData()).Hash()) + v, s, r := tx.GetRawSignatureValues() + V, S, R := ethTx.RawSignatureValues() + require.Equal(t, *v, *V) + require.Equal(t, *s, *S) + require.Equal(t, *r, *R) + tx.SetSignatureValues(cached.BigInt(), v, s, r) + require.Equal(t, fee(tx.GasFeeCap.BigInt(), tx.GasLimit), tx.Fee()) + require.Equal(t, cost(fee(tx.GasFeeCap.BigInt(), tx.GasLimit), tx.Amount.BigInt()), tx.Cost()) + baseFee := big.NewInt(2) + require.Equal(t, EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()), tx.EffectiveGasPrice(baseFee)) + require.Equal(t, fee(EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()), tx.GasLimit), tx.EffectiveFee(baseFee)) + require.Equal(t, cost(fee(EffectiveGasPrice(baseFee, tx.GasFeeCap.BigInt(), tx.GasTipCap.BigInt()), tx.GasLimit), tx.Amount.BigInt()), tx.EffectiveCost(baseFee)) + + require.Nil(t, tx.GetBlobFeeCap()) + require.Nil(t, tx.GetBlobHashes()) +} + +func TestInvalidDynamicFeeTransaction(t *testing.T) { + maxInt64 := big.NewInt(math.MaxInt64) + overflowed := &big.Int{} + // (2^64)^5 > 2^256 + ethTx := mockDynamicFeeTransaction(overflowed.Exp(maxInt64, big.NewInt(5), nil)) + _, err := NewDynamicFeeTx(ethTx) + require.NotNil(t, err) +} + +func TestValidateDynamicFeeTransaction(t *testing.T) { + ethTx := mockDynamicFeeTransaction(big.NewInt(20)) + tx, err := NewDynamicFeeTx(ethTx) + require.Nil(t, err) + gtc := tx.GasTipCap + tx.GasTipCap = nil + require.NotNil(t, tx.Validate()) + ngtc := gtc.Neg() + tx.GasTipCap = &ngtc + require.NotNil(t, tx.Validate()) + tx.GasTipCap = gtc + gfc := tx.GasFeeCap + tx.GasFeeCap = nil + require.NotNil(t, tx.Validate()) + ngfc := gfc.Neg() + tx.GasFeeCap = &ngfc + require.NotNil(t, tx.Validate()) + sgfc := tx.GasTipCap.Sub(sdk.OneInt()) + tx.GasFeeCap = &sgfc + require.NotNil(t, tx.Validate()) + tx.GasFeeCap = gfc + amt := tx.Amount + namt := amt.Neg() + tx.Amount = &namt + require.NotNil(t, tx.Validate()) + tx.Amount = amt + overflowed := &big.Int{} + sdkOverflowed := sdk.NewIntFromBigInt(overflowed.Exp(big.NewInt(math.MaxInt64), big.NewInt(4), nil)) + tx.GasFeeCap = &sdkOverflowed + require.NotNil(t, tx.Validate()) + tx.GasFeeCap = gfc + to := tx.To + tx.To = "xyz" + require.NotNil(t, tx.Validate()) + tx.To = to + chainID := tx.ChainID + tx.ChainID = nil + require.NotNil(t, tx.Validate()) + tx.ChainID = chainID +} diff --git a/x/evm/types/ethtx/int.go b/x/evm/types/ethtx/int.go new file mode 100644 index 0000000000..f829942c4f --- /dev/null +++ b/x/evm/types/ethtx/int.go @@ -0,0 +1,12 @@ +package ethtx + +import ( + "math/big" +) + +const maxBitLen = 256 + +// IsValidInt256 check the bound of 256 bit number +func IsValidInt256(i *big.Int) bool { + return i == nil || i.BitLen() <= maxBitLen +} diff --git a/x/evm/types/ethtx/legacy_tx.go b/x/evm/types/ethtx/legacy_tx.go new file mode 100644 index 0000000000..657a9fd8e1 --- /dev/null +++ b/x/evm/types/ethtx/legacy_tx.go @@ -0,0 +1,202 @@ +package ethtx + +import ( + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/sei-protocol/sei-chain/utils" +) + +func NewLegacyTx(tx *ethtypes.Transaction) (*LegacyTx, error) { + if err := ValidateEthTx(tx); err != nil { + return nil, err + } + txData := &LegacyTx{ + Nonce: tx.Nonce(), + Data: tx.Data(), + GasLimit: tx.Gas(), + } + + v, r, s := tx.RawSignatureValues() + SetConvertIfPresent(tx.To(), func(to *common.Address) string { return to.Hex() }, txData.SetTo) + SetConvertIfPresent(tx.Value(), sdk.NewIntFromBigInt, txData.SetAmount) + SetConvertIfPresent(tx.GasPrice(), sdk.NewIntFromBigInt, txData.SetGasPrice) + + txData.SetSignatureValues(tx.ChainId(), v, r, s) + return txData, txData.Validate() +} + +func (tx *LegacyTx) TxType() uint8 { + return ethtypes.LegacyTxType +} + +func (tx *LegacyTx) Copy() TxData { + return &LegacyTx{ + Nonce: tx.Nonce, + GasPrice: tx.GasPrice, + GasLimit: tx.GasLimit, + To: tx.To, + Amount: tx.Amount, + Data: common.CopyBytes(tx.Data), + V: common.CopyBytes(tx.V), + R: common.CopyBytes(tx.R), + S: common.CopyBytes(tx.S), + } +} + +// copied from go-etherem/core/types:deriveChainId +func (tx *LegacyTx) GetChainID() *big.Int { + v, _, _ := tx.GetRawSignatureValues() + if v.BitLen() <= 64 { + v := v.Uint64() + if v == 27 || v == 28 { + return new(big.Int) + } + return new(big.Int).SetUint64((v - 35) / 2) + } + v = new(big.Int).Sub(v, utils.Big35) + return v.Div(v, utils.Big2) +} + +func (tx *LegacyTx) GetAccessList() ethtypes.AccessList { + return nil +} + +func (tx *LegacyTx) GetData() []byte { + return common.CopyBytes(tx.Data) +} + +func (tx *LegacyTx) GetGas() uint64 { + return tx.GasLimit +} + +func (tx *LegacyTx) GetGasPrice() *big.Int { + if tx.GasPrice == nil { + return nil + } + return tx.GasPrice.BigInt() +} + +func (tx *LegacyTx) GetGasTipCap() *big.Int { + return tx.GetGasPrice() +} + +func (tx *LegacyTx) GetGasFeeCap() *big.Int { + return tx.GetGasPrice() +} + +func (tx *LegacyTx) GetValue() *big.Int { + if tx.Amount == nil { + return nil + } + return tx.Amount.BigInt() +} + +func (tx *LegacyTx) GetNonce() uint64 { return tx.Nonce } + +func (tx *LegacyTx) GetTo() *common.Address { + if tx.To == "" { + return nil + } + to := common.HexToAddress(tx.To) + return &to +} + +func (tx *LegacyTx) AsEthereumData() ethtypes.TxData { + v, r, s := tx.GetRawSignatureValues() + return ðtypes.LegacyTx{ + Nonce: tx.GetNonce(), + GasPrice: tx.GetGasPrice(), + Gas: tx.GetGas(), + To: tx.GetTo(), + Value: tx.GetValue(), + Data: tx.GetData(), + V: v, + R: r, + S: s, + } +} + +func (tx *LegacyTx) GetRawSignatureValues() (v, r, s *big.Int) { + return rawSignatureValues(tx.V, tx.R, tx.S) +} + +func (tx *LegacyTx) SetSignatureValues(_, v, r, s *big.Int) { + if v != nil { + tx.V = v.Bytes() + } + if r != nil { + tx.R = r.Bytes() + } + if s != nil { + tx.S = s.Bytes() + } +} + +func (tx *LegacyTx) GetBlobFeeCap() *big.Int { + return nil +} + +func (tx *LegacyTx) GetBlobHashes() []common.Hash { + return nil +} + +func (tx *LegacyTx) Validate() error { + gasPrice := tx.GetGasPrice() + if gasPrice == nil { + return errors.New("gas price cannot be nil") + } + + if gasPrice.Sign() == -1 { + return fmt.Errorf("gas price cannot be negative %s", gasPrice) + } + if !IsValidInt256(tx.Fee()) { + return errors.New("fee out of bound") + } + + amount := tx.GetValue() + // Amount can be 0 + if amount != nil && amount.Sign() == -1 { + return fmt.Errorf("amount cannot be negative %s", amount) + } + + if tx.To != "" { + if err := ValidateAddress(tx.To); err != nil { + return errors.New("invalid to address") + } + } + + chainID := tx.GetChainID() + + if chainID == nil { + return errors.New( + "chain ID must be present on AccessList txs", + ) + } + + return nil +} + +func (tx LegacyTx) Fee() *big.Int { + return fee(tx.GetGasPrice(), tx.GetGas()) +} + +func (tx LegacyTx) Cost() *big.Int { + return cost(tx.Fee(), tx.GetValue()) +} + +func (tx LegacyTx) EffectiveGasPrice(_ *big.Int) *big.Int { + return tx.GetGasPrice() +} + +func (tx LegacyTx) EffectiveFee(_ *big.Int) *big.Int { + return tx.Fee() +} + +func (tx LegacyTx) EffectiveCost(_ *big.Int) *big.Int { + return tx.Cost() +} diff --git a/x/evm/types/ethtx/legacy_tx_setter.go b/x/evm/types/ethtx/legacy_tx_setter.go new file mode 100644 index 0000000000..a112c9af0b --- /dev/null +++ b/x/evm/types/ethtx/legacy_tx_setter.go @@ -0,0 +1,15 @@ +package ethtx + +import sdk "github.com/cosmos/cosmos-sdk/types" + +func (tx *LegacyTx) SetTo(v string) { + tx.To = v +} + +func (tx *LegacyTx) SetAmount(v sdk.Int) { + tx.Amount = &v +} + +func (tx *LegacyTx) SetGasPrice(v sdk.Int) { + tx.GasPrice = &v +} diff --git a/x/evm/types/ethtx/legacy_tx_test.go b/x/evm/types/ethtx/legacy_tx_test.go new file mode 100644 index 0000000000..3f784de4c3 --- /dev/null +++ b/x/evm/types/ethtx/legacy_tx_test.go @@ -0,0 +1,117 @@ +package ethtx + +import ( + "math" + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" +) + +func mockLegacyTransaction(value *big.Int) *ethtypes.Transaction { + inner := ðtypes.LegacyTx{ + GasPrice: big.NewInt(100), + Gas: 1000, + To: &common.Address{'a'}, + Value: value, + Data: []byte{'b'}, + V: big.NewInt(3), + R: big.NewInt(5), + S: big.NewInt(7), + } + return ethtypes.NewTx(inner) +} + +func TestLegacyTransaction(t *testing.T) { + ethTx := mockLegacyTransaction(big.NewInt(20)) + tx, err := NewLegacyTx(ethTx) + require.Nil(t, err) + require.Nil(t, tx.Validate()) + + require.Equal(t, uint8(ethtypes.LegacyTxType), tx.TxType()) + copy := tx.Copy() + require.Equal(t, tx, copy) + v, r, s := tx.GetRawSignatureValues() + chainID28 := big.NewInt(28) + tx.SetSignatureValues(nil, chainID28, r, s) + require.Equal(t, big.NewInt(0), tx.GetChainID()) + chainID37 := big.NewInt(37) + tx.SetSignatureValues(nil, chainID37, r, s) + require.Equal(t, big.NewInt(1), tx.GetChainID()) + chainIDLarge := new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(35)) + tx.SetSignatureValues(nil, chainIDLarge, r, s) + require.Equal(t, new(big.Int).Div(big.NewInt(math.MaxInt64), big.NewInt(2)), tx.GetChainID()) + tx.SetSignatureValues(nil, v, r, s) + require.Equal(t, common.CopyBytes(tx.Data), tx.GetData()) + require.Equal(t, tx.GasLimit, tx.GetGas()) + gp := tx.GasPrice + tx.GasPrice = nil + require.Nil(t, tx.GetGasPrice()) + tx.GasPrice = gp + require.Equal(t, gp.BigInt(), tx.GetGasPrice()) + require.Equal(t, gp.BigInt(), tx.GetGasTipCap()) + require.Equal(t, gp.BigInt(), tx.GetGasFeeCap()) + amt := tx.Amount + tx.Amount = nil + require.Nil(t, tx.GetValue()) + tx.Amount = amt + require.Equal(t, amt.BigInt(), tx.GetValue()) + require.Equal(t, tx.Nonce, tx.GetNonce()) + to := tx.To + tx.To = "" + require.Nil(t, tx.GetTo()) + tx.To = to + require.Equal(t, common.HexToAddress(to), *tx.GetTo()) + require.Equal(t, ethTx.Hash(), ethtypes.NewTx(tx.AsEthereumData()).Hash()) + V, R, S := ethTx.RawSignatureValues() + require.Equal(t, *v, *V) + require.Equal(t, *s, *S) + require.Equal(t, *r, *R) + tx.SetSignatureValues(nil, v, s, r) + require.Equal(t, fee(tx.GasPrice.BigInt(), tx.GasLimit), tx.Fee()) + require.Equal(t, cost(fee(tx.GasPrice.BigInt(), tx.GasLimit), tx.Amount.BigInt()), tx.Cost()) + require.Equal(t, tx.GasPrice.BigInt(), tx.EffectiveGasPrice(nil)) + require.Equal(t, fee(tx.GasPrice.BigInt(), tx.GasLimit), tx.EffectiveFee(nil)) + require.Equal(t, cost(fee(tx.GasPrice.BigInt(), tx.GasLimit), tx.Amount.BigInt()), tx.EffectiveCost(nil)) + require.Nil(t, tx.GetBlobFeeCap()) + require.Nil(t, tx.GetBlobHashes()) +} + +func TestInvalidLegacyTransaction(t *testing.T) { + maxInt64 := big.NewInt(math.MaxInt64) + overflowed := &big.Int{} + // (2^64)^5 > 2^256 + ethTx := mockLegacyTransaction(overflowed.Exp(maxInt64, big.NewInt(5), nil)) + _, err := NewLegacyTx(ethTx) + require.NotNil(t, err) +} + +func TestValidateLegacyTransaction(t *testing.T) { + ethTx := mockLegacyTransaction(big.NewInt(20)) + tx, err := NewLegacyTx(ethTx) + require.Nil(t, err) + gp := tx.GasPrice + tx.GasPrice = nil + require.NotNil(t, tx.Validate()) + ngp := gp.Neg() + tx.GasPrice = &ngp + require.NotNil(t, tx.Validate()) + tx.GasPrice = gp + amt := tx.Amount + namt := amt.Neg() + tx.Amount = &namt + require.NotNil(t, tx.Validate()) + tx.Amount = amt + overflowed := &big.Int{} + sdkOverflowed := sdk.NewIntFromBigInt(overflowed.Exp(big.NewInt(math.MaxInt64), big.NewInt(4), nil)) + tx.GasPrice = &sdkOverflowed + require.NotNil(t, tx.Validate()) + tx.GasPrice = gp + to := tx.To + tx.To = "xyz" + require.NotNil(t, tx.Validate()) + tx.To = to +} diff --git a/x/evm/types/ethtx/tx.pb.go b/x/evm/types/ethtx/tx.pb.go new file mode 100644 index 0000000000..af0bd45918 --- /dev/null +++ b/x/evm/types/ethtx/tx.pb.go @@ -0,0 +1,3726 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: eth/tx.proto + +package ethtx + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type AccessTuple struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + StorageKeys []string `protobuf:"bytes,2,rep,name=storage_keys,json=storageKeys,proto3" json:"storageKeys"` +} + +func (m *AccessTuple) Reset() { *m = AccessTuple{} } +func (m *AccessTuple) String() string { return proto.CompactTextString(m) } +func (*AccessTuple) ProtoMessage() {} +func (*AccessTuple) Descriptor() ([]byte, []int) { + return fileDescriptor_5aa89218db340ee8, []int{0} +} +func (m *AccessTuple) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessTuple) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessTuple.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AccessTuple) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessTuple.Merge(m, src) +} +func (m *AccessTuple) XXX_Size() int { + return m.Size() +} +func (m *AccessTuple) XXX_DiscardUnknown() { + xxx_messageInfo_AccessTuple.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessTuple proto.InternalMessageInfo + +type AssociateTx struct { + // signature values + V []byte `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"` + R []byte `protobuf:"bytes,2,opt,name=r,proto3" json:"r,omitempty"` + S []byte `protobuf:"bytes,3,opt,name=s,proto3" json:"s,omitempty"` + CustomMessage string `protobuf:"bytes,4,opt,name=custom_message,json=customMessage,proto3" json:"custom_message,omitempty"` +} + +func (m *AssociateTx) Reset() { *m = AssociateTx{} } +func (m *AssociateTx) String() string { return proto.CompactTextString(m) } +func (*AssociateTx) ProtoMessage() {} +func (*AssociateTx) Descriptor() ([]byte, []int) { + return fileDescriptor_5aa89218db340ee8, []int{1} +} +func (m *AssociateTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AssociateTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AssociateTx.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 *AssociateTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_AssociateTx.Merge(m, src) +} +func (m *AssociateTx) XXX_Size() int { + return m.Size() +} +func (m *AssociateTx) XXX_DiscardUnknown() { + xxx_messageInfo_AssociateTx.DiscardUnknown(m) +} + +var xxx_messageInfo_AssociateTx proto.InternalMessageInfo + +type LegacyTx struct { + Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"` + GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"` + GasLimit uint64 `protobuf:"varint,3,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` + To string `protobuf:"bytes,4,opt,name=to,proto3" json:"to,omitempty"` + Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,5,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"` + Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` + // signature values + V []byte `protobuf:"bytes,7,opt,name=v,proto3" json:"v,omitempty"` + R []byte `protobuf:"bytes,8,opt,name=r,proto3" json:"r,omitempty"` + S []byte `protobuf:"bytes,9,opt,name=s,proto3" json:"s,omitempty"` +} + +func (m *LegacyTx) Reset() { *m = LegacyTx{} } +func (m *LegacyTx) String() string { return proto.CompactTextString(m) } +func (*LegacyTx) ProtoMessage() {} +func (*LegacyTx) Descriptor() ([]byte, []int) { + return fileDescriptor_5aa89218db340ee8, []int{2} +} +func (m *LegacyTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *LegacyTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_LegacyTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *LegacyTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_LegacyTx.Merge(m, src) +} +func (m *LegacyTx) XXX_Size() int { + return m.Size() +} +func (m *LegacyTx) XXX_DiscardUnknown() { + xxx_messageInfo_LegacyTx.DiscardUnknown(m) +} + +var xxx_messageInfo_LegacyTx proto.InternalMessageInfo + +type AccessListTx struct { + ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"` + Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + GasPrice *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_price,json=gasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_price,omitempty"` + GasLimit uint64 `protobuf:"varint,4,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` + To string `protobuf:"bytes,5,opt,name=to,proto3" json:"to,omitempty"` + Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"` + Data []byte `protobuf:"bytes,7,opt,name=data,proto3" json:"data,omitempty"` + Accesses AccessList `protobuf:"bytes,8,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"` + // signature values + V []byte `protobuf:"bytes,9,opt,name=v,proto3" json:"v,omitempty"` + R []byte `protobuf:"bytes,10,opt,name=r,proto3" json:"r,omitempty"` + S []byte `protobuf:"bytes,11,opt,name=s,proto3" json:"s,omitempty"` +} + +func (m *AccessListTx) Reset() { *m = AccessListTx{} } +func (m *AccessListTx) String() string { return proto.CompactTextString(m) } +func (*AccessListTx) ProtoMessage() {} +func (*AccessListTx) Descriptor() ([]byte, []int) { + return fileDescriptor_5aa89218db340ee8, []int{3} +} +func (m *AccessListTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessListTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessListTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AccessListTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessListTx.Merge(m, src) +} +func (m *AccessListTx) XXX_Size() int { + return m.Size() +} +func (m *AccessListTx) XXX_DiscardUnknown() { + xxx_messageInfo_AccessListTx.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessListTx proto.InternalMessageInfo + +type DynamicFeeTx struct { + ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"` + Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + GasTipCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_tip_cap,json=gasTipCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_tip_cap,omitempty"` + GasFeeCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=gas_fee_cap,json=gasFeeCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_fee_cap,omitempty"` + GasLimit uint64 `protobuf:"varint,5,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` + To string `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` + Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"` + Data []byte `protobuf:"bytes,8,opt,name=data,proto3" json:"data,omitempty"` + Accesses AccessList `protobuf:"bytes,9,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"` + // signature values + V []byte `protobuf:"bytes,10,opt,name=v,proto3" json:"v,omitempty"` + R []byte `protobuf:"bytes,11,opt,name=r,proto3" json:"r,omitempty"` + S []byte `protobuf:"bytes,12,opt,name=s,proto3" json:"s,omitempty"` +} + +func (m *DynamicFeeTx) Reset() { *m = DynamicFeeTx{} } +func (m *DynamicFeeTx) String() string { return proto.CompactTextString(m) } +func (*DynamicFeeTx) ProtoMessage() {} +func (*DynamicFeeTx) Descriptor() ([]byte, []int) { + return fileDescriptor_5aa89218db340ee8, []int{4} +} +func (m *DynamicFeeTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DynamicFeeTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DynamicFeeTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DynamicFeeTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_DynamicFeeTx.Merge(m, src) +} +func (m *DynamicFeeTx) XXX_Size() int { + return m.Size() +} +func (m *DynamicFeeTx) XXX_DiscardUnknown() { + xxx_messageInfo_DynamicFeeTx.DiscardUnknown(m) +} + +var xxx_messageInfo_DynamicFeeTx proto.InternalMessageInfo + +type BlobTx struct { + ChainID *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chainID"` + Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + GasTipCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=gas_tip_cap,json=gasTipCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_tip_cap,omitempty"` + GasFeeCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,4,opt,name=gas_fee_cap,json=gasFeeCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"gas_fee_cap,omitempty"` + GasLimit uint64 `protobuf:"varint,5,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` + To string `protobuf:"bytes,6,opt,name=to,proto3" json:"to,omitempty"` + Amount *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"` + Data []byte `protobuf:"bytes,8,opt,name=data,proto3" json:"data,omitempty"` + Accesses AccessList `protobuf:"bytes,9,rep,name=accesses,proto3,castrepeated=AccessList" json:"accessList"` + BlobFeeCap *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,10,opt,name=blob_fee_cap,json=blobFeeCap,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"blob_fee_cap,omitempty"` + BlobHashes [][]byte `protobuf:"bytes,11,rep,name=blob_hashes,json=blobHashes,proto3" json:"blob_hashes,omitempty"` + Sidecar *BlobTxSidecar `protobuf:"bytes,12,opt,name=sidecar,proto3" json:"sidecar,omitempty"` + // signature values + V []byte `protobuf:"bytes,13,opt,name=v,proto3" json:"v,omitempty"` + R []byte `protobuf:"bytes,14,opt,name=r,proto3" json:"r,omitempty"` + S []byte `protobuf:"bytes,15,opt,name=s,proto3" json:"s,omitempty"` +} + +func (m *BlobTx) Reset() { *m = BlobTx{} } +func (m *BlobTx) String() string { return proto.CompactTextString(m) } +func (*BlobTx) ProtoMessage() {} +func (*BlobTx) Descriptor() ([]byte, []int) { + return fileDescriptor_5aa89218db340ee8, []int{5} +} +func (m *BlobTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlobTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlobTx.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 *BlobTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlobTx.Merge(m, src) +} +func (m *BlobTx) XXX_Size() int { + return m.Size() +} +func (m *BlobTx) XXX_DiscardUnknown() { + xxx_messageInfo_BlobTx.DiscardUnknown(m) +} + +var xxx_messageInfo_BlobTx proto.InternalMessageInfo + +type BlobTxSidecar struct { + Blobs [][]byte `protobuf:"bytes,1,rep,name=blobs,proto3" json:"blobs,omitempty"` + Commitments [][]byte `protobuf:"bytes,2,rep,name=commitments,proto3" json:"commitments,omitempty"` + Proofs [][]byte `protobuf:"bytes,3,rep,name=proofs,proto3" json:"proofs,omitempty"` +} + +func (m *BlobTxSidecar) Reset() { *m = BlobTxSidecar{} } +func (m *BlobTxSidecar) String() string { return proto.CompactTextString(m) } +func (*BlobTxSidecar) ProtoMessage() {} +func (*BlobTxSidecar) Descriptor() ([]byte, []int) { + return fileDescriptor_5aa89218db340ee8, []int{6} +} +func (m *BlobTxSidecar) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlobTxSidecar) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlobTxSidecar.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 *BlobTxSidecar) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlobTxSidecar.Merge(m, src) +} +func (m *BlobTxSidecar) XXX_Size() int { + return m.Size() +} +func (m *BlobTxSidecar) XXX_DiscardUnknown() { + xxx_messageInfo_BlobTxSidecar.DiscardUnknown(m) +} + +var xxx_messageInfo_BlobTxSidecar proto.InternalMessageInfo + +func (m *BlobTxSidecar) GetBlobs() [][]byte { + if m != nil { + return m.Blobs + } + return nil +} + +func (m *BlobTxSidecar) GetCommitments() [][]byte { + if m != nil { + return m.Commitments + } + return nil +} + +func (m *BlobTxSidecar) GetProofs() [][]byte { + if m != nil { + return m.Proofs + } + return nil +} + +type ExtensionOptionsEthereumTx struct { +} + +func (m *ExtensionOptionsEthereumTx) Reset() { *m = ExtensionOptionsEthereumTx{} } +func (m *ExtensionOptionsEthereumTx) String() string { return proto.CompactTextString(m) } +func (*ExtensionOptionsEthereumTx) ProtoMessage() {} +func (*ExtensionOptionsEthereumTx) Descriptor() ([]byte, []int) { + return fileDescriptor_5aa89218db340ee8, []int{7} +} +func (m *ExtensionOptionsEthereumTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExtensionOptionsEthereumTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExtensionOptionsEthereumTx.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ExtensionOptionsEthereumTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtensionOptionsEthereumTx.Merge(m, src) +} +func (m *ExtensionOptionsEthereumTx) XXX_Size() int { + return m.Size() +} +func (m *ExtensionOptionsEthereumTx) XXX_DiscardUnknown() { + xxx_messageInfo_ExtensionOptionsEthereumTx.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtensionOptionsEthereumTx proto.InternalMessageInfo + +func init() { + proto.RegisterType((*AccessTuple)(nil), "seiprotocol.seichain.eth.AccessTuple") + proto.RegisterType((*AssociateTx)(nil), "seiprotocol.seichain.eth.AssociateTx") + proto.RegisterType((*LegacyTx)(nil), "seiprotocol.seichain.eth.LegacyTx") + proto.RegisterType((*AccessListTx)(nil), "seiprotocol.seichain.eth.AccessListTx") + proto.RegisterType((*DynamicFeeTx)(nil), "seiprotocol.seichain.eth.DynamicFeeTx") + proto.RegisterType((*BlobTx)(nil), "seiprotocol.seichain.eth.BlobTx") + proto.RegisterType((*BlobTxSidecar)(nil), "seiprotocol.seichain.eth.BlobTxSidecar") + proto.RegisterType((*ExtensionOptionsEthereumTx)(nil), "seiprotocol.seichain.eth.ExtensionOptionsEthereumTx") +} + +func init() { proto.RegisterFile("eth/tx.proto", fileDescriptor_5aa89218db340ee8) } + +var fileDescriptor_5aa89218db340ee8 = []byte{ + // 795 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x56, 0xcb, 0x6e, 0x1c, 0x45, + 0x14, 0x9d, 0x47, 0xcf, 0xeb, 0x76, 0xdb, 0x91, 0x4a, 0x11, 0x6a, 0x05, 0x69, 0x7a, 0x64, 0x29, + 0x60, 0x21, 0x65, 0x46, 0x72, 0x58, 0xb1, 0xc2, 0x93, 0x07, 0x24, 0x38, 0x02, 0x35, 0xb3, 0x82, + 0xc5, 0xa8, 0xa6, 0xfa, 0xa6, 0xbb, 0x94, 0xe9, 0xae, 0x56, 0x57, 0x8d, 0xd5, 0xf3, 0x07, 0x2c, + 0xf9, 0x04, 0x56, 0x2c, 0xf8, 0x05, 0x7e, 0x20, 0xcb, 0x2c, 0x11, 0x8b, 0x01, 0xd9, 0x0b, 0x24, + 0x8b, 0x8f, 0x40, 0x55, 0xd5, 0x76, 0xa6, 0x95, 0x8c, 0x44, 0x2c, 0x23, 0x16, 0xb0, 0x72, 0x9d, + 0x5b, 0x55, 0xe7, 0x5e, 0x9f, 0x73, 0x7a, 0x54, 0xe0, 0xa1, 0x4a, 0x26, 0xaa, 0x1c, 0xe7, 0x85, + 0x50, 0x82, 0xf8, 0x12, 0xb9, 0x59, 0x31, 0xb1, 0x1c, 0x4b, 0xe4, 0x2c, 0xa1, 0x3c, 0x1b, 0xa3, + 0x4a, 0xee, 0xdc, 0x8e, 0x45, 0x2c, 0xcc, 0xd6, 0x44, 0xaf, 0xec, 0xf9, 0x03, 0x0a, 0xee, 0x31, + 0x63, 0x28, 0xe5, 0x6c, 0x95, 0x2f, 0x91, 0xf8, 0xd0, 0xa3, 0x51, 0x54, 0xa0, 0x94, 0x7e, 0x73, + 0xd4, 0x3c, 0x1c, 0x84, 0x97, 0x90, 0x1c, 0x81, 0x27, 0x95, 0x28, 0x68, 0x8c, 0xf3, 0x17, 0xb8, + 0x96, 0x7e, 0x6b, 0xd4, 0x3e, 0x1c, 0x4c, 0x6f, 0x5d, 0x6c, 0x02, 0xb7, 0xaa, 0x7f, 0x81, 0x6b, + 0x19, 0x6e, 0x83, 0x4f, 0x9c, 0xef, 0x7e, 0x08, 0x1a, 0x07, 0x11, 0xb8, 0xc7, 0x52, 0x0a, 0xc6, + 0xa9, 0xc2, 0x59, 0x49, 0x3c, 0x68, 0x9e, 0x1a, 0x72, 0x2f, 0x6c, 0x9e, 0x6a, 0x54, 0xf8, 0x2d, + 0x8b, 0x0a, 0x8d, 0xa4, 0xdf, 0xb6, 0x48, 0x92, 0xbb, 0xb0, 0xcf, 0x56, 0x52, 0x89, 0x74, 0x9e, + 0xa2, 0x94, 0x34, 0x46, 0xdf, 0x31, 0x33, 0xed, 0xd9, 0xea, 0x33, 0x5b, 0xac, 0xba, 0xfc, 0xd8, + 0x82, 0xfe, 0x09, 0xc6, 0x94, 0xad, 0x67, 0x25, 0xb9, 0x0d, 0x9d, 0x4c, 0x64, 0x0c, 0x4d, 0x1f, + 0x27, 0xb4, 0x80, 0x7c, 0x06, 0x83, 0x98, 0xca, 0x79, 0x5e, 0x70, 0x86, 0xa6, 0xe7, 0x60, 0xfa, + 0xd1, 0xaf, 0x9b, 0xe0, 0x83, 0x98, 0xab, 0x64, 0xb5, 0x18, 0x33, 0x91, 0x4e, 0x98, 0x90, 0xa9, + 0x90, 0xd5, 0x9f, 0x7b, 0x32, 0x7a, 0x31, 0x51, 0xeb, 0x1c, 0xe5, 0xf8, 0x49, 0xa6, 0xc2, 0x7e, + 0x4c, 0xe5, 0x57, 0xfa, 0x2e, 0x79, 0xdf, 0x12, 0x2d, 0x79, 0xca, 0x95, 0x19, 0xd7, 0x31, 0x9b, + 0x27, 0x1a, 0x93, 0x7d, 0x68, 0x29, 0x51, 0x4d, 0xda, 0x52, 0x82, 0x3c, 0x85, 0xce, 0x29, 0x5d, + 0xae, 0xd0, 0xef, 0x98, 0x8e, 0x1f, 0xff, 0xfd, 0x8e, 0x67, 0x9b, 0xa0, 0x7b, 0x9c, 0x8a, 0x55, + 0xa6, 0x42, 0x4b, 0x41, 0x08, 0x38, 0x11, 0x55, 0xd4, 0xef, 0x1a, 0x89, 0xcc, 0xda, 0xea, 0xd9, + 0xab, 0xe9, 0xd9, 0xaf, 0xe9, 0x39, 0xa8, 0xf4, 0xac, 0x84, 0xfa, 0xb3, 0x0d, 0x9e, 0xb5, 0xfc, + 0x84, 0x4b, 0x35, 0x2b, 0xc9, 0xb7, 0xd0, 0x37, 0x29, 0x99, 0xf3, 0xc8, 0x9a, 0x3e, 0xfd, 0xf4, + 0x9d, 0x66, 0xec, 0x3d, 0xd0, 0xb7, 0x9f, 0x3c, 0xbc, 0xd8, 0x04, 0x3d, 0x66, 0x97, 0x61, 0xb5, + 0x88, 0x5e, 0x3b, 0xd1, 0xda, 0xe9, 0x44, 0xfb, 0xa6, 0x9c, 0x70, 0xde, 0xea, 0x44, 0xe7, 0x4d, + 0x27, 0xba, 0x37, 0xe7, 0x44, 0x6f, 0xcb, 0x09, 0x06, 0x7d, 0x6a, 0x84, 0x45, 0xe9, 0xf7, 0x47, + 0xed, 0x43, 0xf7, 0xe8, 0xee, 0x78, 0xd7, 0xe7, 0x38, 0xde, 0xfa, 0xea, 0xa6, 0xa3, 0x97, 0x9b, + 0xa0, 0x71, 0xb1, 0x09, 0x80, 0x5e, 0xf9, 0xf2, 0xd3, 0x6f, 0x01, 0xbc, 0x76, 0x29, 0xbc, 0x22, + 0xb6, 0x76, 0x0f, 0x6a, 0x76, 0x43, 0xcd, 0x6e, 0xb7, 0x6e, 0xf7, 0xcf, 0x0e, 0x78, 0x0f, 0xd7, + 0x19, 0x4d, 0x39, 0x7b, 0x8c, 0xf8, 0xef, 0xd8, 0xfd, 0x14, 0x5c, 0xed, 0x92, 0xe2, 0xf9, 0x9c, + 0xd1, 0xfc, 0x1a, 0x86, 0x6b, 0x93, 0x67, 0x3c, 0x7f, 0x40, 0xf3, 0x4b, 0xae, 0xe7, 0x88, 0x86, + 0xcb, 0xb9, 0x16, 0xd7, 0x63, 0x44, 0xcd, 0x55, 0x4b, 0x4f, 0xe7, 0xad, 0xe9, 0xe9, 0xbe, 0x99, + 0x9e, 0xde, 0xcd, 0xa5, 0xa7, 0xbf, 0x23, 0x3d, 0x83, 0x7f, 0x34, 0x3d, 0x50, 0x4b, 0x8f, 0x5b, + 0x4b, 0x8f, 0x57, 0x4f, 0xcf, 0x1f, 0x1d, 0xe8, 0x4e, 0x97, 0x62, 0xf1, 0x7f, 0x6e, 0xfe, 0xdb, + 0xb9, 0x39, 0x01, 0x6f, 0xb1, 0x14, 0x8b, 0x2b, 0xf9, 0xe0, 0x9d, 0xe5, 0x03, 0x7d, 0xbf, 0xd2, + 0x2f, 0x00, 0xd7, 0xb0, 0x25, 0x54, 0x26, 0xa8, 0x7f, 0xb1, 0xda, 0x87, 0x9e, 0x3d, 0xf0, 0xb9, + 0xa9, 0x90, 0x63, 0xe8, 0x49, 0x1e, 0x21, 0xa3, 0x85, 0x09, 0xa4, 0x7b, 0xf4, 0xe1, 0xee, 0x7f, + 0xc9, 0xc6, 0xf3, 0x6b, 0x7b, 0x3c, 0xbc, 0xbc, 0x67, 0x93, 0xbe, 0x57, 0x4b, 0xfa, 0x7e, 0x2d, + 0xe9, 0xb7, 0xea, 0x49, 0x9f, 0xc3, 0x5e, 0x8d, 0x49, 0x47, 0x52, 0x4f, 0xa4, 0x1f, 0x42, 0x7a, + 0x3c, 0x0b, 0xc8, 0x08, 0x5c, 0x26, 0xd2, 0x94, 0xab, 0x14, 0x33, 0x65, 0x5f, 0x41, 0x5e, 0xb8, + 0x5d, 0x22, 0xef, 0x41, 0x37, 0x2f, 0x84, 0x78, 0xae, 0x1f, 0x32, 0x7a, 0xb3, 0x42, 0x07, 0x07, + 0x70, 0xe7, 0x51, 0xa9, 0x30, 0x93, 0x5c, 0x64, 0x5f, 0xe6, 0x8a, 0x8b, 0x4c, 0x3e, 0x52, 0x09, + 0x16, 0xb8, 0x4a, 0x67, 0xa5, 0x1d, 0x62, 0xfa, 0xec, 0xe5, 0xd9, 0xb0, 0xf9, 0xea, 0x6c, 0xd8, + 0xfc, 0xfd, 0x6c, 0xd8, 0xfc, 0xfe, 0x7c, 0xd8, 0x78, 0x75, 0x3e, 0x6c, 0xfc, 0x72, 0x3e, 0x6c, + 0x7c, 0x73, 0x7f, 0x4b, 0x66, 0x89, 0xfc, 0xde, 0xa5, 0x16, 0x06, 0x18, 0x31, 0x26, 0xe5, 0x04, + 0x4f, 0x53, 0xab, 0xf8, 0x04, 0x55, 0xa2, 0xca, 0x45, 0xd7, 0x9c, 0xba, 0xff, 0x57, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xcc, 0x38, 0xe1, 0xb7, 0x23, 0x0a, 0x00, 0x00, +} + +func (m *AccessTuple) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AccessTuple) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessTuple) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.StorageKeys) > 0 { + for iNdEx := len(m.StorageKeys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.StorageKeys[iNdEx]) + copy(dAtA[i:], m.StorageKeys[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.StorageKeys[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AssociateTx) 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 *AssociateTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AssociateTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CustomMessage) > 0 { + i -= len(m.CustomMessage) + copy(dAtA[i:], m.CustomMessage) + i = encodeVarintTx(dAtA, i, uint64(len(m.CustomMessage))) + i-- + dAtA[i] = 0x22 + } + if len(m.S) > 0 { + i -= len(m.S) + copy(dAtA[i:], m.S) + i = encodeVarintTx(dAtA, i, uint64(len(m.S))) + i-- + dAtA[i] = 0x1a + } + if len(m.R) > 0 { + i -= len(m.R) + copy(dAtA[i:], m.R) + i = encodeVarintTx(dAtA, i, uint64(len(m.R))) + i-- + dAtA[i] = 0x12 + } + if len(m.V) > 0 { + i -= len(m.V) + copy(dAtA[i:], m.V) + i = encodeVarintTx(dAtA, i, uint64(len(m.V))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *LegacyTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *LegacyTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *LegacyTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.S) > 0 { + i -= len(m.S) + copy(dAtA[i:], m.S) + i = encodeVarintTx(dAtA, i, uint64(len(m.S))) + i-- + dAtA[i] = 0x4a + } + if len(m.R) > 0 { + i -= len(m.R) + copy(dAtA[i:], m.R) + i = encodeVarintTx(dAtA, i, uint64(len(m.R))) + i-- + dAtA[i] = 0x42 + } + if len(m.V) > 0 { + i -= len(m.V) + copy(dAtA[i:], m.V) + i = encodeVarintTx(dAtA, i, uint64(len(m.V))) + i-- + dAtA[i] = 0x3a + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x32 + } + if m.Amount != nil { + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x22 + } + if m.GasLimit != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.GasLimit)) + i-- + dAtA[i] = 0x18 + } + if m.GasPrice != nil { + { + size := m.GasPrice.Size() + i -= size + if _, err := m.GasPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Nonce != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *AccessListTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AccessListTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessListTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.S) > 0 { + i -= len(m.S) + copy(dAtA[i:], m.S) + i = encodeVarintTx(dAtA, i, uint64(len(m.S))) + i-- + dAtA[i] = 0x5a + } + if len(m.R) > 0 { + i -= len(m.R) + copy(dAtA[i:], m.R) + i = encodeVarintTx(dAtA, i, uint64(len(m.R))) + i-- + dAtA[i] = 0x52 + } + if len(m.V) > 0 { + i -= len(m.V) + copy(dAtA[i:], m.V) + i = encodeVarintTx(dAtA, i, uint64(len(m.V))) + i-- + dAtA[i] = 0x4a + } + if len(m.Accesses) > 0 { + for iNdEx := len(m.Accesses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Accesses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x3a + } + if m.Amount != nil { + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x2a + } + if m.GasLimit != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.GasLimit)) + i-- + dAtA[i] = 0x20 + } + if m.GasPrice != nil { + { + size := m.GasPrice.Size() + i -= size + if _, err := m.GasPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Nonce != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x10 + } + if m.ChainID != nil { + { + size := m.ChainID.Size() + i -= size + if _, err := m.ChainID.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *DynamicFeeTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DynamicFeeTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DynamicFeeTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.S) > 0 { + i -= len(m.S) + copy(dAtA[i:], m.S) + i = encodeVarintTx(dAtA, i, uint64(len(m.S))) + i-- + dAtA[i] = 0x62 + } + if len(m.R) > 0 { + i -= len(m.R) + copy(dAtA[i:], m.R) + i = encodeVarintTx(dAtA, i, uint64(len(m.R))) + i-- + dAtA[i] = 0x5a + } + if len(m.V) > 0 { + i -= len(m.V) + copy(dAtA[i:], m.V) + i = encodeVarintTx(dAtA, i, uint64(len(m.V))) + i-- + dAtA[i] = 0x52 + } + if len(m.Accesses) > 0 { + for iNdEx := len(m.Accesses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Accesses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x42 + } + if m.Amount != nil { + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x32 + } + if m.GasLimit != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.GasLimit)) + i-- + dAtA[i] = 0x28 + } + if m.GasFeeCap != nil { + { + size := m.GasFeeCap.Size() + i -= size + if _, err := m.GasFeeCap.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.GasTipCap != nil { + { + size := m.GasTipCap.Size() + i -= size + if _, err := m.GasTipCap.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Nonce != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x10 + } + if m.ChainID != nil { + { + size := m.ChainID.Size() + i -= size + if _, err := m.ChainID.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *BlobTx) 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 *BlobTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlobTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.S) > 0 { + i -= len(m.S) + copy(dAtA[i:], m.S) + i = encodeVarintTx(dAtA, i, uint64(len(m.S))) + i-- + dAtA[i] = 0x7a + } + if len(m.R) > 0 { + i -= len(m.R) + copy(dAtA[i:], m.R) + i = encodeVarintTx(dAtA, i, uint64(len(m.R))) + i-- + dAtA[i] = 0x72 + } + if len(m.V) > 0 { + i -= len(m.V) + copy(dAtA[i:], m.V) + i = encodeVarintTx(dAtA, i, uint64(len(m.V))) + i-- + dAtA[i] = 0x6a + } + if m.Sidecar != nil { + { + size, err := m.Sidecar.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + } + if len(m.BlobHashes) > 0 { + for iNdEx := len(m.BlobHashes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.BlobHashes[iNdEx]) + copy(dAtA[i:], m.BlobHashes[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.BlobHashes[iNdEx]))) + i-- + dAtA[i] = 0x5a + } + } + if m.BlobFeeCap != nil { + { + size := m.BlobFeeCap.Size() + i -= size + if _, err := m.BlobFeeCap.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + if len(m.Accesses) > 0 { + for iNdEx := len(m.Accesses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Accesses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x42 + } + if m.Amount != nil { + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x32 + } + if m.GasLimit != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.GasLimit)) + i-- + dAtA[i] = 0x28 + } + if m.GasFeeCap != nil { + { + size := m.GasFeeCap.Size() + i -= size + if _, err := m.GasFeeCap.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + if m.GasTipCap != nil { + { + size := m.GasTipCap.Size() + i -= size + if _, err := m.GasTipCap.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Nonce != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x10 + } + if m.ChainID != nil { + { + size := m.ChainID.Size() + i -= size + if _, err := m.ChainID.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *BlobTxSidecar) 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 *BlobTxSidecar) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlobTxSidecar) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Proofs) > 0 { + for iNdEx := len(m.Proofs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Proofs[iNdEx]) + copy(dAtA[i:], m.Proofs[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Proofs[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.Commitments) > 0 { + for iNdEx := len(m.Commitments) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Commitments[iNdEx]) + copy(dAtA[i:], m.Commitments[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Commitments[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Blobs) > 0 { + for iNdEx := len(m.Blobs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Blobs[iNdEx]) + copy(dAtA[i:], m.Blobs[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.Blobs[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ExtensionOptionsEthereumTx) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ExtensionOptionsEthereumTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExtensionOptionsEthereumTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *AccessTuple) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.StorageKeys) > 0 { + for _, s := range m.StorageKeys { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *AssociateTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.V) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.R) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.S) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.CustomMessage) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *LegacyTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Nonce != 0 { + n += 1 + sovTx(uint64(m.Nonce)) + } + if m.GasPrice != nil { + l = m.GasPrice.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasLimit != 0 { + n += 1 + sovTx(uint64(m.GasLimit)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Amount != nil { + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.V) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.R) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.S) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *AccessListTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainID != nil { + l = m.ChainID.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.Nonce != 0 { + n += 1 + sovTx(uint64(m.Nonce)) + } + if m.GasPrice != nil { + l = m.GasPrice.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasLimit != 0 { + n += 1 + sovTx(uint64(m.GasLimit)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Amount != nil { + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Accesses) > 0 { + for _, e := range m.Accesses { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + l = len(m.V) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.R) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.S) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *DynamicFeeTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainID != nil { + l = m.ChainID.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.Nonce != 0 { + n += 1 + sovTx(uint64(m.Nonce)) + } + if m.GasTipCap != nil { + l = m.GasTipCap.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasFeeCap != nil { + l = m.GasFeeCap.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasLimit != 0 { + n += 1 + sovTx(uint64(m.GasLimit)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Amount != nil { + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Accesses) > 0 { + for _, e := range m.Accesses { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + l = len(m.V) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.R) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.S) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *BlobTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainID != nil { + l = m.ChainID.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.Nonce != 0 { + n += 1 + sovTx(uint64(m.Nonce)) + } + if m.GasTipCap != nil { + l = m.GasTipCap.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasFeeCap != nil { + l = m.GasFeeCap.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.GasLimit != 0 { + n += 1 + sovTx(uint64(m.GasLimit)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Amount != nil { + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Accesses) > 0 { + for _, e := range m.Accesses { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + if m.BlobFeeCap != nil { + l = m.BlobFeeCap.Size() + n += 1 + l + sovTx(uint64(l)) + } + if len(m.BlobHashes) > 0 { + for _, b := range m.BlobHashes { + l = len(b) + n += 1 + l + sovTx(uint64(l)) + } + } + if m.Sidecar != nil { + l = m.Sidecar.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.V) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.R) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.S) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *BlobTxSidecar) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Blobs) > 0 { + for _, b := range m.Blobs { + l = len(b) + n += 1 + l + sovTx(uint64(l)) + } + } + if len(m.Commitments) > 0 { + for _, b := range m.Commitments { + l = len(b) + n += 1 + l + sovTx(uint64(l)) + } + } + if len(m.Proofs) > 0 { + for _, b := range m.Proofs { + l = len(b) + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *ExtensionOptionsEthereumTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *AccessTuple) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 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: AccessTuple: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessTuple: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 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 + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageKeys", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 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.StorageKeys = append(m.StorageKeys, 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 *AssociateTx) 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: AssociateTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AssociateTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field V", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.V = append(m.V[:0], dAtA[iNdEx:postIndex]...) + if m.V == nil { + m.V = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field R", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.R = append(m.R[:0], dAtA[iNdEx:postIndex]...) + if m.R == nil { + m.R = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field S", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.S = append(m.S[:0], dAtA[iNdEx:postIndex]...) + if m.S == nil { + m.S = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CustomMessage", 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.CustomMessage = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *LegacyTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: LegacyTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: LegacyTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.GasPrice = &v + if err := m.GasPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType) + } + m.GasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.Amount = &v + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field V", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.V = append(m.V[:0], dAtA[iNdEx:postIndex]...) + if m.V == nil { + m.V = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field R", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.R = append(m.R[:0], dAtA[iNdEx:postIndex]...) + if m.R == nil { + m.R = []byte{} + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field S", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.S = append(m.S[:0], dAtA[iNdEx:postIndex]...) + if m.S == nil { + m.S = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AccessListTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AccessListTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessListTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.ChainID = &v + if err := m.ChainID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.GasPrice = &v + if err := m.GasPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType) + } + m.GasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.Amount = &v + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Accesses", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Accesses = append(m.Accesses, AccessTuple{}) + if err := m.Accesses[len(m.Accesses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field V", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.V = append(m.V[:0], dAtA[iNdEx:postIndex]...) + if m.V == nil { + m.V = []byte{} + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field R", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.R = append(m.R[:0], dAtA[iNdEx:postIndex]...) + if m.R == nil { + m.R = []byte{} + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field S", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.S = append(m.S[:0], dAtA[iNdEx:postIndex]...) + if m.S == nil { + m.S = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DynamicFeeTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DynamicFeeTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DynamicFeeTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.ChainID = &v + if err := m.ChainID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasTipCap", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.GasTipCap = &v + if err := m.GasTipCap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasFeeCap", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.GasFeeCap = &v + if err := m.GasFeeCap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType) + } + m.GasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.Amount = &v + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Accesses", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Accesses = append(m.Accesses, AccessTuple{}) + if err := m.Accesses[len(m.Accesses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field V", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.V = append(m.V[:0], dAtA[iNdEx:postIndex]...) + if m.V == nil { + m.V = []byte{} + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field R", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.R = append(m.R[:0], dAtA[iNdEx:postIndex]...) + if m.R == nil { + m.R = []byte{} + } + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field S", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.S = append(m.S[:0], dAtA[iNdEx:postIndex]...) + if m.S == nil { + m.S = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BlobTx) 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: BlobTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlobTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.ChainID = &v + if err := m.ChainID.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasTipCap", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.GasTipCap = &v + if err := m.GasTipCap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasFeeCap", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.GasFeeCap = &v + if err := m.GasFeeCap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType) + } + m.GasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.Amount = &v + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Accesses", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Accesses = append(m.Accesses, AccessTuple{}) + if err := m.Accesses[len(m.Accesses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlobFeeCap", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.BlobFeeCap = &v + if err := m.BlobFeeCap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlobHashes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlobHashes = append(m.BlobHashes, make([]byte, postIndex-iNdEx)) + copy(m.BlobHashes[len(m.BlobHashes)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sidecar", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Sidecar == nil { + m.Sidecar = &BlobTxSidecar{} + } + if err := m.Sidecar.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field V", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.V = append(m.V[:0], dAtA[iNdEx:postIndex]...) + if m.V == nil { + m.V = []byte{} + } + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field R", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.R = append(m.R[:0], dAtA[iNdEx:postIndex]...) + if m.R == nil { + m.R = []byte{} + } + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field S", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.S = append(m.S[:0], dAtA[iNdEx:postIndex]...) + if m.S == nil { + m.S = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BlobTxSidecar) 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: BlobTxSidecar: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlobTxSidecar: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Blobs", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Blobs = append(m.Blobs, make([]byte, postIndex-iNdEx)) + copy(m.Blobs[len(m.Blobs)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Commitments", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Commitments = append(m.Commitments, make([]byte, postIndex-iNdEx)) + copy(m.Commitments[len(m.Commitments)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proofs", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Proofs = append(m.Proofs, make([]byte, postIndex-iNdEx)) + copy(m.Proofs[len(m.Proofs)-1], 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 *ExtensionOptionsEthereumTx) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ExtensionOptionsEthereumTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExtensionOptionsEthereumTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/ethtx/txdata.go b/x/evm/types/ethtx/txdata.go new file mode 100644 index 0000000000..5a661e9542 --- /dev/null +++ b/x/evm/types/ethtx/txdata.go @@ -0,0 +1,105 @@ +package ethtx + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + proto "github.com/gogo/protobuf/proto" + "github.com/sei-protocol/sei-chain/utils" +) + +var ( + _ TxData = &LegacyTx{} + _ TxData = &AccessListTx{} + _ TxData = &DynamicFeeTx{} + _ TxData = &BlobTx{} + _ TxData = &AssociateTx{} +) + +// Unfortunately `TxData` interface in go-ethereum/core/types defines its functions +// as private, so we have to define our own here. +type TxData interface { + proto.Message + TxType() byte + Copy() TxData + GetChainID() *big.Int + GetAccessList() ethtypes.AccessList + GetData() []byte + GetNonce() uint64 + GetGas() uint64 + GetGasPrice() *big.Int + GetGasTipCap() *big.Int + GetGasFeeCap() *big.Int + GetValue() *big.Int + GetTo() *common.Address + + GetRawSignatureValues() (v, r, s *big.Int) + SetSignatureValues(chainID, v, r, s *big.Int) + + AsEthereumData() ethtypes.TxData + Validate() error + + Fee() *big.Int + Cost() *big.Int + + EffectiveGasPrice(baseFee *big.Int) *big.Int + EffectiveFee(baseFee *big.Int) *big.Int + EffectiveCost(baseFee *big.Int) *big.Int + + GetBlobHashes() []common.Hash + GetBlobFeeCap() *big.Int +} + +func NewTxDataFromTx(tx *ethtypes.Transaction) (TxData, error) { + var txData TxData + var err error + switch tx.Type() { + case ethtypes.DynamicFeeTxType: + txData, err = NewDynamicFeeTx(tx) + case ethtypes.AccessListTxType: + txData, err = NewAccessListTx(tx) + case ethtypes.BlobTxType: + txData, err = NewBlobTx(tx) + default: + txData, err = NewLegacyTx(tx) + } + if err != nil { + return nil, err + } + + return txData, nil +} + +func rawSignatureValues(vBz, rBz, sBz []byte) (v, r, s *big.Int) { + if len(vBz) > 0 { + v = new(big.Int).SetBytes(vBz) + } else { + v = utils.Big0 + } + if len(rBz) > 0 { + r = new(big.Int).SetBytes(rBz) + } else { + r = utils.Big0 + } + if len(sBz) > 0 { + s = new(big.Int).SetBytes(sBz) + } else { + s = utils.Big0 + } + return v, r, s +} + +// fee = gas limit * gas price +func fee(gasPrice *big.Int, gas uint64) *big.Int { + gasLimit := new(big.Int).SetUint64(gas) + return new(big.Int).Mul(gasPrice, gasLimit) +} + +// cost = fee + tokens to send +func cost(fee, value *big.Int) *big.Int { + if value != nil { + return new(big.Int).Add(fee, value) + } + return fee +} diff --git a/x/evm/types/ethtx/utils.go b/x/evm/types/ethtx/utils.go new file mode 100644 index 0000000000..ab6d15f6fc --- /dev/null +++ b/x/evm/types/ethtx/utils.go @@ -0,0 +1,57 @@ +package ethtx + +import ( + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common/math" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" +) + +// Effective gas price is the smaller of base fee + tip limit vs total fee limit +func EffectiveGasPrice(baseFee, feeCap, tipCap *big.Int) *big.Int { + return math.BigMin(new(big.Int).Add(tipCap, baseFee), feeCap) +} + +// Convert a value with the provided converter and set it using the provided setter +func SetConvertIfPresent[U comparable, V any](orig U, converter func(U) V, setter func(V)) { + var nilU U + if orig == nilU { + return + } + + setter(converter(orig)) +} + +// validate a ethtypes.Transaction for sdk.Int overflow +func ValidateEthTx(tx *ethtypes.Transaction) error { + if !IsValidInt256(tx.Value()) { + return errors.New("value overflow") + } + if !IsValidInt256(tx.GasPrice()) { + return errors.New("gas price overflow") + } + if !IsValidInt256(tx.GasFeeCap()) { + return errors.New("gas fee cap overflow") + } + if !IsValidInt256(tx.GasTipCap()) { + return errors.New("gas tip cap overflow") + } + if !IsValidInt256(tx.BlobGasFeeCap()) { + return errors.New("blob gas fee cap overflow") + } + return nil +} + +func DecodeSignature(sig []byte) (r, s, v *big.Int, err error) { + if len(sig) != crypto.SignatureLength { + err = fmt.Errorf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength) + return + } + r = new(big.Int).SetBytes(sig[:32]) + s = new(big.Int).SetBytes(sig[32:64]) + v = new(big.Int).SetBytes([]byte{sig[64] + 27}) + return r, s, v, nil +} diff --git a/x/evm/types/ethtx/validations.go b/x/evm/types/ethtx/validations.go new file mode 100644 index 0000000000..0e76d7eb3a --- /dev/null +++ b/x/evm/types/ethtx/validations.go @@ -0,0 +1,19 @@ +package ethtx + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" +) + +// address is validate if it is a hex string (case insensitive) +// of length 40. It may optionally have a '0x' or '0X' prefix. +func ValidateAddress(address string) error { + if !common.IsHexAddress(address) { + return fmt.Errorf( + "address '%s' is not a valid ethereum hex address", + address, + ) + } + return nil +} diff --git a/x/evm/types/ethtx/validations_test.go b/x/evm/types/ethtx/validations_test.go new file mode 100644 index 0000000000..6abf21a278 --- /dev/null +++ b/x/evm/types/ethtx/validations_test.go @@ -0,0 +1,17 @@ +package ethtx + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestValidateAddress(t *testing.T) { + require.NoError(t, ValidateAddress("0x1234567890ABCDEF1234567890abcdef12345678")) + require.NoError(t, ValidateAddress("0X1234567890ABCDEF1234567890abcdef12345678")) + require.NoError(t, ValidateAddress("1234567890ABCDEF1234567890abcdef12345678")) + + require.Error(t, ValidateAddress("0x1234567890ABCDEF1234567890abcdef1234567")) + require.Error(t, ValidateAddress("0x1234567890ABCDEF1234567890abcdef123456789")) + require.Error(t, ValidateAddress("1234567890ABCDEF1234567890abcdef1234567G")) +} diff --git a/x/evm/types/events.go b/x/evm/types/events.go new file mode 100644 index 0000000000..45ec378d9c --- /dev/null +++ b/x/evm/types/events.go @@ -0,0 +1,13 @@ +package types + +const ( + EventTypeAddressAssociated = "address_associated" + EventTypePointerRegistered = "pointer_registered" + + AttributeKeySeiAddress = "sei_addr" + AttributeKeyEvmAddress = "evm_addr" + AttributeKeyPointerType = "pointer_type" + AttributeKeyPointee = "pointee" + AttributeKeyPointerAddress = "pointer_address" + AttributeKeyPointerVersion = "pointer_version" +) diff --git a/x/evm/types/genesis.go b/x/evm/types/genesis.go new file mode 100644 index 0000000000..22bf94966b --- /dev/null +++ b/x/evm/types/genesis.go @@ -0,0 +1,11 @@ +package types + +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + } +} + +func (gs GenesisState) Validate() error { + return gs.Params.Validate() +} diff --git a/x/evm/types/genesis.pb.go b/x/evm/types/genesis.pb.go new file mode 100644 index 0000000000..5b00c8a076 --- /dev/null +++ b/x/evm/types/genesis.pb.go @@ -0,0 +1,610 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// AddressAssociation represents an association between a Cosmos and an Ethereum address. +type AddressAssociation struct { + SeiAddress string `protobuf:"bytes,1,opt,name=sei_address,json=seiAddress,proto3" json:"sei_address,omitempty"` + EthAddress string `protobuf:"bytes,2,opt,name=eth_address,json=ethAddress,proto3" json:"eth_address,omitempty"` +} + +func (m *AddressAssociation) Reset() { *m = AddressAssociation{} } +func (m *AddressAssociation) String() string { return proto.CompactTextString(m) } +func (*AddressAssociation) ProtoMessage() {} +func (*AddressAssociation) Descriptor() ([]byte, []int) { + return fileDescriptor_9f044f30507c97ed, []int{0} +} +func (m *AddressAssociation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddressAssociation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddressAssociation.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 *AddressAssociation) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddressAssociation.Merge(m, src) +} +func (m *AddressAssociation) XXX_Size() int { + return m.Size() +} +func (m *AddressAssociation) XXX_DiscardUnknown() { + xxx_messageInfo_AddressAssociation.DiscardUnknown(m) +} + +var xxx_messageInfo_AddressAssociation proto.InternalMessageInfo + +func (m *AddressAssociation) GetSeiAddress() string { + if m != nil { + return m.SeiAddress + } + return "" +} + +func (m *AddressAssociation) GetEthAddress() string { + if m != nil { + return m.EthAddress + } + return "" +} + +// 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"` +} + +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} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetAddressAssociations() []*AddressAssociation { + if m != nil { + return m.AddressAssociations + } + return nil +} + +func init() { + proto.RegisterType((*AddressAssociation)(nil), "seiprotocol.seichain.evm.AddressAssociation") + 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, +} + +func (m *AddressAssociation) 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 *AddressAssociation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddressAssociation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.EthAddress) > 0 { + i -= len(m.EthAddress) + copy(dAtA[i:], m.EthAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.EthAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.SeiAddress) > 0 { + i -= len(m.SeiAddress) + copy(dAtA[i:], m.SeiAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.SeiAddress))) + 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.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 *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)) + } + } + 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 *GenesisState) 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: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 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 + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AddressAssociations", 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.AddressAssociations = append(m.AddressAssociations, &AddressAssociation{}) + if err := m.AddressAssociations[len(m.AddressAssociations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + 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 skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/gov.go b/x/evm/types/gov.go new file mode 100644 index 0000000000..1ef47ddddc --- /dev/null +++ b/x/evm/types/gov.go @@ -0,0 +1,139 @@ +package types + +import ( + "errors" + "fmt" + "math" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/ethereum/go-ethereum/common" +) + +const ( + ProposalTypeAddERCNativePointer = "AddERCNativePointer" + ProposalTypeAddERCCW20Pointer = "AddERCCW20Pointer" + ProposalTypeAddERCCW721Pointer = "AddERCCW721Pointer" +) + +func init() { + // for routing + govtypes.RegisterProposalType(ProposalTypeAddERCNativePointer) + govtypes.RegisterProposalType(ProposalTypeAddERCCW20Pointer) + govtypes.RegisterProposalType(ProposalTypeAddERCCW721Pointer) + // for marshal and unmarshal + govtypes.RegisterProposalTypeCodec(&AddERCNativePointerProposal{}, "evm/AddERCNativePointerProposal") + govtypes.RegisterProposalTypeCodec(&AddERCCW20PointerProposal{}, "evm/AddERCCW20PointerProposal") + govtypes.RegisterProposalTypeCodec(&AddERCCW721PointerProposal{}, "evm/AddERCCW721PointerProposal") +} + +func (p *AddERCNativePointerProposal) GetTitle() string { return p.Title } + +func (p *AddERCNativePointerProposal) GetDescription() string { return p.Description } + +func (p *AddERCNativePointerProposal) ProposalRoute() string { return RouterKey } + +func (p *AddERCNativePointerProposal) ProposalType() string { + return ProposalTypeAddERCNativePointer +} + +func (p *AddERCNativePointerProposal) ValidateBasic() error { + if p.Pointer != "" && !common.IsHexAddress(p.Pointer) { + return errors.New("pointer address must be either empty or a valid hex-encoded string") + } + + if p.Version > math.MaxUint16 { + return errors.New("pointer version must be <= 65535") + } + + return govtypes.ValidateAbstract(p) +} + +func (p AddERCNativePointerProposal) String() string { + var b strings.Builder + b.WriteString(fmt.Sprintf(`Add ERC native pointer Proposal: + Title: %s + Description: %s + Token: %s + Pointer: %s + Version: %d +`, p.Title, p.Description, p.Token, p.Pointer, p.Version)) + return b.String() +} + +func (p *AddERCCW20PointerProposal) GetTitle() string { return p.Title } + +func (p *AddERCCW20PointerProposal) GetDescription() string { return p.Description } + +func (p *AddERCCW20PointerProposal) ProposalRoute() string { return RouterKey } + +func (p *AddERCCW20PointerProposal) ProposalType() string { + return ProposalTypeAddERCCW20Pointer +} + +func (p *AddERCCW20PointerProposal) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(p.Pointee); err != nil { + return err + } + + if p.Pointer != "" && !common.IsHexAddress(p.Pointer) { + return errors.New("pointer address must be either empty or a valid hex-encoded string") + } + + if p.Version > math.MaxUint16 { + return errors.New("pointer version must be <= 65535") + } + + return govtypes.ValidateAbstract(p) +} + +func (p AddERCCW20PointerProposal) String() string { + var b strings.Builder + b.WriteString(fmt.Sprintf(`Add ERC CW20 pointer Proposal: + Title: %s + Description: %s + Pointee: %s + Pointer: %s + Version: %d +`, p.Title, p.Description, p.Pointee, p.Pointer, p.Version)) + return b.String() +} + +func (p *AddERCCW721PointerProposal) GetTitle() string { return p.Title } + +func (p *AddERCCW721PointerProposal) GetDescription() string { return p.Description } + +func (p *AddERCCW721PointerProposal) ProposalRoute() string { return RouterKey } + +func (p *AddERCCW721PointerProposal) ProposalType() string { + return ProposalTypeAddERCCW721Pointer +} + +func (p *AddERCCW721PointerProposal) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(p.Pointee); err != nil { + return err + } + + if p.Pointer != "" && !common.IsHexAddress(p.Pointer) { + return errors.New("pointer address must be either empty or a valid hex-encoded string") + } + + if p.Version > math.MaxUint16 { + return errors.New("pointer version must be <= 65535") + } + + return govtypes.ValidateAbstract(p) +} + +func (p AddERCCW721PointerProposal) String() string { + var b strings.Builder + b.WriteString(fmt.Sprintf(`Add ERC CW721 pointer Proposal: + Title: %s + Description: %s + Pointee: %s + Pointer: %s + Version: %d +`, p.Title, p.Description, p.Pointee, p.Pointer, p.Version)) + return b.String() +} diff --git a/x/evm/types/gov.pb.go b/x/evm/types/gov.pb.go new file mode 100644 index 0000000000..6e7ef58d29 --- /dev/null +++ b/x/evm/types/gov.pb.go @@ -0,0 +1,1124 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/gov.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type AddERCNativePointerProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty" yaml:"token"` + Pointer string `protobuf:"bytes,4,opt,name=pointer,proto3" json:"pointer,omitempty" yaml:"pointer"` + Version uint32 `protobuf:"varint,5,opt,name=version,proto3" json:"version,omitempty" yaml:"version"` +} + +func (m *AddERCNativePointerProposal) Reset() { *m = AddERCNativePointerProposal{} } +func (*AddERCNativePointerProposal) ProtoMessage() {} +func (*AddERCNativePointerProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_fb66eb1aab5c39af, []int{0} +} +func (m *AddERCNativePointerProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddERCNativePointerProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddERCNativePointerProposal.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AddERCNativePointerProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddERCNativePointerProposal.Merge(m, src) +} +func (m *AddERCNativePointerProposal) XXX_Size() int { + return m.Size() +} +func (m *AddERCNativePointerProposal) XXX_DiscardUnknown() { + xxx_messageInfo_AddERCNativePointerProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_AddERCNativePointerProposal proto.InternalMessageInfo + +type AddERCCW20PointerProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + Pointee string `protobuf:"bytes,3,opt,name=pointee,proto3" json:"pointee,omitempty" yaml:"pointee"` + Pointer string `protobuf:"bytes,4,opt,name=pointer,proto3" json:"pointer,omitempty" yaml:"pointer"` + Version uint32 `protobuf:"varint,5,opt,name=version,proto3" json:"version,omitempty" yaml:"version"` +} + +func (m *AddERCCW20PointerProposal) Reset() { *m = AddERCCW20PointerProposal{} } +func (*AddERCCW20PointerProposal) ProtoMessage() {} +func (*AddERCCW20PointerProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_fb66eb1aab5c39af, []int{1} +} +func (m *AddERCCW20PointerProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddERCCW20PointerProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddERCCW20PointerProposal.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AddERCCW20PointerProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddERCCW20PointerProposal.Merge(m, src) +} +func (m *AddERCCW20PointerProposal) XXX_Size() int { + return m.Size() +} +func (m *AddERCCW20PointerProposal) XXX_DiscardUnknown() { + xxx_messageInfo_AddERCCW20PointerProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_AddERCCW20PointerProposal proto.InternalMessageInfo + +type AddERCCW721PointerProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + Pointee string `protobuf:"bytes,3,opt,name=pointee,proto3" json:"pointee,omitempty" yaml:"pointee"` + Pointer string `protobuf:"bytes,4,opt,name=pointer,proto3" json:"pointer,omitempty" yaml:"pointer"` + Version uint32 `protobuf:"varint,5,opt,name=version,proto3" json:"version,omitempty" yaml:"version"` +} + +func (m *AddERCCW721PointerProposal) Reset() { *m = AddERCCW721PointerProposal{} } +func (*AddERCCW721PointerProposal) ProtoMessage() {} +func (*AddERCCW721PointerProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_fb66eb1aab5c39af, []int{2} +} +func (m *AddERCCW721PointerProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddERCCW721PointerProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddERCCW721PointerProposal.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AddERCCW721PointerProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddERCCW721PointerProposal.Merge(m, src) +} +func (m *AddERCCW721PointerProposal) XXX_Size() int { + return m.Size() +} +func (m *AddERCCW721PointerProposal) XXX_DiscardUnknown() { + xxx_messageInfo_AddERCCW721PointerProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_AddERCCW721PointerProposal proto.InternalMessageInfo + +func init() { + proto.RegisterType((*AddERCNativePointerProposal)(nil), "seiprotocol.seichain.evm.AddERCNativePointerProposal") + proto.RegisterType((*AddERCCW20PointerProposal)(nil), "seiprotocol.seichain.evm.AddERCCW20PointerProposal") + proto.RegisterType((*AddERCCW721PointerProposal)(nil), "seiprotocol.seichain.evm.AddERCCW721PointerProposal") +} + +func init() { proto.RegisterFile("evm/gov.proto", fileDescriptor_fb66eb1aab5c39af) } + +var fileDescriptor_fb66eb1aab5c39af = []byte{ + // 359 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4d, 0x2d, 0xcb, 0xd5, + 0x4f, 0xcf, 0x2f, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x28, 0x4e, 0xcd, 0x04, 0xb3, + 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, 0x33, 0xf3, 0xf4, 0x52, 0xcb, 0x72, + 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x52, 0xfa, 0x20, 0x16, 0x44, 0xbd, 0xd2, 0x44, 0x26, + 0x2e, 0x69, 0xc7, 0x94, 0x14, 0xd7, 0x20, 0x67, 0xbf, 0xc4, 0x92, 0xcc, 0xb2, 0xd4, 0x80, 0xfc, + 0xcc, 0xbc, 0x92, 0xd4, 0xa2, 0x80, 0xa2, 0xfc, 0x82, 0xfc, 0xe2, 0xc4, 0x1c, 0x21, 0x35, 0x2e, + 0xd6, 0x92, 0xcc, 0x92, 0x9c, 0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0x81, 0x4f, 0xf7, + 0xe4, 0x79, 0x2a, 0x13, 0x73, 0x73, 0xac, 0x94, 0xc0, 0xc2, 0x4a, 0x41, 0x10, 0x69, 0x21, 0x0b, + 0x2e, 0xee, 0x94, 0xd4, 0xe2, 0xe4, 0xa2, 0xcc, 0x82, 0x92, 0xcc, 0xfc, 0x3c, 0x09, 0x26, 0xb0, + 0x6a, 0xb1, 0x4f, 0xf7, 0xe4, 0x85, 0x20, 0xaa, 0x91, 0x24, 0x95, 0x82, 0x90, 0x95, 0x82, 0x6d, + 0xc8, 0xcf, 0x4e, 0xcd, 0x93, 0x60, 0xc6, 0xb0, 0x01, 0x24, 0x0c, 0xb2, 0x01, 0x44, 0x0b, 0xe9, + 0x70, 0xb1, 0x17, 0x40, 0x1c, 0x27, 0xc1, 0x02, 0x56, 0x29, 0xf4, 0xe9, 0x9e, 0x3c, 0x1f, 0x44, + 0x25, 0x54, 0x42, 0x29, 0x08, 0xa6, 0x04, 0xa4, 0xba, 0x2c, 0xb5, 0xa8, 0x18, 0xe4, 0x16, 0x56, + 0x05, 0x46, 0x0d, 0x5e, 0x64, 0xd5, 0x50, 0x09, 0xa5, 0x20, 0x98, 0x12, 0x2b, 0x9e, 0x8e, 0x05, + 0xf2, 0x0c, 0x33, 0x16, 0xc8, 0x33, 0xbc, 0x58, 0x20, 0xcf, 0xa0, 0x34, 0x95, 0x89, 0x4b, 0x12, + 0x12, 0x26, 0xce, 0xe1, 0x46, 0x06, 0xf4, 0x0f, 0x11, 0xb8, 0x4f, 0x53, 0xa1, 0x61, 0x82, 0xe1, + 0xd3, 0x54, 0xb8, 0x4f, 0x53, 0xe9, 0x18, 0x2e, 0xd3, 0x98, 0xb8, 0xa4, 0x60, 0xe1, 0x62, 0x6e, + 0x64, 0x38, 0x1a, 0x30, 0xd0, 0x80, 0x71, 0x72, 0x3f, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, + 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, + 0x39, 0x86, 0x28, 0xdd, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xe2, + 0xd4, 0x4c, 0x5d, 0x58, 0xd6, 0x04, 0x73, 0xc0, 0x79, 0x53, 0xbf, 0x42, 0x1f, 0x94, 0x83, 0x4b, + 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xf2, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x08, + 0x8c, 0x8b, 0x94, 0xd5, 0x03, 0x00, 0x00, +} + +func (m *AddERCNativePointerProposal) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddERCNativePointerProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddERCNativePointerProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintGov(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x28 + } + if len(m.Pointer) > 0 { + i -= len(m.Pointer) + copy(dAtA[i:], m.Pointer) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointer))) + i-- + dAtA[i] = 0x22 + } + if len(m.Token) > 0 { + i -= len(m.Token) + copy(dAtA[i:], m.Token) + i = encodeVarintGov(dAtA, i, uint64(len(m.Token))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintGov(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintGov(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddERCCW20PointerProposal) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddERCCW20PointerProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddERCCW20PointerProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintGov(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x28 + } + if len(m.Pointer) > 0 { + i -= len(m.Pointer) + copy(dAtA[i:], m.Pointer) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointer))) + i-- + dAtA[i] = 0x22 + } + if len(m.Pointee) > 0 { + i -= len(m.Pointee) + copy(dAtA[i:], m.Pointee) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointee))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintGov(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintGov(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AddERCCW721PointerProposal) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddERCCW721PointerProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddERCCW721PointerProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintGov(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x28 + } + if len(m.Pointer) > 0 { + i -= len(m.Pointer) + copy(dAtA[i:], m.Pointer) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointer))) + i-- + dAtA[i] = 0x22 + } + if len(m.Pointee) > 0 { + i -= len(m.Pointee) + copy(dAtA[i:], m.Pointee) + i = encodeVarintGov(dAtA, i, uint64(len(m.Pointee))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintGov(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintGov(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGov(dAtA []byte, offset int, v uint64) int { + offset -= sovGov(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *AddERCNativePointerProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Token) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointer) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovGov(uint64(m.Version)) + } + return n +} + +func (m *AddERCCW20PointerProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointee) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointer) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovGov(uint64(m.Version)) + } + return n +} + +func (m *AddERCCW721PointerProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointee) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + l = len(m.Pointer) + if l > 0 { + n += 1 + l + sovGov(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovGov(uint64(m.Version)) + } + return n +} + +func sovGov(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGov(x uint64) (n int) { + return sovGov(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *AddERCNativePointerProposal) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddERCNativePointerProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddERCNativePointerProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Token = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGov(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGov + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddERCCW20PointerProposal) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddERCCW20PointerProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddERCCW20PointerProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGov(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGov + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AddERCCW721PointerProposal) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddERCCW721PointerProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddERCCW721PointerProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGov + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGov + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGov + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGov(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGov + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGov(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGov + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGov + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGov + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGov + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGov + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGov + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGov = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGov = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGov = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/keys.go b/x/evm/types/keys.go new file mode 100644 index 0000000000..b376c2b59c --- /dev/null +++ b/x/evm/types/keys.go @@ -0,0 +1,122 @@ +package types + +import ( + "encoding/binary" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" +) + +const ( + // module name + ModuleName = "evm" + + RouterKey = ModuleName + + // StoreKey is string representation of the store key for auth + StoreKey = "evm" + + MemStoreKey = "evm_mem" + + // QuerierRoute is the querier route for auth + QuerierRoute = ModuleName +) + +var ( + EVMAddressToSeiAddressKeyPrefix = []byte{0x01} + SeiAddressToEVMAddressKeyPrefix = []byte{0x02} + StateKeyPrefix = []byte{0x03} + TransientStateKeyPrefix = []byte{0x04} // deprecated + AccountTransientStateKeyPrefix = []byte{0x05} // deprecated + TransientModuleStateKeyPrefix = []byte{0x06} // deprecated + CodeKeyPrefix = []byte{0x07} + CodeHashKeyPrefix = []byte{0x08} + CodeSizeKeyPrefix = []byte{0x09} + NonceKeyPrefix = []byte{0x0a} + ReceiptKeyPrefix = []byte{0x0b} + WhitelistedCodeHashesForBankSendPrefix = []byte{0x0c} + BlockBloomPrefix = []byte{0x0d} + TxHashesPrefix = []byte{0x0e} + WhitelistedCodeHashesForDelegateCallPrefix = []byte{0x0f} + //mem + TxHashPrefix = []byte{0x10} + TxBloomPrefix = []byte{0x11} + + ReplaySeenAddrPrefix = []byte{0x12} + ReplayedHeight = []byte{0x13} + ReplayInitialHeight = []byte{0x14} + + PointerRegistryPrefix = []byte{0x15} + PointerCWCodePrefix = []byte{0x16} +) + +var ( + PointerERC20NativePrefix = []byte{0x0} + PointerERC20CW20Prefix = []byte{0x1} + PointerERC721CW721Prefix = []byte{0x2} + PointerCW20ERC20Prefix = []byte{0x3} + PointerCW721ERC721Prefix = []byte{0x4} +) + +func EVMAddressToSeiAddressKey(evmAddress common.Address) []byte { + return append(EVMAddressToSeiAddressKeyPrefix, evmAddress[:]...) +} + +func SeiAddressToEVMAddressKey(seiAddress sdk.AccAddress) []byte { + return append(SeiAddressToEVMAddressKeyPrefix, seiAddress...) +} + +func StateKey(evmAddress common.Address) []byte { + return append(StateKeyPrefix, evmAddress[:]...) +} + +func ReceiptKey(txHash common.Hash) []byte { + return append(ReceiptKeyPrefix, txHash[:]...) +} + +func BlockBloomKey(height int64) []byte { + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, uint64(height)) + return append(BlockBloomPrefix, bz...) +} + +func TxHashesKey(height int64) []byte { + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, uint64(height)) + return append(TxHashesPrefix, bz...) +} + +func PointerERC20NativeKey(token string) []byte { + return append( + append(PointerRegistryPrefix, PointerERC20NativePrefix...), + []byte(token)..., + ) +} + +func PointerERC20CW20Key(cw20Address string) []byte { + return append( + append(PointerRegistryPrefix, PointerERC20CW20Prefix...), + []byte(cw20Address)..., + ) +} + +func PointerERC721CW721Key(cw721Address string) []byte { + return append( + append(PointerRegistryPrefix, PointerERC721CW721Prefix...), + []byte(cw721Address)..., + ) +} + +func PointerCW20ERC20Key(erc20Addr common.Address) []byte { + return append( + append(PointerRegistryPrefix, PointerCW20ERC20Prefix...), + erc20Addr[:]..., + ) +} + +func PointerCW721ERC721Key(erc721Addr common.Address) []byte { + return append( + append(PointerRegistryPrefix, PointerCW721ERC721Prefix...), + erc721Addr[:]..., + ) +} diff --git a/x/evm/types/keys_test.go b/x/evm/types/keys_test.go new file mode 100644 index 0000000000..259a4db27d --- /dev/null +++ b/x/evm/types/keys_test.go @@ -0,0 +1,44 @@ +package types_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/sei-protocol/sei-chain/x/evm/types" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" +) + +func TestEVMAddressToSeiAddressKey(t *testing.T) { + evmAddr := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678") + expectedPrefix := types.EVMAddressToSeiAddressKeyPrefix + key := types.EVMAddressToSeiAddressKey(evmAddr) + + require.Equal(t, expectedPrefix[0], key[0], "Key prefix for evm address to sei address key is incorrect") + require.Equal(t, append(expectedPrefix, evmAddr.Bytes()...), key, "Generated key format is incorrect") +} + +func TestSeiAddressToEVMAddressKey(t *testing.T) { + seiAddr := sdk.AccAddress("sei1234567890abcdef1234567890abcdef12345678") + expectedPrefix := types.SeiAddressToEVMAddressKeyPrefix + key := types.SeiAddressToEVMAddressKey(seiAddr) + + require.Equal(t, expectedPrefix[0], key[0], "Key prefix for sei address to evm address key is incorrect") + require.Equal(t, append(expectedPrefix, seiAddr...), key, "Generated key format is incorrect") +} + +func TestStateKey(t *testing.T) { + evmAddr := common.HexToAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") + expectedPrefix := types.StateKeyPrefix + key := types.StateKey(evmAddr) + + require.Equal(t, expectedPrefix[0], key[0], "Key prefix for state key is incorrect") + require.Equal(t, append(expectedPrefix, evmAddr.Bytes()...), key, "Generated key format is incorrect") +} + +func TestBlockBloomKey(t *testing.T) { + height := int64(123456) + key := types.BlockBloomKey(height) + + require.Equal(t, types.BlockBloomPrefix[0], key[0], "Key prefix for block bloom key is incorrect") +} diff --git a/x/evm/types/message_evm_transaction.go b/x/evm/types/message_evm_transaction.go new file mode 100644 index 0000000000..5ab7375793 --- /dev/null +++ b/x/evm/types/message_evm_transaction.go @@ -0,0 +1,79 @@ +package types + +import ( + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/gogo/protobuf/proto" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" +) + +const TypeMsgEVMTransaction = "evm_transaction" + +var ( + _ sdk.Msg = &MsgEVMTransaction{} + _ codectypes.UnpackInterfacesMessage = &MsgEVMTransaction{} +) + +func NewMsgEVMTransaction(txData proto.Message) (*MsgEVMTransaction, error) { + txDataAny, err := codectypes.NewAnyWithValue(txData) + if err != nil { + return nil, err + } + return &MsgEVMTransaction{Data: txDataAny}, nil +} + +func (msg *MsgEVMTransaction) Route() string { + return RouterKey +} + +func (msg *MsgEVMTransaction) Type() string { + return TypeMsgEVMTransaction +} + +func (msg *MsgEVMTransaction) GetSigners() []sdk.AccAddress { + panic("signer should be accessed on EVM transaction level") +} + +func (msg *MsgEVMTransaction) GetSignBytes() []byte { + panic("sign bytes should be accessed on EVM transaction level") +} + +func (msg *MsgEVMTransaction) ValidateBasic() error { + return nil +} + +func (msg *MsgEVMTransaction) AsTransaction() (*ethtypes.Transaction, ethtx.TxData) { + txData, err := UnpackTxData(msg.Data) + if err != nil { + return nil, nil + } + + return ethtypes.NewTx(txData.AsEthereumData()), txData +} + +// UnpackInterfaces implements UnpackInterfacesMesssage.UnpackInterfaces +func (msg *MsgEVMTransaction) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + return unpacker.UnpackAny(msg.Data, new(ethtx.TxData)) +} + +func (msg *MsgEVMTransaction) IsAssociateTx() bool { + txData, err := UnpackTxData(msg.Data) + if err != nil { + // should never happen + panic(err) + } + _, ok := txData.(*ethtx.AssociateTx) + return ok +} + +func MustGetEVMTransactionMessage(tx sdk.Tx) *MsgEVMTransaction { + if len(tx.GetMsgs()) != 1 { + panic("EVM transaction must have exactly 1 message") + } + msg, ok := tx.GetMsgs()[0].(*MsgEVMTransaction) + if !ok { + panic("not EVM message") + } + return msg +} diff --git a/x/evm/types/message_evm_transaction_test.go b/x/evm/types/message_evm_transaction_test.go new file mode 100644 index 0000000000..4303f4c78e --- /dev/null +++ b/x/evm/types/message_evm_transaction_test.go @@ -0,0 +1,113 @@ +package types_test + +import ( + "encoding/hex" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/sei-protocol/sei-chain/app" + testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/sei-protocol/sei-chain/x/evm/derived" + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/sei-protocol/sei-chain/x/evm/types/ethtx" + "github.com/stretchr/testify/require" +) + +func TestIsAssociate(t *testing.T) { + tx, err := types.NewMsgEVMTransaction(ðtx.AssociateTx{}) + require.Nil(t, err) + require.True(t, tx.IsAssociateTx()) +} + +func TestIsNotAssociate(t *testing.T) { + tx, err := types.NewMsgEVMTransaction(nil) + require.Error(t, err) + + tx, err = types.NewMsgEVMTransaction(ðtx.AccessTuple{}) + require.Nil(t, err) + require.False(t, tx.IsAssociateTx()) +} + +func TestAsTransaction(t *testing.T) { + k, ctx := testkeeper.MockEVMKeeper() + chainID := k.ChainID(ctx) + chainCfg := types.DefaultChainConfig() + ethCfg := chainCfg.EthereumConfig(chainID) + blockNum := big.NewInt(ctx.BlockHeight()) + privKey := testkeeper.MockPrivateKey() + testPrivHex := hex.EncodeToString(privKey.Bytes()) + key, _ := crypto.HexToECDSA(testPrivHex) + to := new(common.Address) + txData := ethtypes.DynamicFeeTx{ + Nonce: 1, + GasFeeCap: big.NewInt(10000000000000), + Gas: 1000, + To: to, + Value: big.NewInt(1000000000000000), + Data: []byte("abc"), + ChainID: chainID, + } + + signer := ethtypes.MakeSigner(ethCfg, blockNum, uint64(ctx.BlockTime().Unix())) + tx, err := ethtypes.SignTx(ethtypes.NewTx(&txData), signer, key) + typedTx, err := ethtx.NewDynamicFeeTx(tx) + msg, err := types.NewMsgEVMTransaction(typedTx) + require.Nil(t, err) + ethTx, ethTxData := msg.AsTransaction() + require.Equal(t, chainID, ethTx.ChainId()) + require.Equal(t, uint64(1), ethTx.Nonce()) + require.Equal(t, []byte("abc"), ethTx.Data()) + require.Nil(t, ethTxData.Validate()) + +} + +func TestMustGetEVMTransactionMessage(t *testing.T) { + testMsg := types.MsgEVMTransaction{ + Data: nil, + Derived: nil, + } + testTx := app.NewTestTx([]sdk.Msg{&testMsg}) + + types.MustGetEVMTransactionMessage(testTx) +} + +func TestMustGetEVMTransactionMessageWrongType(t *testing.T) { + + // Non-EVM tx + testMsg := wasmtypes.MsgExecuteContract{ + Contract: "sei1y3pxq5dp900czh0mkudhjdqjq5m8cpmmps8yjw", + Msg: []byte("{\"xyz\":{}}"), + } + testTx := app.NewTestTx([]sdk.Msg{&testMsg}) + + defer func() { recover() }() + types.MustGetEVMTransactionMessage(testTx) + t.Errorf("Should not be able to convert a non evm emssage") +} + +func TestMustGetEVMTransactionMessageMultipleMsgs(t *testing.T) { + testMsg := types.MsgEVMTransaction{ + Data: nil, + Derived: nil, + } + testTx := app.NewTestTx([]sdk.Msg{&testMsg, &testMsg}) + + defer func() { recover() }() + types.MustGetEVMTransactionMessage(testTx) + t.Errorf("Should not be able to convert a non evm emssage") +} + +func TestAttackerUnableToSetDerived(t *testing.T) { + msg := types.MsgEVMTransaction{Derived: &derived.Derived{SenderEVMAddr: common.BytesToAddress([]byte("abc"))}} + bz, err := msg.Marshal() + require.Nil(t, err) + decoded := types.MsgEVMTransaction{} + err = decoded.Unmarshal(bz) + require.Nil(t, err) + require.Equal(t, common.Address{}, decoded.Derived.SenderEVMAddr) +} diff --git a/x/evm/types/message_internal_evm_call.go b/x/evm/types/message_internal_evm_call.go new file mode 100644 index 0000000000..83e33eb7c5 --- /dev/null +++ b/x/evm/types/message_internal_evm_call.go @@ -0,0 +1,30 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + _ sdk.Msg = &MsgInternalEVMCall{} +) + +func NewMessageInternalEVMCall(from sdk.AccAddress, to string, value *sdk.Int, data []byte) *MsgInternalEVMCall { + return &MsgInternalEVMCall{ + Sender: from.String(), + To: to, + Value: value, + Data: data, + } +} + +func (msg *MsgInternalEVMCall) GetSigners() []sdk.AccAddress { + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return []sdk.AccAddress{} + } + return []sdk.AccAddress{senderAddr} +} + +func (msg *MsgInternalEVMCall) ValidateBasic() error { + return nil +} diff --git a/x/evm/types/message_internal_evm_delegate_call.go b/x/evm/types/message_internal_evm_delegate_call.go new file mode 100644 index 0000000000..c38cb60423 --- /dev/null +++ b/x/evm/types/message_internal_evm_delegate_call.go @@ -0,0 +1,31 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + _ sdk.Msg = &MsgInternalEVMDelegateCall{} +) + +func NewMessageInternalEVMDelegateCall(from sdk.AccAddress, to string, codeHash []byte, data []byte, fromContract string) *MsgInternalEVMDelegateCall { + return &MsgInternalEVMDelegateCall{ + Sender: from.String(), + To: to, + Data: data, + CodeHash: codeHash, + FromContract: fromContract, + } +} + +func (msg *MsgInternalEVMDelegateCall) GetSigners() []sdk.AccAddress { + contractAddr, err := sdk.AccAddressFromBech32(msg.FromContract) + if err != nil { + return []sdk.AccAddress{} + } + return []sdk.AccAddress{contractAddr} +} + +func (msg *MsgInternalEVMDelegateCall) ValidateBasic() error { + return nil +} diff --git a/x/evm/types/message_register_pointer.go b/x/evm/types/message_register_pointer.go new file mode 100644 index 0000000000..1f2c124c4d --- /dev/null +++ b/x/evm/types/message_register_pointer.go @@ -0,0 +1,54 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/ethereum/go-ethereum/common" +) + +const TypeMsgRegisterPointer = "evm_register_pointer" + +var ( + _ sdk.Msg = &MsgSend{} +) + +func NewMsgRegisterERC20Pointer(sender sdk.AccAddress, ercAddress common.Address) *MsgRegisterPointer { + return &MsgRegisterPointer{Sender: sender.String(), ErcAddress: ercAddress.Hex(), PointerType: PointerType_ERC20} +} + +func NewMsgRegisterERC721Pointer(sender sdk.AccAddress, ercAddress common.Address) *MsgRegisterPointer { + return &MsgRegisterPointer{Sender: sender.String(), ErcAddress: ercAddress.Hex(), PointerType: PointerType_ERC721} +} + +func (msg *MsgRegisterPointer) Route() string { + return RouterKey +} + +func (msg *MsgRegisterPointer) Type() string { + return TypeMsgRegisterPointer +} + +func (msg *MsgRegisterPointer) GetSigners() []sdk.AccAddress { + from, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + panic(err) + } + return []sdk.AccAddress{from} +} + +func (msg *MsgRegisterPointer) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +func (msg *MsgRegisterPointer) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + if !common.IsHexAddress(msg.ErcAddress) { + return sdkerrors.ErrInvalidAddress + } + + return nil +} diff --git a/x/evm/types/message_send.go b/x/evm/types/message_send.go new file mode 100644 index 0000000000..d1f37e5377 --- /dev/null +++ b/x/evm/types/message_send.go @@ -0,0 +1,54 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/ethereum/go-ethereum/common" +) + +const TypeMsgSend = "evm_send" + +var ( + _ sdk.Msg = &MsgSend{} +) + +func NewMsgSend(fromAddr sdk.AccAddress, toAddress common.Address, amount sdk.Coins) *MsgSend { + return &MsgSend{FromAddress: fromAddr.String(), ToAddress: toAddress.Hex(), Amount: amount} +} + +func (msg *MsgSend) Route() string { + return RouterKey +} + +func (msg *MsgSend) Type() string { + return TypeMsgSend +} + +func (msg *MsgSend) GetSigners() []sdk.AccAddress { + from, err := sdk.AccAddressFromBech32(msg.FromAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{from} +} + +func (msg *MsgSend) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +func (msg *MsgSend) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.FromAddress) + if err != nil { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err) + } + + if !msg.Amount.IsValid() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) + } + + if !msg.Amount.IsAllPositive() { + return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) + } + + return nil +} diff --git a/x/evm/types/message_send_test.go b/x/evm/types/message_send_test.go new file mode 100644 index 0000000000..44bcdedf27 --- /dev/null +++ b/x/evm/types/message_send_test.go @@ -0,0 +1,31 @@ +package types_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "testing" + + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestMessageSendValidate(t *testing.T) { + fromAddr, err := sdk.AccAddressFromBech32("sei1yezq49upxhunjjhudql2fnj5dgvcwjj87pn2wx") + require.Nil(t, err) + msg := types.NewMsgSend(fromAddr, common.HexToAddress("to"), sdk.Coins{sdk.Coin{ + Denom: "sei", + Amount: sdk.NewInt(1), + }}) + require.Nil(t, msg.ValidateBasic()) + + // No coins + msg = types.NewMsgSend(fromAddr, common.HexToAddress("to"), sdk.Coins{}) + require.Error(t, msg.ValidateBasic()) + + // Negative coins + msg = types.NewMsgSend(fromAddr, common.HexToAddress("to"), sdk.Coins{sdk.Coin{ + Denom: "sei", + Amount: sdk.NewInt(-1), + }}) + require.Error(t, msg.ValidateBasic()) +} diff --git a/x/evm/types/params.go b/x/evm/types/params.go new file mode 100644 index 0000000000..da1f1de8a1 --- /dev/null +++ b/x/evm/types/params.go @@ -0,0 +1,146 @@ +package types + +import ( + "encoding/hex" + "errors" + fmt "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "gopkg.in/yaml.v2" +) + +var ( + KeyPriorityNormalizer = []byte("KeyPriorityNormalizer") + KeyBaseFeePerGas = []byte("KeyBaseFeePerGas") + KeyMinFeePerGas = []byte("KeyMinFeePerGas") + KeyChainID = []byte("KeyChainID") + KeyWhitelistedCwCodeHashesForDelegateCall = []byte("KeyWhitelistedCwCodeHashesForDelegateCall") +) + +var DefaultPriorityNormalizer = sdk.NewDec(1) + +// DefaultBaseFeePerGas determines how much usei per gas spent is +// burnt rather than go to validators (similar to base fee on +// Ethereum). +var DefaultBaseFeePerGas = sdk.NewDec(0) +var DefaultMinFeePerGas = sdk.NewDec(1000000000) +var DefaultChainID = sdk.NewInt(713715) + +var DefaultWhitelistedCwCodeHashesForDelegateCall = generateDefaultWhitelistedCwCodeHashesForDelegateCall() + +var _ paramtypes.ParamSet = (*Params)(nil) + +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +func DefaultParams() Params { + return Params{ + PriorityNormalizer: DefaultPriorityNormalizer, + BaseFeePerGas: DefaultBaseFeePerGas, + MinimumFeePerGas: DefaultMinFeePerGas, + ChainId: DefaultChainID, + WhitelistedCwCodeHashesForDelegateCall: DefaultWhitelistedCwCodeHashesForDelegateCall, + } +} + +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyPriorityNormalizer, &p.PriorityNormalizer, validatePriorityNormalizer), + paramtypes.NewParamSetPair(KeyBaseFeePerGas, &p.BaseFeePerGas, validateBaseFeePerGas), + paramtypes.NewParamSetPair(KeyMinFeePerGas, &p.MinimumFeePerGas, validateMinFeePerGas), + paramtypes.NewParamSetPair(KeyChainID, &p.ChainId, validateChainID), + paramtypes.NewParamSetPair(KeyWhitelistedCwCodeHashesForDelegateCall, &p.WhitelistedCwCodeHashesForDelegateCall, validateWhitelistedCwHashesForDelegateCall), + } +} + +func (p Params) Validate() error { + if err := validatePriorityNormalizer(p.PriorityNormalizer); err != nil { + return err + } + if err := validateBaseFeePerGas(p.BaseFeePerGas); err != nil { + return err + } + if err := validateMinFeePerGas(p.MinimumFeePerGas); err != nil { + return err + } + if p.MinimumFeePerGas.LT(p.BaseFeePerGas) { + return errors.New("minimum fee cannot be lower than base fee") + } + if err := validateChainID(p.ChainId); err != nil { + return err + } + return validateWhitelistedCwHashesForDelegateCall(p.WhitelistedCwCodeHashesForDelegateCall) +} + +func (p Params) String() string { + out, _ := yaml.Marshal(p) + return string(out) +} + +func validatePriorityNormalizer(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if !v.IsPositive() { + return fmt.Errorf("nonpositive priority normalizer: %d", v) + } + + return nil +} + +func validateBaseFeePerGas(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("negative base fee per gas: %d", v) + } + + return nil +} + +func validateMinFeePerGas(i interface{}) error { + v, ok := i.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("negative min fee per gas: %d", v) + } + + return nil +} + +func validateChainID(i interface{}) error { + v, ok := i.(sdk.Int) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + if v.IsNegative() { + return fmt.Errorf("negative chain ID: %d", v) + } + + return nil +} + +func validateWhitelistedCwHashesForDelegateCall(i interface{}) error { + _, ok := i.([][]byte) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + return nil +} + +func generateDefaultWhitelistedCwCodeHashesForDelegateCall() [][]byte { + cw20, _ := hex.DecodeString("A25D78D7ACD2EE47CC39C224E162FE79B53E6BBE6ED2A56E8C0A86593EBE6102") + cw721, _ := hex.DecodeString("94CDD9C3E85C26F7CEC43C23BFB4B3B2B2D71A0A8D85C58DF12FFEC0741FEBC8") + return [][]byte{cw20, cw721} +} diff --git a/x/evm/types/params.pb.go b/x/evm/types/params.pb.go new file mode 100644 index 0000000000..ebd0b5f36a --- /dev/null +++ b/x/evm/types/params.pb.go @@ -0,0 +1,536 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/params.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the parameters for the module. +type Params struct { + // string base_denom = 1 [ + // (gogoproto.moretags) = "yaml:\"base_denom\"", + // (gogoproto.jsontag) = "base_denom" + // ]; + PriorityNormalizer github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=priority_normalizer,json=priorityNormalizer,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"priority_normalizer" yaml:"priority_normalizer"` + BaseFeePerGas github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=base_fee_per_gas,json=baseFeePerGas,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"base_fee_per_gas" yaml:"base_fee_per_gas"` + MinimumFeePerGas github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=minimum_fee_per_gas,json=minimumFeePerGas,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"minimum_fee_per_gas" yaml:"minimum_fee_per_gas"` + // ChainConfig chain_config = 5 [(gogoproto.moretags) = "yaml:\"chain_config\"", (gogoproto.nullable) = false]; + ChainId github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=chain_id,json=chainId,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"chain_id" yaml:"chain_id"` + // repeated string whitelisted_codehashes_bank_send = 7 [ + // (gogoproto.moretags) = "yaml:\"whitelisted_codehashes_bank_send\"", + // (gogoproto.jsontag) = "whitelisted_codehashes_bank_send" + // ]; + WhitelistedCwCodeHashesForDelegateCall [][]byte `protobuf:"bytes,8,rep,name=whitelisted_cw_code_hashes_for_delegate_call,json=whitelistedCwCodeHashesForDelegateCall,proto3" json:"whitelisted_cw_code_hashes_for_delegate_call" yaml:"whitelisted_cw_code_hashes_for_delegate_call"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_9272f3679901ea94, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetWhitelistedCwCodeHashesForDelegateCall() [][]byte { + if m != nil { + return m.WhitelistedCwCodeHashesForDelegateCall + } + return nil +} + +func init() { + proto.RegisterType((*Params)(nil), "seiprotocol.seichain.evm.Params") +} + +func init() { proto.RegisterFile("evm/params.proto", fileDescriptor_9272f3679901ea94) } + +var fileDescriptor_9272f3679901ea94 = []byte{ + // 459 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xb1, 0x6f, 0xd3, 0x40, + 0x18, 0xc5, 0x6d, 0x5a, 0x42, 0xb1, 0x40, 0x44, 0x2e, 0x12, 0x56, 0x06, 0x5f, 0xe5, 0xa1, 0xea, + 0x40, 0xec, 0xa1, 0x5b, 0xc7, 0xa4, 0x6a, 0xe9, 0x00, 0xaa, 0x3c, 0x22, 0xa1, 0xd3, 0xe5, 0xfc, + 0xc5, 0x3e, 0x71, 0xe7, 0xb3, 0xee, 0xdc, 0x86, 0xf0, 0x07, 0x30, 0x23, 0xc4, 0xc0, 0xc8, 0x3f, + 0x83, 0xd4, 0xb1, 0x23, 0x62, 0x38, 0xa1, 0x64, 0xcb, 0x18, 0x89, 0x1d, 0xe5, 0x9c, 0xb4, 0x05, + 0xb2, 0x84, 0xc9, 0x9f, 0xdf, 0xfb, 0xee, 0xf9, 0xa7, 0x67, 0x9d, 0xd7, 0x86, 0x4b, 0x91, 0x54, + 0x44, 0x11, 0xa1, 0xe3, 0x4a, 0xc9, 0x5a, 0xfa, 0x81, 0x06, 0x66, 0x27, 0x2a, 0x79, 0xac, 0x81, + 0xd1, 0x82, 0xb0, 0x32, 0x86, 0x4b, 0xd1, 0x79, 0x9a, 0xcb, 0x5c, 0x5a, 0x2b, 0x59, 0x4c, 0xcd, + 0x7e, 0xc7, 0x26, 0x50, 0x59, 0x0e, 0x59, 0xde, 0x28, 0xd1, 0xaf, 0xfb, 0x5e, 0xeb, 0xdc, 0x46, + 0xfa, 0x9f, 0x5d, 0x6f, 0xb7, 0x52, 0x4c, 0x2a, 0x56, 0x8f, 0x71, 0x29, 0x95, 0x20, 0x9c, 0xbd, + 0x07, 0x15, 0xdc, 0xdb, 0x73, 0x0f, 0x1e, 0xf6, 0xe8, 0x95, 0x41, 0xce, 0x0f, 0x83, 0xf6, 0x73, + 0x56, 0x17, 0x17, 0x83, 0x98, 0xca, 0x45, 0x92, 0x16, 0x52, 0x2f, 0x1f, 0x5d, 0x9d, 0xbd, 0x4d, + 0xea, 0x71, 0x05, 0x3a, 0x3e, 0x06, 0x3a, 0x33, 0x68, 0x5d, 0xd8, 0xdc, 0xa0, 0xce, 0x98, 0x08, + 0x7e, 0x14, 0xad, 0x31, 0xa3, 0xd4, 0x5f, 0xa9, 0xaf, 0x6e, 0x44, 0xff, 0x83, 0xeb, 0xb5, 0x07, + 0x44, 0x03, 0x1e, 0x02, 0xe0, 0x0a, 0x14, 0xce, 0x89, 0x0e, 0xb6, 0x2c, 0xd3, 0x9b, 0x8d, 0x99, + 0xfe, 0x49, 0x9a, 0x1b, 0xf4, 0xac, 0x01, 0xfa, 0xdb, 0x89, 0xd2, 0xc7, 0x0b, 0xe9, 0x04, 0xe0, + 0x1c, 0xd4, 0x29, 0xd1, 0xfe, 0x27, 0xd7, 0xdb, 0x15, 0xac, 0x64, 0xe2, 0x42, 0xfc, 0xc1, 0xb2, + 0xfd, 0xbf, 0xfd, 0xac, 0x09, 0xbb, 0xed, 0x67, 0x8d, 0x19, 0xa5, 0xed, 0xa5, 0x7a, 0x0b, 0x55, + 0x78, 0x3b, 0xf6, 0xa7, 0x63, 0x96, 0x05, 0x2d, 0x0b, 0xf2, 0x72, 0x03, 0x90, 0xb3, 0xb2, 0x9e, + 0x19, 0x74, 0x93, 0x30, 0x37, 0xe8, 0x49, 0xf3, 0xf5, 0x95, 0x12, 0xa5, 0x0f, 0xec, 0x78, 0x96, + 0xf9, 0xdf, 0x5c, 0xef, 0xf9, 0xa8, 0x60, 0x35, 0x70, 0xa6, 0x6b, 0xc8, 0x30, 0x1d, 0x61, 0x2a, + 0x33, 0xc0, 0x05, 0xd1, 0x05, 0x68, 0x3c, 0x94, 0x0a, 0x67, 0xc0, 0x21, 0x27, 0x35, 0x60, 0x4a, + 0x38, 0x0f, 0x76, 0xf6, 0xb6, 0x0e, 0x1e, 0xf5, 0xf2, 0x99, 0x41, 0x1b, 0x9d, 0x9b, 0x1b, 0x74, + 0xd8, 0x40, 0x6c, 0x72, 0x2a, 0x4a, 0xf7, 0xef, 0xac, 0xf7, 0x47, 0x7d, 0x99, 0xc1, 0x0b, 0xbb, + 0x7b, 0x22, 0xd5, 0xf1, 0x72, 0xb3, 0x4f, 0x38, 0x3f, 0xda, 0xfe, 0xf2, 0x15, 0x39, 0xbd, 0xd3, + 0xab, 0x49, 0xe8, 0x5e, 0x4f, 0x42, 0xf7, 0xe7, 0x24, 0x74, 0x3f, 0x4e, 0x43, 0xe7, 0x7a, 0x1a, + 0x3a, 0xdf, 0xa7, 0xa1, 0xf3, 0xba, 0x7b, 0xa7, 0x37, 0x0d, 0xac, 0xbb, 0xba, 0x5f, 0xf6, 0xc5, + 0x96, 0x91, 0xbc, 0x4b, 0x16, 0xf7, 0xc8, 0x56, 0x38, 0x68, 0x59, 0xff, 0xf0, 0x77, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x44, 0xc2, 0x9d, 0x94, 0x9d, 0x03, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.WhitelistedCwCodeHashesForDelegateCall) > 0 { + for iNdEx := len(m.WhitelistedCwCodeHashesForDelegateCall) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.WhitelistedCwCodeHashesForDelegateCall[iNdEx]) + copy(dAtA[i:], m.WhitelistedCwCodeHashesForDelegateCall[iNdEx]) + i = encodeVarintParams(dAtA, i, uint64(len(m.WhitelistedCwCodeHashesForDelegateCall[iNdEx]))) + i-- + dAtA[i] = 0x42 + } + } + { + size := m.ChainId.Size() + i -= size + if _, err := m.ChainId.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + { + size := m.MinimumFeePerGas.Size() + i -= size + if _, err := m.MinimumFeePerGas.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size := m.BaseFeePerGas.Size() + i -= size + if _, err := m.BaseFeePerGas.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.PriorityNormalizer.Size() + i -= size + if _, err := m.PriorityNormalizer.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.PriorityNormalizer.Size() + n += 1 + l + sovParams(uint64(l)) + l = m.BaseFeePerGas.Size() + n += 1 + l + sovParams(uint64(l)) + l = m.MinimumFeePerGas.Size() + n += 1 + l + sovParams(uint64(l)) + l = m.ChainId.Size() + n += 1 + l + sovParams(uint64(l)) + if len(m.WhitelistedCwCodeHashesForDelegateCall) > 0 { + for _, b := range m.WhitelistedCwCodeHashesForDelegateCall { + l = len(b) + n += 1 + l + sovParams(uint64(l)) + } + } + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PriorityNormalizer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + 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 ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PriorityNormalizer.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BaseFeePerGas", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + 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 ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.BaseFeePerGas.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinimumFeePerGas", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + 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 ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinimumFeePerGas.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + 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 ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ChainId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WhitelistedCwCodeHashesForDelegateCall", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WhitelistedCwCodeHashesForDelegateCall = append(m.WhitelistedCwCodeHashesForDelegateCall, make([]byte, postIndex-iNdEx)) + copy(m.WhitelistedCwCodeHashesForDelegateCall[len(m.WhitelistedCwCodeHashesForDelegateCall)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/params_test.go b/x/evm/types/params_test.go new file mode 100644 index 0000000000..99218af7c5 --- /dev/null +++ b/x/evm/types/params_test.go @@ -0,0 +1,57 @@ +package types_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "testing" + + "github.com/sei-protocol/sei-chain/x/evm/types" + "github.com/stretchr/testify/require" +) + +func TestDefaultParams(t *testing.T) { + require.Equal(t, types.Params{ + PriorityNormalizer: types.DefaultPriorityNormalizer, + BaseFeePerGas: types.DefaultBaseFeePerGas, + MinimumFeePerGas: types.DefaultMinFeePerGas, + ChainId: types.DefaultChainID, + WhitelistedCwCodeHashesForDelegateCall: types.DefaultWhitelistedCwCodeHashesForDelegateCall, + }, types.DefaultParams()) + + require.Nil(t, types.DefaultParams().Validate()) +} + +func TestValidateParamsInvalidPriorityNormalizer(t *testing.T) { + params := types.DefaultParams() + params.PriorityNormalizer = sdk.NewDec(-1) // Set to invalid negative value + + err := params.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "nonpositive priority normalizer") +} + +func TestValidateParamsNegativeBaseFeePerGas(t *testing.T) { + params := types.DefaultParams() + params.BaseFeePerGas = sdk.NewDec(-1) // Set to invalid negative value + + err := params.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "negative base fee per gas") +} + +func TestValidateParamsNegativeChainID(t *testing.T) { + params := types.DefaultParams() + params.ChainId = sdk.NewInt(-1) // Set to invalid negative value + + err := params.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "negative chain ID") +} + +func TestBaseFeeMinimumFee(t *testing.T) { + params := types.DefaultParams() + params.MinimumFeePerGas = sdk.NewDec(1) + params.BaseFeePerGas = params.MinimumFeePerGas.Add(sdk.NewDec(1)) + err := params.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "minimum fee cannot be lower than base fee") +} diff --git a/x/evm/types/query.pb.go b/x/evm/types/query.pb.go new file mode 100644 index 0000000000..5c80febcc6 --- /dev/null +++ b/x/evm/types/query.pb.go @@ -0,0 +1,1971 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/query.proto + +package types + +import ( + context "context" + fmt "fmt" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type QuerySeiAddressByEVMAddressRequest struct { + EvmAddress string `protobuf:"bytes,1,opt,name=evm_address,json=evmAddress,proto3" json:"evm_address,omitempty"` +} + +func (m *QuerySeiAddressByEVMAddressRequest) Reset() { *m = QuerySeiAddressByEVMAddressRequest{} } +func (m *QuerySeiAddressByEVMAddressRequest) String() string { return proto.CompactTextString(m) } +func (*QuerySeiAddressByEVMAddressRequest) ProtoMessage() {} +func (*QuerySeiAddressByEVMAddressRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{0} +} +func (m *QuerySeiAddressByEVMAddressRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySeiAddressByEVMAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySeiAddressByEVMAddressRequest.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 *QuerySeiAddressByEVMAddressRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySeiAddressByEVMAddressRequest.Merge(m, src) +} +func (m *QuerySeiAddressByEVMAddressRequest) XXX_Size() int { + return m.Size() +} +func (m *QuerySeiAddressByEVMAddressRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySeiAddressByEVMAddressRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySeiAddressByEVMAddressRequest proto.InternalMessageInfo + +func (m *QuerySeiAddressByEVMAddressRequest) GetEvmAddress() string { + if m != nil { + return m.EvmAddress + } + return "" +} + +type QuerySeiAddressByEVMAddressResponse struct { + SeiAddress string `protobuf:"bytes,1,opt,name=sei_address,json=seiAddress,proto3" json:"sei_address,omitempty"` + Associated bool `protobuf:"varint,2,opt,name=associated,proto3" json:"associated,omitempty"` +} + +func (m *QuerySeiAddressByEVMAddressResponse) Reset() { *m = QuerySeiAddressByEVMAddressResponse{} } +func (m *QuerySeiAddressByEVMAddressResponse) String() string { return proto.CompactTextString(m) } +func (*QuerySeiAddressByEVMAddressResponse) ProtoMessage() {} +func (*QuerySeiAddressByEVMAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{1} +} +func (m *QuerySeiAddressByEVMAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySeiAddressByEVMAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySeiAddressByEVMAddressResponse.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 *QuerySeiAddressByEVMAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySeiAddressByEVMAddressResponse.Merge(m, src) +} +func (m *QuerySeiAddressByEVMAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *QuerySeiAddressByEVMAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySeiAddressByEVMAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySeiAddressByEVMAddressResponse proto.InternalMessageInfo + +func (m *QuerySeiAddressByEVMAddressResponse) GetSeiAddress() string { + if m != nil { + return m.SeiAddress + } + return "" +} + +func (m *QuerySeiAddressByEVMAddressResponse) GetAssociated() bool { + if m != nil { + return m.Associated + } + return false +} + +type QueryEVMAddressBySeiAddressRequest struct { + SeiAddress string `protobuf:"bytes,1,opt,name=sei_address,json=seiAddress,proto3" json:"sei_address,omitempty"` +} + +func (m *QueryEVMAddressBySeiAddressRequest) Reset() { *m = QueryEVMAddressBySeiAddressRequest{} } +func (m *QueryEVMAddressBySeiAddressRequest) String() string { return proto.CompactTextString(m) } +func (*QueryEVMAddressBySeiAddressRequest) ProtoMessage() {} +func (*QueryEVMAddressBySeiAddressRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{2} +} +func (m *QueryEVMAddressBySeiAddressRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryEVMAddressBySeiAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryEVMAddressBySeiAddressRequest.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 *QueryEVMAddressBySeiAddressRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryEVMAddressBySeiAddressRequest.Merge(m, src) +} +func (m *QueryEVMAddressBySeiAddressRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryEVMAddressBySeiAddressRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryEVMAddressBySeiAddressRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryEVMAddressBySeiAddressRequest proto.InternalMessageInfo + +func (m *QueryEVMAddressBySeiAddressRequest) GetSeiAddress() string { + if m != nil { + return m.SeiAddress + } + return "" +} + +type QueryEVMAddressBySeiAddressResponse struct { + EvmAddress string `protobuf:"bytes,1,opt,name=evm_address,json=evmAddress,proto3" json:"evm_address,omitempty"` + Associated bool `protobuf:"varint,2,opt,name=associated,proto3" json:"associated,omitempty"` +} + +func (m *QueryEVMAddressBySeiAddressResponse) Reset() { *m = QueryEVMAddressBySeiAddressResponse{} } +func (m *QueryEVMAddressBySeiAddressResponse) String() string { return proto.CompactTextString(m) } +func (*QueryEVMAddressBySeiAddressResponse) ProtoMessage() {} +func (*QueryEVMAddressBySeiAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{3} +} +func (m *QueryEVMAddressBySeiAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryEVMAddressBySeiAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryEVMAddressBySeiAddressResponse.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 *QueryEVMAddressBySeiAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryEVMAddressBySeiAddressResponse.Merge(m, src) +} +func (m *QueryEVMAddressBySeiAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryEVMAddressBySeiAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryEVMAddressBySeiAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryEVMAddressBySeiAddressResponse proto.InternalMessageInfo + +func (m *QueryEVMAddressBySeiAddressResponse) GetEvmAddress() string { + if m != nil { + return m.EvmAddress + } + return "" +} + +func (m *QueryEVMAddressBySeiAddressResponse) GetAssociated() bool { + if m != nil { + return m.Associated + } + return false +} + +type QueryStaticCallRequest struct { + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + To string `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` +} + +func (m *QueryStaticCallRequest) Reset() { *m = QueryStaticCallRequest{} } +func (m *QueryStaticCallRequest) String() string { return proto.CompactTextString(m) } +func (*QueryStaticCallRequest) ProtoMessage() {} +func (*QueryStaticCallRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{4} +} +func (m *QueryStaticCallRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryStaticCallRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryStaticCallRequest.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 *QueryStaticCallRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryStaticCallRequest.Merge(m, src) +} +func (m *QueryStaticCallRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryStaticCallRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryStaticCallRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryStaticCallRequest proto.InternalMessageInfo + +func (m *QueryStaticCallRequest) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +func (m *QueryStaticCallRequest) GetTo() string { + if m != nil { + return m.To + } + return "" +} + +type QueryStaticCallResponse struct { + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *QueryStaticCallResponse) Reset() { *m = QueryStaticCallResponse{} } +func (m *QueryStaticCallResponse) String() string { return proto.CompactTextString(m) } +func (*QueryStaticCallResponse) ProtoMessage() {} +func (*QueryStaticCallResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{5} +} +func (m *QueryStaticCallResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryStaticCallResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryStaticCallResponse.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 *QueryStaticCallResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryStaticCallResponse.Merge(m, src) +} +func (m *QueryStaticCallResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryStaticCallResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryStaticCallResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryStaticCallResponse proto.InternalMessageInfo + +func (m *QueryStaticCallResponse) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +type QueryPointerRequest struct { + PointerType PointerType `protobuf:"varint,1,opt,name=pointer_type,json=pointerType,proto3,enum=seiprotocol.seichain.evm.PointerType" json:"pointer_type,omitempty"` + Pointee string `protobuf:"bytes,2,opt,name=pointee,proto3" json:"pointee,omitempty"` +} + +func (m *QueryPointerRequest) Reset() { *m = QueryPointerRequest{} } +func (m *QueryPointerRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPointerRequest) ProtoMessage() {} +func (*QueryPointerRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{6} +} +func (m *QueryPointerRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPointerRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPointerRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryPointerRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPointerRequest.Merge(m, src) +} +func (m *QueryPointerRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPointerRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPointerRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPointerRequest proto.InternalMessageInfo + +func (m *QueryPointerRequest) GetPointerType() PointerType { + if m != nil { + return m.PointerType + } + return PointerType_ERC20 +} + +func (m *QueryPointerRequest) GetPointee() string { + if m != nil { + return m.Pointee + } + return "" +} + +type QueryPointerResponse struct { + Pointer string `protobuf:"bytes,1,opt,name=pointer,proto3" json:"pointer,omitempty"` + Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` + Exists bool `protobuf:"varint,3,opt,name=exists,proto3" json:"exists,omitempty"` +} + +func (m *QueryPointerResponse) Reset() { *m = QueryPointerResponse{} } +func (m *QueryPointerResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPointerResponse) ProtoMessage() {} +func (*QueryPointerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_11c0d37eed5339f7, []int{7} +} +func (m *QueryPointerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPointerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPointerResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryPointerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPointerResponse.Merge(m, src) +} +func (m *QueryPointerResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPointerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPointerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPointerResponse proto.InternalMessageInfo + +func (m *QueryPointerResponse) GetPointer() string { + if m != nil { + return m.Pointer + } + return "" +} + +func (m *QueryPointerResponse) GetVersion() uint32 { + if m != nil { + return m.Version + } + return 0 +} + +func (m *QueryPointerResponse) GetExists() bool { + if m != nil { + return m.Exists + } + return false +} + +func init() { + proto.RegisterType((*QuerySeiAddressByEVMAddressRequest)(nil), "seiprotocol.seichain.evm.QuerySeiAddressByEVMAddressRequest") + proto.RegisterType((*QuerySeiAddressByEVMAddressResponse)(nil), "seiprotocol.seichain.evm.QuerySeiAddressByEVMAddressResponse") + proto.RegisterType((*QueryEVMAddressBySeiAddressRequest)(nil), "seiprotocol.seichain.evm.QueryEVMAddressBySeiAddressRequest") + proto.RegisterType((*QueryEVMAddressBySeiAddressResponse)(nil), "seiprotocol.seichain.evm.QueryEVMAddressBySeiAddressResponse") + proto.RegisterType((*QueryStaticCallRequest)(nil), "seiprotocol.seichain.evm.QueryStaticCallRequest") + proto.RegisterType((*QueryStaticCallResponse)(nil), "seiprotocol.seichain.evm.QueryStaticCallResponse") + proto.RegisterType((*QueryPointerRequest)(nil), "seiprotocol.seichain.evm.QueryPointerRequest") + proto.RegisterType((*QueryPointerResponse)(nil), "seiprotocol.seichain.evm.QueryPointerResponse") +} + +func init() { proto.RegisterFile("evm/query.proto", fileDescriptor_11c0d37eed5339f7) } + +var fileDescriptor_11c0d37eed5339f7 = []byte{ + // 547 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0xcd, 0x6e, 0xd3, 0x4c, + 0x14, 0x8d, 0xf3, 0x7d, 0x6d, 0xe9, 0x6d, 0x29, 0xd2, 0x80, 0x42, 0x14, 0x21, 0x53, 0x99, 0x1f, + 0x45, 0x48, 0xb6, 0xa1, 0x6c, 0xcb, 0x82, 0xa0, 0x0a, 0x36, 0x48, 0x60, 0x10, 0x0b, 0x36, 0xd1, + 0xc4, 0xb9, 0xa4, 0x23, 0xc5, 0x1e, 0xd7, 0x33, 0xb1, 0xea, 0x2d, 0x4f, 0x80, 0x04, 0x2f, 0xc0, + 0xc3, 0x20, 0xb1, 0xac, 0x60, 0xc3, 0x12, 0x25, 0x3c, 0x08, 0xf2, 0x78, 0x9c, 0xb8, 0x6d, 0x62, + 0xb7, 0xec, 0xe6, 0x8e, 0xe7, 0x9c, 0x7b, 0xce, 0xf5, 0xb9, 0x70, 0x0d, 0x93, 0xc0, 0x3d, 0x9a, + 0x60, 0x9c, 0x3a, 0x51, 0xcc, 0x25, 0x27, 0x6d, 0x81, 0x4c, 0x9d, 0x7c, 0x3e, 0x76, 0x04, 0x32, + 0xff, 0x90, 0xb2, 0xd0, 0xc1, 0x24, 0xe8, 0xdc, 0x1a, 0x71, 0x3e, 0x1a, 0xa3, 0x4b, 0x23, 0xe6, + 0xd2, 0x30, 0xe4, 0x92, 0x4a, 0xc6, 0x43, 0x91, 0xe3, 0x3a, 0x8a, 0x08, 0xc3, 0x49, 0xa0, 0x2f, + 0xac, 0x03, 0xb0, 0x5e, 0x67, 0xbc, 0x6f, 0x90, 0x3d, 0x1d, 0x0e, 0x63, 0x14, 0xa2, 0x97, 0x1e, + 0xbc, 0x7b, 0xa9, 0xcf, 0x1e, 0x1e, 0x4d, 0x50, 0x48, 0x72, 0x1b, 0xb6, 0x30, 0x09, 0xfa, 0x34, + 0xbf, 0x6d, 0x1b, 0xbb, 0x46, 0x77, 0xd3, 0x03, 0x4c, 0x02, 0xfd, 0xce, 0xfa, 0x00, 0x77, 0x2a, + 0x69, 0x44, 0xc4, 0x43, 0x81, 0x19, 0x8f, 0x40, 0x76, 0x96, 0x47, 0xcc, 0x41, 0xc4, 0x04, 0xa0, + 0x42, 0x70, 0x9f, 0x51, 0x89, 0xc3, 0x76, 0x73, 0xd7, 0xe8, 0x5e, 0xf1, 0x4a, 0x37, 0x73, 0xb9, + 0x0b, 0xee, 0x5e, 0xa9, 0x67, 0x49, 0x6e, 0x65, 0x9b, 0xb9, 0xdc, 0x55, 0x34, 0x0b, 0xb9, 0x95, + 0xb6, 0x6b, 0xe5, 0xee, 0x43, 0x2b, 0x1f, 0x4b, 0xf6, 0x17, 0xfc, 0x67, 0x74, 0x3c, 0x2e, 0x24, + 0x12, 0xf8, 0x7f, 0x48, 0x25, 0x55, 0x9c, 0xdb, 0x9e, 0x3a, 0x93, 0x1d, 0x68, 0x4a, 0xae, 0x58, + 0x36, 0xbd, 0xa6, 0xe4, 0x96, 0x0d, 0x37, 0xcf, 0xa1, 0xb5, 0xb2, 0x25, 0x70, 0x2b, 0x85, 0xeb, + 0xea, 0xf9, 0x2b, 0xce, 0x42, 0x89, 0x71, 0xd1, 0xe9, 0x05, 0x6c, 0x47, 0xf9, 0x4d, 0x5f, 0xa6, + 0x11, 0x2a, 0xc8, 0xce, 0xde, 0x3d, 0x67, 0x55, 0x82, 0x1c, 0x8d, 0x7f, 0x9b, 0x46, 0xe8, 0x6d, + 0x45, 0x8b, 0x82, 0xb4, 0x61, 0x23, 0x2f, 0x51, 0x8b, 0x2c, 0x4a, 0x6b, 0x00, 0x37, 0x4e, 0xb7, + 0xd6, 0x32, 0xe7, 0x88, 0x58, 0x0f, 0xaf, 0x28, 0xb3, 0x2f, 0x09, 0xc6, 0x82, 0xf1, 0x50, 0x71, + 0x5d, 0xf5, 0x8a, 0x92, 0xb4, 0x60, 0x1d, 0x8f, 0x99, 0x90, 0xa2, 0xfd, 0x9f, 0x9a, 0xa7, 0xae, + 0xf6, 0x7e, 0xac, 0xc1, 0x9a, 0x6a, 0x42, 0xbe, 0x19, 0xd0, 0x5a, 0x1e, 0x34, 0xb2, 0xbf, 0xda, + 0x56, 0x7d, 0xcc, 0x3b, 0x4f, 0xfe, 0x11, 0x9d, 0xbb, 0xb5, 0x9c, 0x8f, 0x3f, 0xff, 0x7c, 0x6e, + 0x76, 0xc9, 0x7d, 0x57, 0x20, 0xb3, 0x0b, 0x1e, 0xb7, 0xe0, 0x71, 0xb3, 0xdd, 0x2b, 0xe5, 0x52, + 0xf9, 0x58, 0x9e, 0xc0, 0x5a, 0x1f, 0x95, 0xf9, 0xaf, 0xf5, 0x51, 0x1d, 0xfb, 0x0b, 0xf9, 0x28, + 0xed, 0x05, 0xf9, 0x6a, 0x00, 0x2c, 0x32, 0x4a, 0x1e, 0xd6, 0x4d, 0xf1, 0xec, 0x32, 0x74, 0x1e, + 0x5d, 0x02, 0x71, 0x99, 0x59, 0x2b, 0x58, 0xdf, 0xcf, 0x44, 0x7d, 0x31, 0x60, 0x43, 0xa7, 0x93, + 0xd8, 0x35, 0xed, 0x4e, 0x2f, 0x50, 0xc7, 0xb9, 0xe8, 0x73, 0x2d, 0xed, 0x81, 0x92, 0x76, 0x97, + 0x58, 0x15, 0xd2, 0xf4, 0x1a, 0xf4, 0x9e, 0x7f, 0x9f, 0x9a, 0xc6, 0xc9, 0xd4, 0x34, 0x7e, 0x4f, + 0x4d, 0xe3, 0xd3, 0xcc, 0x6c, 0x9c, 0xcc, 0xcc, 0xc6, 0xaf, 0x99, 0xd9, 0x78, 0x6f, 0x8f, 0x98, + 0x3c, 0x9c, 0x0c, 0x1c, 0x9f, 0x07, 0xe7, 0x78, 0xec, 0x9c, 0xe8, 0x58, 0x51, 0x65, 0x4b, 0x2d, + 0x06, 0xeb, 0xea, 0xfb, 0xe3, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x7d, 0xec, 0x65, 0x60, 0x2a, + 0x06, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + SeiAddressByEVMAddress(ctx context.Context, in *QuerySeiAddressByEVMAddressRequest, opts ...grpc.CallOption) (*QuerySeiAddressByEVMAddressResponse, error) + EVMAddressBySeiAddress(ctx context.Context, in *QueryEVMAddressBySeiAddressRequest, opts ...grpc.CallOption) (*QueryEVMAddressBySeiAddressResponse, error) + StaticCall(ctx context.Context, in *QueryStaticCallRequest, opts ...grpc.CallOption) (*QueryStaticCallResponse, error) + Pointer(ctx context.Context, in *QueryPointerRequest, opts ...grpc.CallOption) (*QueryPointerResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) SeiAddressByEVMAddress(ctx context.Context, in *QuerySeiAddressByEVMAddressRequest, opts ...grpc.CallOption) (*QuerySeiAddressByEVMAddressResponse, error) { + out := new(QuerySeiAddressByEVMAddressResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Query/SeiAddressByEVMAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) EVMAddressBySeiAddress(ctx context.Context, in *QueryEVMAddressBySeiAddressRequest, opts ...grpc.CallOption) (*QueryEVMAddressBySeiAddressResponse, error) { + out := new(QueryEVMAddressBySeiAddressResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Query/EVMAddressBySeiAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) StaticCall(ctx context.Context, in *QueryStaticCallRequest, opts ...grpc.CallOption) (*QueryStaticCallResponse, error) { + out := new(QueryStaticCallResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Query/StaticCall", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) Pointer(ctx context.Context, in *QueryPointerRequest, opts ...grpc.CallOption) (*QueryPointerResponse, error) { + out := new(QueryPointerResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Query/Pointer", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + SeiAddressByEVMAddress(context.Context, *QuerySeiAddressByEVMAddressRequest) (*QuerySeiAddressByEVMAddressResponse, error) + EVMAddressBySeiAddress(context.Context, *QueryEVMAddressBySeiAddressRequest) (*QueryEVMAddressBySeiAddressResponse, error) + StaticCall(context.Context, *QueryStaticCallRequest) (*QueryStaticCallResponse, error) + Pointer(context.Context, *QueryPointerRequest) (*QueryPointerResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) SeiAddressByEVMAddress(ctx context.Context, req *QuerySeiAddressByEVMAddressRequest) (*QuerySeiAddressByEVMAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SeiAddressByEVMAddress not implemented") +} +func (*UnimplementedQueryServer) EVMAddressBySeiAddress(ctx context.Context, req *QueryEVMAddressBySeiAddressRequest) (*QueryEVMAddressBySeiAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method EVMAddressBySeiAddress not implemented") +} +func (*UnimplementedQueryServer) StaticCall(ctx context.Context, req *QueryStaticCallRequest) (*QueryStaticCallResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method StaticCall not implemented") +} +func (*UnimplementedQueryServer) Pointer(ctx context.Context, req *QueryPointerRequest) (*QueryPointerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Pointer not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_SeiAddressByEVMAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuerySeiAddressByEVMAddressRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).SeiAddressByEVMAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Query/SeiAddressByEVMAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).SeiAddressByEVMAddress(ctx, req.(*QuerySeiAddressByEVMAddressRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_EVMAddressBySeiAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryEVMAddressBySeiAddressRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).EVMAddressBySeiAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Query/EVMAddressBySeiAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).EVMAddressBySeiAddress(ctx, req.(*QueryEVMAddressBySeiAddressRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_StaticCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryStaticCallRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).StaticCall(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Query/StaticCall", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).StaticCall(ctx, req.(*QueryStaticCallRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_Pointer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPointerRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Pointer(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Query/Pointer", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Pointer(ctx, req.(*QueryPointerRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "seiprotocol.seichain.evm.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SeiAddressByEVMAddress", + Handler: _Query_SeiAddressByEVMAddress_Handler, + }, + { + MethodName: "EVMAddressBySeiAddress", + Handler: _Query_EVMAddressBySeiAddress_Handler, + }, + { + MethodName: "StaticCall", + Handler: _Query_StaticCall_Handler, + }, + { + MethodName: "Pointer", + Handler: _Query_Pointer_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "evm/query.proto", +} + +func (m *QuerySeiAddressByEVMAddressRequest) 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 *QuerySeiAddressByEVMAddressRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySeiAddressByEVMAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.EvmAddress) > 0 { + i -= len(m.EvmAddress) + copy(dAtA[i:], m.EvmAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.EvmAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QuerySeiAddressByEVMAddressResponse) 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 *QuerySeiAddressByEVMAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySeiAddressByEVMAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Associated { + i-- + if m.Associated { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.SeiAddress) > 0 { + i -= len(m.SeiAddress) + copy(dAtA[i:], m.SeiAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.SeiAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryEVMAddressBySeiAddressRequest) 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 *QueryEVMAddressBySeiAddressRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryEVMAddressBySeiAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.SeiAddress) > 0 { + i -= len(m.SeiAddress) + copy(dAtA[i:], m.SeiAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.SeiAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryEVMAddressBySeiAddressResponse) 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 *QueryEVMAddressBySeiAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryEVMAddressBySeiAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Associated { + i-- + if m.Associated { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.EvmAddress) > 0 { + i -= len(m.EvmAddress) + copy(dAtA[i:], m.EvmAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.EvmAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryStaticCallRequest) 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 *QueryStaticCallRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryStaticCallRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintQuery(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x12 + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryStaticCallResponse) 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 *QueryStaticCallResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryStaticCallResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryPointerRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryPointerRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPointerRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Pointee) > 0 { + i -= len(m.Pointee) + copy(dAtA[i:], m.Pointee) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Pointee))) + i-- + dAtA[i] = 0x12 + } + if m.PointerType != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PointerType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryPointerResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryPointerResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPointerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Exists { + i-- + if m.Exists { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.Version != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x10 + } + if len(m.Pointer) > 0 { + i -= len(m.Pointer) + copy(dAtA[i:], m.Pointer) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Pointer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QuerySeiAddressByEVMAddressRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.EvmAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QuerySeiAddressByEVMAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SeiAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Associated { + n += 2 + } + return n +} + +func (m *QueryEVMAddressBySeiAddressRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SeiAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryEVMAddressBySeiAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.EvmAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Associated { + n += 2 + } + return n +} + +func (m *QueryStaticCallRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Data) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryStaticCallResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Data) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPointerRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PointerType != 0 { + n += 1 + sovQuery(uint64(m.PointerType)) + } + l = len(m.Pointee) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPointerResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Pointer) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovQuery(uint64(m.Version)) + } + if m.Exists { + n += 2 + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QuerySeiAddressByEVMAddressRequest) 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: QuerySeiAddressByEVMAddressRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySeiAddressByEVMAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EvmAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EvmAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuerySeiAddressByEVMAddressResponse) 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: QuerySeiAddressByEVMAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySeiAddressByEVMAddressResponse: 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 ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SeiAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Associated", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Associated = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryEVMAddressBySeiAddressRequest) 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: QueryEVMAddressBySeiAddressRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryEVMAddressBySeiAddressRequest: 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 ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SeiAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryEVMAddressBySeiAddressResponse) 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: QueryEVMAddressBySeiAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryEVMAddressBySeiAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EvmAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EvmAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Associated", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Associated = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryStaticCallRequest) 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: QueryStaticCallRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryStaticCallRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryStaticCallResponse) 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: QueryStaticCallResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryStaticCallResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryPointerRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryPointerRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPointerRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PointerType", wireType) + } + m.PointerType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PointerType |= PointerType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryPointerResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryPointerResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPointerResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pointer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Pointer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Exists", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Exists = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/query.pb.gw.go b/x/evm/types/query.pb.gw.go new file mode 100644 index 0000000000..8d4d10c212 --- /dev/null +++ b/x/evm/types/query.pb.gw.go @@ -0,0 +1,420 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: evm/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +var ( + filter_Query_SeiAddressByEVMAddress_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_SeiAddressByEVMAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySeiAddressByEVMAddressRequest + 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_SeiAddressByEVMAddress_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.SeiAddressByEVMAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_SeiAddressByEVMAddress_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySeiAddressByEVMAddressRequest + 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_SeiAddressByEVMAddress_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.SeiAddressByEVMAddress(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_EVMAddressBySeiAddress_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_EVMAddressBySeiAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryEVMAddressBySeiAddressRequest + 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_EVMAddressBySeiAddress_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.EVMAddressBySeiAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_EVMAddressBySeiAddress_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryEVMAddressBySeiAddressRequest + 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_EVMAddressBySeiAddress_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EVMAddressBySeiAddress(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_StaticCall_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_StaticCall_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryStaticCallRequest + 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_StaticCall_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.StaticCall(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_StaticCall_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryStaticCallRequest + 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_StaticCall_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.StaticCall(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_Pointer_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_Pointer_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPointerRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Pointer_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Pointer(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Pointer_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPointerRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_Pointer_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Pointer(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_SeiAddressByEVMAddress_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_SeiAddressByEVMAddress_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_SeiAddressByEVMAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_EVMAddressBySeiAddress_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_EVMAddressBySeiAddress_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_EVMAddressBySeiAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_StaticCall_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_StaticCall_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_StaticCall_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Pointer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Pointer_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Pointer_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_SeiAddressByEVMAddress_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_SeiAddressByEVMAddress_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_SeiAddressByEVMAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_EVMAddressBySeiAddress_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_EVMAddressBySeiAddress_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_EVMAddressBySeiAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_StaticCall_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_StaticCall_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_StaticCall_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Pointer_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Pointer_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Pointer_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_SeiAddressByEVMAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "sei_address"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_EVMAddressBySeiAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "evm_address"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_StaticCall_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "static_call"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_Pointer_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"sei-protocol", "seichain", "evm", "pointer"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Query_SeiAddressByEVMAddress_0 = runtime.ForwardResponseMessage + + forward_Query_EVMAddressBySeiAddress_0 = runtime.ForwardResponseMessage + + forward_Query_StaticCall_0 = runtime.ForwardResponseMessage + + forward_Query_Pointer_0 = runtime.ForwardResponseMessage +) diff --git a/x/evm/types/receipt.pb.go b/x/evm/types/receipt.pb.go new file mode 100644 index 0000000000..1cbb846e8e --- /dev/null +++ b/x/evm/types/receipt.pb.go @@ -0,0 +1,1221 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/receipt.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Log struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Topics []string `protobuf:"bytes,2,rep,name=topics,proto3" json:"topics,omitempty"` + Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` + Index uint32 `protobuf:"varint,4,opt,name=index,proto3" json:"index,omitempty"` +} + +func (m *Log) Reset() { *m = Log{} } +func (m *Log) String() string { return proto.CompactTextString(m) } +func (*Log) ProtoMessage() {} +func (*Log) Descriptor() ([]byte, []int) { + return fileDescriptor_d864f6bdca684f52, []int{0} +} +func (m *Log) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Log) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Log.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Log) XXX_Merge(src proto.Message) { + xxx_messageInfo_Log.Merge(m, src) +} +func (m *Log) XXX_Size() int { + return m.Size() +} +func (m *Log) XXX_DiscardUnknown() { + xxx_messageInfo_Log.DiscardUnknown(m) +} + +var xxx_messageInfo_Log proto.InternalMessageInfo + +func (m *Log) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *Log) GetTopics() []string { + if m != nil { + return m.Topics + } + return nil +} + +func (m *Log) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +func (m *Log) GetIndex() uint32 { + if m != nil { + return m.Index + } + return 0 +} + +type Receipt struct { + TxType uint32 `protobuf:"varint,1,opt,name=tx_type,json=txType,proto3" json:"tx_type,omitempty" yaml:"tx_type"` + CumulativeGasUsed uint64 `protobuf:"varint,2,opt,name=cumulative_gas_used,json=cumulativeGasUsed,proto3" json:"cumulative_gas_used,omitempty" yaml:"cumulative_gas_used"` + ContractAddress string `protobuf:"bytes,3,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty" yaml:"contract_address"` + TxHashHex string `protobuf:"bytes,4,opt,name=tx_hash_hex,json=txHashHex,proto3" json:"tx_hash_hex,omitempty" yaml:"tx_hash_hex"` + GasUsed uint64 `protobuf:"varint,5,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty" yaml:"gas_used"` + EffectiveGasPrice uint64 `protobuf:"varint,6,opt,name=effective_gas_price,json=effectiveGasPrice,proto3" json:"effective_gas_price,omitempty" yaml:"effective_gas_price"` + BlockNumber uint64 `protobuf:"varint,7,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty" yaml:"block_number"` + TransactionIndex uint32 `protobuf:"varint,8,opt,name=transaction_index,json=transactionIndex,proto3" json:"transaction_index,omitempty" yaml:"transaction_index"` + Status uint32 `protobuf:"varint,9,opt,name=status,proto3" json:"status,omitempty" yaml:"status"` + From string `protobuf:"bytes,10,opt,name=from,proto3" json:"from,omitempty" yaml:"from"` + To string `protobuf:"bytes,11,opt,name=to,proto3" json:"to,omitempty" yaml:"to"` + VmError string `protobuf:"bytes,12,opt,name=vm_error,json=vmError,proto3" json:"vm_error,omitempty" yaml:"vm_error"` + Logs []*Log `protobuf:"bytes,13,rep,name=logs,proto3" json:"logs,omitempty"` + LogsBloom []byte `protobuf:"bytes,14,opt,name=logsBloom,proto3" json:"logsBloom,omitempty"` +} + +func (m *Receipt) Reset() { *m = Receipt{} } +func (m *Receipt) String() string { return proto.CompactTextString(m) } +func (*Receipt) ProtoMessage() {} +func (*Receipt) Descriptor() ([]byte, []int) { + return fileDescriptor_d864f6bdca684f52, []int{1} +} +func (m *Receipt) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Receipt) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Receipt.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 *Receipt) XXX_Merge(src proto.Message) { + xxx_messageInfo_Receipt.Merge(m, src) +} +func (m *Receipt) XXX_Size() int { + return m.Size() +} +func (m *Receipt) XXX_DiscardUnknown() { + xxx_messageInfo_Receipt.DiscardUnknown(m) +} + +var xxx_messageInfo_Receipt proto.InternalMessageInfo + +func (m *Receipt) GetTxType() uint32 { + if m != nil { + return m.TxType + } + return 0 +} + +func (m *Receipt) GetCumulativeGasUsed() uint64 { + if m != nil { + return m.CumulativeGasUsed + } + return 0 +} + +func (m *Receipt) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *Receipt) GetTxHashHex() string { + if m != nil { + return m.TxHashHex + } + return "" +} + +func (m *Receipt) GetGasUsed() uint64 { + if m != nil { + return m.GasUsed + } + return 0 +} + +func (m *Receipt) GetEffectiveGasPrice() uint64 { + if m != nil { + return m.EffectiveGasPrice + } + return 0 +} + +func (m *Receipt) GetBlockNumber() uint64 { + if m != nil { + return m.BlockNumber + } + return 0 +} + +func (m *Receipt) GetTransactionIndex() uint32 { + if m != nil { + return m.TransactionIndex + } + return 0 +} + +func (m *Receipt) GetStatus() uint32 { + if m != nil { + return m.Status + } + return 0 +} + +func (m *Receipt) GetFrom() string { + if m != nil { + return m.From + } + return "" +} + +func (m *Receipt) GetTo() string { + if m != nil { + return m.To + } + return "" +} + +func (m *Receipt) GetVmError() string { + if m != nil { + return m.VmError + } + return "" +} + +func (m *Receipt) GetLogs() []*Log { + if m != nil { + return m.Logs + } + return nil +} + +func (m *Receipt) GetLogsBloom() []byte { + if m != nil { + return m.LogsBloom + } + return nil +} + +func init() { + proto.RegisterType((*Log)(nil), "seiprotocol.seichain.evm.Log") + proto.RegisterType((*Receipt)(nil), "seiprotocol.seichain.evm.Receipt") +} + +func init() { proto.RegisterFile("evm/receipt.proto", fileDescriptor_d864f6bdca684f52) } + +var fileDescriptor_d864f6bdca684f52 = []byte{ + // 610 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x53, 0x41, 0x4f, 0xdb, 0x4c, + 0x10, 0xc5, 0x49, 0x48, 0xf0, 0x86, 0x00, 0xd9, 0x20, 0x58, 0xf1, 0x81, 0x1d, 0xed, 0x77, 0x49, + 0x55, 0xe1, 0xa8, 0xad, 0xd4, 0x03, 0xb7, 0x46, 0x6a, 0x01, 0x09, 0xa1, 0x6a, 0xd5, 0x5e, 0x7a, + 0xb1, 0x36, 0x9b, 0xc5, 0xb1, 0x6a, 0x7b, 0x2d, 0xef, 0x3a, 0x32, 0xff, 0xa2, 0x3f, 0xab, 0x47, + 0x8e, 0x3d, 0x59, 0x15, 0xfc, 0x03, 0xdf, 0x2b, 0x55, 0x5e, 0xdb, 0x01, 0x21, 0x7a, 0xf2, 0xcc, + 0x7b, 0x6f, 0x76, 0xe6, 0x8d, 0x35, 0x60, 0xc8, 0x57, 0xe1, 0x34, 0xe1, 0x8c, 0xfb, 0xb1, 0x72, + 0xe2, 0x44, 0x28, 0x01, 0x91, 0xe4, 0xbe, 0x8e, 0x98, 0x08, 0x1c, 0xc9, 0x7d, 0xb6, 0xa4, 0x7e, + 0xe4, 0xf0, 0x55, 0x78, 0xb4, 0xef, 0x09, 0x4f, 0x68, 0x6a, 0x5a, 0x46, 0x95, 0x1e, 0x53, 0xd0, + 0xbe, 0x12, 0x1e, 0x44, 0xa0, 0x47, 0x17, 0x8b, 0x84, 0x4b, 0x89, 0x8c, 0xb1, 0x31, 0x31, 0x49, + 0x93, 0xc2, 0x03, 0xd0, 0x55, 0x22, 0xf6, 0x99, 0x44, 0xad, 0x71, 0x7b, 0x62, 0x92, 0x3a, 0x83, + 0x10, 0x74, 0x16, 0x54, 0x51, 0xd4, 0x1e, 0x1b, 0x93, 0x6d, 0xa2, 0x63, 0xb8, 0x0f, 0x36, 0xfd, + 0x68, 0xc1, 0x33, 0xd4, 0x19, 0x1b, 0x93, 0x01, 0xa9, 0x12, 0xfc, 0x67, 0x13, 0xf4, 0x48, 0x35, + 0x24, 0x7c, 0x0d, 0x7a, 0x2a, 0x73, 0xd5, 0x6d, 0xcc, 0x75, 0x9f, 0xc1, 0x0c, 0x16, 0xb9, 0xbd, + 0x73, 0x4b, 0xc3, 0xe0, 0x0c, 0xd7, 0x04, 0x26, 0x5d, 0x95, 0x7d, 0xb9, 0x8d, 0x39, 0xbc, 0x06, + 0x23, 0x96, 0x86, 0x69, 0x40, 0x95, 0xbf, 0xe2, 0xae, 0x47, 0xa5, 0x9b, 0x4a, 0xbe, 0x40, 0xad, + 0xb1, 0x31, 0xe9, 0xcc, 0xac, 0x22, 0xb7, 0x8f, 0xaa, 0xc2, 0x17, 0x44, 0x98, 0x0c, 0x1f, 0xd1, + 0x73, 0x2a, 0xbf, 0x4a, 0xbe, 0x80, 0x9f, 0xc0, 0x1e, 0x13, 0x91, 0x4a, 0x28, 0x53, 0x6e, 0xe3, + 0xb6, 0x1c, 0xdf, 0x9c, 0xfd, 0x57, 0xe4, 0xf6, 0x61, 0xfd, 0xd8, 0x33, 0x05, 0x26, 0xbb, 0x0d, + 0xf4, 0xa1, 0x5e, 0xc9, 0x7b, 0xd0, 0x57, 0x99, 0xbb, 0xa4, 0x72, 0xe9, 0x2e, 0x6b, 0xb3, 0xe6, + 0xec, 0xa0, 0xc8, 0x6d, 0xb8, 0x36, 0xd2, 0x90, 0x98, 0x98, 0x2a, 0xbb, 0xa0, 0x72, 0x79, 0xc1, + 0x33, 0xe8, 0x80, 0xad, 0xb5, 0x89, 0x4d, 0x6d, 0x62, 0x54, 0xe4, 0xf6, 0x6e, 0x55, 0xf4, 0x38, + 0x79, 0xcf, 0xab, 0xe7, 0xbd, 0x06, 0x23, 0x7e, 0x73, 0xc3, 0xd9, 0xda, 0x59, 0x9c, 0xf8, 0x8c, + 0xa3, 0xee, 0x73, 0xff, 0x2f, 0x88, 0x30, 0x19, 0xae, 0xd1, 0x73, 0x2a, 0x3f, 0x97, 0x18, 0x3c, + 0x03, 0xdb, 0xf3, 0x40, 0xb0, 0xef, 0x6e, 0x94, 0x86, 0x73, 0x9e, 0xa0, 0x9e, 0x7e, 0xe8, 0xb0, + 0xc8, 0xed, 0x51, 0xf5, 0xd0, 0x53, 0x16, 0x93, 0xbe, 0x4e, 0xaf, 0x75, 0x06, 0x2f, 0xc1, 0x50, + 0x25, 0x34, 0x92, 0x94, 0x29, 0x5f, 0x44, 0x6e, 0xf5, 0x9b, 0xb7, 0xf4, 0x2f, 0x3c, 0x2e, 0x72, + 0x1b, 0xd5, 0xce, 0x9f, 0x4b, 0x30, 0xd9, 0x7b, 0x82, 0x5d, 0x96, 0x10, 0x7c, 0x05, 0xba, 0x52, + 0x51, 0x95, 0x4a, 0x64, 0xea, 0xfa, 0x61, 0x91, 0xdb, 0x83, 0xaa, 0xbe, 0xc2, 0x31, 0xa9, 0x05, + 0xf0, 0x7f, 0xd0, 0xb9, 0x49, 0x44, 0x88, 0x80, 0x5e, 0xf1, 0x6e, 0x91, 0xdb, 0xfd, 0x4a, 0x58, + 0xa2, 0x98, 0x68, 0x12, 0x9e, 0x80, 0x96, 0x12, 0xa8, 0xaf, 0x25, 0x83, 0x22, 0xb7, 0xcd, 0x7a, + 0x16, 0x81, 0x49, 0x4b, 0x89, 0x72, 0xeb, 0xab, 0xd0, 0xe5, 0x49, 0x22, 0x12, 0xb4, 0xad, 0x45, + 0x4f, 0xb6, 0xde, 0x30, 0x98, 0xf4, 0x56, 0xe1, 0xc7, 0x32, 0x82, 0x6f, 0x40, 0x27, 0x10, 0x9e, + 0x44, 0x83, 0x71, 0x7b, 0xd2, 0x7f, 0x7b, 0xe2, 0xfc, 0xeb, 0xa0, 0x9c, 0x2b, 0xe1, 0x11, 0x2d, + 0x85, 0xc7, 0xc0, 0x2c, 0xbf, 0xb3, 0x40, 0x88, 0x10, 0xed, 0xe8, 0x83, 0x78, 0x04, 0x66, 0xe7, + 0x3f, 0xef, 0x2d, 0xe3, 0xee, 0xde, 0x32, 0x7e, 0xdf, 0x5b, 0xc6, 0x8f, 0x07, 0x6b, 0xe3, 0xee, + 0xc1, 0xda, 0xf8, 0xf5, 0x60, 0x6d, 0x7c, 0x3b, 0xf5, 0x7c, 0xb5, 0x4c, 0xe7, 0x0e, 0x13, 0xe1, + 0x54, 0x72, 0xff, 0xb4, 0xe9, 0xa3, 0x13, 0xdd, 0x68, 0x9a, 0x4d, 0xcb, 0x1b, 0x2f, 0xef, 0x42, + 0xce, 0xbb, 0x9a, 0x7f, 0xf7, 0x37, 0x00, 0x00, 0xff, 0xff, 0x24, 0x16, 0xa8, 0xf6, 0xf7, 0x03, + 0x00, 0x00, +} + +func (m *Log) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Log) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Log) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Index != 0 { + i = encodeVarintReceipt(dAtA, i, uint64(m.Index)) + i-- + dAtA[i] = 0x20 + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintReceipt(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x1a + } + if len(m.Topics) > 0 { + for iNdEx := len(m.Topics) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Topics[iNdEx]) + copy(dAtA[i:], m.Topics[iNdEx]) + i = encodeVarintReceipt(dAtA, i, uint64(len(m.Topics[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintReceipt(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Receipt) 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 *Receipt) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Receipt) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.LogsBloom) > 0 { + i -= len(m.LogsBloom) + copy(dAtA[i:], m.LogsBloom) + i = encodeVarintReceipt(dAtA, i, uint64(len(m.LogsBloom))) + i-- + dAtA[i] = 0x72 + } + if len(m.Logs) > 0 { + for iNdEx := len(m.Logs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Logs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintReceipt(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x6a + } + } + if len(m.VmError) > 0 { + i -= len(m.VmError) + copy(dAtA[i:], m.VmError) + i = encodeVarintReceipt(dAtA, i, uint64(len(m.VmError))) + i-- + dAtA[i] = 0x62 + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintReceipt(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x5a + } + if len(m.From) > 0 { + i -= len(m.From) + copy(dAtA[i:], m.From) + i = encodeVarintReceipt(dAtA, i, uint64(len(m.From))) + i-- + dAtA[i] = 0x52 + } + if m.Status != 0 { + i = encodeVarintReceipt(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x48 + } + if m.TransactionIndex != 0 { + i = encodeVarintReceipt(dAtA, i, uint64(m.TransactionIndex)) + i-- + dAtA[i] = 0x40 + } + if m.BlockNumber != 0 { + i = encodeVarintReceipt(dAtA, i, uint64(m.BlockNumber)) + i-- + dAtA[i] = 0x38 + } + if m.EffectiveGasPrice != 0 { + i = encodeVarintReceipt(dAtA, i, uint64(m.EffectiveGasPrice)) + i-- + dAtA[i] = 0x30 + } + if m.GasUsed != 0 { + i = encodeVarintReceipt(dAtA, i, uint64(m.GasUsed)) + i-- + dAtA[i] = 0x28 + } + if len(m.TxHashHex) > 0 { + i -= len(m.TxHashHex) + copy(dAtA[i:], m.TxHashHex) + i = encodeVarintReceipt(dAtA, i, uint64(len(m.TxHashHex))) + i-- + dAtA[i] = 0x22 + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintReceipt(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0x1a + } + if m.CumulativeGasUsed != 0 { + i = encodeVarintReceipt(dAtA, i, uint64(m.CumulativeGasUsed)) + i-- + dAtA[i] = 0x10 + } + if m.TxType != 0 { + i = encodeVarintReceipt(dAtA, i, uint64(m.TxType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintReceipt(dAtA []byte, offset int, v uint64) int { + offset -= sovReceipt(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Log) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovReceipt(uint64(l)) + } + if len(m.Topics) > 0 { + for _, s := range m.Topics { + l = len(s) + n += 1 + l + sovReceipt(uint64(l)) + } + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovReceipt(uint64(l)) + } + if m.Index != 0 { + n += 1 + sovReceipt(uint64(m.Index)) + } + return n +} + +func (m *Receipt) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.TxType != 0 { + n += 1 + sovReceipt(uint64(m.TxType)) + } + if m.CumulativeGasUsed != 0 { + n += 1 + sovReceipt(uint64(m.CumulativeGasUsed)) + } + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovReceipt(uint64(l)) + } + l = len(m.TxHashHex) + if l > 0 { + n += 1 + l + sovReceipt(uint64(l)) + } + if m.GasUsed != 0 { + n += 1 + sovReceipt(uint64(m.GasUsed)) + } + if m.EffectiveGasPrice != 0 { + n += 1 + sovReceipt(uint64(m.EffectiveGasPrice)) + } + if m.BlockNumber != 0 { + n += 1 + sovReceipt(uint64(m.BlockNumber)) + } + if m.TransactionIndex != 0 { + n += 1 + sovReceipt(uint64(m.TransactionIndex)) + } + if m.Status != 0 { + n += 1 + sovReceipt(uint64(m.Status)) + } + l = len(m.From) + if l > 0 { + n += 1 + l + sovReceipt(uint64(l)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovReceipt(uint64(l)) + } + l = len(m.VmError) + if l > 0 { + n += 1 + l + sovReceipt(uint64(l)) + } + if len(m.Logs) > 0 { + for _, e := range m.Logs { + l = e.Size() + n += 1 + l + sovReceipt(uint64(l)) + } + } + l = len(m.LogsBloom) + if l > 0 { + n += 1 + l + sovReceipt(uint64(l)) + } + return n +} + +func sovReceipt(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozReceipt(x uint64) (n int) { + return sovReceipt(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Log) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Log: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Log: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + 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 ErrInvalidLengthReceipt + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Topics", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + 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 ErrInvalidLengthReceipt + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Topics = append(m.Topics, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthReceipt + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Index", wireType) + } + m.Index = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Index |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipReceipt(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReceipt + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Receipt) 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 ErrIntOverflowReceipt + } + 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: Receipt: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Receipt: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxType", wireType) + } + m.TxType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxType |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CumulativeGasUsed", wireType) + } + m.CumulativeGasUsed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CumulativeGasUsed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + 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 ErrInvalidLengthReceipt + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHashHex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + 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 ErrInvalidLengthReceipt + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHashHex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasUsed", wireType) + } + m.GasUsed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasUsed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EffectiveGasPrice", wireType) + } + m.EffectiveGasPrice = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EffectiveGasPrice |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockNumber", wireType) + } + m.BlockNumber = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockNumber |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TransactionIndex", wireType) + } + m.TransactionIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TransactionIndex |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field From", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + 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 ErrInvalidLengthReceipt + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.From = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + 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 ErrInvalidLengthReceipt + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VmError", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + 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 ErrInvalidLengthReceipt + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.VmError = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Logs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthReceipt + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Logs = append(m.Logs, &Log{}) + if err := m.Logs[len(m.Logs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LogsBloom", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowReceipt + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthReceipt + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthReceipt + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LogsBloom = append(m.LogsBloom[:0], dAtA[iNdEx:postIndex]...) + if m.LogsBloom == nil { + m.LogsBloom = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipReceipt(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthReceipt + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipReceipt(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowReceipt + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowReceipt + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowReceipt + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthReceipt + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupReceipt + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthReceipt + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthReceipt = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowReceipt = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupReceipt = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/tx.pb.go b/x/evm/types/tx.pb.go new file mode 100644 index 0000000000..d9989aee0a --- /dev/null +++ b/x/evm/types/tx.pb.go @@ -0,0 +1,2654 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/codec/types" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + github_com_sei_protocol_sei_chain_x_evm_derived "github.com/sei-protocol/sei-chain/x/evm/derived" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type MsgEVMTransaction struct { + Data *types.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + Derived *github_com_sei_protocol_sei_chain_x_evm_derived.Derived `protobuf:"bytes,2,opt,name=derived,proto3,customtype=github.com/sei-protocol/sei-chain/x/evm/derived.Derived" json:"derived,omitempty"` +} + +func (m *MsgEVMTransaction) Reset() { *m = MsgEVMTransaction{} } +func (m *MsgEVMTransaction) String() string { return proto.CompactTextString(m) } +func (*MsgEVMTransaction) ProtoMessage() {} +func (*MsgEVMTransaction) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{0} +} +func (m *MsgEVMTransaction) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgEVMTransaction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgEVMTransaction.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 *MsgEVMTransaction) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgEVMTransaction.Merge(m, src) +} +func (m *MsgEVMTransaction) XXX_Size() int { + return m.Size() +} +func (m *MsgEVMTransaction) XXX_DiscardUnknown() { + xxx_messageInfo_MsgEVMTransaction.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgEVMTransaction proto.InternalMessageInfo + +func (m *MsgEVMTransaction) GetData() *types.Any { + if m != nil { + return m.Data + } + return nil +} + +type MsgEVMTransactionResponse struct { + GasUsed uint64 `protobuf:"varint,1,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` + VmError string `protobuf:"bytes,2,opt,name=vm_error,json=vmError,proto3" json:"vm_error,omitempty"` + ReturnData []byte `protobuf:"bytes,3,opt,name=return_data,json=returnData,proto3" json:"return_data,omitempty"` + Hash string `protobuf:"bytes,4,opt,name=hash,proto3" json:"hash,omitempty"` +} + +func (m *MsgEVMTransactionResponse) Reset() { *m = MsgEVMTransactionResponse{} } +func (m *MsgEVMTransactionResponse) String() string { return proto.CompactTextString(m) } +func (*MsgEVMTransactionResponse) ProtoMessage() {} +func (*MsgEVMTransactionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{1} +} +func (m *MsgEVMTransactionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgEVMTransactionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgEVMTransactionResponse.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 *MsgEVMTransactionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgEVMTransactionResponse.Merge(m, src) +} +func (m *MsgEVMTransactionResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgEVMTransactionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgEVMTransactionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgEVMTransactionResponse proto.InternalMessageInfo + +func (m *MsgEVMTransactionResponse) GetGasUsed() uint64 { + if m != nil { + return m.GasUsed + } + return 0 +} + +func (m *MsgEVMTransactionResponse) GetVmError() string { + if m != nil { + return m.VmError + } + return "" +} + +func (m *MsgEVMTransactionResponse) GetReturnData() []byte { + if m != nil { + return m.ReturnData + } + return nil +} + +func (m *MsgEVMTransactionResponse) GetHash() string { + if m != nil { + return m.Hash + } + return "" +} + +type MsgInternalEVMCall struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + Value *github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=value,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"value,omitempty"` + To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"` + Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *MsgInternalEVMCall) Reset() { *m = MsgInternalEVMCall{} } +func (m *MsgInternalEVMCall) String() string { return proto.CompactTextString(m) } +func (*MsgInternalEVMCall) ProtoMessage() {} +func (*MsgInternalEVMCall) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{2} +} +func (m *MsgInternalEVMCall) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgInternalEVMCall) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInternalEVMCall.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 *MsgInternalEVMCall) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInternalEVMCall.Merge(m, src) +} +func (m *MsgInternalEVMCall) XXX_Size() int { + return m.Size() +} +func (m *MsgInternalEVMCall) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInternalEVMCall.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInternalEVMCall proto.InternalMessageInfo + +func (m *MsgInternalEVMCall) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgInternalEVMCall) GetTo() string { + if m != nil { + return m.To + } + return "" +} + +func (m *MsgInternalEVMCall) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +type MsgInternalEVMCallResponse struct { +} + +func (m *MsgInternalEVMCallResponse) Reset() { *m = MsgInternalEVMCallResponse{} } +func (m *MsgInternalEVMCallResponse) String() string { return proto.CompactTextString(m) } +func (*MsgInternalEVMCallResponse) ProtoMessage() {} +func (*MsgInternalEVMCallResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{3} +} +func (m *MsgInternalEVMCallResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgInternalEVMCallResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInternalEVMCallResponse.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 *MsgInternalEVMCallResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInternalEVMCallResponse.Merge(m, src) +} +func (m *MsgInternalEVMCallResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgInternalEVMCallResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInternalEVMCallResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInternalEVMCallResponse proto.InternalMessageInfo + +type MsgInternalEVMDelegateCall struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + CodeHash []byte `protobuf:"bytes,2,opt,name=codeHash,proto3" json:"codeHash,omitempty"` + To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"` + Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` + FromContract string `protobuf:"bytes,5,opt,name=fromContract,proto3" json:"fromContract,omitempty"` +} + +func (m *MsgInternalEVMDelegateCall) Reset() { *m = MsgInternalEVMDelegateCall{} } +func (m *MsgInternalEVMDelegateCall) String() string { return proto.CompactTextString(m) } +func (*MsgInternalEVMDelegateCall) ProtoMessage() {} +func (*MsgInternalEVMDelegateCall) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{4} +} +func (m *MsgInternalEVMDelegateCall) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgInternalEVMDelegateCall) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInternalEVMDelegateCall.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 *MsgInternalEVMDelegateCall) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInternalEVMDelegateCall.Merge(m, src) +} +func (m *MsgInternalEVMDelegateCall) XXX_Size() int { + return m.Size() +} +func (m *MsgInternalEVMDelegateCall) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInternalEVMDelegateCall.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInternalEVMDelegateCall proto.InternalMessageInfo + +func (m *MsgInternalEVMDelegateCall) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgInternalEVMDelegateCall) GetCodeHash() []byte { + if m != nil { + return m.CodeHash + } + return nil +} + +func (m *MsgInternalEVMDelegateCall) GetTo() string { + if m != nil { + return m.To + } + return "" +} + +func (m *MsgInternalEVMDelegateCall) GetData() []byte { + if m != nil { + return m.Data + } + return nil +} + +func (m *MsgInternalEVMDelegateCall) GetFromContract() string { + if m != nil { + return m.FromContract + } + return "" +} + +type MsgInternalEVMDelegateCallResponse struct { +} + +func (m *MsgInternalEVMDelegateCallResponse) Reset() { *m = MsgInternalEVMDelegateCallResponse{} } +func (m *MsgInternalEVMDelegateCallResponse) String() string { return proto.CompactTextString(m) } +func (*MsgInternalEVMDelegateCallResponse) ProtoMessage() {} +func (*MsgInternalEVMDelegateCallResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{5} +} +func (m *MsgInternalEVMDelegateCallResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgInternalEVMDelegateCallResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInternalEVMDelegateCallResponse.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 *MsgInternalEVMDelegateCallResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInternalEVMDelegateCallResponse.Merge(m, src) +} +func (m *MsgInternalEVMDelegateCallResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgInternalEVMDelegateCallResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInternalEVMDelegateCallResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInternalEVMDelegateCallResponse proto.InternalMessageInfo + +type MsgSend struct { + FromAddress string `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` + ToAddress string `protobuf:"bytes,2,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + Amount github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=amount,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amount"` +} + +func (m *MsgSend) Reset() { *m = MsgSend{} } +func (m *MsgSend) String() string { return proto.CompactTextString(m) } +func (*MsgSend) ProtoMessage() {} +func (*MsgSend) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{6} +} +func (m *MsgSend) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSend.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 *MsgSend) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSend.Merge(m, src) +} +func (m *MsgSend) XXX_Size() int { + return m.Size() +} +func (m *MsgSend) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSend.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSend proto.InternalMessageInfo + +func (m *MsgSend) GetFromAddress() string { + if m != nil { + return m.FromAddress + } + return "" +} + +func (m *MsgSend) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *MsgSend) GetAmount() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Amount + } + return nil +} + +type MsgSendResponse struct { +} + +func (m *MsgSendResponse) Reset() { *m = MsgSendResponse{} } +func (m *MsgSendResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSendResponse) ProtoMessage() {} +func (*MsgSendResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{7} +} +func (m *MsgSendResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSendResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSendResponse.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 *MsgSendResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSendResponse.Merge(m, src) +} +func (m *MsgSendResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSendResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSendResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSendResponse proto.InternalMessageInfo + +type MsgRegisterPointer struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + PointerType PointerType `protobuf:"varint,2,opt,name=pointer_type,json=pointerType,proto3,enum=seiprotocol.seichain.evm.PointerType" json:"pointer_type,omitempty"` + ErcAddress string `protobuf:"bytes,3,opt,name=erc_address,json=ercAddress,proto3" json:"erc_address,omitempty"` +} + +func (m *MsgRegisterPointer) Reset() { *m = MsgRegisterPointer{} } +func (m *MsgRegisterPointer) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterPointer) ProtoMessage() {} +func (*MsgRegisterPointer) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{8} +} +func (m *MsgRegisterPointer) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterPointer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterPointer.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRegisterPointer) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterPointer.Merge(m, src) +} +func (m *MsgRegisterPointer) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterPointer) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterPointer.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterPointer proto.InternalMessageInfo + +func (m *MsgRegisterPointer) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgRegisterPointer) GetPointerType() PointerType { + if m != nil { + return m.PointerType + } + return PointerType_ERC20 +} + +func (m *MsgRegisterPointer) GetErcAddress() string { + if m != nil { + return m.ErcAddress + } + return "" +} + +type MsgRegisterPointerResponse struct { + PointerAddress string `protobuf:"bytes,1,opt,name=pointer_address,json=pointerAddress,proto3" json:"pointer_address,omitempty"` +} + +func (m *MsgRegisterPointerResponse) Reset() { *m = MsgRegisterPointerResponse{} } +func (m *MsgRegisterPointerResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRegisterPointerResponse) ProtoMessage() {} +func (*MsgRegisterPointerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d72e73a3d1d93781, []int{9} +} +func (m *MsgRegisterPointerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRegisterPointerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRegisterPointerResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRegisterPointerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRegisterPointerResponse.Merge(m, src) +} +func (m *MsgRegisterPointerResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRegisterPointerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRegisterPointerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRegisterPointerResponse proto.InternalMessageInfo + +func (m *MsgRegisterPointerResponse) GetPointerAddress() string { + if m != nil { + return m.PointerAddress + } + return "" +} + +func init() { + proto.RegisterType((*MsgEVMTransaction)(nil), "seiprotocol.seichain.evm.MsgEVMTransaction") + proto.RegisterType((*MsgEVMTransactionResponse)(nil), "seiprotocol.seichain.evm.MsgEVMTransactionResponse") + proto.RegisterType((*MsgInternalEVMCall)(nil), "seiprotocol.seichain.evm.MsgInternalEVMCall") + proto.RegisterType((*MsgInternalEVMCallResponse)(nil), "seiprotocol.seichain.evm.MsgInternalEVMCallResponse") + proto.RegisterType((*MsgInternalEVMDelegateCall)(nil), "seiprotocol.seichain.evm.MsgInternalEVMDelegateCall") + proto.RegisterType((*MsgInternalEVMDelegateCallResponse)(nil), "seiprotocol.seichain.evm.MsgInternalEVMDelegateCallResponse") + proto.RegisterType((*MsgSend)(nil), "seiprotocol.seichain.evm.MsgSend") + proto.RegisterType((*MsgSendResponse)(nil), "seiprotocol.seichain.evm.MsgSendResponse") + proto.RegisterType((*MsgRegisterPointer)(nil), "seiprotocol.seichain.evm.MsgRegisterPointer") + proto.RegisterType((*MsgRegisterPointerResponse)(nil), "seiprotocol.seichain.evm.MsgRegisterPointerResponse") +} + +func init() { proto.RegisterFile("evm/tx.proto", fileDescriptor_d72e73a3d1d93781) } + +var fileDescriptor_d72e73a3d1d93781 = []byte{ + // 744 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x94, 0xcd, 0x4e, 0xdb, 0x48, + 0x1c, 0xc0, 0xe3, 0x24, 0x10, 0x32, 0x89, 0x12, 0x61, 0xa1, 0x55, 0x12, 0xed, 0x26, 0xac, 0xb5, + 0x1f, 0xd9, 0x0f, 0xec, 0x25, 0xac, 0xb4, 0x87, 0xbd, 0x2c, 0x81, 0x68, 0xe1, 0x10, 0x69, 0xe5, + 0x05, 0x0e, 0xbd, 0x44, 0x13, 0xfb, 0x8f, 0x63, 0x35, 0x9e, 0x89, 0x66, 0xc6, 0x11, 0x79, 0x81, + 0x9e, 0xab, 0xaa, 0x52, 0xfb, 0x0c, 0x3d, 0xf5, 0x29, 0x2a, 0x8e, 0x1c, 0x2b, 0x0e, 0xb4, 0x82, + 0x17, 0xa9, 0x66, 0xc6, 0x71, 0x4b, 0x50, 0x28, 0x9c, 0x3c, 0xf3, 0xff, 0xfc, 0xfd, 0x3f, 0xc6, + 0xa8, 0x0c, 0xd3, 0xc8, 0x11, 0x67, 0xf6, 0x84, 0x51, 0x41, 0xcd, 0x1a, 0x87, 0x50, 0x9d, 0x3c, + 0x3a, 0xb6, 0x39, 0x84, 0xde, 0x08, 0x87, 0xc4, 0x86, 0x69, 0xd4, 0xa8, 0x07, 0x94, 0x06, 0x63, + 0x70, 0x94, 0x76, 0x18, 0x9f, 0x3a, 0x98, 0xcc, 0xb4, 0x53, 0x63, 0x23, 0xa0, 0x01, 0x55, 0x47, + 0x47, 0x9e, 0x12, 0x69, 0xd3, 0xa3, 0x3c, 0xa2, 0xdc, 0x19, 0x62, 0x0e, 0xce, 0x74, 0x7b, 0x08, + 0x02, 0x6f, 0x3b, 0x1e, 0x0d, 0x49, 0xa2, 0xaf, 0xca, 0xc4, 0x40, 0xe2, 0x88, 0x6b, 0x81, 0xf5, + 0xd2, 0x40, 0xeb, 0x7d, 0x1e, 0xf4, 0x4e, 0xfa, 0x47, 0x0c, 0x13, 0x8e, 0x3d, 0x11, 0x52, 0x62, + 0xb6, 0x51, 0xde, 0xc7, 0x02, 0xd7, 0x8c, 0x4d, 0xa3, 0x5d, 0xea, 0x6c, 0xd8, 0x1a, 0xc3, 0x9e, + 0x63, 0xd8, 0xbb, 0x64, 0xe6, 0x2a, 0x0b, 0xf3, 0x18, 0x15, 0x7c, 0x60, 0xe1, 0x14, 0xfc, 0x5a, + 0x76, 0xd3, 0x68, 0x97, 0xbb, 0x7f, 0x5f, 0x5e, 0xb5, 0xfe, 0x0a, 0x42, 0x31, 0x8a, 0x87, 0xb6, + 0x47, 0x23, 0x87, 0x43, 0xb8, 0x35, 0x2f, 0x4e, 0x5d, 0x54, 0x75, 0xce, 0x99, 0x23, 0x49, 0x12, + 0x57, 0x7b, 0x5f, 0x7f, 0xdd, 0x79, 0x2c, 0xeb, 0x99, 0x81, 0xea, 0x77, 0xb0, 0x5c, 0xe0, 0x13, + 0x4a, 0x38, 0x98, 0x75, 0xb4, 0x16, 0x60, 0x3e, 0x88, 0x39, 0xf8, 0x0a, 0x31, 0xef, 0x16, 0x02, + 0xcc, 0x8f, 0x39, 0xf8, 0x52, 0x35, 0x8d, 0x06, 0xc0, 0x18, 0x65, 0x0a, 0xa8, 0xe8, 0x16, 0xa6, + 0x51, 0x4f, 0x5e, 0xcd, 0x16, 0x2a, 0x31, 0x10, 0x31, 0x23, 0x03, 0x55, 0x5b, 0x4e, 0xe2, 0xba, + 0x48, 0x8b, 0xf6, 0x65, 0x2d, 0x26, 0xca, 0x8f, 0x30, 0x1f, 0xd5, 0xf2, 0xca, 0x4f, 0x9d, 0xad, + 0x17, 0x06, 0x32, 0xfb, 0x3c, 0x38, 0x24, 0x02, 0x18, 0xc1, 0xe3, 0xde, 0x49, 0x7f, 0x0f, 0x8f, + 0xc7, 0xe6, 0x37, 0x68, 0x95, 0x03, 0xf1, 0x81, 0xa9, 0xfc, 0x45, 0x37, 0xb9, 0x99, 0xff, 0xa0, + 0x95, 0x29, 0x1e, 0xc7, 0xa0, 0x73, 0x77, 0x7f, 0xbd, 0xbc, 0x6a, 0xfd, 0xf4, 0x45, 0x33, 0x92, + 0xe9, 0xe8, 0xcf, 0x16, 0xf7, 0x9f, 0x3a, 0x62, 0x36, 0x01, 0x6e, 0x1f, 0x12, 0xe1, 0x6a, 0x47, + 0xb3, 0x82, 0xb2, 0x82, 0x2a, 0xb8, 0xa2, 0x9b, 0x15, 0x54, 0x42, 0x29, 0xdc, 0xbc, 0xc2, 0x55, + 0x67, 0xeb, 0x5b, 0xd4, 0xb8, 0xcb, 0x34, 0xef, 0x8e, 0xf5, 0xda, 0x58, 0x54, 0xef, 0xc3, 0x18, + 0x02, 0x2c, 0xe0, 0x5e, 0xf4, 0x06, 0x5a, 0xf3, 0xa8, 0x0f, 0x07, 0xb2, 0x03, 0x6a, 0x94, 0x6e, + 0x7a, 0x7f, 0x08, 0x94, 0x69, 0xa1, 0xf2, 0x29, 0xa3, 0xd1, 0x1e, 0x25, 0x82, 0x61, 0x4f, 0xd4, + 0x56, 0x94, 0xf5, 0x2d, 0x99, 0xf5, 0x03, 0xb2, 0x96, 0x93, 0xa5, 0x05, 0xbc, 0x35, 0x50, 0xa1, + 0xcf, 0x83, 0xff, 0x81, 0xf8, 0xe6, 0xf7, 0x3a, 0xea, 0x00, 0xfb, 0x3e, 0x03, 0xce, 0x13, 0xe6, + 0x92, 0x94, 0xed, 0x6a, 0x91, 0xf9, 0x1d, 0x42, 0x82, 0xa6, 0x06, 0x7a, 0xe8, 0x45, 0x41, 0xe7, + 0x6a, 0x0f, 0xad, 0xe2, 0x88, 0xc6, 0x44, 0xd4, 0x72, 0x9b, 0xb9, 0x76, 0xa9, 0x53, 0xb7, 0x75, + 0xfb, 0x6d, 0xf9, 0x46, 0xec, 0xe4, 0x8d, 0xd8, 0x7b, 0x34, 0x24, 0xdd, 0x3f, 0xce, 0xaf, 0x5a, + 0x99, 0x37, 0x1f, 0x5a, 0xed, 0x07, 0x8c, 0x4c, 0x3a, 0x70, 0x37, 0x09, 0x6d, 0xad, 0xa3, 0x6a, + 0x42, 0x9c, 0x56, 0xf1, 0x4a, 0x6f, 0x8e, 0x0b, 0x41, 0xc8, 0x05, 0xb0, 0xff, 0x68, 0x28, 0xcb, + 0x5e, 0xda, 0xfe, 0x03, 0x54, 0x9e, 0x68, 0x93, 0x81, 0x4c, 0xa0, 0xea, 0xa8, 0x74, 0x7e, 0xb4, + 0x97, 0xfd, 0x1b, 0xec, 0x24, 0xe0, 0xd1, 0x6c, 0x02, 0x6e, 0x69, 0xf2, 0xf9, 0x22, 0xf7, 0x1c, + 0x98, 0x97, 0x36, 0x44, 0x4f, 0x0d, 0x01, 0xf3, 0x92, 0x8e, 0x58, 0x3d, 0xb5, 0x1f, 0x0b, 0x60, + 0xe9, 0xe3, 0xfa, 0x19, 0x55, 0xe7, 0x20, 0xb7, 0x9b, 0x5e, 0x49, 0xc4, 0x49, 0x98, 0xce, 0xbb, + 0x2c, 0xca, 0xf5, 0x79, 0x60, 0x32, 0x54, 0x59, 0xf8, 0x7d, 0xfc, 0xb6, 0x9c, 0xfa, 0xce, 0xa3, + 0x6e, 0xec, 0x3c, 0xc2, 0x38, 0x85, 0x3c, 0x42, 0x79, 0xbd, 0x1e, 0xf7, 0x3a, 0x4b, 0x93, 0xc6, + 0x2f, 0x5f, 0x35, 0x49, 0xa3, 0xc6, 0xa8, 0xba, 0x38, 0xae, 0xdf, 0xef, 0xf5, 0x5e, 0xb0, 0x6e, + 0xfc, 0xf9, 0x18, 0xeb, 0x79, 0xda, 0xee, 0xbf, 0xe7, 0xd7, 0x4d, 0xe3, 0xe2, 0xba, 0x69, 0x7c, + 0xbc, 0x6e, 0x1a, 0xcf, 0x6f, 0x9a, 0x99, 0x8b, 0x9b, 0x66, 0xe6, 0xfd, 0x4d, 0x33, 0xf3, 0x64, + 0xeb, 0xa1, 0x3f, 0x52, 0xb5, 0x93, 0xc3, 0x55, 0xa5, 0xdf, 0xf9, 0x14, 0x00, 0x00, 0xff, 0xff, + 0x51, 0x5e, 0xb8, 0x08, 0x5f, 0x06, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + EVMTransaction(ctx context.Context, in *MsgEVMTransaction, opts ...grpc.CallOption) (*MsgEVMTransactionResponse, error) + Send(ctx context.Context, in *MsgSend, opts ...grpc.CallOption) (*MsgSendResponse, error) + RegisterPointer(ctx context.Context, in *MsgRegisterPointer, opts ...grpc.CallOption) (*MsgRegisterPointerResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) EVMTransaction(ctx context.Context, in *MsgEVMTransaction, opts ...grpc.CallOption) (*MsgEVMTransactionResponse, error) { + out := new(MsgEVMTransactionResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Msg/EVMTransaction", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Send(ctx context.Context, in *MsgSend, opts ...grpc.CallOption) (*MsgSendResponse, error) { + out := new(MsgSendResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Msg/Send", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) RegisterPointer(ctx context.Context, in *MsgRegisterPointer, opts ...grpc.CallOption) (*MsgRegisterPointerResponse, error) { + out := new(MsgRegisterPointerResponse) + err := c.cc.Invoke(ctx, "/seiprotocol.seichain.evm.Msg/RegisterPointer", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + EVMTransaction(context.Context, *MsgEVMTransaction) (*MsgEVMTransactionResponse, error) + Send(context.Context, *MsgSend) (*MsgSendResponse, error) + RegisterPointer(context.Context, *MsgRegisterPointer) (*MsgRegisterPointerResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) EVMTransaction(ctx context.Context, req *MsgEVMTransaction) (*MsgEVMTransactionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method EVMTransaction not implemented") +} +func (*UnimplementedMsgServer) Send(ctx context.Context, req *MsgSend) (*MsgSendResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Send not implemented") +} +func (*UnimplementedMsgServer) RegisterPointer(ctx context.Context, req *MsgRegisterPointer) (*MsgRegisterPointerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RegisterPointer not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_EVMTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgEVMTransaction) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).EVMTransaction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Msg/EVMTransaction", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).EVMTransaction(ctx, req.(*MsgEVMTransaction)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Send_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSend) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Send(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Msg/Send", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Send(ctx, req.(*MsgSend)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_RegisterPointer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRegisterPointer) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RegisterPointer(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/seiprotocol.seichain.evm.Msg/RegisterPointer", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RegisterPointer(ctx, req.(*MsgRegisterPointer)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "seiprotocol.seichain.evm.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "EVMTransaction", + Handler: _Msg_EVMTransaction_Handler, + }, + { + MethodName: "Send", + Handler: _Msg_Send_Handler, + }, + { + MethodName: "RegisterPointer", + Handler: _Msg_RegisterPointer_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "evm/tx.proto", +} + +func (m *MsgEVMTransaction) 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 *MsgEVMTransaction) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgEVMTransaction) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Derived != nil { + { + size := m.Derived.Size() + i -= size + if _, err := m.Derived.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Data != nil { + { + size, err := m.Data.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgEVMTransactionResponse) 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 *MsgEVMTransactionResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgEVMTransactionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Hash) > 0 { + i -= len(m.Hash) + copy(dAtA[i:], m.Hash) + i = encodeVarintTx(dAtA, i, uint64(len(m.Hash))) + i-- + dAtA[i] = 0x22 + } + if len(m.ReturnData) > 0 { + i -= len(m.ReturnData) + copy(dAtA[i:], m.ReturnData) + i = encodeVarintTx(dAtA, i, uint64(len(m.ReturnData))) + i-- + dAtA[i] = 0x1a + } + if len(m.VmError) > 0 { + i -= len(m.VmError) + copy(dAtA[i:], m.VmError) + i = encodeVarintTx(dAtA, i, uint64(len(m.VmError))) + i-- + dAtA[i] = 0x12 + } + if m.GasUsed != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.GasUsed)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgInternalEVMCall) 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 *MsgInternalEVMCall) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInternalEVMCall) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x22 + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x1a + } + if m.Value != nil { + { + size := m.Value.Size() + i -= size + if _, err := m.Value.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + 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 *MsgInternalEVMCallResponse) 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 *MsgInternalEVMCallResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInternalEVMCallResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgInternalEVMDelegateCall) 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 *MsgInternalEVMDelegateCall) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInternalEVMDelegateCall) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FromContract) > 0 { + i -= len(m.FromContract) + copy(dAtA[i:], m.FromContract) + i = encodeVarintTx(dAtA, i, uint64(len(m.FromContract))) + i-- + dAtA[i] = 0x2a + } + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x22 + } + if len(m.To) > 0 { + i -= len(m.To) + copy(dAtA[i:], m.To) + i = encodeVarintTx(dAtA, i, uint64(len(m.To))) + i-- + dAtA[i] = 0x1a + } + if len(m.CodeHash) > 0 { + i -= len(m.CodeHash) + copy(dAtA[i:], m.CodeHash) + i = encodeVarintTx(dAtA, i, uint64(len(m.CodeHash))) + 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 *MsgInternalEVMDelegateCallResponse) 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 *MsgInternalEVMDelegateCallResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInternalEVMDelegateCallResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgSend) 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 *MsgSend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSend) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amount) > 0 { + for iNdEx := len(m.Amount) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amount[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.FromAddress) > 0 { + i -= len(m.FromAddress) + copy(dAtA[i:], m.FromAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.FromAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSendResponse) 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 *MsgSendResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSendResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgRegisterPointer) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRegisterPointer) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterPointer) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ErcAddress) > 0 { + i -= len(m.ErcAddress) + copy(dAtA[i:], m.ErcAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ErcAddress))) + i-- + dAtA[i] = 0x1a + } + if m.PointerType != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PointerType)) + i-- + dAtA[i] = 0x10 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRegisterPointerResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRegisterPointerResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRegisterPointerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PointerAddress) > 0 { + i -= len(m.PointerAddress) + copy(dAtA[i:], m.PointerAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.PointerAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgEVMTransaction) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Data != nil { + l = m.Data.Size() + n += 1 + l + sovTx(uint64(l)) + } + if m.Derived != nil { + l = m.Derived.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgEVMTransactionResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.GasUsed != 0 { + n += 1 + sovTx(uint64(m.GasUsed)) + } + l = len(m.VmError) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ReturnData) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Hash) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgInternalEVMCall) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Value != nil { + l = m.Value.Size() + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgInternalEVMCallResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgInternalEVMDelegateCall) 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.CodeHash) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.To) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.FromContract) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgInternalEVMDelegateCallResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgSend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FromAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Amount) > 0 { + for _, e := range m.Amount { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgSendResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgRegisterPointer) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PointerType != 0 { + n += 1 + sovTx(uint64(m.PointerType)) + } + l = len(m.ErcAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRegisterPointerResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PointerAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgEVMTransaction) 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: MsgEVMTransaction: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgEVMTransaction: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Data == nil { + m.Data = &types.Any{} + } + if err := m.Data.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Derived", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_sei_protocol_sei_chain_x_evm_derived.Derived + m.Derived = &v + if err := m.Derived.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgEVMTransactionResponse) 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: MsgEVMTransactionResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgEVMTransactionResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasUsed", wireType) + } + m.GasUsed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasUsed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field VmError", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.VmError = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReturnData", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ReturnData = append(m.ReturnData[:0], dAtA[iNdEx:postIndex]...) + if m.ReturnData == nil { + m.ReturnData = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + 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 *MsgInternalEVMCall) 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: MsgInternalEVMCall: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInternalEVMCall: 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 Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var v github_com_cosmos_cosmos_sdk_types.Int + m.Value = &v + if err := m.Value.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + 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 *MsgInternalEVMCallResponse) 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: MsgInternalEVMCallResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInternalEVMCallResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgInternalEVMDelegateCall) 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: MsgInternalEVMDelegateCall: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInternalEVMDelegateCall: 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 CodeHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CodeHash = append(m.CodeHash[:0], dAtA[iNdEx:postIndex]...) + if m.CodeHash == nil { + m.CodeHash = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field To", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.To = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromContract", 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.FromContract = 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 *MsgInternalEVMDelegateCallResponse) 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: MsgInternalEVMDelegateCallResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInternalEVMDelegateCallResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSend) 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: MsgSend: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSend: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromAddress", 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.FromAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", 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.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amount = append(m.Amount, types1.Coin{}) + if err := m.Amount[len(m.Amount)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSendResponse) 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: MsgSendResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSendResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRegisterPointer) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRegisterPointer: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterPointer: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PointerType", wireType) + } + m.PointerType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PointerType |= PointerType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErcAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ErcAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRegisterPointerResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRegisterPointerResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterPointerResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PointerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PointerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/types.pb.go b/x/evm/types/types.pb.go new file mode 100644 index 0000000000..e3156fffe1 --- /dev/null +++ b/x/evm/types/types.pb.go @@ -0,0 +1,321 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: evm/types.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Whitelist struct { + Hashes []string `protobuf:"bytes,1,rep,name=hashes,proto3" json:"hashes,omitempty" yaml:"hashes"` +} + +func (m *Whitelist) Reset() { *m = Whitelist{} } +func (m *Whitelist) String() string { return proto.CompactTextString(m) } +func (*Whitelist) ProtoMessage() {} +func (*Whitelist) Descriptor() ([]byte, []int) { + return fileDescriptor_6eba926c274d8fd0, []int{0} +} +func (m *Whitelist) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Whitelist) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Whitelist.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 *Whitelist) XXX_Merge(src proto.Message) { + xxx_messageInfo_Whitelist.Merge(m, src) +} +func (m *Whitelist) XXX_Size() int { + return m.Size() +} +func (m *Whitelist) XXX_DiscardUnknown() { + xxx_messageInfo_Whitelist.DiscardUnknown(m) +} + +var xxx_messageInfo_Whitelist proto.InternalMessageInfo + +func (m *Whitelist) GetHashes() []string { + if m != nil { + return m.Hashes + } + return nil +} + +func init() { + proto.RegisterType((*Whitelist)(nil), "seiprotocol.seichain.evm.Whitelist") +} + +func init() { proto.RegisterFile("evm/types.proto", fileDescriptor_6eba926c274d8fd0) } + +var fileDescriptor_6eba926c274d8fd0 = []byte{ + // 184 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4f, 0x2d, 0xcb, 0xd5, + 0x2f, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x28, 0x4e, 0xcd, + 0x04, 0xb3, 0x92, 0xf3, 0x73, 0xf4, 0x8a, 0x53, 0x33, 0x93, 0x33, 0x12, 0x33, 0xf3, 0xf4, 0x52, + 0xcb, 0x72, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, 0xc1, 0x52, 0xfa, 0x20, 0x16, 0x44, 0xbd, 0x92, + 0x19, 0x17, 0x67, 0x78, 0x46, 0x66, 0x49, 0x6a, 0x4e, 0x66, 0x71, 0x89, 0x90, 0x26, 0x17, 0x5b, + 0x46, 0x62, 0x71, 0x46, 0x6a, 0xb1, 0x04, 0xa3, 0x02, 0xb3, 0x06, 0xa7, 0x93, 0xe0, 0xa7, 0x7b, + 0xf2, 0xbc, 0x95, 0x89, 0xb9, 0x39, 0x56, 0x4a, 0x10, 0x71, 0xa5, 0x20, 0xa8, 0x02, 0x27, 0xf7, + 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, + 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, 0x4d, 0xcf, 0x2c, 0xc9, 0x28, + 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x2f, 0x4e, 0xcd, 0xd4, 0x85, 0xb9, 0x06, 0xcc, 0x01, 0x3b, + 0x47, 0xbf, 0x42, 0x1f, 0xee, 0xec, 0x24, 0x36, 0xb0, 0xbc, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, + 0x04, 0x5a, 0x09, 0xa5, 0xca, 0x00, 0x00, 0x00, +} + +func (m *Whitelist) 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 *Whitelist) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Whitelist) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Hashes) > 0 { + for iNdEx := len(m.Hashes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Hashes[iNdEx]) + copy(dAtA[i:], m.Hashes[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Hashes[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Whitelist) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Hashes) > 0 { + for _, s := range m.Hashes { + l = len(s) + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Whitelist) 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 ErrIntOverflowTypes + } + 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: Whitelist: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Whitelist: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Hashes", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Hashes = append(m.Hashes, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTypes + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/evm/types/whitelist.go b/x/evm/types/whitelist.go new file mode 100644 index 0000000000..6a06b603c7 --- /dev/null +++ b/x/evm/types/whitelist.go @@ -0,0 +1,12 @@ +package types + +import "github.com/ethereum/go-ethereum/common" + +func (w *Whitelist) IsHashInWhiteList(h common.Hash) bool { + for _, s := range w.Hashes { + if s == h.Hex() { + return true + } + } + return false +} diff --git a/x/mint/keeper/genesis_test.go b/x/mint/keeper/genesis_test.go index 5cd8368773..540862b939 100644 --- a/x/mint/keeper/genesis_test.go +++ b/x/mint/keeper/genesis_test.go @@ -13,7 +13,7 @@ import ( ) func TestGenesis(t *testing.T) { - app := app.Setup(false) + app := app.Setup(false, false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) now := time.Now() diff --git a/x/mint/keeper/grpc_query_test.go b/x/mint/keeper/grpc_query_test.go index e35670dedd..1898a88f82 100644 --- a/x/mint/keeper/grpc_query_test.go +++ b/x/mint/keeper/grpc_query_test.go @@ -25,7 +25,7 @@ type MintTestSuite struct { } func (suite *MintTestSuite) SetupTest() { - app := app.Setup(false) + app := app.Setup(false, false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry()) diff --git a/x/mint/keeper/integration_test.go b/x/mint/keeper/integration_test.go index 32f43acdaf..8f70639ce0 100644 --- a/x/mint/keeper/integration_test.go +++ b/x/mint/keeper/integration_test.go @@ -10,7 +10,7 @@ import ( // returns context and an app with updated mint keeper func createTestApp(isCheckTx bool) (*app.App, sdk.Context) { - app := app.Setup(isCheckTx) + app := app.Setup(isCheckTx, false) ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{}) app.MintKeeper.SetParams(ctx, types.DefaultParams()) diff --git a/x/mint/module_test.go b/x/mint/module_test.go index 4477cd3222..a0499b035d 100644 --- a/x/mint/module_test.go +++ b/x/mint/module_test.go @@ -32,7 +32,7 @@ func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { } func TestNewProposalHandler(t *testing.T) { - app := app.Setup(false) + app := app.Setup(false, false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) app.MintKeeper.SetParams(ctx, types.DefaultParams()) diff --git a/x/mint/types/minter_test.go b/x/mint/types/minter_test.go index 8106752b8d..227614b105 100644 --- a/x/mint/types/minter_test.go +++ b/x/mint/types/minter_test.go @@ -421,7 +421,7 @@ func TestRecordSuccessfulMint(t *testing.T) { sdk.DefaultBondDenom, 1000, ) - app := app.Setup(false) + app := app.Setup(false, false) ctx := app.BaseApp.NewContext(false, tmproto.Header{}) currentTime := time.Now().UTC() diff --git a/x/oracle/types/test_utils.go b/x/oracle/types/test_utils.go index 5aae985ba7..78e0968aa3 100755 --- a/x/oracle/types/test_utils.go +++ b/x/oracle/types/test_utils.go @@ -24,17 +24,17 @@ func GenerateRandomTestCase() (rates []float64, valValAddrs []sdk.ValAddress, st base := math.Pow10(OracleDecPrecision) - rand.Seed(int64(time.Now().Nanosecond())) - numInputs := 10 + (rand.Int() % 100) + r := rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) + numInputs := 10 + (r.Int() % 100) for i := 0; i < numInputs; i++ { - rate := float64(int64(rand.Float64()*base)) / base + rate := float64(int64(r.Float64()*base)) / base rates = append(rates, rate) pubKey := secp256k1.GenPrivKey().PubKey() valValAddr := sdk.ValAddress(pubKey.Address()) valValAddrs = append(valValAddrs, valValAddr) - power := rand.Int63()%1000 + 1 + power := r.Int63()%1000 + 1 mockValidator := NewMockValidator(valValAddr, power) mockValidators = append(mockValidators, mockValidator) } diff --git a/x/tokenfactory/keeper/migrations.go b/x/tokenfactory/keeper/migrations.go index dafa9416d3..b58f47c09f 100644 --- a/x/tokenfactory/keeper/migrations.go +++ b/x/tokenfactory/keeper/migrations.go @@ -54,7 +54,6 @@ func (m Migrator) Migrate3to4(ctx sdk.Context) error { fmt.Printf("Migrating denom: %s\n", denom) m.SetMetadata(&denomMetadata) m.keeper.bankKeeper.SetDenomMetaData(ctx, denomMetadata) - } return nil } diff --git a/x/tokenfactory/keeper/migrations_test.go b/x/tokenfactory/keeper/migrations_test.go index 4f75273ad1..860d5a6b9c 100644 --- a/x/tokenfactory/keeper/migrations_test.go +++ b/x/tokenfactory/keeper/migrations_test.go @@ -1,10 +1,12 @@ package keeper import ( - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "strings" "testing" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/store" @@ -20,11 +22,13 @@ import ( func TestMigrate2to3(t *testing.T) { storeKey := sdk.NewKVStoreKey(types.StoreKey) + bankstorekey := sdk.NewKVStoreKey(banktypes.StoreKey) memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) db := tmdb.NewMemDB() stateStore := store.NewCommitMultiStore(db) stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) + stateStore.MountStoreWithDB(bankstorekey, sdk.StoreTypeIAVL, db) stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) require.NoError(t, stateStore.LoadLatestVersion()) @@ -55,7 +59,7 @@ func TestMigrate2to3(t *testing.T) { store.Set(oldCreatorSpecificPrefix, []byte("garbage value whitelist creator")) require.True(t, store.Has(oldCreateDenomFeeWhitelistPrefix)) require.True(t, store.Has(oldCreatorSpecificPrefix)) - newKeeper := NewKeeper(cdc, storeKey, paramsSubspace, nil, nil, nil) + newKeeper := NewKeeper(cdc, storeKey, paramsSubspace, nil, bankkeeper.NewBaseKeeper(cdc, bankstorekey, nil, paramsSubspace, nil), nil) m := NewMigrator(newKeeper) err := m.Migrate2to3(ctx) require.Nil(t, err) @@ -66,6 +70,11 @@ func TestMigrate2to3(t *testing.T) { params := types.Params{} paramsSubspace.GetParamSet(ctx, ¶ms) require.Equal(t, types.Params{}, params) + + m.keeper.addDenomFromCreator(ctx, "creator", "test_denom") + m.keeper.bankKeeper.SetDenomMetaData(ctx, banktypes.Metadata{Base: "test_denom", Name: "test_denom", Symbol: "test_denom"}) + err = m.Migrate3to4(ctx) + require.Nil(t, err) } func TestMigrate3To4(t *testing.T) { diff --git a/x/tokenfactory/types/events.go b/x/tokenfactory/types/events.go index bae168d958..e1492e1b0b 100644 --- a/x/tokenfactory/types/events.go +++ b/x/tokenfactory/types/events.go @@ -4,9 +4,10 @@ package types // event types // nolint const ( - AttributeAmount = "amount" - AttributeCreator = "creator" - AttributeSubdenom = "subdenom" + AttributeAmount = "amount" + AttributeCreator = "creator" + AttributeSubdenom = "subdenom" + //nolint:gosec AttributeNewTokenDenom = "new_token_denom" AttributeMintToAddress = "mint_to_address" AttributeBurnFromAddress = "burn_from_address" diff --git a/x/tokenfactory/types/query.pb.go b/x/tokenfactory/types/query.pb.go index 9970bd0754..b1c6dade3b 100644 --- a/x/tokenfactory/types/query.pb.go +++ b/x/tokenfactory/types/query.pb.go @@ -344,7 +344,7 @@ func (m *QueryDenomMetadataRequest) GetDenom() string { return "" } -// QueryDenomMetadataResponse is the response type for the Query/DenomMetadata RPC +// QueryDenomMetadataResponse is the response type for the Query/DenomMetadata gRPC // method. type QueryDenomMetadataResponse struct { // metadata describes and provides all the client information for the requested token.