From 4437ab1f398607defb3cbf4a87fb900ba7233bcc Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Wed, 2 Oct 2024 09:24:43 -0400 Subject: [PATCH 01/25] Update go, fedora in dockerfile --- tests/container-scripts/run-testnet.sh | 74 -------------------------- tests/dockerfile/Dockerfile | 7 +-- 2 files changed, 4 insertions(+), 77 deletions(-) delete mode 100755 tests/container-scripts/run-testnet.sh diff --git a/tests/container-scripts/run-testnet.sh b/tests/container-scripts/run-testnet.sh deleted file mode 100755 index c377c9a7..00000000 --- a/tests/container-scripts/run-testnet.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash -set -eux -# your gaiad binary name -BIN=althea - -NODES=$1 - -for i in $(seq 1 $NODES); -do - # add this ip for loopback dialing - ip addr add 7.7.7.$i/32 dev eth0 || true # allowed to fail - - GAIA_HOME="--home /validator$i" - # this implicitly caps us at ~6000 nodes for this sim - # note that we start on 26656 the idea here is that the first - # node (node 1) is at the expected contact address from the gentx - # faciliating automated peer exchange - if [[ "$i" -eq 1 ]]; then - # node one gets localhost so we can easily shunt these ports - # to the docker host - RPC_ADDRESS="--rpc.laddr tcp://0.0.0.0:26657" - GRPC_ADDRESS="--grpc.address 0.0.0.0:9090" - GRPC_WEB_ADDRESS="--grpc-web.address 0.0.0.0:9092" - ETH_RPC_ADDRESS="--json-rpc.address 0.0.0.0:8545" - ETH_RPC_WS_ADDRESS="--json-rpc.ws-address 0.0.0.0:8546" - sed -i 's/enable-unsafe-cors = false/enable-unsafe-cors = true/g' /validator$i/config/app.toml - sed -i 's/enabled-unsafe-cors = false/enabled-unsafe-cors = true/g' /validator$i/config/app.toml - sed -i 's/enable = false/enable = true/g' /validator$i/config/app.toml #enables more than we want, but will work for now - else - # move these to another port and address, not becuase they will - # be used there, but instead to prevent them from causing problems - # you also can't duplicate the port selection against localhost - # for reasons that are not clear to me right now. - RPC_ADDRESS="--rpc.laddr tcp://7.7.7.$i:26658" - GRPC_ADDRESS="--grpc.address 7.7.7.$i:9091" - GRPC_WEB_ADDRESS="--grpc-web.address 7.7.7.$i:9093" - ETH_RPC_ADDRESS="--json-rpc.address 7.7.7.$i:8545" - ETH_RPC_WS_ADDRESS="--json-rpc.address 7.7.7.$i:8546" - fi - LISTEN_ADDRESS="--address tcp://7.7.7.$i:26655" - P2P_ADDRESS="--p2p.laddr tcp://7.7.7.$i:26656" - LOG_LEVEL="--log_level info" - INVARIANTS_CHECK="--inv-check-period 1" - ARGS="$GAIA_HOME $LISTEN_ADDRESS $RPC_ADDRESS $GRPC_ADDRESS $GRPC_WEB_ADDRESS $ETH_RPC_ADDRESS $ETH_RPC_WS_ADDRESS $INVARIANTS_CHECK $LOG_LEVEL $P2P_ADDRESS" - $BIN $ARGS start &> /validator$i/logs & -done - -# Setup the IBC test chain (chain id ibc-test-1) using gaiad as the binary -# Creates the same number of validators as the althea chain above, with their home directories at /ibc-validator# -BIN=gaiad -for i in $(seq 1 $NODES); -do - ip addr add 7.7.8.$i/32 dev eth0 || true # allowed to fail - - GAIA_HOME="--home /ibc-validator$i" - if [[ "$i" -eq 1 ]]; then - # node one gets localhost so we can easily shunt these ports - # to the docker host - RPC_ADDRESS="--rpc.laddr tcp://0.0.0.0:27657" - GRPC_ADDRESS="--grpc.address 0.0.0.0:9190" - # Must remap the grpc-web address because it conflicts with what we want to use - GRPC_WEB_ADDRESS="--grpc-web.address 0.0.0.0:9192" - else - RPC_ADDRESS="--rpc.laddr tcp://7.7.8.$i:26658" - GRPC_ADDRESS="--grpc.address 7.7.8.$i:9091" - # Must remap the grpc-web address because it conflicts with what we want to use - GRPC_WEB_ADDRESS="--grpc-web.address 7.7.8.$i:9093" - fi - LISTEN_ADDRESS="--address tcp://7.7.8.$i:26655" - P2P_ADDRESS="--p2p.laddr tcp://7.7.8.$i:26656" - LOG_LEVEL="--log_level info" - ARGS="$GAIA_HOME $LISTEN_ADDRESS $RPC_ADDRESS $GRPC_ADDRESS $GRPC_WEB_ADDRESS $LOG_LEVEL $P2P_ADDRESS" - $BIN $ARGS start &> /ibc-validator$i/logs & -done \ No newline at end of file diff --git a/tests/dockerfile/Dockerfile b/tests/dockerfile/Dockerfile index 5d00f446..44ae817b 100755 --- a/tests/dockerfile/Dockerfile +++ b/tests/dockerfile/Dockerfile @@ -1,8 +1,9 @@ -FROM fedora:37 +FROM fedora:40 ENV GOPATH=/go ENV PATH=$PATH:/go/bin -RUN dnf install -y git make gcc gcc-c++ which iproute iputils procps-ng vim-minimal tmux net-tools htop tar jq npm openssl-devel perl rust cargo golang wget - +RUN dnf install -y git make gcc gcc-c++ which iproute iputils procps-ng vim-minimal tmux net-tools htop tar jq npm openssl-devel perl rust cargo wget +COPY --from=golang:1.22 /usr/local/go/ /usr/local/go/ +ENV PATH="/usr/local/go/bin:${PATH}" # Download the althea gaia fork as a IBC test chain ADD https://github.com/althea-net/ibc-test-chain/releases/download/v9.1.5/gaiad-v9.1.5-linux-amd64 /usr/bin/gaiad # Setup Hermes for IBC connections between chains From 85b8bd9ec405f8494a0bcd3d255fb1b012439830 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Tue, 1 Oct 2024 14:53:18 -0400 Subject: [PATCH 02/25] Upgrade SDK to v0.46.16, IBC to 6.3.1, Ethermint to v0.22, add upgrade --- .github/workflows/integration-tests.yml | 16 + app/ante/handler_options.go | 85 +- app/ante/utils_test.go | 16 +- app/app.go | 367 ++++-- app/migrate.go | 8 +- app/sigverify.go | 2 +- app/upgrades/neutrino/README.md | 9 + app/upgrades/neutrino/handler.go | 32 + app/upgrades/register.go | 26 + cmd/althea/genaccounts.go | 9 +- cmd/althea/root.go | 61 +- cmd/althea/testnet.go | 17 +- go.mod | 242 ++-- go.sum | 1100 +++++++++++------ ibcutils/testing/app.go | 11 +- ibcutils/testing/chain.go | 20 +- ibcutils/testing/config.go | 10 +- ibcutils/testing/endpoint.go | 14 +- ibcutils/testing/events.go | 6 +- ibcutils/testing/path.go | 2 +- ibcutils/testing/values.go | 8 +- ibcutils/utils.go | 4 +- ibcutils/utils_test.go | 6 +- integration_tests/test_runner/src/bin/main.rs | 23 + .../test_runner/src/tests/mod.rs | 1 + .../test_runner/src/tests/upgrade.rs | 169 +++ .../manual-upgrade-test-internal.sh | 58 + tests/container-scripts/run-testnet.sh | 95 ++ tests/container-scripts/setup-validators.sh | 10 + tests/container-scripts/start-dlv.sh | 7 + .../upgrade-test-internal.sh | 53 + tests/manual-upgrade-test.sh | 31 + tests/run-upgrade-test.sh | 37 + x/gasfree/keeper/keeper.go | 5 +- x/lockup/ante.go | 2 +- x/lockup/ante_test.go | 26 +- x/lockup/keeper/keeper.go | 5 +- x/lockup/keeper/test_common.go | 39 +- x/lockup/types/genesis.go | 2 +- x/microtx/keeper/keeper.go | 7 +- x/microtx/keeper/liquid_account.go | 2 +- x/microtx/types/msgs.go | 2 +- x/nativedex/client/cli/utils.go | 6 +- x/nativedex/client/proposal_handler.go | 17 + x/nativedex/keeper/keeper.go | 5 +- x/nativedex/proposal_handler.go | 6 +- x/nativedex/types/codec.go | 4 +- x/nativedex/types/proposal.go | 71 +- x/onboarding/ibc_middleware.go | 17 +- x/onboarding/ibc_module_test.go | 14 +- x/onboarding/keeper/ibc_callbacks.go | 8 +- x/onboarding/keeper/ibc_callbacks_test.go | 38 +- x/onboarding/keeper/keeper.go | 20 +- x/onboarding/keeper/utils_test.go | 4 +- x/onboarding/testutil/helpers.go | 2 +- x/onboarding/types/interfaces.go | 8 +- 56 files changed, 1978 insertions(+), 887 deletions(-) create mode 100644 app/upgrades/neutrino/README.md create mode 100644 app/upgrades/neutrino/handler.go create mode 100644 app/upgrades/register.go create mode 100644 integration_tests/test_runner/src/tests/upgrade.rs create mode 100755 tests/container-scripts/manual-upgrade-test-internal.sh create mode 100755 tests/container-scripts/run-testnet.sh create mode 100755 tests/container-scripts/start-dlv.sh create mode 100755 tests/container-scripts/upgrade-test-internal.sh create mode 100755 tests/manual-upgrade-test.sh create mode 100755 tests/run-upgrade-test.sh create mode 100644 x/nativedex/client/proposal_handler.go diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 013a9f44..2ade30ea 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -216,3 +216,19 @@ jobs: run: tests/all-up-test.sh DEX_OPS_PROPOSAL env: NO_IMAGE_BUILD: True + UPGRADE: + needs: native_token + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: jpribyl/action-docker-layer-caching@v0.1.1 + with: + key: integration-test-cache-{hash} + restore-keys: | + integration-test-cache- + - name: Tests the nativedex OpsProposal function + run: tests/all-up-test.sh DEX_OPS_PROPOSAL + - name: Tests the Neutrino + run: tests/run-upgrade-test.sh v1.4.0 + env: + NO_IMAGE_BUILD: True diff --git a/app/ante/handler_options.go b/app/ante/handler_options.go index 65202cfe..226c15cb 100644 --- a/app/ante/handler_options.go +++ b/app/ante/handler_options.go @@ -1,7 +1,10 @@ package ante import ( + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/tx/signing" @@ -9,12 +12,14 @@ import ( authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ibcante "github.com/cosmos/ibc-go/v6/modules/core/ante" + ibckeeper "github.com/cosmos/ibc-go/v6/modules/core/keeper" ethante "github.com/evmos/ethermint/app/ante" + ethtypes "github.com/evmos/ethermint/types" evmkeeper "github.com/evmos/ethermint/x/evm/keeper" evmtypes "github.com/evmos/ethermint/x/evm/types" + feemarketkeeper "github.com/evmos/ethermint/x/feemarket/keeper" "github.com/AltheaFoundation/althea-L1/x/gasfree" gasfreekeeper "github.com/AltheaFoundation/althea-L1/x/gasfree/keeper" @@ -24,42 +29,42 @@ import ( // HandlerOptions defines the list of module keepers required to run the canto // AnteHandler decorators. type HandlerOptions struct { - AccountKeeper AccountKeeper - BankKeeper evmtypes.BankKeeper - IBCKeeper *ibckeeper.Keeper - FeeMarketKeeper evmtypes.FeeMarketKeeper - EvmKeeper *evmkeeper.Keeper - FeegrantKeeper ante.FeegrantKeeper - SignModeHandler authsigning.SignModeHandler - SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error - Cdc codec.BinaryCodec - MaxTxGasWanted uint64 - GasfreeKeeper *gasfreekeeper.Keeper - MicrotxKeeper *microtxkeeper.Keeper + AccountKeeper AccountKeeper + BankKeeper evmtypes.BankKeeper + IBCKeeper *ibckeeper.Keeper + FeeMarketKeeper feemarketkeeper.Keeper + EvmKeeper *evmkeeper.Keeper + FeegrantKeeper ante.FeegrantKeeper + SignModeHandler authsigning.SignModeHandler + SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error + MaxTxGasWanted uint64 + ExtensionOptionChecker ante.ExtensionOptionChecker + TxFeeChecker ante.TxFeeChecker + DisabledAuthzMsgs []string + Cdc codec.BinaryCodec + GasfreeKeeper *gasfreekeeper.Keeper + MicrotxKeeper *microtxkeeper.Keeper } // Validate checks if the keepers are defined func (options HandlerOptions) Validate() error { if options.AccountKeeper == nil { - return sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler") + return errorsmod.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler") } if options.BankKeeper == nil { - return sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for AnteHandler") + return errorsmod.Wrap(sdkerrors.ErrLogic, "bank keeper is required for AnteHandler") } if options.SignModeHandler == nil { - return sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") - } - if options.FeeMarketKeeper == nil { - return sdkerrors.Wrap(sdkerrors.ErrLogic, "fee market keeper is required for AnteHandler") + return errorsmod.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") } if options.EvmKeeper == nil { - return sdkerrors.Wrap(sdkerrors.ErrLogic, "evm keeper is required for AnteHandler") + return errorsmod.Wrap(sdkerrors.ErrLogic, "evm keeper is required for AnteHandler") } if options.GasfreeKeeper == nil { - return sdkerrors.Wrap(sdkerrors.ErrLogic, "gasfree keeper is required for AnteHandler") + return errorsmod.Wrap(sdkerrors.ErrLogic, "gasfree keeper is required for AnteHandler") } if options.MicrotxKeeper == nil { - return sdkerrors.Wrap(sdkerrors.ErrLogic, "microtx keeper is required for AnteHandler") + return errorsmod.Wrap(sdkerrors.ErrLogic, "microtx keeper is required for AnteHandler") } return nil } @@ -83,22 +88,33 @@ func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler { ) } +func CosmosExtensionOptionChecker(any *codectypes.Any) bool { + a := ethtypes.HasDynamicFeeExtensionOption(any) + b := hasEIP712ExtensionOption(any) + + return a || b +} + +func hasEIP712ExtensionOption(any *codectypes.Any) bool { + _, ok := any.GetCachedValue().(*ethtypes.ExtensionOptionsWeb3Tx) + return ok +} + // newCosmosAnteHandler creates the default ante handler for Cosmos transactions func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { return sdk.ChainAnteDecorators( ethante.RejectMessagesDecorator{}, // reject MsgEthereumTxs + ethante.NewAuthzLimiterDecorator(options.DisabledAuthzMsgs), ante.NewSetUpContextDecorator(), - ante.NewRejectExtensionOptionsDecorator(), + ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), ante.NewValidateBasicDecorator(), - // Gasfree txs ignore the mempool fee requirement - gasfree.NewSelectiveBypassDecorator(*options.GasfreeKeeper, ante.NewMempoolFeeDecorator()), + ante.NewTxTimeoutHeightDecorator(), // Gasfree txs ignore the min gas price requirement gasfree.NewSelectiveBypassDecorator(*options.GasfreeKeeper, ethante.NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper)), - ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), // Gasfree txs do not have fees deducted the normal way, their fees will be deducted separately - gasfree.NewSelectiveBypassDecorator(*options.GasfreeKeeper, ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper)), + gasfree.NewSelectiveBypassDecorator(*options.GasfreeKeeper, ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, nil)), // Charge gas fees for gasfree messages NewChargeGasfreeFeesDecorator(options.AccountKeeper, *options.GasfreeKeeper, *options.MicrotxKeeper), NewValidatorCommissionDecorator(options.Cdc), @@ -108,7 +124,7 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), - ibcante.NewAnteDecorator(options.IBCKeeper), + ibcante.NewRedundantRelayDecorator(options.IBCKeeper), ethante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), NewSetAccountTypeDecorator(options.AccountKeeper, options.EvmKeeper.AccountProtoFn), ) @@ -118,23 +134,24 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { func newCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler { return sdk.ChainAnteDecorators( ethante.RejectMessagesDecorator{}, // reject MsgEthereumTxs + ethante.NewAuthzLimiterDecorator(options.DisabledAuthzMsgs), ante.NewSetUpContextDecorator(), - ante.NewMempoolFeeDecorator(), + ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), ante.NewValidateBasicDecorator(), - ethante.NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), ante.NewTxTimeoutHeightDecorator(), + ethante.NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), + ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, nil), NewValidatorCommissionDecorator(options.Cdc), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), // Note: signature verification uses EIP instead of the cosmos signature validator - ethante.NewEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler, ""), // Pass no chain id to have it parsed from the Cosmos chain id + ethante.NewLegacyEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler, ""), // Pass no chain id to have it parsed from the Cosmos chain id ante.NewIncrementSequenceDecorator(options.AccountKeeper), - ibcante.NewAnteDecorator(options.IBCKeeper), + ibcante.NewRedundantRelayDecorator(options.IBCKeeper), ethante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), NewSetAccountTypeDecorator(options.AccountKeeper, options.EvmKeeper.AccountProtoFn), ) diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index faf18774..34ab2289 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + apitypes "github.com/ethereum/go-ethereum/signer/core/apitypes" "github.com/stretchr/testify/suite" client "github.com/cosmos/cosmos-sdk/client" @@ -22,7 +23,7 @@ import ( "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx/signing" - "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -39,7 +40,7 @@ import ( evmtypes "github.com/evmos/ethermint/x/evm/types" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" - cantoante "github.com/Canto-Network/Canto/v5/app/ante" + cantoante "github.com/Canto-Network/Canto/v6/app/ante" althea "github.com/AltheaFoundation/althea-L1/app" ante "github.com/AltheaFoundation/althea-L1/app/ante" @@ -119,12 +120,12 @@ func (suite *AnteTestSuite) SetupTest() { // Also make a copy of the old Canto antehandler we were using to ensure that our changes fix the problem // nolint: exhaustruct oldAnteHandler := cantoante.NewAnteHandler(cantoante.HandlerOptions{ - AccountKeeper: suite.app.AccountKeeper, + AccountKeeper: *suite.app.AccountKeeper, BankKeeper: suite.app.BankKeeper, EvmKeeper: suite.app.EvmKeeper, FeegrantKeeper: nil, IBCKeeper: suite.app.IbcKeeper, - FeeMarketKeeper: suite.app.FeemarketKeeper, + FeeMarketKeeper: *suite.app.FeemarketKeeper, SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), SigGasConsumer: althea.SigVerificationGasConsumer, }) @@ -390,13 +391,12 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder( fee := legacytx.NewStdFee(gas, gasAmount) accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber() - data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, []sdk.Msg{msg}, "") - typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msg, data, &eip712.FeeDelegationOptions{ + data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, []sdk.Msg{msg}, "", nil) + typedData, err := eip712.LegacyWrapTxToTypedData(ethermintCodec, ethChainId, msg, data, &eip712.FeeDelegationOptions{ FeePayer: from, }) suite.Require().NoError(err) - - sigHash, err := eip712.ComputeTypedDataHash(typedData) + sigHash, _, err := apitypes.TypedDataAndHash(typedData) suite.Require().NoError(err) // Sign typedData diff --git a/app/app.go b/app/app.go index 2ae94dc7..212951e9 100644 --- a/app/app.go +++ b/app/app.go @@ -21,23 +21,28 @@ import ( // Cosmos SDK "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" + nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" - "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/server/config" servertypes "github.com/cosmos/cosmos-sdk/server/types" "github.com/cosmos/cosmos-sdk/simapp" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/cosmos/cosmos-sdk/store/streaming" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + "github.com/cosmos/cosmos-sdk/x/auth/posthandler" authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/auth/vesting" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" "github.com/cosmos/cosmos-sdk/x/authz" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" @@ -60,8 +65,14 @@ import ( "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/cosmos-sdk/x/group" + groupkeeper "github.com/cosmos/cosmos-sdk/x/group/keeper" + groupmodule "github.com/cosmos/cosmos-sdk/x/group/module" "github.com/cosmos/cosmos-sdk/x/mint" mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" @@ -82,35 +93,38 @@ import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" // Cosmos IBC-Go - ica "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts" - icahost "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host" - icahostkeeper "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/keeper" - icahosttypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/host/types" - icatypes "github.com/cosmos/ibc-go/v4/modules/apps/27-interchain-accounts/types" - transfer "github.com/cosmos/ibc-go/v4/modules/apps/transfer" - ibctransferkeeper "github.com/cosmos/ibc-go/v4/modules/apps/transfer/keeper" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - ibc "github.com/cosmos/ibc-go/v4/modules/core" - ibcclient "github.com/cosmos/ibc-go/v4/modules/core/02-client" - ibcclientclient "github.com/cosmos/ibc-go/v4/modules/core/02-client/client" - ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" - ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" - ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + ica "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts" + icahost "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/host/keeper" + icahosttypes "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v6/modules/apps/27-interchain-accounts/types" + transfer "github.com/cosmos/ibc-go/v6/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v6/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v6/modules/core" + ibcclient "github.com/cosmos/ibc-go/v6/modules/core/02-client" + ibcclientclient "github.com/cosmos/ibc-go/v6/modules/core/02-client/client" + ibcclienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + ibchost "github.com/cosmos/ibc-go/v6/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v6/modules/core/keeper" + ibctesting "github.com/cosmos/ibc-go/v6/testing/types" // EVM + ERC20 - "github.com/Canto-Network/Canto/v5/x/erc20" - erc20client "github.com/Canto-Network/Canto/v5/x/erc20/client" - erc20keeper "github.com/Canto-Network/Canto/v5/x/erc20/keeper" - erc20types "github.com/Canto-Network/Canto/v5/x/erc20/types" + "github.com/Canto-Network/Canto/v6/x/erc20" + erc20client "github.com/Canto-Network/Canto/v6/x/erc20/client" + erc20keeper "github.com/Canto-Network/Canto/v6/x/erc20/keeper" + erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" + ethante "github.com/evmos/ethermint/app/ante" + "github.com/evmos/ethermint/ethereum/eip712" ethermintsrvflags "github.com/evmos/ethermint/server/flags" ethtypes "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm" - evmrest "github.com/evmos/ethermint/x/evm/client/rest" evmkeeper "github.com/evmos/ethermint/x/evm/keeper" evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/evmos/ethermint/x/evm/vm/geth" "github.com/evmos/ethermint/x/feemarket" feemarketkeeper "github.com/evmos/ethermint/x/feemarket/keeper" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" @@ -120,6 +134,8 @@ import ( "github.com/AltheaFoundation/althea-L1/app/ante" altheaappparams "github.com/AltheaFoundation/althea-L1/app/params" + "github.com/AltheaFoundation/althea-L1/app/upgrades" + "github.com/AltheaFoundation/althea-L1/app/upgrades/neutrino" altheacfg "github.com/AltheaFoundation/althea-L1/config" "github.com/AltheaFoundation/althea-L1/x/gasfree" gasfreekeeper "github.com/AltheaFoundation/althea-L1/x/gasfree/keeper" @@ -175,20 +191,23 @@ var ( mint.AppModuleBasic{}, distr.AppModuleBasic{}, gov.NewAppModuleBasic( - paramsclient.ProposalHandler, - distrclient.ProposalHandler, - upgradeclient.ProposalHandler, - upgradeclient.CancelProposalHandler, - ibcclientclient.UpdateClientProposalHandler, - ibcclientclient.UpgradeProposalHandler, - erc20client.RegisterCoinProposalHandler, - erc20client.RegisterERC20ProposalHandler, - erc20client.ToggleTokenConversionProposalHandler, + []govclient.ProposalHandler{ + paramsclient.ProposalHandler, + distrclient.ProposalHandler, + upgradeclient.LegacyProposalHandler, + upgradeclient.LegacyCancelProposalHandler, + ibcclientclient.UpdateClientProposalHandler, + ibcclientclient.UpgradeProposalHandler, + erc20client.RegisterCoinProposalHandler, + erc20client.RegisterERC20ProposalHandler, + erc20client.ToggleTokenConversionProposalHandler, + }, ), params.AppModuleBasic{}, crisis.AppModuleBasic{}, slashing.AppModuleBasic{}, ibc.AppModuleBasic{}, + // TODO: Add feegrant upgrade.AppModuleBasic{}, evidence.AppModuleBasic{}, transfer.AppModuleBasic{}, @@ -201,6 +220,7 @@ var ( erc20.AppModuleBasic{}, feemarket.AppModuleBasic{}, ica.AppModuleBasic{}, + groupmodule.AppModuleBasic{}, ) // module account permissions @@ -249,24 +269,25 @@ type AltheaApp struct { // nolint: golint invCheckPeriod uint // keys to access the substores - keys map[string]*sdk.KVStoreKey - tKeys map[string]*sdk.TransientStoreKey - memKeys map[string]*sdk.MemoryStoreKey + keys map[string]*storetypes.KVStoreKey + tKeys map[string]*storetypes.TransientStoreKey + memKeys map[string]*storetypes.MemoryStoreKey // keepers // NOTE: If you add anything to this struct, add a nil check to ValidateMembers below! - AccountKeeper *authkeeper.AccountKeeper - AuthzKeeper *authzkeeper.Keeper - BankKeeper *bankkeeper.BaseKeeper - CapabilityKeeper *capabilitykeeper.Keeper - StakingKeeper *stakingkeeper.Keeper - SlashingKeeper *slashingkeeper.Keeper - MintKeeper *mintkeeper.Keeper - DistrKeeper *distrkeeper.Keeper - GovKeeper *govkeeper.Keeper - CrisisKeeper *crisiskeeper.Keeper - UpgradeKeeper *upgradekeeper.Keeper - ParamsKeeper *paramskeeper.Keeper + AccountKeeper *authkeeper.AccountKeeper + AuthzKeeper *authzkeeper.Keeper + BankKeeper *bankkeeper.BaseKeeper + CapabilityKeeper *capabilitykeeper.Keeper + StakingKeeper *stakingkeeper.Keeper + SlashingKeeper *slashingkeeper.Keeper + MintKeeper *mintkeeper.Keeper + DistrKeeper *distrkeeper.Keeper + GovKeeper *govkeeper.Keeper + CrisisKeeper *crisiskeeper.Keeper + UpgradeKeeper *upgradekeeper.Keeper + ParamsKeeper *paramskeeper.Keeper + // TODO: Add feegrant IbcKeeper *ibckeeper.Keeper EvidenceKeeper *evidencekeeper.Keeper IbcTransferKeeper *ibctransferkeeper.Keeper @@ -274,6 +295,7 @@ type AltheaApp struct { // nolint: golint Erc20Keeper *erc20keeper.Keeper FeemarketKeeper *feemarketkeeper.Keeper IcaHostKeeper *icahostkeeper.Keeper + GroupKeeper *groupkeeper.Keeper LockupKeeper *lockupkeeper.Keeper MicrotxKeeper *microtxkeeper.Keeper @@ -364,6 +386,9 @@ func (app AltheaApp) ValidateMembers() { if app.IcaHostKeeper == nil { panic("Nil IcaHostKeeper!") } + if app.GroupKeeper == nil { + panic("Nil GroupKeeper!") + } if app.LockupKeeper == nil { panic("Nil LockupKeeper!") @@ -417,6 +442,8 @@ func NewAltheaApp( legacyAmino := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry + eip712.SetEncodingConfig(simappparams.EncodingConfig(encodingConfig)) + // Baseapp initialization, provides correct implementation of ABCI layer, I/O services, state storage, and more bApp := *baseapp.NewBaseApp(Name, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) @@ -431,7 +458,8 @@ func NewAltheaApp( ibchost.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, erc20types.StoreKey, evmtypes.StoreKey, feemarkettypes.StoreKey, - icahosttypes.StoreKey, + icahosttypes.StoreKey, group.StoreKey, + // TODO: Add feegrant lockuptypes.StoreKey, microtxtypes.StoreKey, gasfreetypes.StoreKey, onboardingtypes.StoreKey, nativedextypes.StoreKey, @@ -444,6 +472,12 @@ func NewAltheaApp( // bidirectional capability references for efficient lookup, but the KV store only contains a one-way mapping memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + // load state streaming if enabled + if _, _, err := streaming.LoadStreamingServices(&bApp, appOpts, appCodec, keys); err != nil { + fmt.Printf("failed to load state streaming: %s", err) + os.Exit(1) + } + // nolint: exhaustruct app := &AltheaApp{ BaseApp: &bApp, @@ -466,7 +500,7 @@ func NewAltheaApp( paramsKeeper := initParamsKeeper(appCodec, legacyAmino, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey]) app.ParamsKeeper = ¶msKeeper - bApp.SetParamStore(paramsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramskeeper.ConsensusParamsKeyTable())) + bApp.SetParamStore(paramsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramstypes.ConsensusParamsKeyTable())) // Capability keeper has the function to create "Scoped Keepers" which partition the capabilities a module is aware of // for security. Create all Scoped Keepers between here and the capabilityKeeper.Seal() call below. @@ -495,6 +529,7 @@ func NewAltheaApp( app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms, + altheacfg.Bech32PrefixAccAddr, ) app.AccountKeeper = &accountKeeper @@ -502,6 +537,7 @@ func NewAltheaApp( keys[authzkeeper.StoreKey], appCodec, bApp.MsgServiceRouter(), + accountKeeper, ) app.AuthzKeeper = &authzKeeper @@ -531,7 +567,6 @@ func NewAltheaApp( bankKeeper, stakingKeeper, authtypes.FeeCollectorName, - app.ModuleAccountAddrs(), ) app.DistrKeeper = &distrKeeper @@ -549,6 +584,7 @@ func NewAltheaApp( appCodec, homePath, &bApp, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) app.UpgradeKeeper = &upgradeKeeper @@ -566,23 +602,29 @@ func NewAltheaApp( tracer := cast.ToString(appOpts.Get(ethermintsrvflags.EVMTracer)) // Feemarket implements EIP-1559 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) on Cosmos + fmSs := app.GetSubspace(feemarkettypes.ModuleName) feemarketKeeper := feemarketkeeper.NewKeeper( - appCodec, app.GetSubspace(feemarkettypes.ModuleName), + appCodec, + authtypes.NewModuleAddress(govtypes.ModuleName), keys[feemarkettypes.StoreKey], tkeys[feemarkettypes.TransientKey], + fmSs, ) app.FeemarketKeeper = &feemarketKeeper // EVM calls the go-ethereum source code within ABCI to implement an EVM within Althea Chain + evmSs := app.GetSubspace(evmtypes.ModuleName) evmKeeper := *evmkeeper.NewKeeper( appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey], - app.GetSubspace(evmtypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName), accountKeeper, bankKeeper, stakingKeeper, feemarketKeeper, + nil, geth.NewEVM, tracer, + evmSs, ethtypes.ProtoAccountWithAddress, ) @@ -619,7 +661,7 @@ func NewAltheaApp( icaHostKeeper := icahostkeeper.NewKeeper( appCodec, keys[icahosttypes.StoreKey], app.GetSubspace(icahosttypes.SubModuleName), - ibcKeeper.ChannelKeeper, &ibcKeeper.PortKeeper, + ibcKeeper.ChannelKeeper, ibcKeeper.ChannelKeeper, &ibcKeeper.PortKeeper, accountKeeper, scopedICAHostKeeper, app.MsgServiceRouter(), ) app.IcaHostKeeper = &icaHostKeeper @@ -669,6 +711,8 @@ func NewAltheaApp( ) app.CrisisKeeper = &crisisKeeper + // TODO: add feegrant keeper + // Nativedex allows management of the native DEX instance from the Cosmos side nativedexKeeper := nativedexkeeper.NewKeeper( keys[nativedextypes.StoreKey], appCodec, app.GetSubspace(nativedextypes.ModuleName), @@ -677,8 +721,8 @@ func NewAltheaApp( app.NativedexKeeper = &nativedexKeeper // Register custom governance proposal logic via router keys and handler functions - govRouter := govtypes.NewRouter() - govRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). + govRouter := govv1beta1.NewRouter() + govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler). AddRoute(paramsproposal.RouterKey, params.NewParamChangeProposalHandler(paramsKeeper)). AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(distrKeeper)). AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(upgradeKeeper)). @@ -686,6 +730,7 @@ func NewAltheaApp( AddRoute(erc20types.RouterKey, erc20.NewErc20ProposalHandler(&erc20Keeper)). AddRoute(nativedextypes.RouterKey, nativedex.NewNativeDexProposalHandler(&nativedexKeeper)) + govConfig := govtypes.DefaultConfig() govKeeper := govkeeper.NewKeeper( appCodec, keys[govtypes.StoreKey], @@ -694,7 +739,13 @@ func NewAltheaApp( bankKeeper, stakingKeeper, govRouter, + app.MsgServiceRouter(), + govConfig, ) + govKeeper = *govKeeper.SetHooks(govtypes.NewMultiGovHooks( + // Register any governance hooks here + )) + app.GovKeeper = &govKeeper evidenceKeeper := *evidencekeeper.NewKeeper( @@ -705,6 +756,10 @@ func NewAltheaApp( ) app.EvidenceKeeper = &evidenceKeeper + groupConfig := group.DefaultConfig() + groupKeeper := groupkeeper.NewKeeper(keys[group.StoreKey], appCodec, app.MsgServiceRouter(), app.AccountKeeper, groupConfig) + app.GroupKeeper = &groupKeeper + // Althea custom modules // Lockup locks the chain at genesis to prevent native token transfers before the chain is sufficiently decentralized @@ -745,6 +800,7 @@ func NewAltheaApp( accountKeeper, nil, ), + vesting.NewAppModule(accountKeeper, bankKeeper), authzmodule.NewAppModule( appCodec, authzKeeper, @@ -765,6 +821,7 @@ func NewAltheaApp( &crisisKeeper, skipGenesisInvariants, ), + // TODO: Add feegrant app module gov.NewAppModule( appCodec, govKeeper, @@ -775,6 +832,7 @@ func NewAltheaApp( appCodec, mintKeeper, accountKeeper, + nil, ), slashing.NewAppModule( appCodec, @@ -790,7 +848,8 @@ func NewAltheaApp( bankKeeper, stakingKeeper, ), - staking.NewAppModule(appCodec, + staking.NewAppModule( + appCodec, stakingKeeper, accountKeeper, bankKeeper, @@ -800,15 +859,16 @@ func NewAltheaApp( ibc.NewAppModule(&ibcKeeper), params.NewAppModule(paramsKeeper), ibcTransferAppModule, - evm.NewAppModule(&evmKeeper, accountKeeper), + feemarket.NewAppModule(feemarketKeeper, fmSs), + evm.NewAppModule(&evmKeeper, accountKeeper, evmSs), erc20.NewAppModule(erc20Keeper, accountKeeper), - feemarket.NewAppModule(feemarketKeeper), icaAppModule, gasfree.NewAppModule(gasfreeKeeper), lockup.NewAppModule(lockupKeeper, bankKeeper), microtx.NewAppModule(microtxKeeper, accountKeeper), onboarding.NewAppModule(onboardingKeeper), nativedex.NewAppModule(nativedexKeeper, accountKeeper), + groupmodule.NewAppModule(appCodec, groupKeeper, accountKeeper, bankKeeper, interfaceRegistry), ) app.MM = &mm @@ -830,14 +890,16 @@ func NewAltheaApp( evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName, + ibctransfertypes.ModuleName, + authtypes.ModuleName, banktypes.ModuleName, + govtypes.ModuleName, crisistypes.ModuleName, - authtypes.ModuleName, - ibctransfertypes.ModuleName, genutiltypes.ModuleName, authz.ModuleName, - govtypes.ModuleName, + //TODO: Add feegrant paramstypes.ModuleName, + vestingtypes.ModuleName, gasfreetypes.ModuleName, lockuptypes.ModuleName, microtxtypes.ModuleName, @@ -845,6 +907,7 @@ func NewAltheaApp( onboardingtypes.ModuleName, nativedextypes.ModuleName, icatypes.ModuleName, + group.ModuleName, ) // Determine the order in which modules' EndBlock() functions are called each block @@ -853,28 +916,31 @@ func NewAltheaApp( crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName, - icatypes.ModuleName, - evmtypes.ModuleName, feemarkettypes.ModuleName, - upgradetypes.ModuleName, + evmtypes.ModuleName, + erc20types.ModuleName, + ibchost.ModuleName, + ibctransfertypes.ModuleName, + icatypes.ModuleName, capabilitytypes.ModuleName, - minttypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, - evidencetypes.ModuleName, - onboardingtypes.ModuleName, - ibchost.ModuleName, - banktypes.ModuleName, - authtypes.ModuleName, - ibctransfertypes.ModuleName, + minttypes.ModuleName, genutiltypes.ModuleName, + evidencetypes.ModuleName, authz.ModuleName, + // TODO: add feegrant paramstypes.ModuleName, + upgradetypes.ModuleName, + vestingtypes.ModuleName, + onboardingtypes.ModuleName, gasfreetypes.ModuleName, lockuptypes.ModuleName, microtxtypes.ModuleName, nativedextypes.ModuleName, - erc20types.ModuleName, + group.ModuleName, ) // Determine the order in which modules' InitGenesis() functions are called at chain genesis @@ -888,23 +954,26 @@ func NewAltheaApp( slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, - upgradetypes.ModuleName, ibchost.ModuleName, evmtypes.ModuleName, feemarkettypes.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName, + icatypes.ModuleName, authz.ModuleName, + // TODO: add feegrant paramstypes.ModuleName, + upgradetypes.ModuleName, + vestingtypes.ModuleName, gasfreetypes.ModuleName, lockuptypes.ModuleName, microtxtypes.ModuleName, erc20types.ModuleName, onboardingtypes.ModuleName, nativedextypes.ModuleName, + group.ModuleName, crisistypes.ModuleName, - icatypes.ModuleName, ) // -------------------------------------------------------------------------- @@ -923,7 +992,7 @@ func NewAltheaApp( bank.NewAppModule(appCodec, bankKeeper, accountKeeper), capability.NewAppModule(appCodec, capabilityKeeper), gov.NewAppModule(appCodec, govKeeper, accountKeeper, bankKeeper), - mint.NewAppModule(appCodec, mintKeeper, accountKeeper), + mint.NewAppModule(appCodec, mintKeeper, accountKeeper, nil), staking.NewAppModule(appCodec, stakingKeeper, accountKeeper, bankKeeper), distr.NewAppModule(appCodec, distrKeeper, accountKeeper, bankKeeper, stakingKeeper), slashing.NewAppModule(appCodec, slashingKeeper, accountKeeper, bankKeeper, stakingKeeper), @@ -931,8 +1000,8 @@ func NewAltheaApp( evidence.NewAppModule(evidenceKeeper), ibc.NewAppModule(&ibcKeeper), ibcTransferAppModule, - evm.NewAppModule(&evmKeeper, accountKeeper), - feemarket.NewAppModule(feemarketKeeper), + evm.NewAppModule(&evmKeeper, accountKeeper, evmSs), + feemarket.NewAppModule(feemarketKeeper, fmSs), ) app.sm = &sm @@ -950,18 +1019,12 @@ func NewAltheaApp( // Create the chain of mempool Tx filter functions, aka the AnteHandler - options := app.NewAnteHandlerOptions(appOpts) - if err := options.Validate(); err != nil { - panic(fmt.Errorf("invalid antehandler options: %v", err)) - } - ah := ante.NewAnteHandler(options) - - // Create the lockup AnteHandler, to ensure sufficient decentralization before funds may be transferred - lockupAnteHandler := lockup.NewWrappedLockupAnteHandler(ah, lockupKeeper, appCodec) - app.SetAnteHandler(lockupAnteHandler) + app.setAnteHandler(appOpts) + app.setPostHandler() // Register the configured upgrades for the upgrade module app.registerUpgradeHandlers() + app.registerStoreLoaders() if loadLatest { if err := app.LoadLatestVersion(); err != nil { @@ -1012,6 +1075,29 @@ func (app *AltheaApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) ab return app.MM.InitGenesis(ctx, app.appCodec, genesisState) } +func (app *AltheaApp) setAnteHandler(appOpts servertypes.AppOptions) { + options := app.NewAnteHandlerOptions(appOpts) + if err := options.Validate(); err != nil { + panic(fmt.Errorf("invalid antehandler options: %v", err)) + } + ah := ante.NewAnteHandler(options) + + // Create the lockup AnteHandler, to ensure sufficient decentralization before funds may be transferred + lockupAnteHandler := lockup.NewWrappedLockupAnteHandler(ah, *app.LockupKeeper, app.AppCodec()) + app.SetAnteHandler(lockupAnteHandler) +} + +func (app *AltheaApp) setPostHandler() { + postHandler, err := posthandler.NewPostHandler( + posthandler.HandlerOptions{}, + ) + if err != nil { + panic(err) + } + + app.SetPostHandler(postHandler) +} + // LoadHeight loads the blockchain a particular height func (app *AltheaApp) LoadHeight(height int64) error { return app.LoadVersion(height) @@ -1063,21 +1149,21 @@ func (app *AltheaApp) InterfaceRegistry() types.InterfaceRegistry { // GetKey returns the KVStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *AltheaApp) GetKey(storeKey string) *sdk.KVStoreKey { +func (app *AltheaApp) GetKey(storeKey string) *storetypes.KVStoreKey { return app.keys[storeKey] } // GetTKey returns the TransientStoreKey for the provided store key. // // NOTE: This is solely to be used for testing purposes. -func (app *AltheaApp) GetTKey(storeKey string) *sdk.TransientStoreKey { +func (app *AltheaApp) GetTKey(storeKey string) *storetypes.TransientStoreKey { return app.tKeys[storeKey] } // GetMemKey returns the MemStoreKey for the provided mem key. // // NOTE: This is solely used for testing purposes. -func (app *AltheaApp) GetMemKey(storeKey string) *sdk.MemoryStoreKey { +func (app *AltheaApp) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { return app.memKeys[storeKey] } @@ -1085,7 +1171,7 @@ func (app *AltheaApp) GetMemKey(storeKey string) *sdk.MemoryStoreKey { func (app *AltheaApp) GetBaseApp() *baseapp.BaseApp { return app.BaseApp } // GetStakingKeeper returns the staking Keeper, used for testing -func (app *AltheaApp) GetStakingKeeper() stakingkeeper.Keeper { return *app.StakingKeeper } +func (app *AltheaApp) GetStakingKeeper() ibctesting.StakingKeeper { return *app.StakingKeeper } // GetIBCKeeper returns the IBC Keeper, used for testing func (app *AltheaApp) GetIBCKeeper() *ibckeeper.Keeper { return app.IbcKeeper } @@ -1112,14 +1198,6 @@ func (app *AltheaApp) SimulationManager() *module.SimulationManager { // API server. func (app *AltheaApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { clientCtx := apiSvr.ClientCtx - // SDK /node_info, /syncing, /blocks, and /validatorsets REST endpoints - rpc.RegisterRoutes(clientCtx, apiSvr.Router) - - // Note: Delegates requests to the EVM if given a hash variable with a leading "0x" - evmrest.RegisterTxRoutes(clientCtx, apiSvr.Router) // Cosmos and EVM /txs REST endpoints - - // Note: The Cosmos REST registration has been replaced by evmrest's - // authrest.RegisterTxRoutes(clientCtx, apiSvr.Router) // Cosmos /txs REST endpoints // GRPC endpoints under /cosmos.base.tendermint.v1beta1.Service // including GetNodeInfo, GetSyncing, GetLatestBlock, GetBlockByHeight, GetLatestValidatorSet, GetValidatorSetByHeight @@ -1129,17 +1207,33 @@ func (app *AltheaApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.API // including Simulate, GetTx, BroadcastTx, GetTxsEvent, GetBlockWithTxs authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) - // Register all REST routes declared by modules in the ModuleBasics - ModuleBasics.RegisterRESTRoutes(clientCtx, apiSvr.Router) // Register all GRPC routes declared by modules in the ModuleBasics ModuleBasics.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + nodeservice.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter) + // TODO: build the custom swagger files and add here? if apiConfig.Swagger { RegisterSwaggerAPI(clientCtx, apiSvr.Router) } } +// RegisterTxService registers all Protobuf-based Tx receiving gRPC services based on what is registered in the +// interface registry. These are stapled on to the baseapp's gRPC Query router +func (app *AltheaApp) RegisterTxService(clientCtx client.Context) { + authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) +} + +// RegisterTendermintService registers the /cosmos.base.tendermint.v1beta1.Service query endpoints on the baseapp's +// gRPC query router +func (app *AltheaApp) RegisterTendermintService(clientCtx client.Context) { + tmservice.RegisterTendermintService(clientCtx, app.BaseApp.GRPCQueryRouter(), app.interfaceRegistry, app.Query) +} + +func (app *AltheaApp) RegisterNodeService(clientCtx client.Context) { + nodeservice.RegisterNodeService(clientCtx, app.GRPCQueryRouter()) +} + // RegisterSwaggerAPI registers swagger route with API Server // TODO: build the custom swagger files and add here? func RegisterSwaggerAPI(ctx client.Context, rtr *mux.Router) { @@ -1152,18 +1246,6 @@ func RegisterSwaggerAPI(ctx client.Context, rtr *mux.Router) { rtr.PathPrefix("/swagger/").Handler(http.StripPrefix("/swagger/", staticServer)) } -// RegisterTxService registers all Protobuf-based Tx receiving gRPC services based on what is registered in the -// interface registry. These are stapled on to the baseapp's gRPC Query router -func (app *AltheaApp) RegisterTxService(clientCtx client.Context) { - authtx.RegisterTxService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.BaseApp.Simulate, app.interfaceRegistry) -} - -// RegisterTendermintService registers the /cosmos.base.tendermint.v1beta1.Service query endpoints on the baseapp's -// gRPC query router -func (app *AltheaApp) RegisterTendermintService(clientCtx client.Context) { - tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry) -} - // GetMaccPerms returns a copy of the module account permissions func GetMaccPerms() map[string][]string { dupMaccPerms := make(map[string][]string) @@ -1174,7 +1256,7 @@ func GetMaccPerms() map[string][]string { } // initParamsKeeper constructs params' keeper and all module param subspaces -func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper { +func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey) paramskeeper.Keeper { paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey) paramsKeeper.Subspace(authtypes.ModuleName) @@ -1183,16 +1265,16 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(minttypes.ModuleName) paramsKeeper.Subspace(distrtypes.ModuleName) paramsKeeper.Subspace(slashingtypes.ModuleName) - paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()) + paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1.ParamKeyTable()) paramsKeeper.Subspace(crisistypes.ModuleName) paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) paramsKeeper.Subspace(lockuptypes.ModuleName) paramsKeeper.Subspace(microtxtypes.ModuleName) paramsKeeper.Subspace(gasfreetypes.ModuleName) - paramsKeeper.Subspace(evmtypes.ModuleName) + paramsKeeper.Subspace(evmtypes.ModuleName).WithKeyTable(evmtypes.ParamKeyTable()) paramsKeeper.Subspace(erc20types.ModuleName) - paramsKeeper.Subspace(feemarkettypes.ModuleName) + paramsKeeper.Subspace(feemarkettypes.ModuleName).WithKeyTable(feemarkettypes.ParamKeyTable()) paramsKeeper.Subspace(icahosttypes.SubModuleName) paramsKeeper.Subspace(onboardingtypes.ModuleName) paramsKeeper.Subspace(nativedextypes.ModuleName) @@ -1202,7 +1284,37 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino // registerUpgradeHandlers registers in-place upgrades, which are faster and easier than genesis-based upgrades func (app *AltheaApp) registerUpgradeHandlers() { - // No op + upgrades.RegisterUpgradeHandlers( + app.MM, app.Configurator, app.UpgradeKeeper, app.CrisisKeeper, + ) +} + +// registerStoreLoaders handles special upgrades where module stores are added, removed, or renamed +func (app *AltheaApp) registerStoreLoaders() { + upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() + if err != nil { + panic(fmt.Sprintf("failed to read upgrade info from disk %s", err)) + } + if app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + return + } + + // STORE LOADER CONFIGURATION: + // Added: []string{"newmodule"}, // We are adding these modules + // Renamed: []storetypes.StoreRename{{"foo", "bar"}}, example foo to bar rename + // Deleted: []string{"bazmodule"}, example deleted bazmodule + + // Group module store loader setup + if upgradeInfo.Name == neutrino.PlanName { + // Register the Group module as a new module that needs a new store allocated + storeUpgrades := storetypes.StoreUpgrades{ + Added: []string{group.StoreKey}, + Renamed: nil, + Deleted: nil, + } + + app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) + } } func (app *AltheaApp) NewAnteHandlerOptions(appOpts servertypes.AppOptions) ante.HandlerOptions { @@ -1210,15 +1322,22 @@ func (app *AltheaApp) NewAnteHandlerOptions(appOpts servertypes.AppOptions) ante return ante.HandlerOptions{ AccountKeeper: app.AccountKeeper, BankKeeper: app.BankKeeper, - IBCKeeper: app.IbcKeeper, - FeeMarketKeeper: app.FeemarketKeeper, - EvmKeeper: app.EvmKeeper, - FeegrantKeeper: nil, SignModeHandler: app.EncodingConfig.TxConfig.SignModeHandler(), - SigGasConsumer: SigVerificationGasConsumer, - Cdc: app.AppCodec(), - MaxTxGasWanted: maxGasWanted, - GasfreeKeeper: app.GasfreeKeeper, - MicrotxKeeper: app.MicrotxKeeper, + // TODO: Add feegrant + FeegrantKeeper: nil, + SigGasConsumer: SigVerificationGasConsumer, + IBCKeeper: app.IbcKeeper, + EvmKeeper: app.EvmKeeper, + FeeMarketKeeper: *app.FeemarketKeeper, + MaxTxGasWanted: maxGasWanted, + ExtensionOptionChecker: ante.CosmosExtensionOptionChecker, + TxFeeChecker: ethante.NewDynamicFeeChecker(app.EvmKeeper), + DisabledAuthzMsgs: []string{ + sdk.MsgTypeURL((&evmtypes.MsgEthereumTx{})), + sdk.MsgTypeURL((&vestingtypes.MsgCreateVestingAccount{})), + }, + Cdc: app.AppCodec(), + GasfreeKeeper: app.GasfreeKeeper, + MicrotxKeeper: app.MicrotxKeeper, } } diff --git a/app/migrate.go b/app/migrate.go index 0d417836..db34f55e 100644 --- a/app/migrate.go +++ b/app/migrate.go @@ -21,10 +21,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" "github.com/cosmos/cosmos-sdk/x/genutil/types" staking "github.com/cosmos/cosmos-sdk/x/staking/types" - ibcxfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - "github.com/cosmos/ibc-go/v4/modules/core/exported" - ibccoretypes "github.com/cosmos/ibc-go/v4/modules/core/types" + ibcxfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + host "github.com/cosmos/ibc-go/v6/modules/core/24-host" + "github.com/cosmos/ibc-go/v6/modules/core/exported" + ibccoretypes "github.com/cosmos/ibc-go/v6/modules/core/types" "github.com/pkg/errors" "github.com/spf13/cobra" tmjson "github.com/tendermint/tendermint/libs/json" diff --git a/app/sigverify.go b/app/sigverify.go index a424b773..130703dd 100644 --- a/app/sigverify.go +++ b/app/sigverify.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/tx/signing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - canto "github.com/Canto-Network/Canto/v5/app" + canto "github.com/Canto-Network/Canto/v6/app" ) const ( diff --git a/app/upgrades/neutrino/README.md b/app/upgrades/neutrino/README.md new file mode 100644 index 00000000..c71b0539 --- /dev/null +++ b/app/upgrades/neutrino/README.md @@ -0,0 +1,9 @@ +# Neutrino UPGRADE + +The *Neutrino* upgrade contains the following changes. + +## Summary of Changes + +* Update the Cosmos SDK to v0.46.16, IBC to v6.3.1 +* Update Ethermint to 0.22 +* Update CometBFT to v0.34.35 to address multiple CVEs \ No newline at end of file diff --git a/app/upgrades/neutrino/handler.go b/app/upgrades/neutrino/handler.go new file mode 100644 index 00000000..fa9d9a13 --- /dev/null +++ b/app/upgrades/neutrino/handler.go @@ -0,0 +1,32 @@ +package neutrino + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" +) + +var PlanName = "neutrino" + +func GetNeutrinoUpgradeHandler( + mm *module.Manager, configurator *module.Configurator, crisisKeeper *crisiskeeper.Keeper, +) func( + ctx sdk.Context, plan upgradetypes.Plan, vmap module.VersionMap, +) (module.VersionMap, error) { + if mm == nil { + panic("Nil argument to GetNeutrinoUpgradeHandler") + } + return func(ctx sdk.Context, plan upgradetypes.Plan, vmap module.VersionMap) (module.VersionMap, error) { + ctx.Logger().Info("Module Consensus Version Map", "vmap", vmap) + + ctx.Logger().Info("Neutrino Upgrade: Running any configured module migrations") + out, outErr := mm.RunMigrations(ctx, *configurator, vmap) + + ctx.Logger().Info("Asserting invariants after upgrade") + crisisKeeper.AssertInvariants(ctx) + + ctx.Logger().Info("Neutrino Upgrade Successful") + return out, outErr + } +} diff --git a/app/upgrades/register.go b/app/upgrades/register.go new file mode 100644 index 00000000..cc4bc419 --- /dev/null +++ b/app/upgrades/register.go @@ -0,0 +1,26 @@ +package upgrades + +import ( + "github.com/cosmos/cosmos-sdk/types/module" + crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + + "github.com/AltheaFoundation/althea-L1/app/upgrades/neutrino" +) + +// RegisterUpgradeHandlers registers handlers for all upgrades +// Note: This method has crazy parameters because of circular import issues, I didn't want to make an AltheaApp struct +// along with an interface +func RegisterUpgradeHandlers( + mm *module.Manager, configurator *module.Configurator, upgradeKeeper *upgradekeeper.Keeper, + crisisKeeper *crisiskeeper.Keeper, +) { + if mm == nil || configurator == nil || crisisKeeper == nil || upgradeKeeper == nil { + panic("Nil argument to RegisterUpgradeHandlers()!") + } + // Neutrino upgrade + upgradeKeeper.SetUpgradeHandler( + neutrino.PlanName, + neutrino.GetNeutrinoUpgradeHandler(mm, configurator, crisisKeeper), + ) +} diff --git a/cmd/althea/genaccounts.go b/cmd/althea/genaccounts.go index 8bff951a..1ce21ef4 100644 --- a/cmd/althea/genaccounts.go +++ b/cmd/althea/genaccounts.go @@ -40,7 +40,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) - depCdc := clientCtx.JSONCodec + depCdc := clientCtx.Codec cdc := depCdc.(codec.Codec) serverCtx := server.GetServerContextFromCmd(cmd) @@ -57,7 +57,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa } // attempt to lookup address from Keybase if no address was provided - kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf) + kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, clientCtx.HomeDir, inBuf, cdc) if err != nil { return err } @@ -67,7 +67,10 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa return fmt.Errorf("failed to get address from Keybase: %w", err) } - addr = info.GetAddress() + addr, err = info.GetAddress() + if err != nil { + return fmt.Errorf("failed to parse address: %w", err) + } } coins, err := sdk.ParseCoinsNormalized(args[1]) diff --git a/cmd/althea/root.go b/cmd/althea/root.go index da4fc4d8..8f4b1641 100644 --- a/cmd/althea/root.go +++ b/cmd/althea/root.go @@ -18,7 +18,6 @@ import ( tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/client/debug" @@ -27,8 +26,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" - "github.com/cosmos/cosmos-sdk/snapshots" - "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" @@ -44,6 +41,7 @@ import ( "github.com/spf13/cobra" // EVM + ethermintclient "github.com/evmos/ethermint/client" ethermintserver "github.com/evmos/ethermint/server" ethermintserverconfig "github.com/evmos/ethermint/server/config" @@ -117,7 +115,12 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { cmd.SetOut(cmd.OutOrStdout()) cmd.SetErr(cmd.ErrOrStderr()) - initClientCtx, err := config.ReadFromClientConfig(initClientCtx) + initClientCtx, err := client.ReadPersistentCommandFlags(initClientCtx, cmd.Flags()) + if err != nil { + return err + } + + initClientCtx, err = config.ReadFromClientConfig(initClientCtx) if err != nil { return fmt.Errorf("unable to update context with client.toml config: %v", err) } @@ -131,7 +134,7 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { // Takes all these configurations and applies them, additionally configuring Tendermint // to adhere to these desires - return server.InterceptConfigsPreRunHandler(cmd, altheaAppTemplate, altheaAppConfig) + return server.InterceptConfigsPreRunHandler(cmd, altheaAppTemplate, altheaAppConfig, initTendermintConfig()) }, } @@ -149,6 +152,18 @@ func initAppConfig() (string, interface{}) { return appTempl, appCfg } +// initTendermintConfig helps to override default Tendermint Config values. +// return tmcfg.DefaultConfig if no custom configuration is required for the application. +func initTendermintConfig() *cfg.Config { + cfg := cfg.DefaultConfig() + + // these values put a higher strain on node memory + // cfg.P2P.MaxNumInboundPeers = 100 + // cfg.P2P.MaxNumOutboundPeers = 40 + + return cfg +} + // Execute executes the root command. func Execute(rootCmd *cobra.Command, defaultHome string) error { // Create and set a client.Context on the command's Context. During the pre-run @@ -187,7 +202,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig *params.EncodingConfig) ac := appCreator{encodingConfig} // The ethermint server commands perform a lot of modifications on top of the base ones, notably setting up the // EVM JSONRPC server, tx indexer, and some various improvements like closing the DB automatically - ethermintserver.AddCommands(rootCmd, althea.DefaultNodeHome, ac.newApp, ac.createSimappAndExport, addModuleInitFlags) + ethermintserver.AddCommands(rootCmd, ethermintserver.NewDefaultStartOptions(ac.newApp, althea.DefaultNodeHome), ac.createSimappAndExport, addModuleInitFlags) rootCmd.AddCommand(ethermintserver.NewIndexTxCmd()) @@ -356,6 +371,7 @@ func txCommand() *cobra.Command { authcmd.GetBroadcastCommand(), authcmd.GetEncodeCommand(), authcmd.GetDecodeCommand(), + authcmd.GetAuxToFeeCommand(), flags.LineBreak, vestingcli.GetTxCmd(), ) @@ -374,49 +390,20 @@ type appCreator struct { // newApp is an AppCreator used for the start command, anything which must be passed to NewAltheaApp (in app.go) // can be fetched and added here func (a appCreator) newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { - var cache sdk.MultiStorePersistentCache - - if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) { - cache = store.NewCommitKVStoreCacheManager() - } + baseappOptions := server.DefaultBaseappOptions(appOpts) skipUpgradeHeights := make(map[int64]bool) for _, h := range cast.ToIntSlice(appOpts.Get(server.FlagUnsafeSkipUpgrades)) { skipUpgradeHeights[int64(h)] = true } - pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) - if err != nil { - panic(err) - } - - snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots") - snapshotDB, err := sdk.NewLevelDB("metadata", snapshotDir) - if err != nil { - panic(err) - } - snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) - if err != nil { - panic(err) - } - return althea.NewAltheaApp( logger, db, traceStore, true, skipUpgradeHeights, cast.ToString(appOpts.Get(flags.FlagHome)), cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)), *a.encCfg, appOpts, - baseapp.SetPruning(pruningOpts), - baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), - baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), - baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))), - baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), - baseapp.SetInterBlockCache(cache), - baseapp.SetTrace(cast.ToBool(appOpts.Get(server.FlagTrace))), - baseapp.SetIndexEvents(cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents))), - baseapp.SetSnapshotStore(snapshotStore), - baseapp.SetSnapshotInterval(cast.ToUint64(appOpts.Get(server.FlagStateSyncSnapshotInterval))), - baseapp.SetSnapshotKeepRecent(cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent))), + baseappOptions..., ) } diff --git a/cmd/althea/testnet.go b/cmd/althea/testnet.go index 2291cfa9..075cecd0 100644 --- a/cmd/althea/testnet.go +++ b/cmd/althea/testnet.go @@ -25,6 +25,7 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/server" srvconfig "github.com/cosmos/cosmos-sdk/server/config" + "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -166,7 +167,7 @@ func InitTestnet( memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip) genFiles = append(genFiles, nodeConfig.GenesisFile()) - kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, nodeDir, inBuf) + kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, nodeDir, inBuf, clientCtx.Codec) if err != nil { return err } @@ -177,7 +178,7 @@ func InitTestnet( return err } - addr, secret, err := server.GenerateSaveCoinKey(kb, nodeDirName, true, algo) + addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, "", true, algo) if err != nil { _ = os.RemoveAll(outputDir) return err @@ -269,11 +270,11 @@ func initGenFiles( genFiles []string, numValidators int, ) error { - appGenState := mbm.DefaultGenesis(clientCtx.JSONCodec) + appGenState := mbm.DefaultGenesis(clientCtx.Codec) // set the accounts in the genesis state var authGenState authtypes.GenesisState - clientCtx.JSONCodec.MustUnmarshalJSON(appGenState[authtypes.ModuleName], &authGenState) + clientCtx.Codec.MustUnmarshalJSON(appGenState[authtypes.ModuleName], &authGenState) accounts, err := authtypes.PackAccounts(genAccounts) if err != nil { @@ -281,14 +282,14 @@ func initGenFiles( } authGenState.Accounts = accounts - appGenState[authtypes.ModuleName] = clientCtx.JSONCodec.MustMarshalJSON(&authGenState) + appGenState[authtypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&authGenState) // set the balances in the genesis state var bankGenState banktypes.GenesisState - clientCtx.JSONCodec.MustUnmarshalJSON(appGenState[banktypes.ModuleName], &bankGenState) + clientCtx.Codec.MustUnmarshalJSON(appGenState[banktypes.ModuleName], &bankGenState) bankGenState.Balances = genBalances - appGenState[banktypes.ModuleName] = clientCtx.JSONCodec.MustMarshalJSON(&bankGenState) + appGenState[banktypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&bankGenState) appGenStateJSON, err := json.MarshalIndent(appGenState, "", " ") if err != nil { @@ -335,7 +336,7 @@ func collectGenFiles( return err } - nodeAppState, err := genutil.GenAppStateFromConfig(clientCtx.JSONCodec, clientCtx.TxConfig, nodeConfig, initCfg, *genDoc, genBalIterator) + nodeAppState, err := genutil.GenAppStateFromConfig(clientCtx.Codec, clientCtx.TxConfig, nodeConfig, initCfg, *genDoc, genBalIterator) if err != nil { return err } diff --git a/go.mod b/go.mod index 9cc2a061..658cbde3 100644 --- a/go.mod +++ b/go.mod @@ -1,97 +1,143 @@ module github.com/AltheaFoundation/althea-L1 -go 1.19 +go 1.22.0 + +toolchain go1.22.7 require ( - github.com/Canto-Network/Canto/v5 v5.2.0 - github.com/cosmos/cosmos-sdk v0.45.16 - github.com/cosmos/ibc-go/v4 v4.3.1 - github.com/evmos/ethermint v0.19.9 + github.com/Canto-Network/Canto/v6 v6.0.1 + github.com/cosmos/cosmos-sdk v0.46.17 + github.com/cosmos/ibc-go/v6 v6.3.1 + github.com/evmos/ethermint v0.22.3 + github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect + github.com/tendermint/tendermint v0.35.9 + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 ) replace ( - // Canto unfortunately has their module listed as .../Canto/v2 @ versions v3.0.0, v4.0.0, and v5.0.0 - // and the v5.x.x releases declare the version as .../Canto/v6 - github.com/Canto-Network/Canto/v5 => github.com/AltheaFoundation/canto/v5 v5.2.0 - github.com/btcsuite/btcutil => github.com/btcsuite/btcd/btcutil v1.1.3 - github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23 v0.0.0-20221014140410-2582f0aab7b2 - github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.45.16 + github.com/Canto-Network/Canto/v6 => github.com/AltheaFoundation/canto/v6 v6.0.1 + + github.com/cosmos/cosmos-sdk => github.com/althea-net/cosmos-sdk v0.46.17 + github.com/cosmos/ibc-go/v6 => github.com/cosmos/ibc-go/v6 v6.3.1 - github.com/cosmos/cosmos-sdk/simapp => cosmossdk.io/simapp v0.0.0-20230531154223-5097b0c22672 - // Ethermint's older versions are not compatible with the end of line sdk v0.45.x - github.com/evmos/ethermint => github.com/AltheaFoundation/ethermint v0.19.9 + github.com/evmos/ethermint => github.com/AltheaFoundation/ethermint v0.22.3 - github.com/gogo/grpc => google.golang.org/grpc v1.33.2 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 - github.com/tendermint/tendermint => github.com/cometbft/cometbft v0.34.27 + + // Fix node query errors like "failed to load state at height 5; version does not exist (latest height: 5)" + github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + + // v0.34.35 resolves multiple CVEs + github.com/tendermint/tendermint => github.com/cometbft/cometbft v0.34.35 // Canto forked github.com/evmos/evmos, which was originally github.com/tharsis/evmos - github.com/tharsis/evmos => github.com/Canto-Network/Canto/v5 v5.0.1 - google.golang.org/grpc => google.golang.org/grpc v1.33.2 + github.com/tharsis/evmos => github.com/Canto-Network/Canto/v6 v6.0.1 + + // Fix error "github.com/cosmos/gogoproto@v1.4.7/proto/merge.go:123:28: in call to slices.SortFunc, type func(x *descriptorpb.FileDescriptorProto, y *descriptorpb.FileDescriptorProto) bool of func(x, y *descriptorpb.FileDescriptor Proto) bool {…} does not match inferred type func(a *descriptorpb.FileDescriptorProto, b *descriptorpb.FileDescriptorProto) int for func(a E, b E) int" + golang.org/x/exp => golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb + ) require ( github.com/cosmos/go-bip39 v1.0.0 - github.com/ethereum/go-ethereum v1.10.19 + github.com/ethereum/go-ethereum v1.10.26 github.com/gogo/protobuf v1.3.3 - github.com/golang/protobuf v1.5.3 + github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 - github.com/spf13/cast v1.5.0 - github.com/spf13/cobra v1.6.1 - github.com/stretchr/testify v1.8.2 - github.com/tendermint/tendermint v0.34.27 + github.com/spf13/cast v1.7.0 + github.com/spf13/cobra v1.8.1 + github.com/stretchr/testify v1.9.0 github.com/tendermint/tm-db v0.6.7 - google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 - google.golang.org/grpc v1.54.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 + google.golang.org/grpc v1.66.1 ) -require github.com/stretchr/objx v0.5.0 // indirect +require ( + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + cloud.google.com/go/storage v1.38.0 // indirect + github.com/aws/aws-sdk-go v1.44.122 // indirect + github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect + github.com/bufbuild/protocompile v0.14.1 // indirect + github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect + github.com/cockroachdb/apd/v2 v2.0.2 // indirect + github.com/cosmos/gogoproto v1.4.7 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-getter v1.7.0 // indirect + github.com/hashicorp/go-safetemp v1.0.0 // indirect + github.com/hashicorp/go-version v1.6.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/leodido/go-urn v1.2.1 // indirect + github.com/manifoldco/promptui v0.9.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/sjson v1.2.5 // indirect + github.com/ugorji/go/codec v1.2.7 // indirect + github.com/ulikunitz/xz v0.5.10 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect + google.golang.org/api v0.171.0 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) require ( - cosmossdk.io/api v0.2.6 // indirect - cosmossdk.io/core v0.5.1 // indirect - cosmossdk.io/depinject v1.0.0-alpha.3 // indirect cosmossdk.io/errors v1.0.0-beta.7 - cosmossdk.io/math v1.0.0 // indirect + cosmossdk.io/math v1.0.0 filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.1 // indirect - github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect - github.com/DataDog/zstd v1.5.0 // indirect - github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect + github.com/ChainSafe/go-schnorrkel v1.1.0 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect - github.com/Workiva/go-datastructures v1.0.53 // indirect + github.com/Workiva/go-datastructures v1.1.5 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect - github.com/btcsuite/btcd v0.23.4 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect - github.com/btcsuite/btcd/btcutil v1.1.2 // indirect - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect + github.com/btcsuite/btcd v0.24.2 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/btcsuite/btcd/btcutil v1.1.6 // indirect + github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cockroachdb/errors v1.9.1 // indirect - github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 // indirect - github.com/cockroachdb/redact v1.1.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coinbase/rosetta-sdk-go v0.7.9 // indirect - github.com/cometbft/cometbft-db v0.7.0 // indirect + github.com/cometbft/cometbft-db v0.9.5 // indirect github.com/confio/ics23/go v0.9.0 // indirect - github.com/cosmos/btcutil v1.0.4 // indirect - github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect + github.com/cosmos/btcutil v1.0.5 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.3 // indirect github.com/cosmos/gorocksdb v1.2.0 // indirect - github.com/cosmos/iavl v0.19.5 // indirect + github.com/cosmos/iavl v0.19.6 // indirect github.com/cosmos/ledger-cosmos-go v0.12.4 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect github.com/danieljoos/wincred v1.1.2 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set v1.8.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect @@ -103,27 +149,26 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/edsrzf/mmap-go v1.0.0 // indirect - github.com/felixge/httpsnoop v1.0.2 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect - github.com/getsentry/sentry-go v0.17.0 // indirect - github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/kit v0.13.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect - github.com/go-stack/stack v1.8.0 // indirect + github.com/go-stack/stack v1.8.1 // indirect github.com/gobwas/ws v1.1.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/gateway v1.1.0 // indirect - github.com/golang/glog v1.1.0 // indirect + github.com/golang/glog v1.2.2 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/btree v1.1.2 // indirect + github.com/google/btree v1.1.3 // 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 + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect @@ -134,55 +179,45 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.1 // indirect + github.com/holiman/uint256 v1.2.2 // indirect github.com/huin/goupnp v1.0.3 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/klauspost/compress v1.16.3 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/lib/pq v1.10.7 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/linxGnu/grocksdb v1.7.16 // indirect - github.com/magiconair/properties v1.8.6 // indirect + github.com/linxGnu/grocksdb v1.9.3 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect - github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/highwayhash v1.0.2 // indirect + github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect + github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/gomega v1.20.0 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect - github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.20.3 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.59.1 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/tsdb v0.10.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/regen-network/cosmos-proto v0.3.1 github.com/rjeczalik/notify v0.9.2 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect - github.com/rs/cors v1.8.3 // indirect - github.com/rs/zerolog v1.27.0 // indirect - github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/rs/zerolog v1.29.1 // indirect + github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect - github.com/spf13/afero v1.9.2 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/afero v1.11.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.14.0 // indirect - github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect - github.com/subosito/gotenv v1.4.1 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect - github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect + github.com/spf13/viper v1.19.0 // indirect + github.com/status-im/keycard-go v0.2.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.5.0 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect @@ -190,17 +225,16 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect - go.etcd.io/bbolt v1.3.7 // indirect + go.etcd.io/bbolt v1.3.11 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 - golang.org/x/net v0.9.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.7.0 // indirect - golang.org/x/term v0.7.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.1.0 // indirect - google.golang.org/protobuf v1.30.0 + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/term v0.24.0 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/time v0.5.0 // indirect + google.golang.org/protobuf v1.34.2 gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 9e852ebc..df18a798 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -17,38 +17,179 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= +cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.38.0 h1:Az68ZRGlnNTpIBbLjSMIV2BDcwwXYlRlQzis0llkpJg= +cloud.google.com/go/storage v1.38.0/go.mod h1:tlUADB0mAb9BgYls9lq+8MGkfzOXuLrnHXlpHmvFJoY= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= -cosmossdk.io/api v0.2.6 h1:AoNwaLLapcLsphhMK6+o0kZl+D6MMUaHVqSdwinASGU= -cosmossdk.io/api v0.2.6/go.mod h1:u/d+GAxil0nWpl1XnQL8nkziQDIWuBDhv8VnDm/s6dI= -cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI= -cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE= -cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= -cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= cosmossdk.io/math v1.0.0 h1:ro9w7eKx23om2tZz/VM2Pf+z2WAbGX1yDQQOJ6iGeJw= cosmossdk.io/math v1.0.0/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -58,38 +199,28 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= -github.com/AltheaFoundation/canto/v5 v5.2.0 h1:8/JY1HnGUW4LTPRDQhXp3o7SCXBppcyLhzYM6SR6fb4= -github.com/AltheaFoundation/canto/v5 v5.2.0/go.mod h1:ycgU4yxtNf9kFVaMY7IsQ094kgBK3T+DSkNEhaIA/z8= -github.com/AltheaFoundation/ethermint v0.19.9 h1:Z5cAgNPwV3luTseFxJF2scBsk2YgtreTD7jOb24gWdA= -github.com/AltheaFoundation/ethermint v0.19.9/go.mod h1:D1Jfhqtrb0q12IQLLB6w0jfjcSl/EMRCR3VKJVVPXSM= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/AltheaFoundation/canto/v6 v6.0.1 h1:3NaThdYw6AZD2bf12bz8Qa3beXDbe0a5pNDB0lAitv4= +github.com/AltheaFoundation/canto/v6 v6.0.1/go.mod h1:CaaiFJ+WEL09j7JTI58JNBrd9p0d7a54eTt61a+nEDk= +github.com/AltheaFoundation/ethermint v0.22.3 h1:NlGZmFveXsFtiOFiTXiEwyA5qTbatJtleWL2yx5h/Ow= +github.com/AltheaFoundation/ethermint v0.22.3/go.mod h1:Pu0VyapSeMO2o7LlvHVn2ir+P9RuUxhIiIv6VYaFivw= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= -github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= -github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= -github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= -github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= -github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= +github.com/ChainSafe/go-schnorrkel v1.1.0 h1:rZ6EU+CZFCjB4sHUE1jIu8VDoB/wRKZxoe1tkcO71Wk= +github.com/ChainSafe/go-schnorrkel v1.1.0/go.mod h1:ABkENxiP+cvjFiByMIZ9LYbRoNNLeBLiakC1XeTFxfE= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/DataDog/zstd v1.5.0 h1:+K/VEwIAaPcHiMtQvpLD4lqW7f0Gk3xdYZmI1hD+CXo= github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= -github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= -github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= @@ -99,15 +230,14 @@ github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= -github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= +github.com/Workiva/go-datastructures v1.1.5 h1:5YfhQ4ry7bZc2Mc7R0YZyYwpf5c6t1cEFvdAhd6Mkf4= +github.com/Workiva/go-datastructures v1.1.5/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM= -github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= +github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I= +github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -115,6 +245,9 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= +github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/althea-net/cosmos-sdk v0.46.17 h1:SG2dTF7CT1M2RB6cDJZijACuRj9m9p8DWcMpG8DVLJY= +github.com/althea-net/cosmos-sdk v0.46.17/go.mod h1:/iMlaT3rCQ9RS5M/40MfrM6lRwiwhAgx87nzMmYXxI8= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= @@ -129,6 +262,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.44.122 h1:p6mw01WBaNpbdP2xrisz5tIkcNwzj/HysobNoaAHjgo= +github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= github.com/aws/aws-sdk-go-v2/config v1.1.1/go.mod h1:0XsVy9lBI/BCXm+2Tuvt39YmdHwS5unDQmxZOYe8F5Y= @@ -139,11 +274,12 @@ github.com/aws/aws-sdk-go-v2/service/route53 v1.1.1/go.mod h1:rLiOUrPLW/Er5kRcQ7 github.com/aws/aws-sdk-go-v2/service/sso v1.1.1/go.mod h1:SuZJxklHxLAXgLTc1iFXbEWkXs7QRTQpCLGaKIprQW0= github.com/aws/aws-sdk-go-v2/service/sts v1.1.1/go.mod h1:Wi0EBZwiz/K44YliU0EKxqTCJGUfYTWXrrBwkq736bM= github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= -github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= +github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -154,24 +290,28 @@ github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13P github.com/btcsuite/btcd v0.21.0-beta.0.20201114000516-e9c7a5ac6401/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= -github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= -github.com/btcsuite/btcd v0.23.4 h1:IzV6qqkfwbItOS/sg/aDfPDsjPP8twrCOE2R93hxMlQ= -github.com/btcsuite/btcd v0.23.4/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= +github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= +github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= -github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= -github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= -github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= -github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= -github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= +github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= +github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= +github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= @@ -179,6 +319,8 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= +github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -193,93 +335,88 @@ github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cloudflare-go v0.14.0/go.mod h1:EnwdgGMaFOruiPZRFSgn+TsQ3hQ7C/YWzIGLeu5c304= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= +github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= -github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= -github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= -github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= -github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= -github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677 h1:qbb/AE938DFhOajUYh9+OXELpSF9KZw2ZivtmW6eX1Q= -github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677/go.mod h1:890yq1fUb9b6dGNwssgeUO5vQV9qfXnCPxAJhBQfXw0= -github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= -github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= -github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/kryptology v1.8.0/go.mod h1:RYXOAPdzOGUe3qlSFkMGn58i3xUA8hmxYHksuq+8ciI= github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZr9ZvoCcA= github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= -github.com/cometbft/cometbft v0.34.27 h1:ri6BvmwjWR0gurYjywcBqRe4bbwc3QVs9KRcCzgh/J0= -github.com/cometbft/cometbft v0.34.27/go.mod h1:BcCbhKv7ieM0KEddnYXvQZR+pZykTKReJJYf7YC7qhw= -github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0ucsbo= -github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= +github.com/cometbft/cometbft v0.34.35 h1:GOjfoIDFwIGVS1BEKbxb9N/ppIuLrwnzcauLLV1i0B4= +github.com/cometbft/cometbft v0.34.35/go.mod h1:qrHyZj3Efj8Hw8EHslaVYtTwXpF2BBZfk+/tgdlJee8= +github.com/cometbft/cometbft-db v0.9.5 h1:ZlIm/peuB9BlRuK01/b/hIIWH2U2m2Q0DNfZ7JmCvhY= +github.com/cometbft/cometbft-db v0.9.5/go.mod h1:Sr3SrYWcAyGvL0HzZMaSJOGMWDEIyiXV1QjCMxM/HNk= +github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= +github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= github.com/consensys/bavard v0.1.8-0.20210915155054-088da2f7f54a/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.4.1-0.20210426202927-39ac3d4b3f1f/go.mod h1:815PAHg3wvysy0SyIqanF8gZ0Y1wjk/hrDHD/iT88+Q= github.com/consensys/gnark-crypto v0.5.3/go.mod h1:hOdPlWQV1gDLp7faZVeg8Y0iEPFaOUnCc4XeCCk96p0= -github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= +github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= +github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cosmos/btcutil v1.0.4 h1:n7C2ngKXo7UC9gNyMNLbzqz7Asuf+7Qv4gnX/rOdQ44= -github.com/cosmos/btcutil v1.0.4/go.mod h1:Ffqc8Hn6TJUdDgHBwIZLtrLQC1KdJ9jGJl/TvgUaxbU= -github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32 h1:zlCp9n3uwQieELltZWHRmwPmPaZ8+XoL2Sj+A2YJlr8= -github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32/go.mod h1:kwMlEC4wWvB48zAShGKVqboJL6w4zCLesaNQ3YLU2BQ= -github.com/cosmos/cosmos-proto v1.0.0-beta.2 h1:X3OKvWgK9Gsejo0F1qs5l8Qn6xJV/AzgIWR2wZ8Nua8= -github.com/cosmos/cosmos-proto v1.0.0-beta.2/go.mod h1:+XRCLJ14pr5HFEHIUcn51IKXD1Fy3rkEQqt4WqmN4V0= -github.com/cosmos/cosmos-sdk v0.45.16 h1:5ba/Bh5/LE55IwHQuCU4fiG4eXeDKtSWzehXRpaKDcw= -github.com/cosmos/cosmos-sdk v0.45.16/go.mod h1:bScuNwWAP0TZJpUf+SHXRU3xGoUPp+X9nAzfeIXts40= -github.com/cosmos/cosmos-sdk/ics23 v0.0.0-20221014140410-2582f0aab7b2 h1:/ml8JZ7wuhQqa2ArobstL7DVaLyOYnUnE7ZdZG5OAb0= -github.com/cosmos/cosmos-sdk/ics23 v0.0.0-20221014140410-2582f0aab7b2/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpFP3wWDPgdHPargtyw30= -github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= +github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= +github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= +github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o= +github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= +github.com/cosmos/gogoproto v1.4.7 h1:RzYKVnsEC7UIkDnhTIkqEB7LnIQbsySvmNEqPCiPevk= +github.com/cosmos/gogoproto v1.4.7/go.mod h1:gxGePp9qedovvl/StQL2BIJ6qlIBn1+9YxR0IulGBKA= github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= -github.com/cosmos/iavl v0.19.5 h1:rGA3hOrgNxgRM5wYcSCxgQBap7fW82WZgY78V9po/iY= -github.com/cosmos/iavl v0.19.5/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= -github.com/cosmos/ibc-go/v4 v4.3.1 h1:xbg0CaCdxK3lvgGvSaI91ROOLd7s30UqEcexH6Ba4Ys= -github.com/cosmos/ibc-go/v4 v4.3.1/go.mod h1:89E+K9CxpkS/etLEcG026jPM/RSnVMcfesvRYp/0aKI= +github.com/cosmos/iavl v0.19.6 h1:XY78yEeNPrEYyNCKlqr9chrwoeSDJ0bV2VjocTk//OU= +github.com/cosmos/iavl v0.19.6/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= +github.com/cosmos/ibc-go/v6 v6.3.1 h1:/5ur3AsmNW8WuOevfODHlaY5Ze236PBNE3vVo9o3fQA= +github.com/cosmos/ibc-go/v6 v6.3.1/go.mod h1:Dm14j9s094bGyCEE8W4fD+2t8IneHv+cz+80Mvwjr1w= 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.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cucumber/common/gherkin/go/v22 v22.0.0 h1:4K8NqptbvdOrjL9DEea6HFjSpbdT9+Q5kgLpmmsHYl0= -github.com/cucumber/common/messages/go/v17 v17.1.1 h1:RNqopvIFyLWnKv0LfATh34SWBhXeoFTJnSrgm9cT/Ts= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= @@ -292,7 +429,6 @@ github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= @@ -310,8 +446,10 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= @@ -328,75 +466,74 @@ github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFP github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.10.17/go.mod h1:Lt5WzjM07XlXc95YzrhosmR4J9Ahd6X2wyEV2SvGhk0= -github.com/ethereum/go-ethereum v1.10.19 h1:EOR5JbL4MD5yeOqv8W2iC1s4NximrTjqFccUz8lyBRA= -github.com/ethereum/go-ethereum v1.10.19/go.mod h1:IJBNMtzKcNHPtllYihy6BL2IgK1u+32JriaTbdt4v+w= +github.com/ethereum/go-ethereum v1.10.26 h1:i/7d9RBBwiXCEuyduBQzJw/mKmnvzsN14jqBmytw72s= +github.com/ethereum/go-ethereum v1.10.26/go.mod h1:EYFyF19u3ezGLD4RqOkLq+ZCXzYbLoNDdZlMt7kyKFg= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= -github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= -github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= -github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= -github.com/getsentry/sentry-go v0.17.0 h1:UustVWnOoDFHBS7IJUB2QK/nB5pap748ZEp0swnQJak= -github.com/getsentry/sentry-go v0.17.0/go.mod h1:B82dxtBvxG0KaPD8/hfSV+VcHD+Lg/xUS4JuQn1P4cM= -github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= -github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= -github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= +github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= +github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= +github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= @@ -406,17 +543,22 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= @@ -427,37 +569,37 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= 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/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= -github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -474,20 +616,20 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 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= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= -github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -500,16 +642,24 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +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/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/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -521,17 +671,39 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= +github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= @@ -541,11 +713,11 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= @@ -558,7 +730,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= -github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= @@ -570,6 +741,10 @@ github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpx github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-getter v1.7.0 h1:bzrYP+qu/gMrL1au7/aDvkoOVGUJpeKBgbqRHACAFDY= +github.com/hashicorp/go-getter v1.7.0/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -577,6 +752,8 @@ github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iP github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= +github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -584,6 +761,7 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -601,24 +779,21 @@ github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3s github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o= -github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/holiman/uint256 v1.2.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk= +github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= -github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/flux v0.65.1/go.mod h1:J754/zds0vvpfwuq7Gc2wRdVwEodfpCFM7mYlOw2LqY= github.com/influxdata/influxdb v1.8.3/go.mod h1:JugdFhsvvI8gadxOI6noqNeeBHvWNTbfYGtiAn+2jhI= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= @@ -631,20 +806,17 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= -github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= -github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= -github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= -github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= -github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= -github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/protoreflect v1.13.1-0.20220928232736-101791cb1b4c h1:XImQJfpJLmGEEd8ll5yPVyL/aEvmgGHW4WYTyNseLOM= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= @@ -656,127 +828,106 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= -github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= -github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= -github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= -github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= -github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= -github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= -github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= -github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= -github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= -github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= -github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= -github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/linxGnu/grocksdb v1.7.16 h1:Q2co1xrpdkr5Hx3Fp+f+f7fRGhQFQhvi/+226dtLmA8= -github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= +github.com/linxGnu/grocksdb v1.9.3 h1:s1cbPcOd0cU2SKXRG1nEqCOWYAELQjdqg3RVI2MH9ik= +github.com/linxGnu/grocksdb v1.9.3/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= +github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= -github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= -github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= -github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= -github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miguelmota/go-ethereum-hdwallet v0.1.1 h1:zdXGlHao7idpCBjEGTXThVAtMKs+IxAgivZ75xqkWK0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= -github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b h1:QrHweqAtyJ9EwCaGHBu1fghwxIPiopAHV06JlXrMHjk= +github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b/go.mod h1:xxLb2ip6sSUts3g1irPVHyk/DGslwQsNOo9I7smJfNU= +github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -787,6 +938,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -795,10 +948,11 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -808,17 +962,14 @@ github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/neilotoole/errgroup v0.1.6/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -827,23 +978,24 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= +github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= -github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= -github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/runc v1.2.0-rc.2 h1:5P32s2x9w1gAk20jbkwbQCZCfqVFashCwjD1UL2Ykc4= +github.com/opencontainers/runc v1.2.0-rc.2/go.mod h1:H8njh/SD+WY9bYMmVsEEWDJgJdviOSDjNeXMjeNbYCE= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -854,7 +1006,7 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= -github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ= +github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -862,31 +1014,26 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= -github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -894,18 +1041,16 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= +github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -914,20 +1059,16 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= +github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic= github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4= @@ -938,7 +1079,6 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzywPxOvwMdxcg= github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= -github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGnWA97M= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= @@ -948,32 +1088,32 @@ github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= -github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= -github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= +github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +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= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= -github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= -github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= -github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= +github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -981,45 +1121,47 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= -github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 h1:Oo2KZNP70KE0+IUJSidPj/BFS/RXNHmKIJOdckzml2E= -github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= +github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1030,14 +1172,13 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= -github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8= @@ -1046,9 +1187,16 @@ github.com/tidwall/btree v1.5.0 h1:iV0yVY/frd7r6qGBXfEYs7DH0gTDgrKTrDjS7xt/IyQ= github.com/tidwall/btree v1.5.0/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= @@ -1064,47 +1212,45 @@ github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:s github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 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.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/urfave/cli/v2 v2.10.2 h1:x3p8awjp/2arX+Nl/G2040AZpOCHS/eMJJ1/a+mye4Y= +github.com/urfave/cli/v2 v2.10.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= +go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1114,13 +1260,29 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -1136,8 +1298,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1145,32 +1305,15 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -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= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -1182,20 +1325,19 @@ golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1205,7 +1347,6 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1215,7 +1356,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1238,20 +1378,29 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= 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= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1261,8 +1410,24 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1274,9 +1439,13 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1285,10 +1454,8 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1301,7 +1468,6 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1336,42 +1502,60 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210316164454-77fc1eacc6aa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.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= -golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= 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= @@ -1381,25 +1565,25 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1407,9 +1591,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1425,7 +1607,6 @@ golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1445,23 +1626,31 @@ golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= -gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= @@ -1485,6 +1674,38 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= +google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1492,7 +1713,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1534,14 +1754,124 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44 h1:EfLuoKW5WfkgVdDy7dTK8qSbH37AX5mj/MFh+bGPz14= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= -google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +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-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= +google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= +google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU= +google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM= +google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1554,33 +1884,31 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 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= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -1593,14 +1921,12 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1613,6 +1939,7 @@ nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0 nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= +pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= @@ -1620,4 +1947,5 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/ibcutils/testing/app.go b/ibcutils/testing/app.go index 395f0fab..c41e9156 100644 --- a/ibcutils/testing/app.go +++ b/ibcutils/testing/app.go @@ -18,16 +18,17 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/cosmos/ibc-go/v4/modules/core/keeper" - "github.com/cosmos/ibc-go/v4/testing/simapp" + "github.com/cosmos/ibc-go/v6/modules/core/keeper" + "github.com/cosmos/ibc-go/v6/testing/simapp" + ibctesting "github.com/cosmos/ibc-go/v6/testing/types" ethermint "github.com/evmos/ethermint/types" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" @@ -45,7 +46,7 @@ type TestingApp interface { // ibc-go additions GetBaseApp() *baseapp.BaseApp - GetStakingKeeper() stakingkeeper.Keeper + GetStakingKeeper() ibctesting.StakingKeeper GetIBCKeeper() *keeper.Keeper GetScopedIBCKeeper() capabilitykeeper.ScopedKeeper GetTxConfig() client.TxConfig @@ -54,7 +55,7 @@ type TestingApp interface { AppCodec() codec.Codec // Implemented by BaseApp - LastCommitID() sdk.CommitID + LastCommitID() storetypes.CommitID LastBlockHeight() int64 } diff --git a/ibcutils/testing/chain.go b/ibcutils/testing/chain.go index 8574451d..426726d4 100644 --- a/ibcutils/testing/chain.go +++ b/ibcutils/testing/chain.go @@ -19,15 +19,15 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/teststaking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - "github.com/cosmos/ibc-go/v4/modules/core/exported" - "github.com/cosmos/ibc-go/v4/modules/core/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v4/testing/mock" - "github.com/cosmos/ibc-go/v4/testing/simapp" - "github.com/cosmos/ibc-go/v4/testing/simapp/helpers" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v6/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v6/modules/core/24-host" + "github.com/cosmos/ibc-go/v6/modules/core/exported" + "github.com/cosmos/ibc-go/v6/modules/core/types" + ibctmtypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v6/testing/mock" + "github.com/cosmos/ibc-go/v6/testing/simapp" + "github.com/cosmos/ibc-go/v6/testing/simapp/helpers" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/tmhash" @@ -555,7 +555,7 @@ func SignAndDeliver( // Simulate a sending a transaction and committing a block // nolint: exhaustruct app.BeginBlock(abci.RequestBeginBlock{Header: header}) - gInfo, res, err := app.Deliver(txCfg.TxEncoder(), tx) + gInfo, res, err := app.SimDeliver(txCfg.TxEncoder(), tx) if expPass { require.NoError(t, err) diff --git a/ibcutils/testing/config.go b/ibcutils/testing/config.go index b75ecc8d..8bcc92aa 100644 --- a/ibcutils/testing/config.go +++ b/ibcutils/testing/config.go @@ -3,11 +3,11 @@ package ibctesting import ( "time" - connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v4/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v4/testing/mock" + connectiontypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v6/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v6/testing/mock" ) type ClientConfig interface { diff --git a/ibcutils/testing/endpoint.go b/ibcutils/testing/endpoint.go index 409aa81f..dc3d620d 100644 --- a/ibcutils/testing/endpoint.go +++ b/ibcutils/testing/endpoint.go @@ -6,13 +6,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v4/modules/core/24-host" - "github.com/cosmos/ibc-go/v4/modules/core/exported" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v6/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v6/modules/core/24-host" + "github.com/cosmos/ibc-go/v6/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" ) // Endpoint is a which represents a channel endpoint and its associated diff --git a/ibcutils/testing/events.go b/ibcutils/testing/events.go index a1ba73c1..8df9f000 100644 --- a/ibcutils/testing/events.go +++ b/ibcutils/testing/events.go @@ -6,9 +6,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" ) // ParseClientIDFromEvents parses events emitted from a MsgCreateClient and returns the diff --git a/ibcutils/testing/path.go b/ibcutils/testing/path.go index eb9c94f5..2b4b9f6b 100644 --- a/ibcutils/testing/path.go +++ b/ibcutils/testing/path.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" ) // Path contains two endpoints representing two chains connected over IBC diff --git a/ibcutils/testing/values.go b/ibcutils/testing/values.go index 283eb69e..0627ab99 100644 --- a/ibcutils/testing/values.go +++ b/ibcutils/testing/values.go @@ -7,10 +7,10 @@ package ibctesting import ( "time" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" - ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" - "github.com/cosmos/ibc-go/v4/testing/mock" + ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + connectiontypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types" + ibctmtypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v6/testing/mock" ) const ( diff --git a/ibcutils/utils.go b/ibcutils/utils.go index 523a2dab..364726f1 100644 --- a/ibcutils/utils.go +++ b/ibcutils/utils.go @@ -6,8 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" ) // GetTransferSenderRecipient returns the sender and recipient sdk.AccAddresses diff --git a/ibcutils/utils_test.go b/ibcutils/utils_test.go index a295fd0e..0e109938 100644 --- a/ibcutils/utils_test.go +++ b/ibcutils/utils_test.go @@ -7,9 +7,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - ibctesting "github.com/cosmos/ibc-go/v4/testing" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v6/testing" ) func init() { diff --git a/integration_tests/test_runner/src/bin/main.rs b/integration_tests/test_runner/src/bin/main.rs index 3636aea4..965fd6b7 100644 --- a/integration_tests/test_runner/src/bin/main.rs +++ b/integration_tests/test_runner/src/bin/main.rs @@ -4,6 +4,7 @@ #[macro_use] extern crate log; +use althea_proto::cosmos_sdk_proto::ibc; use deep_space::Coin; use deep_space::Contact; use deep_space::PrivateKey; @@ -29,6 +30,8 @@ use test_runner::tests::onboarding::onboarding_default_params; use test_runner::tests::onboarding::onboarding_delist_after; use test_runner::tests::onboarding::onboarding_disable_after; use test_runner::tests::onboarding::onboarding_disabled_whitelisted; +use test_runner::tests::upgrade::upgrade_part_1; +use test_runner::tests::upgrade::upgrade_part_2; use test_runner::utils::one_atom; use test_runner::utils::one_hundred_eth; use test_runner::utils::send_funds_bulk; @@ -268,6 +271,26 @@ pub async fn main() { ) .await; return; + } else if test_type == "UPGRADE_PART_1" { + upgrade_part_1( + &web30, + &contact, + &ibc_contact, + keys, + ibc_keys, + erc20_addresses, + ) + .await; + } else if test_type == "UPGRADE_PART_2" { + upgrade_part_2( + &web30, + &contact, + &ibc_contact, + keys, + ibc_keys, + erc20_addresses, + ) + .await; } else { panic!("Unknown test type: {:?}", test_type); } diff --git a/integration_tests/test_runner/src/tests/mod.rs b/integration_tests/test_runner/src/tests/mod.rs index 323bf475..1ebfcd3b 100644 --- a/integration_tests/test_runner/src/tests/mod.rs +++ b/integration_tests/test_runner/src/tests/mod.rs @@ -6,3 +6,4 @@ pub mod lockup; pub mod microtx_fees; pub mod native_token; pub mod onboarding; +pub mod upgrade; \ No newline at end of file diff --git a/integration_tests/test_runner/src/tests/upgrade.rs b/integration_tests/test_runner/src/tests/upgrade.rs new file mode 100644 index 00000000..32e68f99 --- /dev/null +++ b/integration_tests/test_runner/src/tests/upgrade.rs @@ -0,0 +1,169 @@ +use crate::utils::{ + execute_upgrade_proposal, wait_for_block, UpgradeProposalParams, ValidatorKeys, EVM_USER_KEYS, +}; +use clarity::Address as EthAddress; +use deep_space::client::ChainStatus; +use deep_space::{Contact, CosmosPrivateKey}; +use std::time::Duration; +use tokio::time::sleep as delay_for; +use web30::client::Web3; + +use super::erc20_conversion::erc20_conversion_test; +use super::microtx_fees::microtx_fees_test; +use super::native_token::native_token_test; + +pub const UPGRADE_NAME: &str = "neutrino"; + +/// Perform a series of integration tests to seed the system with data, then submit and pass a chain +/// upgrade proposal +/// NOTE: To run this test, use the tests/run-upgrade-test.sh command with an old binary +#[allow(clippy::too_many_arguments)] +pub async fn upgrade_part_1( + web30: &Web3, + althea_contact: &Contact, + ibc_contact: &Contact, + keys: Vec, + ibc_keys: Vec, + erc20_addresses: Vec, +) { + info!("Starting upgrade test part 1"); + + run_all_recoverable_tests(web30, althea_contact, keys.clone(), erc20_addresses.clone()).await; + run_upgrade_specific_tests( + web30, + althea_contact, + ibc_contact, + keys.clone(), + ibc_keys.clone(), + erc20_addresses.clone(), + false, + ) + .await; + + let upgrade_height = run_upgrade(althea_contact, keys, UPGRADE_NAME.to_string(), false).await; + + info!( + "Ready to run the new binary, waiting for chain panic at upgrade height of {}!", + upgrade_height + ); + // Wait for the block before the upgrade height, we won't get a response from the chain + let res = wait_for_block(althea_contact, (upgrade_height - 1) as u64).await; + if res.is_err() { + panic!("Unable to wait for upgrade! {}", res.err().unwrap()); + } + + delay_for(Duration::from_secs(10)).await; // wait for the new block to halt the chain + let status = althea_contact.get_chain_status().await; + info!( + "Done waiting, chain should be halted, status response: {:?}", + status + ); +} + +/// Perform a series of integration tests after an upgrade has executed +/// NOTE: To run this test, follow the instructions for v2_upgrade_part_1 and WAIT FOR CHAIN HALT, +/// then finally run tests/run-tests.sh with V2_UPGRADE_PART_2 as the test type. +#[allow(clippy::too_many_arguments)] +pub async fn upgrade_part_2( + web30: &Web3, + althea_contact: &Contact, + ibc_contact: &Contact, + keys: Vec, + ibc_keys: Vec, + erc20_addresses: Vec, +) { + info!("Starting upgrade_part_2 test"); + + run_all_recoverable_tests(web30, althea_contact, keys.clone(), erc20_addresses.clone()).await; + run_upgrade_specific_tests( + web30, + althea_contact, + ibc_contact, + keys.clone(), + ibc_keys, + erc20_addresses.clone(), + true, + ) + .await; +} + +pub async fn run_upgrade( + contact: &Contact, + keys: Vec, + plan_name: String, + wait_for_upgrade: bool, +) -> i64 { + let curr_height = contact.get_chain_status().await.unwrap(); + let curr_height = if let ChainStatus::Moving { block_height } = curr_height { + block_height + } else { + panic!("Chain is not moving!"); + }; + let upgrade_height = (curr_height + 40) as i64; + let upgrade_prop_params = UpgradeProposalParams { + upgrade_height, + plan_name, + plan_info: "upgrade info here".to_string(), + proposal_title: "proposal title here".to_string(), + proposal_desc: "proposal description here".to_string(), + }; + info!( + "Starting upgrade vote with params name: {}, height: {}", + upgrade_prop_params.plan_name.clone(), + upgrade_height + ); + execute_upgrade_proposal(contact, &keys, None, upgrade_prop_params).await; + + if wait_for_upgrade { + info!( + "Ready to run the new binary, waiting for chain panic at upgrade height of {}!", + upgrade_height + ); + // Wait for the block before the upgrade height, we won't get a response from the chain + let res = wait_for_block(contact, (upgrade_height - 1) as u64).await; + if res.is_err() { + panic!("Unable to wait for upgrade! {}", res.err().unwrap()); + } + + delay_for(Duration::from_secs(10)).await; // wait for the new block to halt the chain + let status = contact.get_chain_status().await; + info!( + "Done waiting, chain should be halted, status response: {:?}", + status + ); + } + upgrade_height +} + +/// Runs many integration tests, but only the ones which DO NOT corrupt state +pub async fn run_all_recoverable_tests( + web30: &Web3, + contact: &Contact, + keys: Vec, + erc20_addresses: Vec, +) { + native_token_test(contact, web30, keys.clone()).await; + erc20_conversion_test( + contact, + web30, + keys.clone(), + EVM_USER_KEYS.clone(), + erc20_addresses, + ) + .await; + microtx_fees_test(contact, keys.clone()).await; +} + +// These tests should fail in upgrade_part_1() but pass in upgrade_part_2() +#[allow(clippy::too_many_arguments)] +pub async fn run_upgrade_specific_tests( + _web30: &Web3, + _althea_contact: &Contact, + _ibc_contact: &Contact, + _keys: Vec, + _ibc_keys: Vec, + _erc20_addresses: Vec, + _post_upgrade: bool, +) { + // TODO: Add any tests here +} diff --git a/tests/container-scripts/manual-upgrade-test-internal.sh b/tests/container-scripts/manual-upgrade-test-internal.sh new file mode 100755 index 00000000..7b80df4e --- /dev/null +++ b/tests/container-scripts/manual-upgrade-test-internal.sh @@ -0,0 +1,58 @@ +#!/bin/bash +set -eux +# Number of validators to start +NODES=$1 +# old binary version to run +OLD_VERSION=$2 + +chmod -R 777 /root/ + +echo "Downloading old althea version at https://github.com/AltheaFoundation/althea-L1/releases/download/${OLD_VERSION}/althea-linux-amd64" +wget https://github.com/AltheaFoundation/althea-L1/releases/download/${OLD_VERSION}/althea-linux-amd64 +mv althea-linux-amd64 oldalthea +# Make old althea executable +chmod +x oldalthea + +export OLD_BINARY_LOCATION=/oldalthea + +# Prepare the contracts for later deployment +pushd /althea +pushd solidity/ +HUSKY_SKIP_INSTALL=1 npm install +npm run typechain +popd +pushd solidity-dex +npx hardhat compile +popd + +export PATH=$PATH:/usr/local/go/bin +make +make install +cd /althea/ +tests/container-scripts/setup-validators.sh $NODES +tests/container-scripts/setup-ibc-validators.sh $NODES + +# Run the old binary +tests/container-scripts/run-testnet.sh $NODES + + +# deploy the ethereum contracts +pushd integration_tests/test_runner +DEPLOY_CONTRACTS=1 RUST_BACKTRACE=full NO_GAS_OPT=1 RUST_LOG="INFO" PATH=$PATH:$HOME/.cargo/bin cargo run --release --bin test-runner +popd + +# This allows the tester to run the first part of the test +# immediately if the nodes are killed by a different process + +read -p "Old binary is running, use tests/run-tests.sh to run tests/populate pre-upgrade state! Hit Enter to continue to part 2..." + + +unset OLD_BINARY_LOCATION +# Run the new binary +pkill oldalthea || true # allowed to fail +tests/container-scripts/run-testnet.sh $NODES + +# This allows the tester to run the first part of the test +# immediately if the nodes are killed by a different process + +read -p "New binary is running, use tests/run-tests.sh to run tests on the upgraded chain! Hit Enter to close the container and end all tests..." \ No newline at end of file diff --git a/tests/container-scripts/run-testnet.sh b/tests/container-scripts/run-testnet.sh new file mode 100755 index 00000000..149346c5 --- /dev/null +++ b/tests/container-scripts/run-testnet.sh @@ -0,0 +1,95 @@ +#!/bin/bash +set -eux +# your gaiad binary name +BIN=althea + +NODES=$1 +set +u +TEST_TYPE=$2 + +GITHUB_ACTIONS_PATH="/home/runner/work/AltheaFoundation/althea-L1/" +DOCKER_PATH="/althea/" + +if [[ -d "$GITHUB_ACTIONS_PATH" ]]; then + FOLDER_PATH="$GITHUB_ACTIONS_PATH" +elif [[ -d "$DOCKER_PATH" ]]; then + FOLDER_PATH="$DOCKER_PATH" +else + echo "Error: Neither $GITHUB_ACTIONS_PATH nor $DOCKER_PATH exists." + exit 1 +fi + +if [[ ! -z ${OLD_BINARY_LOCATION} ]]; then + BIN=$OLD_BINARY_LOCATION +fi +set -u + +for i in $(seq 1 $NODES); +do + # add this ip for loopback dialing + ip addr add 7.7.7.$i/32 dev eth0 || true # allowed to fail + + GAIA_HOME="--home /validator$i" + # this implicitly caps us at ~6000 nodes for this sim + # note that we start on 26656 the idea here is that the first + # node (node 1) is at the expected contact address from the gentx + # faciliating automated peer exchange + if [[ "$i" -eq 1 ]]; then + # node one gets localhost so we can easily shunt these ports + # to the docker host + RPC_ADDRESS="--rpc.laddr tcp://0.0.0.0:26657" + GRPC_ADDRESS="--grpc.address 0.0.0.0:9090" + GRPC_WEB_ADDRESS="--grpc-web.address 0.0.0.0:9092" + ETH_RPC_ADDRESS="--json-rpc.address 0.0.0.0:8545" + ETH_RPC_WS_ADDRESS="--json-rpc.ws-address 0.0.0.0:8546" + sed -i 's/enable-unsafe-cors = false/enable-unsafe-cors = true/g' /validator$i/config/app.toml + sed -i 's/enabled-unsafe-cors = false/enabled-unsafe-cors = true/g' /validator$i/config/app.toml + sed -i 's/enable = false/enable = true/g' /validator$i/config/app.toml #enables more than we want, but will work for now + else + # move these to another port and address, not becuase they will + # be used there, but instead to prevent them from causing problems + # you also can't duplicate the port selection against localhost + # for reasons that are not clear to me right now. + RPC_ADDRESS="--rpc.laddr tcp://7.7.7.$i:26658" + GRPC_ADDRESS="--grpc.address 7.7.7.$i:9091" + GRPC_WEB_ADDRESS="--grpc-web.address 7.7.7.$i:9093" + ETH_RPC_ADDRESS="--json-rpc.address 7.7.7.$i:8545" + ETH_RPC_WS_ADDRESS="--json-rpc.address 7.7.7.$i:8546" + fi + LISTEN_ADDRESS="--address tcp://7.7.7.$i:26655" + P2P_ADDRESS="--p2p.laddr tcp://7.7.7.$i:26656" + LOG_LEVEL="--log_level info" + INVARIANTS_CHECK="--inv-check-period 1" + MIN_GAS_PRICES="--minimum-gas-prices 0stake" + + ARGS="$GAIA_HOME $LISTEN_ADDRESS $RPC_ADDRESS $GRPC_ADDRESS $GRPC_WEB_ADDRESS $ETH_RPC_ADDRESS $ETH_RPC_WS_ADDRESS $INVARIANTS_CHECK $LOG_LEVEL $P2P_ADDRESS $MIN_GAS_PRICES" + $BIN $ARGS start &> /validator$i/logs & +done + +# Setup the IBC test chain (chain id ibc-test-1) using gaiad as the binary +# Creates the same number of validators as the althea chain above, with their home directories at /ibc-validator# +BIN=gaiad +for i in $(seq 1 $NODES); +do + ip addr add 7.7.8.$i/32 dev eth0 || true # allowed to fail + + GAIA_HOME="--home /ibc-validator$i" + if [[ "$i" -eq 1 ]]; then + # node one gets localhost so we can easily shunt these ports + # to the docker host + RPC_ADDRESS="--rpc.laddr tcp://0.0.0.0:27657" + GRPC_ADDRESS="--grpc.address 0.0.0.0:9190" + # Must remap the grpc-web address because it conflicts with what we want to use + GRPC_WEB_ADDRESS="--grpc-web.address 0.0.0.0:9192" + else + RPC_ADDRESS="--rpc.laddr tcp://7.7.8.$i:26658" + GRPC_ADDRESS="--grpc.address 7.7.8.$i:9091" + # Must remap the grpc-web address because it conflicts with what we want to use + GRPC_WEB_ADDRESS="--grpc-web.address 7.7.8.$i:9093" + fi + LISTEN_ADDRESS="--address tcp://7.7.8.$i:26655" + P2P_ADDRESS="--p2p.laddr tcp://7.7.8.$i:26656" + LOG_LEVEL="--log_level info" + ARGS="$GAIA_HOME $LISTEN_ADDRESS $RPC_ADDRESS $GRPC_ADDRESS $GRPC_WEB_ADDRESS $LOG_LEVEL $P2P_ADDRESS" + $BIN $ARGS start &> /ibc-validator$i/logs & +done \ No newline at end of file diff --git a/tests/container-scripts/setup-validators.sh b/tests/container-scripts/setup-validators.sh index 75325579..d804e68e 100755 --- a/tests/container-scripts/setup-validators.sh +++ b/tests/container-scripts/setup-validators.sh @@ -7,6 +7,16 @@ CHAIN_ID="althea_6633438-1" NODES=$1 +# When doing an upgrade test we need to run init using the old binary so we don't include newly added fields +set +u +if [[ ! -z ${OLD_BINARY_LOCATION} ]]; then + echo "Replacing althea with $OLD_BINARY_LOCATION" + BIN=$OLD_BINARY_LOCATION +else + echo "Old binary not set, using regular althea" +fi +set -u + STAKING_TOKEN="aalthea" ALLOC_18_DECIMALS="1000000000000000000000000" ALLOC_6_DECIMALS="1000000000000" diff --git a/tests/container-scripts/start-dlv.sh b/tests/container-scripts/start-dlv.sh new file mode 100755 index 00000000..544c4763 --- /dev/null +++ b/tests/container-scripts/start-dlv.sh @@ -0,0 +1,7 @@ +#! /bin/bash + +# Find the PID of the validator1 node +VALIDATOR_1_PID=$(ps -eafww | grep /validator1 | head -n1 | awk '{print $2}') + +# Run dlv and attach to validator1 +/althea/tests/assets/dlv attach $VALIDATOR_1_PID --listen=:2345 --headless --api-version=2 --accept-multiclient --continue & \ No newline at end of file diff --git a/tests/container-scripts/upgrade-test-internal.sh b/tests/container-scripts/upgrade-test-internal.sh new file mode 100755 index 00000000..da3fc95b --- /dev/null +++ b/tests/container-scripts/upgrade-test-internal.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -eux +# Number of validators to start +NODES=$1 +# old binary version to run +OLD_VERSION=$2 + +echo "Downloading old althea version at https://github.com/AltheaFoundation/althea-L1/releases/download/${OLD_VERSION}/althea-linux-amd64" +wget https://github.com/AltheaFoundation/althea-L1/releases/download/${OLD_VERSION}/althea-linux-amd64 +mv althea-linux-amd64 oldalthea +# Make old althea executable +chmod +x oldalthea + +export OLD_BINARY_LOCATION=/oldalthea + +# Prepare the contracts for later deployment +pushd /althea/solidity/ +HUSKY_SKIP_INSTALL=1 npm install +npm run typechain +popd + +pushd /althea/solidity-dex/ +npx hardhat compile +popd + +pushd /althea/ +export PATH=$PATH:/usr/local/go/bin +make +make install +tests/container-scripts/setup-validators.sh $NODES +tests/container-scripts/setup-ibc-validators.sh $NODES + +# Run the old binary +tests/container-scripts/run-testnet.sh $NODES +popd + +# deploy the ethereum contracts +pushd /althea/integration_tests/test_runner +DEPLOY_CONTRACTS=1 RUST_BACKTRACE=full NO_GAS_OPT=1 RUST_LOG="INFO" PATH=$PATH:$HOME/.cargo/bin cargo run --release --bin test-runner +popd + +# Run the pre-upgrade tests +pushd /althea/ +tests/container-scripts/integration-tests.sh $NODES UPGRADE_PART_1 + +unset OLD_BINARY_LOCATION +# Run the new binary +pkill oldalthea || true # allowed to fail +tests/container-scripts/run-testnet.sh $NODES + +# Run the post-upgrade test +tests/container-scripts/integration-tests.sh $NODES UPGRADE_PART_2 +popd diff --git a/tests/manual-upgrade-test.sh b/tests/manual-upgrade-test.sh new file mode 100755 index 00000000..0ed0a339 --- /dev/null +++ b/tests/manual-upgrade-test.sh @@ -0,0 +1,31 @@ +#!/bin/bash +OLD_VERSION=$1 +set -eux + +if [[ -z "${OLD_VERSION}" ]]; then + echo "Must provide old althea version for upgrade test, make sure it matches a version at https://github.com/AltheaFoundation/althea-L1/releases" + exit 1 +fi + +# Remove existing container instance +set +e +docker rm -f althea_test_instance +set -e + +# the directory of this script, useful for allowing this script +# to be run with any PWD +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +NODES=4 + +# setup for Mac apple silicon compatibility +PLATFORM_CMD="" +if [[ "$OSTYPE" == "darwin"* ]]; then + if [[ -n $(sysctl -a | grep brand | grep "Apple") ]]; then + echo "Setting --platform=linux/amd64 for Mac apple silicon compatibility" + PLATFORM_CMD="--platform=linux/amd64"; fi +fi + +# Run new test container instance +PORTS="-p 9090:9090 -p 26657:26657 -p 1317:1317 -p 8545:8545" +docker run --name althea_test_instance --mount type=bind,source="$(pwd)"/,target=/althea $PLATFORM_CMD --cap-add=NET_ADMIN $PORTS -it althea-base /bin/bash /althea/tests/container-scripts/manual-upgrade-test-internal.sh $NODES $OLD_VERSION diff --git a/tests/run-upgrade-test.sh b/tests/run-upgrade-test.sh new file mode 100755 index 00000000..f4e3a43f --- /dev/null +++ b/tests/run-upgrade-test.sh @@ -0,0 +1,37 @@ +#!/bin/bash +OLD_VERSION=$1 +set -eux + +if [[ -z "${OLD_VERSION}" ]]; then + echo "Must provide old althea-l1 version for upgrade test, make sure it matches a version at https://github.com/AltheaFoundation/althea-L1/releases" + exit 1 +fi + +# Remove existing container instance +set +e +docker rm -f althea_all_up_test_instance +set -e + +# the directory of this script, useful for allowing this script +# to be run with any PWD +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +set +u +if [[ -z ${NO_IMAGE_BUILD} ]]; then +bash $DIR/build-container.sh +fi +set -u + +NODES=4 + +# setup for Mac apple silicon compatibility +PLATFORM_CMD="" +if [[ "$OSTYPE" == "darwin"* ]]; then + if [[ -n $(sysctl -a | grep brand | grep "Apple") ]]; then + echo "Setting --platform=linux/amd64 for Mac apple silicon compatibility" + PLATFORM_CMD="--platform=linux/amd64"; fi +fi + +# Run new test container instance +PORTS="-p 9090:9090 -p 26657:26657 -p 1317:1317 -p 8545:8545" +docker run --name althea_all_up_test_instance $PLATFORM_CMD --cap-add=NET_ADMIN $PORTS althea-base /bin/bash /althea/tests/container-scripts/upgrade-test-internal.sh $NODES $OLD_VERSION diff --git a/x/gasfree/keeper/keeper.go b/x/gasfree/keeper/keeper.go index 23b721de..7a32bbe7 100644 --- a/x/gasfree/keeper/keeper.go +++ b/x/gasfree/keeper/keeper.go @@ -2,6 +2,7 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/authz" @@ -11,12 +12,12 @@ import ( ) type Keeper struct { - storeKey sdk.StoreKey + storeKey storetypes.StoreKey paramSpace paramstypes.Subspace Cdc codec.Codec } -func NewKeeper(cdc codec.Codec, storeKey sdk.StoreKey, paramSpace paramstypes.Subspace) Keeper { +func NewKeeper(cdc codec.Codec, storeKey storetypes.StoreKey, paramSpace paramstypes.Subspace) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) diff --git a/x/lockup/ante.go b/x/lockup/ante.go index 974a7d53..5f869855 100644 --- a/x/lockup/ante.go +++ b/x/lockup/ante.go @@ -13,7 +13,7 @@ import ( authz "github.com/cosmos/cosmos-sdk/x/authz" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" microtxtypes "github.com/AltheaFoundation/althea-L1/x/microtx/types" diff --git a/x/lockup/ante_test.go b/x/lockup/ante_test.go index 12a26ae5..8b638750 100644 --- a/x/lockup/ante_test.go +++ b/x/lockup/ante_test.go @@ -10,8 +10,8 @@ import ( authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + ibcclienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" "github.com/stretchr/testify/assert" "github.com/AltheaFoundation/althea-L1/x/lockup/keeper" @@ -166,7 +166,7 @@ func AnteHandlerUnlockedHappy(t *testing.T, handler sdk.AnteHandler, keeper keep func GetAllowedMsgSendTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory, txCfg client.TxConfig) sdk.Tx { msgSend := GetAllowedMsgSend(keeper, ctx) - txBld, err := tx.BuildUnsignedTx(txFct, &msgSend) + txBld, err := txFct.BuildUnsignedTx(&msgSend) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", msgSend, err)) } @@ -191,7 +191,7 @@ func GetAllowedLargeTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory, msgSend := GetAllowedMsgSend(keeper, ctx) multiSend := GetAllowedMultiSendMsg(keeper, ctx) unimportant := GetUnimportantMsg() - txBld, err := tx.BuildUnsignedTx(txFct, &msgSend, &multiSend, &msgSend, &multiSend, &unimportant, &unimportant) + txBld, err := txFct.BuildUnsignedTx(&msgSend, &multiSend, &msgSend, &multiSend, &unimportant, &unimportant) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", msgSend, err)) } @@ -201,7 +201,7 @@ func GetAllowedLargeTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory, func GetAllowedMultiSendTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory, txCfg client.TxConfig) sdk.Tx { multiSend := GetAllowedMultiSendMsg(keeper, ctx) - txBld, err := tx.BuildUnsignedTx(txFct, &multiSend) + txBld, err := txFct.BuildUnsignedTx(&multiSend) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", multiSend, err)) } @@ -224,7 +224,7 @@ func GetAllowedMultiSendMsg(keeper keeper.Keeper, ctx sdk.Context) banktypes.Msg func GetUnimportantTx(txFct tx.Factory, txCfg client.TxConfig) sdk.Tx { unimportantMsg := GetUnimportantMsg() - txBld, err := tx.BuildUnsignedTx(txFct, &unimportantMsg) + txBld, err := txFct.BuildUnsignedTx(&unimportantMsg) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", unimportantMsg, err)) } @@ -244,7 +244,7 @@ func GetUnimportantMsg() stakingtypes.MsgCreateValidator { func GetAllowedMsgTransferTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory, txCfg client.TxConfig) sdk.Tx { msgTransfer := GetAllowedMsgTransfer(keeper, ctx) - txBld, err := tx.BuildUnsignedTx(txFct, &msgTransfer) + txBld, err := txFct.BuildUnsignedTx(&msgTransfer) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", msgTransfer, err)) } @@ -276,7 +276,7 @@ func GetAllowedMsgTransfer(keeper keeper.Keeper, ctx sdk.Context) ibctransfertyp func GetAllowedMsgMicrotxTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory, txCfg client.TxConfig) sdk.Tx { msgMicrotx := GetAllowedMsgMicrotx(keeper, ctx) - txBld, err := tx.BuildUnsignedTx(txFct, &msgMicrotx) + txBld, err := txFct.BuildUnsignedTx(&msgMicrotx) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", msgMicrotx, err)) } @@ -309,7 +309,7 @@ func GetUnallowedMsgSendTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Facto toAddr := "0x0000000000000000000000000000000000000000" amount := sdk.NewCoins(sdk.NewCoin("aalthea", sdk.NewInt(1000000000000000000))) msgSend := banktypes.MsgSend{FromAddress: fromAddr, ToAddress: toAddr, Amount: amount} - txBld, err := tx.BuildUnsignedTx(txFct, &msgSend) + txBld, err := txFct.BuildUnsignedTx(&msgSend) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", msgSend, err)) } @@ -319,7 +319,7 @@ func GetUnallowedMsgSendTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Facto func GetUnallowedMultiSendTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory, txCfg client.TxConfig) sdk.Tx { multiSend := GetUnallowedMultiSendMsg(keeper, ctx) - txBld, err := tx.BuildUnsignedTx(txFct, &multiSend) + txBld, err := txFct.BuildUnsignedTx(&multiSend) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", multiSend, err)) } @@ -345,7 +345,7 @@ func GetUnallowedLargeTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory multiSend := GetAllowedMultiSendMsg(keeper, ctx) badMultiSend := GetUnallowedMultiSendMsg(keeper, ctx) unimportant := GetUnimportantMsg() - txBld, err := tx.BuildUnsignedTx(txFct, &msgSend, &multiSend, &msgSend, &badMultiSend, &multiSend, &unimportant, &unimportant) + txBld, err := txFct.BuildUnsignedTx(&msgSend, &multiSend, &msgSend, &badMultiSend, &multiSend, &unimportant, &unimportant) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", msgSend, err)) } @@ -355,7 +355,7 @@ func GetUnallowedLargeTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory func GetUnallowedMsgTransferTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory, txCfg client.TxConfig) sdk.Tx { msgTransfer := GetUnallowedMsgTransfer(keeper, ctx) - txBld, err := tx.BuildUnsignedTx(txFct, &msgTransfer) + txBld, err := txFct.BuildUnsignedTx(&msgTransfer) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", msgTransfer, err)) } @@ -387,7 +387,7 @@ func GetUnallowedMsgTransfer(keeper keeper.Keeper, ctx sdk.Context) ibctransfert func GetUnallowedMsgMicrotxTx(keeper keeper.Keeper, ctx sdk.Context, txFct tx.Factory, txCfg client.TxConfig) sdk.Tx { msgMicrotx := GetUnallowedMsgMicrotx(keeper, ctx) - txBld, err := tx.BuildUnsignedTx(txFct, &msgMicrotx) + txBld, err := txFct.BuildUnsignedTx(&msgMicrotx) if err != nil { panic(fmt.Sprintf("Unable to build unsigned transaction containing %v: %v", msgMicrotx, err)) } diff --git a/x/lockup/keeper/keeper.go b/x/lockup/keeper/keeper.go index f7e17145..7d4c5f29 100644 --- a/x/lockup/keeper/keeper.go +++ b/x/lockup/keeper/keeper.go @@ -2,6 +2,7 @@ package keeper import ( "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" @@ -10,12 +11,12 @@ import ( ) type Keeper struct { - storeKey sdk.StoreKey + storeKey storetypes.StoreKey paramSpace paramstypes.Subspace cdc codec.BinaryCodec } -func NewKeeper(cdc codec.BinaryCodec, storeKey sdk.StoreKey, paramSpace paramstypes.Subspace) Keeper { +func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, paramSpace paramstypes.Subspace) Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) diff --git a/x/lockup/keeper/test_common.go b/x/lockup/keeper/test_common.go index d8a55b3d..4554a980 100644 --- a/x/lockup/keeper/test_common.go +++ b/x/lockup/keeper/test_common.go @@ -10,6 +10,7 @@ import ( ccodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/cosmos-sdk/store" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" @@ -27,8 +28,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/evidence" "github.com/cosmos/cosmos-sdk/x/genutil" "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/params" paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" @@ -68,7 +72,7 @@ var ( staking.AppModuleBasic{}, mint.AppModuleBasic{}, distribution.AppModuleBasic{}, - gov.NewAppModuleBasic(paramsclient.ProposalHandler), + gov.NewAppModuleBasic([]govclient.ProposalHandler{paramsclient.ProposalHandler}), params.AppModuleBasic{}, crisis.AppModuleBasic{}, slashing.AppModuleBasic{}, @@ -104,13 +108,13 @@ func CreateTestEnv(t *testing.T) TestInput { // Initialize memory database and mount stores on it db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) - ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyBank, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(keyDistro, sdk.StoreTypeIAVL, db) - ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) - ms.MountStoreWithDB(keyGov, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyAcc, storetypes.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyParams, storetypes.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyStaking, storetypes.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyBank, storetypes.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyDistro, storetypes.StoreTypeIAVL, db) + ms.MountStoreWithDB(tkeyParams, storetypes.StoreTypeTransient, db) + ms.MountStoreWithDB(keyGov, storetypes.StoreTypeIAVL, db) err := ms.LoadLatestVersion() require.Nil(t, err) @@ -149,6 +153,7 @@ func CreateTestEnv(t *testing.T) TestInput { getSubspace(paramsKeeper, authtypes.ModuleName), authtypes.ProtoBaseAccount, // prototype maccPerms, + "althea", ) blockedAddr := make(map[string]bool, len(maccPerms)) @@ -169,7 +174,7 @@ func CreateTestEnv(t *testing.T) TestInput { stakingKeeper := stakingkeeper.NewKeeper(protoCodec, keyStaking, accountKeeper, bankKeeper, getSubspace(paramsKeeper, stakingtypes.ModuleName)) stakingKeeper.SetParams(ctx, TestingStakeParams) - distKeeper := distrkeeper.NewKeeper(protoCodec, keyDistro, getSubspace(paramsKeeper, distrtypes.ModuleName), accountKeeper, bankKeeper, stakingKeeper, authtypes.FeeCollectorName, nil) + distKeeper := distrkeeper.NewKeeper(protoCodec, keyDistro, getSubspace(paramsKeeper, distrtypes.ModuleName), accountKeeper, bankKeeper, stakingKeeper, authtypes.FeeCollectorName) distKeeper.SetParams(ctx, distrtypes.DefaultParams()) // set genesis items required for distribution @@ -209,18 +214,20 @@ func CreateTestEnv(t *testing.T) TestInput { // nolint: exhaustruct router.AddRoute(distribution.AppModule{}.Route()) - govRouter := govtypes.NewRouter(). + govRouter := govv1beta1.NewRouter(). AddRoute(paramsproposal.RouterKey, params.NewParamChangeProposalHandler(paramsKeeper)). - AddRoute(govtypes.RouterKey, govtypes.ProposalHandler) + AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler) + govConfig := govtypes.DefaultConfig() govKeeper := govkeeper.NewKeeper( - protoCodec, keyGov, getSubspace(paramsKeeper, govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()), accountKeeper, bankKeeper, stakingKeeper, govRouter, + protoCodec, keyGov, getSubspace(paramsKeeper, govtypes.ModuleName).WithKeyTable(govv1.ParamKeyTable()), accountKeeper, bankKeeper, stakingKeeper, govRouter, + baseapp.NewMsgServiceRouter(), govConfig, ) - govKeeper.SetProposalID(ctx, govtypes.DefaultStartingProposalID) - govKeeper.SetDepositParams(ctx, govtypes.DefaultDepositParams()) - govKeeper.SetVotingParams(ctx, govtypes.DefaultVotingParams()) - govKeeper.SetTallyParams(ctx, govtypes.DefaultTallyParams()) + govKeeper.SetProposalID(ctx, govv1beta1.DefaultStartingProposalID) + govKeeper.SetDepositParams(ctx, govv1.DefaultDepositParams()) + govKeeper.SetVotingParams(ctx, govv1.DefaultVotingParams()) + govKeeper.SetTallyParams(ctx, govv1.DefaultTallyParams()) k := NewKeeper(protoCodec, lockupKey, getSubspace(paramsKeeper, types.ModuleName)) InitGenesis(ctx, k, *types.DefaultGenesisState()) diff --git a/x/lockup/types/genesis.go b/x/lockup/types/genesis.go index fc5920c0..8b7c5d16 100644 --- a/x/lockup/types/genesis.go +++ b/x/lockup/types/genesis.go @@ -7,7 +7,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" "github.com/AltheaFoundation/althea-L1/config" microtxtypes "github.com/AltheaFoundation/althea-L1/x/microtx/types" diff --git a/x/microtx/keeper/keeper.go b/x/microtx/keeper/keeper.go index 489431f0..9311ecee 100644 --- a/x/microtx/keeper/keeper.go +++ b/x/microtx/keeper/keeper.go @@ -6,13 +6,14 @@ import ( "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" 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" - erc20keeper "github.com/Canto-Network/Canto/v5/x/erc20/keeper" + erc20keeper "github.com/Canto-Network/Canto/v6/x/erc20/keeper" evmkeeper "github.com/evmos/ethermint/x/evm/keeper" gasfreekeeper "github.com/AltheaFoundation/althea-L1/x/gasfree/keeper" @@ -22,7 +23,7 @@ import ( // Keeper maintains the link to storage and exposes getter/setter methods for the various parts of the state machine type Keeper struct { // NOTE: If you add anything to this struct, add a nil check to ValidateMembers below! - storeKey sdk.StoreKey // Unexposed key to access store from sdk.Context + storeKey storetypes.StoreKey // Unexposed key to access store from sdk.Context paramSpace paramtypes.Subspace // NOTE: If you add anything to this struct, add a nil check to ValidateMembers below! @@ -55,7 +56,7 @@ func (k Keeper) ValidateMembers() { // NewKeeper returns a new instance of the microtx keeper func NewKeeper( - storeKey sdk.StoreKey, + storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace, cdc codec.BinaryCodec, bankKeeper *bankkeeper.BaseKeeper, diff --git a/x/microtx/keeper/liquid_account.go b/x/microtx/keeper/liquid_account.go index 5f160038..53587297 100644 --- a/x/microtx/keeper/liquid_account.go +++ b/x/microtx/keeper/liquid_account.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/evmos/ethermint/crypto/ethsecp256k1" - erc20types "github.com/Canto-Network/Canto/v5/x/erc20/types" + erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/cosmos/cosmos-sdk/store/prefix" diff --git a/x/microtx/types/msgs.go b/x/microtx/types/msgs.go index 5885b032..172c7dc3 100644 --- a/x/microtx/types/msgs.go +++ b/x/microtx/types/msgs.go @@ -3,7 +3,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - authlegacy "github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx" + authlegacy "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" ) const ( diff --git a/x/nativedex/client/cli/utils.go b/x/nativedex/client/cli/utils.go index 06ad2c74..0b83c4d4 100644 --- a/x/nativedex/client/cli/utils.go +++ b/x/nativedex/client/cli/utils.go @@ -13,7 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/gov/client/cli" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/AltheaFoundation/althea-L1/x/nativedex/types" ) @@ -64,9 +64,9 @@ func GenericProposalCmdSetup(cmd *cobra.Command) (setup GenericProposalSetup, er return } -func GenericProposalCmdBroadcast(cmd *cobra.Command, clientCtx client.Context, content govtypes.Content, deposit sdk.Coins, from sdk.AccAddress) error { +func GenericProposalCmdBroadcast(cmd *cobra.Command, clientCtx client.Context, content govv1beta1.Content, deposit sdk.Coins, from sdk.AccAddress) error { - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from) + msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, from) if err != nil { return err } diff --git a/x/nativedex/client/proposal_handler.go b/x/nativedex/client/proposal_handler.go new file mode 100644 index 00000000..1ce0772b --- /dev/null +++ b/x/nativedex/client/proposal_handler.go @@ -0,0 +1,17 @@ +package client + +import ( + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + + "github.com/AltheaFoundation/althea-L1/x/nativedex/client/cli" +) + +var ( + UpgradeProxyHandler = govclient.NewProposalHandler(cli.NewUpgradeProxyProposalCmd) + CollectTreasuryHandler = govclient.NewProposalHandler(cli.NewCollectTreasuryProposalCmd) + SetTreasuryHandler = govclient.NewProposalHandler(cli.NewSetTreasuryProposalCmd) + AuthorityTransferHandler = govclient.NewProposalHandler(cli.NewAuthorityTransferProposalCmd) + HotPathOpenHandler = govclient.NewProposalHandler(cli.NewHotPathOpenProposalCmd) + SetSafeModeHandler = govclient.NewProposalHandler(cli.NewSetSafeModeProposalCmd) + TransferGovernanceHandler = govclient.NewProposalHandler(cli.NewTransferGovernanceProposalCmd) +) diff --git a/x/nativedex/keeper/keeper.go b/x/nativedex/keeper/keeper.go index 8a185f1b..61912e0f 100644 --- a/x/nativedex/keeper/keeper.go +++ b/x/nativedex/keeper/keeper.go @@ -7,6 +7,7 @@ import ( "github.com/tendermint/tendermint/libs/log" "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" @@ -15,7 +16,7 @@ import ( type ( Keeper struct { - storeKey sdk.StoreKey + storeKey storetypes.StoreKey cdc codec.BinaryCodec paramSpace paramtypes.Subspace @@ -24,7 +25,7 @@ type ( ) func NewKeeper( - storeKey sdk.StoreKey, + storeKey storetypes.StoreKey, cdc codec.BinaryCodec, ps paramtypes.Subspace, diff --git a/x/nativedex/proposal_handler.go b/x/nativedex/proposal_handler.go index 8ddebf86..7ca4dba9 100644 --- a/x/nativedex/proposal_handler.go +++ b/x/nativedex/proposal_handler.go @@ -3,7 +3,7 @@ package nativedex import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/ethereum/go-ethereum/common" "github.com/AltheaFoundation/althea-L1/contracts" @@ -26,8 +26,8 @@ const ( ) // Return governance handler to process dex governance proposals -func NewNativeDexProposalHandler(k *keeper.Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) error { +func NewNativeDexProposalHandler(k *keeper.Keeper) govv1beta1.Handler { + return func(ctx sdk.Context, content govv1beta1.Content) error { switch c := content.(type) { case *types.UpgradeProxyProposal: return handleUpgradeProxyProposal(ctx, k, c) diff --git a/x/nativedex/types/codec.go b/x/nativedex/types/codec.go index 061def9a..97a62449 100644 --- a/x/nativedex/types/codec.go +++ b/x/nativedex/types/codec.go @@ -4,7 +4,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/types/msgservice" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) func RegisterCodec(cdc *codec.LegacyAmino) { @@ -13,7 +13,7 @@ func RegisterCodec(cdc *codec.LegacyAmino) { // nolint: exhaustruct func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations( - (*govtypes.Content)(nil), + (*govv1beta1.Content)(nil), &UpgradeProxyProposal{}, &CollectTreasuryProposal{}, &SetTreasuryProposal{}, diff --git a/x/nativedex/types/proposal.go b/x/nativedex/types/proposal.go index 7ad423aa..70118850 100644 --- a/x/nativedex/types/proposal.go +++ b/x/nativedex/types/proposal.go @@ -6,6 +6,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) const ( @@ -25,38 +26,28 @@ var AcceptableCallpathIndexes []uint64 = []uint64{1, 2, 3, 4, 5, 6, 7, 3500, 999 // nolint: exhaustruct var ( - _ govtypes.Content = &UpgradeProxyProposal{} - _ govtypes.Content = &CollectTreasuryProposal{} - _ govtypes.Content = &SetTreasuryProposal{} - _ govtypes.Content = &AuthorityTransferProposal{} - _ govtypes.Content = &HotPathOpenProposal{} - _ govtypes.Content = &SetSafeModeProposal{} - _ govtypes.Content = &TransferGovernanceProposal{} - _ govtypes.Content = &OpsProposal{} + _ govv1beta1.Content = &UpgradeProxyProposal{} + _ govv1beta1.Content = &CollectTreasuryProposal{} + _ govv1beta1.Content = &SetTreasuryProposal{} + _ govv1beta1.Content = &AuthorityTransferProposal{} + _ govv1beta1.Content = &HotPathOpenProposal{} + _ govv1beta1.Content = &SetSafeModeProposal{} + _ govv1beta1.Content = &TransferGovernanceProposal{} ) // Register Compound Proposal type as a valid proposal type in goveranance module // nolint: exhaustruct func init() { - govtypes.RegisterProposalType(ProposalTypeUpgradeProxy) - govtypes.RegisterProposalTypeCodec(&UpgradeProxyProposal{}, "nativedex/UpgradeProxyProposal") - govtypes.RegisterProposalType(ProposalTypeCollectTreasury) - govtypes.RegisterProposalTypeCodec(&CollectTreasuryProposal{}, "nativedex/CollectTreasuryProposal") - govtypes.RegisterProposalType(ProposalTypeSetTreasury) - govtypes.RegisterProposalTypeCodec(&SetTreasuryProposal{}, "nativedex/SetTreasuryProposal") - govtypes.RegisterProposalType(ProposalTypeAuthorityTransfer) - govtypes.RegisterProposalTypeCodec(&AuthorityTransferProposal{}, "nativedex/AuthorityTransferProposal") - govtypes.RegisterProposalType(ProposalTypeHotPathOpen) - govtypes.RegisterProposalTypeCodec(&HotPathOpenProposal{}, "nativedex/HotPathOpenProposal") - govtypes.RegisterProposalType(ProposalTypeSetSafeMode) - govtypes.RegisterProposalTypeCodec(&SetSafeModeProposal{}, "nativedex/SetSafeModeProposal") - govtypes.RegisterProposalType(ProposalTypeTransferGovernance) - govtypes.RegisterProposalTypeCodec(&TransferGovernanceProposal{}, "nativedex/TransferGovernanceProposal") - govtypes.RegisterProposalType(ProposalTypeOps) - govtypes.RegisterProposalTypeCodec(&OpsProposal{}, "nativedex/OpsProposal") + govv1beta1.RegisterProposalType(ProposalTypeUpgradeProxy) + govv1beta1.RegisterProposalType(ProposalTypeCollectTreasury) + govv1beta1.RegisterProposalType(ProposalTypeSetTreasury) + govv1beta1.RegisterProposalType(ProposalTypeAuthorityTransfer) + govv1beta1.RegisterProposalType(ProposalTypeHotPathOpen) + govv1beta1.RegisterProposalType(ProposalTypeSetSafeMode) + govv1beta1.RegisterProposalType(ProposalTypeTransferGovernance) } -func NewUpgradeProxyProposal(title, description string, md UpgradeProxyMetadata) govtypes.Content { +func NewUpgradeProxyProposal(title, description string, md UpgradeProxyMetadata) govv1beta1.Content { return &UpgradeProxyProposal{ Title: title, Description: description, @@ -71,7 +62,7 @@ func (*UpgradeProxyProposal) ProposalType() string { } func (p *UpgradeProxyProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(p); err != nil { + if err := govv1beta1.ValidateAbstract(p); err != nil { return err } @@ -87,7 +78,7 @@ func (p *UpgradeProxyProposal) ValidateBasic() error { return nil } -func NewCollectTreasuryProposal(title, description string, md CollectTreasuryMetadata, inSafeMode bool) govtypes.Content { +func NewCollectTreasuryProposal(title, description string, md CollectTreasuryMetadata, inSafeMode bool) govv1beta1.Content { return &CollectTreasuryProposal{ Title: title, Description: description, @@ -103,7 +94,7 @@ func (*CollectTreasuryProposal) ProposalType() string { } func (p *CollectTreasuryProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(p); err != nil { + if err := govv1beta1.ValidateAbstract(p); err != nil { return err } @@ -115,7 +106,7 @@ func (p *CollectTreasuryProposal) ValidateBasic() error { return nil } -func NewSetTreasuryProposal(title, description string, md SetTreasuryMetadata, inSafeMode bool) govtypes.Content { +func NewSetTreasuryProposal(title, description string, md SetTreasuryMetadata, inSafeMode bool) govv1beta1.Content { return &SetTreasuryProposal{ Title: title, Description: description, @@ -131,7 +122,7 @@ func (*SetTreasuryProposal) ProposalType() string { } func (p *SetTreasuryProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(p); err != nil { + if err := govv1beta1.ValidateAbstract(p); err != nil { return err } @@ -143,7 +134,7 @@ func (p *SetTreasuryProposal) ValidateBasic() error { return nil } -func NewAuthorityTransferProposal(title, description string, md AuthorityTransferMetadata, inSafeMode bool) govtypes.Content { +func NewAuthorityTransferProposal(title, description string, md AuthorityTransferMetadata, inSafeMode bool) govv1beta1.Content { return &AuthorityTransferProposal{ Title: title, Description: description, @@ -159,7 +150,7 @@ func (*AuthorityTransferProposal) ProposalType() string { } func (p *AuthorityTransferProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(p); err != nil { + if err := govv1beta1.ValidateAbstract(p); err != nil { return err } @@ -171,7 +162,7 @@ func (p *AuthorityTransferProposal) ValidateBasic() error { return nil } -func NewHotPathOpenProposal(title, description string, md HotPathOpenMetadata, inSafeMode bool) govtypes.Content { +func NewHotPathOpenProposal(title, description string, md HotPathOpenMetadata, inSafeMode bool) govv1beta1.Content { return &HotPathOpenProposal{ Title: title, Description: description, @@ -187,7 +178,7 @@ func (*HotPathOpenProposal) ProposalType() string { } func (p *HotPathOpenProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(p); err != nil { + if err := govv1beta1.ValidateAbstract(p); err != nil { return err } @@ -197,7 +188,7 @@ func (p *HotPathOpenProposal) ValidateBasic() error { return nil } -func NewSetSafeModeProposal(title, description string, md SetSafeModeMetadata, inSafeMode bool) govtypes.Content { +func NewSetSafeModeProposal(title, description string, md SetSafeModeMetadata, inSafeMode bool) govv1beta1.Content { return &SetSafeModeProposal{ Title: title, Description: description, @@ -213,7 +204,7 @@ func (*SetSafeModeProposal) ProposalType() string { } func (p *SetSafeModeProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(p); err != nil { + if err := govv1beta1.ValidateAbstract(p); err != nil { return err } @@ -223,7 +214,7 @@ func (p *SetSafeModeProposal) ValidateBasic() error { return nil } -func NewTransferGovernanceProposal(title, description string, md TransferGovernanceMetadata) govtypes.Content { +func NewTransferGovernanceProposal(title, description string, md TransferGovernanceMetadata) govv1beta1.Content { return &TransferGovernanceProposal{ Title: title, Description: description, @@ -238,7 +229,7 @@ func (*TransferGovernanceProposal) ProposalType() string { } func (p *TransferGovernanceProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(p); err != nil { + if err := govv1beta1.ValidateAbstract(p); err != nil { return err } @@ -255,7 +246,7 @@ func (p *TransferGovernanceProposal) ValidateBasic() error { return nil } -func NewOpsProposal(title, description string, md OpsMetadata) govtypes.Content { +func NewOpsProposal(title, description string, md OpsMetadata) govv1beta1.Content { return &OpsProposal{ Title: title, Description: description, @@ -270,7 +261,7 @@ func (*OpsProposal) ProposalType() string { } func (p *OpsProposal) ValidateBasic() error { - if err := govtypes.ValidateAbstract(p); err != nil { + if err := govv1beta1.ValidateAbstract(p); err != nil { return err } diff --git a/x/onboarding/ibc_middleware.go b/x/onboarding/ibc_middleware.go index b164ddc3..5eac99d3 100644 --- a/x/onboarding/ibc_middleware.go +++ b/x/onboarding/ibc_middleware.go @@ -4,9 +4,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v4/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v6/modules/core/exported" "github.com/AltheaFoundation/althea-L1/x/onboarding/keeper" ) @@ -51,9 +52,13 @@ func (im IBCMiddleware) OnRecvPacket( func (im IBCMiddleware) SendPacket( ctx sdk.Context, chanCap *capabilitytypes.Capability, - packet exported.PacketI, -) error { - return im.keeper.SendPacket(ctx, chanCap, packet) + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (sequence uint64, err error) { + return im.keeper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) } // WriteAcknowledgement implements the ICS4 Wrapper interface diff --git a/x/onboarding/ibc_module_test.go b/x/onboarding/ibc_module_test.go index 23dc20f0..c3ea888f 100644 --- a/x/onboarding/ibc_module_test.go +++ b/x/onboarding/ibc_module_test.go @@ -10,13 +10,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - ibcgotesting "github.com/cosmos/ibc-go/v4/testing" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + ibcgotesting "github.com/cosmos/ibc-go/v6/testing" evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/Canto-Network/Canto/v5/contracts" + "github.com/Canto-Network/Canto/v6/contracts" althea "github.com/AltheaFoundation/althea-L1/app" ibctesting "github.com/AltheaFoundation/althea-L1/ibcutils/testing" @@ -98,7 +98,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { // send coins from chainA to chainB // auto swap and auto convert should happen - msg := transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0) + msg := transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") res, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -132,7 +132,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { // IBC transfer to blocked address blockedAddr := "althea10d07y265gmmuvt4z0w9aw880jnsr700jwqkt6k" coinToSendToB = suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom) - msg = transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), blockedAddr, timeoutHeight, 0) + msg = transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), blockedAddr, timeoutHeight, 0, "") res, err = suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed @@ -154,7 +154,7 @@ func (suite *TransferTestSuite) TestHandleMsgTransfer() { balanceVoucherBefore = suite.chainB.App.(*althea.AltheaApp).BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom()) balanceErc20Before = erc20Keeper.BalanceOf(suite.chainB.GetContext(), contracts.ERC20MinterBurnerDecimalsContract.ABI, pair.GetERC20Contract(), common.BytesToAddress(suite.chainB.SenderAccount.GetAddress().Bytes())) - msg = transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0) + msg = transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coinToSendToB, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0, "") res, err = suite.chainA.SendMsgs(msg) suite.Require().NoError(err) // message committed diff --git a/x/onboarding/keeper/ibc_callbacks.go b/x/onboarding/keeper/ibc_callbacks.go index 3954aa26..d5807a5d 100644 --- a/x/onboarding/keeper/ibc_callbacks.go +++ b/x/onboarding/keeper/ibc_callbacks.go @@ -7,11 +7,11 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - "github.com/cosmos/ibc-go/v4/modules/core/exported" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + "github.com/cosmos/ibc-go/v6/modules/core/exported" - erc20types "github.com/Canto-Network/Canto/v5/x/erc20/types" + erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" "github.com/AltheaFoundation/althea-L1/ibcutils" "github.com/AltheaFoundation/althea-L1/x/onboarding/types" diff --git a/x/onboarding/keeper/ibc_callbacks_test.go b/x/onboarding/keeper/ibc_callbacks_test.go index 07fe3e2d..cdbc168e 100644 --- a/x/onboarding/keeper/ibc_callbacks_test.go +++ b/x/onboarding/keeper/ibc_callbacks_test.go @@ -9,19 +9,21 @@ import ( evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/stretchr/testify/mock" + math "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" - ibcgotesting "github.com/cosmos/ibc-go/v4/testing" - ibcmock "github.com/cosmos/ibc-go/v4/testing/mock" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + ibcgotesting "github.com/cosmos/ibc-go/v6/testing" + ibcmock "github.com/cosmos/ibc-go/v6/testing/mock" - "github.com/Canto-Network/Canto/v5/contracts" - erc20types "github.com/Canto-Network/Canto/v5/x/erc20/types" + "github.com/Canto-Network/Canto/v6/contracts" + erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" "github.com/AltheaFoundation/althea-L1/x/onboarding/keeper" onboardingtest "github.com/AltheaFoundation/althea-L1/x/onboarding/testutil" @@ -98,7 +100,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { // Setup Cosmos <=> althea IBC relayer denom := "uUSDC" ibcDenom := uusdcIbcdenom - transferAmount := sdk.NewIntWithDecimal(25, 6) + transferAmount := math.NewIntWithDecimal(25, 6) sourceChannel := "channel-0" altheaChannel := sourceChannel path := fmt.Sprintf("%s/%s", transfertypes.PortID, altheaChannel) @@ -119,7 +121,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "fail - invalid sender - missing '1' ", func() { - transfer := transfertypes.NewFungibleTokenPacketData(denom, "100", "althea", ethsecpAddrAlthea) + transfer := transfertypes.NewFungibleTokenPacketData(denom, "100", "althea", ethsecpAddrAlthea, "") bz := transfertypes.ModuleCdc.MustMarshalJSON(&transfer) packet = channeltypes.NewPacket(bz, 100, transfertypes.PortID, sourceChannel, transfertypes.PortID, altheaChannel, timeoutHeight, 0) }, @@ -130,7 +132,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { { "fail - invalid sender - invalid bech32", func() { - transfer := transfertypes.NewFungibleTokenPacketData(denom, "100", "badba1sv9m0g7ycejwr3s369km58h5qe7xj77hvcxrms", ethsecpAddrAlthea) + transfer := transfertypes.NewFungibleTokenPacketData(denom, "100", "badba1sv9m0g7ycejwr3s369km58h5qe7xj77hvcxrms", ethsecpAddrAlthea, "") bz := transfertypes.ModuleCdc.MustMarshalJSON(&transfer) packet = channeltypes.NewPacket(bz, 100, transfertypes.PortID, sourceChannel, transfertypes.PortID, altheaChannel, timeoutHeight, 0) }, @@ -144,7 +146,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { distrAcc := suite.app.AccountKeeper.GetModuleAccount(suite.ctx, distrtypes.ModuleName) suite.Require().NotNil(distrAcc) addr := distrAcc.GetAddress().String() - transfer := transfertypes.NewFungibleTokenPacketData(denom, "100", addr, addr) + transfer := transfertypes.NewFungibleTokenPacketData(denom, "100", addr, addr, "") bz := transfertypes.ModuleCdc.MustMarshalJSON(&transfer) packet = channeltypes.NewPacket(bz, 100, transfertypes.PortID, sourceChannel, transfertypes.PortID, altheaChannel, timeoutHeight, 0) }, @@ -170,7 +172,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { denom = "uUSDT" ibcDenom = uusdtIbcdenom - transfer := transfertypes.NewFungibleTokenPacketData(denom, transferAmount.String(), secpAddrCosmos, ethsecpAddrAlthea) + transfer := transfertypes.NewFungibleTokenPacketData(denom, transferAmount.String(), secpAddrCosmos, ethsecpAddrAlthea, "") bz := transfertypes.ModuleCdc.MustMarshalJSON(&transfer) packet = channeltypes.NewPacket(bz, 100, transfertypes.PortID, sourceChannel, transfertypes.PortID, altheaChannel, timeoutHeight, 0) }, @@ -184,8 +186,8 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { denom = uusdcCh100DenomTrace.BaseDenom ibcDenom = uusdcCh100IbcDenom altheaChannel = "channel-100" - transferAmount = sdk.NewIntWithDecimal(25, 6) - transfer := transfertypes.NewFungibleTokenPacketData(denom, transferAmount.String(), secpAddrCosmos, ethsecpAddrAlthea) + transferAmount = math.NewIntWithDecimal(25, 6) + transfer := transfertypes.NewFungibleTokenPacketData(denom, transferAmount.String(), secpAddrCosmos, ethsecpAddrAlthea, "") bz := transfertypes.ModuleCdc.MustMarshalJSON(&transfer) packet = channeltypes.NewPacket(bz, 100, transfertypes.PortID, sourceChannel, transfertypes.PortID, altheaChannel, timeoutHeight, 0) }, @@ -200,8 +202,8 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { ibcDenom = uusdcIbcdenom altheaChannel = sourceChannel - transferAmount = sdk.NewIntWithDecimal(25, 6) - transfer := transfertypes.NewFungibleTokenPacketData(denom, transferAmount.String(), secpAddrCosmos, ethsecpAddrAlthea) + transferAmount = math.NewIntWithDecimal(25, 6) + transfer := transfertypes.NewFungibleTokenPacketData(denom, transferAmount.String(), secpAddrCosmos, ethsecpAddrAlthea, "") bz := transfertypes.ModuleCdc.MustMarshalJSON(&transfer) packet = channeltypes.NewPacket(bz, 100, transfertypes.PortID, sourceChannel, transfertypes.PortID, altheaChannel, timeoutHeight, 0) @@ -212,7 +214,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { }, true, - sdk.NewCoin(uusdcIbcdenom, sdk.NewIntWithDecimal(25, 6)), + sdk.NewCoin(uusdcIbcdenom, math.NewIntWithDecimal(25, 6)), sdk.NewInt(0), }, } @@ -220,7 +222,7 @@ func (suite *KeeperTestSuite) TestOnRecvPacket() { suite.Run(fmt.Sprintf("Case %s", tc.name), func() { suite.SetupTest() // reset - coins := sdk.NewCoins(sdk.NewCoin("aalthea", sdk.NewIntWithDecimal(10000, 18)), sdk.NewCoin(uusdcIbcdenom, sdk.NewIntWithDecimal(10000, 6))) + coins := sdk.NewCoins(sdk.NewCoin("aalthea", math.NewIntWithDecimal(10000, 18)), sdk.NewCoin(uusdcIbcdenom, math.NewIntWithDecimal(10000, 6))) suite.Require().NoError(suite.app.BankKeeper.MintCoins(suite.ctx, evmtypes.ModuleName, coins)) err = suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, evmtypes.ModuleName, secpAddr, coins) suite.Require().NoError(err) diff --git a/x/onboarding/keeper/keeper.go b/x/onboarding/keeper/keeper.go index 24d177ff..dc5a9bc2 100644 --- a/x/onboarding/keeper/keeper.go +++ b/x/onboarding/keeper/keeper.go @@ -9,15 +9,15 @@ import ( capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" - "github.com/cosmos/ibc-go/v4/modules/core/exported" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + "github.com/cosmos/ibc-go/v6/modules/core/exported" "github.com/AltheaFoundation/althea-L1/x/onboarding/types" ) // nolint: exhaustruct -var _ transfertypes.ICS4Wrapper = Keeper{} +var _ porttypes.ICS4Wrapper = Keeper{} // Keeper struct type Keeper struct { @@ -74,8 +74,16 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { // SendPacket implements the ICS4Wrapper interface from the transfer module. // It calls the underlying SendPacket function directly to move down the middleware stack. -func (k Keeper) SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet exported.PacketI) error { - return k.Ics4Wrapper.SendPacket(ctx, channelCap, packet) +func (k Keeper) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (sequence uint64, err error) { + return k.Ics4Wrapper.SendPacket(ctx, chanCap, sourcePort, sourceChannel, timeoutHeight, timeoutTimestamp, data) } // WriteAcknowledgement implements the ICS4Wrapper interface from the transfer module. diff --git a/x/onboarding/keeper/utils_test.go b/x/onboarding/keeper/utils_test.go index 718c18f7..c572a198 100644 --- a/x/onboarding/keeper/utils_test.go +++ b/x/onboarding/keeper/utils_test.go @@ -8,8 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" "github.com/AltheaFoundation/althea-L1/x/onboarding/types" ) diff --git a/x/onboarding/testutil/helpers.go b/x/onboarding/testutil/helpers.go index c1362504..0cb570a6 100644 --- a/x/onboarding/testutil/helpers.go +++ b/x/onboarding/testutil/helpers.go @@ -7,7 +7,7 @@ import ( "golang.org/x/exp/slices" sdk "github.com/cosmos/cosmos-sdk/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" ibcgotesting "github.com/AltheaFoundation/althea-L1/ibcutils/testing" ) diff --git a/x/onboarding/types/interfaces.go b/x/onboarding/types/interfaces.go index 30bd46a9..4fdeb3ef 100644 --- a/x/onboarding/types/interfaces.go +++ b/x/onboarding/types/interfaces.go @@ -12,13 +12,13 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - transfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" - channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" evmtypes "github.com/evmos/ethermint/x/evm/types" - erc20types "github.com/Canto-Network/Canto/v5/x/erc20/types" + erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" ) type Erc20Keeper interface { From ef43ff0f285f7c333ca020c76b5124acb5e24b9f Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 7 Oct 2024 14:46:17 -0400 Subject: [PATCH 03/25] Configure block max gas in test env --- tests/container-scripts/setup-validators.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/container-scripts/setup-validators.sh b/tests/container-scripts/setup-validators.sh index d804e68e..8a8d5e62 100755 --- a/tests/container-scripts/setup-validators.sh +++ b/tests/container-scripts/setup-validators.sh @@ -55,6 +55,8 @@ $BIN init $STARTING_VALIDATOR_HOME --chain-id=$CHAIN_ID validator$STARTING_VALID ## we could keep a hardcoded genesis file around but that would prevent us from ## testing the generated one with the default values provided by the module. cp /validator$STARTING_VALIDATOR/config/genesis.json /genesis.json +# Set the default max gas per block to a positive value (100 million) +jq '.consensus_params.block.max_gas = "100000000"' /genesis.json > tmp_genesis.json && mv tmp_genesis.json /genesis.json # add in denom metadata for both native tokens jq '.app_state.bank.denom_metadata += [{"name": "althea", "symbol": "althea", "base": "aalthea", display: "althea", "description": "The native staking token of althea-L1 (18 decimals)", "denom_units": [{"denom": "aalthea", "exponent": 0, "aliases": ["attoalthea", "althea-wei"]}, {"denom": "nalthea", "exponent": 9, "aliases": ["nanoalthea", "althea-gwei"]}, {"denom": "althea", "exponent": 18}]}]' /genesis.json > tmp_genesis.json && mv tmp_genesis.json /genesis.json jq '.app_state.bank.denom_metadata += [{"name": "FOO", "symbol": "FOO", "base": "ufootoken", display: "footoken", "description": "A non-staking native test token (6 decimals)", "denom_units": [{"denom": "ufootoken", "exponent": 0}, {"denom": "footoken", "exponent": 6}]}]' /genesis.json > tmp_genesis.json && mv tmp_genesis.json /genesis.json From f764a697d76056986955264f87ad53a4b2a160e9 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Thu, 3 Oct 2024 12:06:28 -0400 Subject: [PATCH 04/25] Configure althea root cmd --- cmd/althea/root.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cmd/althea/root.go b/cmd/althea/root.go index 8f4b1641..69e9d7e6 100644 --- a/cmd/althea/root.go +++ b/cmd/althea/root.go @@ -11,6 +11,11 @@ import ( "os" "path/filepath" + "github.com/cosmos/go-bip39" + "github.com/pkg/errors" + "github.com/spf13/cast" + "github.com/spf13/cobra" + cfg "github.com/tendermint/tendermint/config" tmcli "github.com/tendermint/tendermint/libs/cli" "github.com/tendermint/tendermint/libs/log" @@ -26,23 +31,20 @@ import ( "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/types" - vestingcli "github.com/cosmos/cosmos-sdk/x/auth/vesting/client/cli" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/crisis" "github.com/cosmos/cosmos-sdk/x/genutil" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" - "github.com/cosmos/go-bip39" - "github.com/pkg/errors" - "github.com/spf13/cast" - "github.com/spf13/cobra" // EVM ethermintclient "github.com/evmos/ethermint/client" + "github.com/evmos/ethermint/ethereum/eip712" ethermintserver "github.com/evmos/ethermint/server" ethermintserverconfig "github.com/evmos/ethermint/server/config" ethermintserverflags "github.com/evmos/ethermint/server/flags" @@ -108,6 +110,8 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { WithKeyringOptions(keyring.Option()). WithViper(EnvPrefix) + eip712.SetEncodingConfig(simappparams.EncodingConfig(encodingConfig)) + rootCmd := &cobra.Command{ Use: althea.Name, Short: "Althea L1: Submit transactions or run a validator", @@ -372,8 +376,6 @@ func txCommand() *cobra.Command { authcmd.GetEncodeCommand(), authcmd.GetDecodeCommand(), authcmd.GetAuxToFeeCommand(), - flags.LineBreak, - vestingcli.GetTxCmd(), ) althea.ModuleBasics.AddTxCommands(cmd) From 1b91186b30f6b0a43afa4ae3670e8e35afba4e5a Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 7 Oct 2024 14:16:04 -0400 Subject: [PATCH 05/25] Copy ERC20 module implementation from Canto repo --- app/ante/charge_gasfree_fees_test.go | 2 +- app/ante/cosmos_handler_test.go | 4 +- app/ante/eth_set_pubkey_test.go | 13 - app/ante/utils_test.go | 20 +- app/app.go | 31 +- app/genesis.go | 14 +- app/sigverify.go | 80 +- app/testutil.go | 175 ++- go.mod | 15 +- go.sum | 10 +- testutil/fund.go | 29 + testutil/network/doc.go | 65 + testutil/network/network.go | 694 ++++++++++ testutil/network/network_test.go | 64 + testutil/network/util.go | 256 ++++ x/erc20/client/cli/query.go | 128 ++ x/erc20/client/cli/tx.go | 363 ++++++ x/erc20/client/cli/utils.go | 25 + x/erc20/client/proposal_handler.go | 13 + x/erc20/genesis.go | 40 + x/erc20/genesis_test.go | 160 +++ x/erc20/handler.go | 27 + x/erc20/keeper/evm.go | 241 ++++ x/erc20/keeper/evm_hooks.go | 157 +++ x/erc20/keeper/evm_hooks_test.go | 431 +++++++ x/erc20/keeper/evm_test.go | 386 ++++++ x/erc20/keeper/grpc_query.go | 85 ++ x/erc20/keeper/grpc_query_test.go | 170 +++ x/erc20/keeper/integration_test.go | 302 +++++ x/erc20/keeper/keeper.go | 53 + x/erc20/keeper/keeper_test.go | 518 ++++++++ x/erc20/keeper/migrations.go | 27 + x/erc20/keeper/mint.go | 66 + x/erc20/keeper/mint_test.go | 112 ++ x/erc20/keeper/msg_server.go | 526 ++++++++ x/erc20/keeper/msg_server_test.go | 1344 ++++++++++++++++++++ x/erc20/keeper/params.go | 18 + x/erc20/keeper/params_test.go | 12 + x/erc20/keeper/proposals.go | 216 ++++ x/erc20/keeper/proposals_test.go | 473 +++++++ x/erc20/keeper/token_pairs.go | 129 ++ x/erc20/keeper/token_pairs_test.go | 234 ++++ x/erc20/migrations/v2/migration.go | 21 + x/erc20/migrations/v2/migration_test.go | 54 + x/erc20/module.go | 181 +++ x/erc20/proposal_handler.go | 77 ++ x/erc20/types/codec.go | 60 + x/erc20/types/erc20.pb.go | 1401 +++++++++++++++++++++ x/erc20/types/errors.go | 21 + x/erc20/types/events.go | 33 + x/erc20/types/evm.go | 33 + x/erc20/types/evm_test.go | 13 + x/erc20/types/genesis.go | 44 + x/erc20/types/genesis.pb.go | 598 +++++++++ x/erc20/types/genesis_test.go | 148 +++ x/erc20/types/interfaces.go | 43 + x/erc20/types/keys.go | 39 + x/erc20/types/msg.go | 111 ++ x/erc20/types/msg_test.go | 247 ++++ x/erc20/types/params.go | 57 + x/erc20/types/params_test.go | 55 + x/erc20/types/proposal.go | 163 +++ x/erc20/types/proposal_test.go | 279 ++++ x/erc20/types/query.pb.go | 1399 ++++++++++++++++++++ x/erc20/types/query.pb.gw.go | 337 +++++ x/erc20/types/token_pair.go | 54 + x/erc20/types/token_pair_test.go | 159 +++ x/erc20/types/tx.pb.go | 1140 +++++++++++++++++ x/erc20/types/tx.pb.gw.go | 254 ++++ x/erc20/types/utils.go | 83 ++ x/erc20/types/utils_test.go | 249 ++++ x/gasfree/module_test.go | 121 +- x/lockup/keeper/test_common.go | 9 +- x/microtx/keeper/keeper.go | 2 +- x/microtx/keeper/liquid_account.go | 2 +- x/onboarding/genesis_test.go | 8 +- x/onboarding/ibc_module_test.go | 2 +- x/onboarding/keeper/ibc_callbacks.go | 3 +- x/onboarding/keeper/ibc_callbacks_test.go | 4 +- x/onboarding/keeper/keeper_test.go | 42 +- x/onboarding/types/interfaces.go | 2 +- 81 files changed, 15077 insertions(+), 199 deletions(-) create mode 100644 testutil/fund.go create mode 100644 testutil/network/doc.go create mode 100644 testutil/network/network.go create mode 100644 testutil/network/network_test.go create mode 100644 testutil/network/util.go create mode 100644 x/erc20/client/cli/query.go create mode 100644 x/erc20/client/cli/tx.go create mode 100644 x/erc20/client/cli/utils.go create mode 100644 x/erc20/client/proposal_handler.go create mode 100644 x/erc20/genesis.go create mode 100644 x/erc20/genesis_test.go create mode 100644 x/erc20/handler.go create mode 100644 x/erc20/keeper/evm.go create mode 100644 x/erc20/keeper/evm_hooks.go create mode 100644 x/erc20/keeper/evm_hooks_test.go create mode 100644 x/erc20/keeper/evm_test.go create mode 100644 x/erc20/keeper/grpc_query.go create mode 100644 x/erc20/keeper/grpc_query_test.go create mode 100644 x/erc20/keeper/integration_test.go create mode 100644 x/erc20/keeper/keeper.go create mode 100644 x/erc20/keeper/keeper_test.go create mode 100644 x/erc20/keeper/migrations.go create mode 100644 x/erc20/keeper/mint.go create mode 100644 x/erc20/keeper/mint_test.go create mode 100644 x/erc20/keeper/msg_server.go create mode 100644 x/erc20/keeper/msg_server_test.go create mode 100644 x/erc20/keeper/params.go create mode 100644 x/erc20/keeper/params_test.go create mode 100644 x/erc20/keeper/proposals.go create mode 100644 x/erc20/keeper/proposals_test.go create mode 100644 x/erc20/keeper/token_pairs.go create mode 100644 x/erc20/keeper/token_pairs_test.go create mode 100644 x/erc20/migrations/v2/migration.go create mode 100644 x/erc20/migrations/v2/migration_test.go create mode 100644 x/erc20/module.go create mode 100644 x/erc20/proposal_handler.go create mode 100644 x/erc20/types/codec.go create mode 100644 x/erc20/types/erc20.pb.go create mode 100644 x/erc20/types/errors.go create mode 100644 x/erc20/types/events.go create mode 100644 x/erc20/types/evm.go create mode 100644 x/erc20/types/evm_test.go create mode 100644 x/erc20/types/genesis.go create mode 100644 x/erc20/types/genesis.pb.go create mode 100644 x/erc20/types/genesis_test.go create mode 100644 x/erc20/types/interfaces.go create mode 100644 x/erc20/types/keys.go create mode 100644 x/erc20/types/msg.go create mode 100644 x/erc20/types/msg_test.go create mode 100644 x/erc20/types/params.go create mode 100644 x/erc20/types/params_test.go create mode 100644 x/erc20/types/proposal.go create mode 100644 x/erc20/types/proposal_test.go create mode 100644 x/erc20/types/query.pb.go create mode 100644 x/erc20/types/query.pb.gw.go create mode 100644 x/erc20/types/token_pair.go create mode 100644 x/erc20/types/token_pair_test.go create mode 100644 x/erc20/types/tx.pb.go create mode 100644 x/erc20/types/tx.pb.gw.go create mode 100644 x/erc20/types/utils.go create mode 100644 x/erc20/types/utils_test.go diff --git a/app/ante/charge_gasfree_fees_test.go b/app/ante/charge_gasfree_fees_test.go index f27965e3..6f502ab4 100644 --- a/app/ante/charge_gasfree_fees_test.go +++ b/app/ante/charge_gasfree_fees_test.go @@ -192,6 +192,6 @@ func (suite *AnteTestSuite) TestChargeGasfreeFeesDecorator() { // nolint: exhaustruct suite.app.GasfreeKeeper.SetGasFreeMessageTypes(bothGasfreeCtx, []string{sdk.MsgTypeURL(µtxtypes.MsgMicrotx{}), sdk.MsgTypeURL(&banktypes.MsgSend{})}) - // Expect the error from the mempool fee decorator to contain something like "insufficient fees; got: x required: provided fee < minimum global feey" + // Expect the error from the mempool fee decorator to contain something like "insufficient fees; got: x required: provided fee < minimum global fee y" suite.Require().NoError(runGasfreeTests(suite, gasfreeMicrotxCtx, gasfreeSendCtx, noGasfreeCtx, bothGasfreeCtx, msgMicrotxTx, msgSendTx, bothTx, addr, testDenom)) } diff --git a/app/ante/cosmos_handler_test.go b/app/ante/cosmos_handler_test.go index abf8e190..5edaab43 100644 --- a/app/ante/cosmos_handler_test.go +++ b/app/ante/cosmos_handler_test.go @@ -115,8 +115,8 @@ func (suite *AnteTestSuite) TestCosmosAnteHandlerMempoolFeeBypass() { // nolint: exhaustruct suite.app.GasfreeKeeper.SetGasFreeMessageTypes(bothGasfreeCtx, []string{sdk.MsgTypeURL(µtxtypes.MsgMicrotx{}), sdk.MsgTypeURL(&banktypes.MsgSend{})}) - // Expect the error from the mempool fee decorator to contain something like "insufficient fees; got: x required: provided fee < minimum global feey" - suite.Require().NoError(runBypassTest(suite, "insufficient fees; got:", gasfreeMicrotxCtx, gasfreeSendCtx, noGasfreeCtx, bothGasfreeCtx, msgMicrotxTx, msgSendTx, bothTx)) + // Expect the error from the mempool fee decorator to contain something like "insufficient fees; got: x required: provided fee < minimum global fee" + suite.Require().NoError(runBypassTest(suite, "provided fee < minimum global fee", gasfreeMicrotxCtx, gasfreeSendCtx, noGasfreeCtx, bothGasfreeCtx, msgMicrotxTx, msgSendTx, bothTx)) } // Checks that the MinGasPrices antedecorator is bypassed for applicable txs diff --git a/app/ante/eth_set_pubkey_test.go b/app/ante/eth_set_pubkey_test.go index 412b4b2b..189b13c3 100644 --- a/app/ante/eth_set_pubkey_test.go +++ b/app/ante/eth_set_pubkey_test.go @@ -153,19 +153,6 @@ func (suite *AnteTestSuite) TestEthSetPubkeyHandler() { suite.Require().Error(err) } suite.Require().True(tc.correctPubKey(pubKey), "PubKey type incorrect after AnteHandler") - - // Now check the old antehandler against the same Tx, see if it would create a pubkey - ctx, _ = suite.ctx.CacheContext() - suite.testCaseSetup(ctx, addr, tc.startBaseAcc) - // nolint: errcheck - _, _ = suite.oldAnteHandler(ctx, tx, false) - acc = suite.app.AccountKeeper.GetAccount(ctx, addr) - pubKey = acc.GetPubKey() - if tc.expOldPubKey { - suite.Require().True(pubKey != nil && tc.correctPubKey(pubKey), "Old ante handler should have set a pubkey") - } else { - suite.Require().True(pubKey == nil, "Old ante handler should have set a pubkey") - } }) } } diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index 34ab2289..be0eab38 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -40,8 +40,6 @@ import ( evmtypes "github.com/evmos/ethermint/x/evm/types" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" - cantoante "github.com/Canto-Network/Canto/v6/app/ante" - althea "github.com/AltheaFoundation/althea-L1/app" ante "github.com/AltheaFoundation/althea-L1/app/ante" altheaconfig "github.com/AltheaFoundation/althea-L1/config" @@ -55,7 +53,6 @@ type AnteTestSuite struct { app *althea.AltheaApp clientCtx client.Context anteHandler sdk.AnteHandler - oldAnteHandler sdk.AnteHandler ethSigner ethtypes.Signer enableFeemarket bool evmParamsOption func(*evmtypes.Params) @@ -73,12 +70,13 @@ func (suite *AnteTestSuite) SetupTest() { cfg := sdk.GetConfig() cfg.SetBech32PrefixForAccount("althea", "altheapub") - suite.app = althea.Setup(checkTx, func(app *althea.AltheaApp, genesis althea.GenesisState) althea.GenesisState { + suite.app = althea.NewSetup(checkTx, func(app *althea.AltheaApp, genesis simapp.GenesisState) simapp.GenesisState { if suite.enableFeemarket { // setup feemarketGenesis params feemarketGenesis := feemarkettypes.DefaultGenesisState() feemarketGenesis.Params.EnableHeight = 1 feemarketGenesis.Params.NoBaseFee = false + feemarketGenesis.BlockGas = 30000000 // Verify feeMarket genesis err := feemarketGenesis.Validate() suite.Require().NoError(err) @@ -117,20 +115,6 @@ func (suite *AnteTestSuite) SetupTest() { suite.anteHandler = anteHandler - // Also make a copy of the old Canto antehandler we were using to ensure that our changes fix the problem - // nolint: exhaustruct - oldAnteHandler := cantoante.NewAnteHandler(cantoante.HandlerOptions{ - AccountKeeper: *suite.app.AccountKeeper, - BankKeeper: suite.app.BankKeeper, - EvmKeeper: suite.app.EvmKeeper, - FeegrantKeeper: nil, - IBCKeeper: suite.app.IbcKeeper, - FeeMarketKeeper: *suite.app.FeemarketKeeper, - SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), - SigGasConsumer: althea.SigVerificationGasConsumer, - }) - suite.oldAnteHandler = oldAnteHandler - // Defines the siging method (e.g. homestead, london, etc) suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()) } diff --git a/app/app.go b/app/app.go index 212951e9..ade22785 100644 --- a/app/app.go +++ b/app/app.go @@ -112,11 +112,6 @@ import ( // EVM + ERC20 - "github.com/Canto-Network/Canto/v6/x/erc20" - erc20client "github.com/Canto-Network/Canto/v6/x/erc20/client" - erc20keeper "github.com/Canto-Network/Canto/v6/x/erc20/keeper" - erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" - ethante "github.com/evmos/ethermint/app/ante" "github.com/evmos/ethermint/ethereum/eip712" ethermintsrvflags "github.com/evmos/ethermint/server/flags" @@ -137,6 +132,10 @@ import ( "github.com/AltheaFoundation/althea-L1/app/upgrades" "github.com/AltheaFoundation/althea-L1/app/upgrades/neutrino" altheacfg "github.com/AltheaFoundation/althea-L1/config" + "github.com/AltheaFoundation/althea-L1/x/erc20" + erc20client "github.com/AltheaFoundation/althea-L1/x/erc20/client" + erc20keeper "github.com/AltheaFoundation/althea-L1/x/erc20/keeper" + erc20types "github.com/AltheaFoundation/althea-L1/x/erc20/types" "github.com/AltheaFoundation/althea-L1/x/gasfree" gasfreekeeper "github.com/AltheaFoundation/althea-L1/x/gasfree/keeper" gasfreetypes "github.com/AltheaFoundation/althea-L1/x/gasfree/types" @@ -578,6 +577,16 @@ func NewAltheaApp( ) app.SlashingKeeper = &slashingKeeper + // Connect the inter-module staking hooks together, these are the only modules allowed to interact with how staking + // works, including inflationary staking rewards and punishing bad actors (excluding genutil which works at genesis to + // seed the set of validators from the genesis txs set) + stakingKeeper.SetHooks( + stakingtypes.NewMultiStakingHooks( + distrKeeper.Hooks(), + slashingKeeper.Hooks(), + ), + ) + upgradeKeeper := upgradekeeper.NewKeeper( skipUpgradeHeights, keys[upgradetypes.StoreKey], @@ -682,16 +691,6 @@ func NewAltheaApp( ibcRouter.AddRoute(icahosttypes.SubModuleName, icaHostStack) ibcKeeper.SetRouter(ibcRouter) - // Connect the inter-module staking hooks together, these are the only modules allowed to interact with how staking - // works, including inflationary staking rewards and punishing bad actors (excluding genutil which works at genesis to - // seed the set of validators from the genesis txs set) - stakingKeeper.SetHooks( - stakingtypes.NewMultiStakingHooks( - distrKeeper.Hooks(), - slashingKeeper.Hooks(), - ), - ) - mintKeeper := mintkeeper.NewKeeper( appCodec, keys[minttypes.StoreKey], @@ -1065,7 +1064,7 @@ func (app *AltheaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci // InitChainer deserializes the given chain genesis state, registers in-place upgrade migrations, and delegates // the ABCI InitGenesis execution to the ModuleManager func (app *AltheaApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { - var genesisState GenesisState + var genesisState simapp.GenesisState if err := tmjson.Unmarshal(req.AppStateBytes, &genesisState); err != nil { panic(err) } diff --git a/app/genesis.go b/app/genesis.go index 284efda6..d1d293c0 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -1,20 +1,10 @@ package althea import ( - "encoding/json" + "github.com/cosmos/cosmos-sdk/simapp" ) -// The genesis state of the blockchain is represented here as a map of raw json -// messages key'd by a identifier string. -// The identifier is used to determine which module genesis information belongs -// to so it may be appropriately routed during init chain. -// Within this application default genesis information is retrieved from -// the ModuleBasicManager which populates json from each BasicModule -// object provided to it during init. -type GenesisState map[string]json.RawMessage - -// NewDefaultGenesisState generates the default state for the application. -func NewDefaultGenesisState() GenesisState { +func NewDefaultGenesisState() simapp.GenesisState { encCfg := MakeEncodingConfig() return ModuleBasics.DefaultGenesis(encCfg.Codec) } diff --git a/app/sigverify.go b/app/sigverify.go index 130703dd..cdf75cce 100644 --- a/app/sigverify.go +++ b/app/sigverify.go @@ -1,12 +1,19 @@ package althea import ( + "fmt" + + errorsmod "cosmossdk.io/errors" + + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/crypto/types/multisig" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/types/tx/signing" + authante "github.com/cosmos/cosmos-sdk/x/auth/ante" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - - canto "github.com/Canto-Network/Canto/v6/app" + "github.com/evmos/ethermint/crypto/ethsecp256k1" ) const ( @@ -38,6 +45,73 @@ func SigVerificationGasConsumer( return nil default: - return canto.SigVerificationGasConsumer(meter, sig, params) + return CantoSigVerificationGasConsumer(meter, sig, params) + } +} + +var _ authante.SignatureVerificationGasConsumer = CantoSigVerificationGasConsumer + +// SigVerificationGasConsumer is the canto implementation of SignatureVerificationGasConsumer. It consumes gas +// for signature verification based upon the public key type. The cost is fetched from the given params and is matched +// by the concrete type. +// The types of keys supported are: +// +// - ethsecp256k1 (Ethereum keys) +// +// - ed25519 (Validators) +// +// - multisig (Cosmos SDK multisigs) +func CantoSigVerificationGasConsumer( + meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params, +) error { + pubkey := sig.PubKey + switch pubkey := pubkey.(type) { + + case *ethsecp256k1.PubKey: + // Ethereum keys + meter.ConsumeGas(secp256k1VerifyCost, "ante verify: eth_secp256k1") + return nil + case *ed25519.PubKey: + // Validator keys + meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") + return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "ED25519 public keys are unsupported") + + case multisig.PubKey: + // Multisig keys + multisignature, ok := sig.Data.(*signing.MultiSignatureData) + if !ok { + return fmt.Errorf("expected %T, got, %T", &signing.MultiSignatureData{}, sig.Data) + } + return ConsumeMultisignatureVerificationGas(meter, multisignature, pubkey, params, sig.Sequence) + + default: + return errorsmod.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized/unsupported public key type: %T", pubkey) } } + +// ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature +func ConsumeMultisignatureVerificationGas( + meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey, + params authtypes.Params, accSeq uint64, +) error { + size := sig.BitArray.Count() + sigIndex := 0 + + for i := 0; i < size; i++ { + if !sig.BitArray.GetIndex(i) { + continue + } + sigV2 := signing.SignatureV2{ + PubKey: pubkey.GetPubKeys()[i], + Data: sig.Signatures[sigIndex], + Sequence: accSeq, + } + err := SigVerificationGasConsumer(meter, sigV2, params) + if err != nil { + return err + } + sigIndex++ + } + + return nil +} diff --git a/app/testutil.go b/app/testutil.go index b387c6e9..a3a7f875 100644 --- a/app/testutil.go +++ b/app/testutil.go @@ -10,11 +10,26 @@ import ( tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tm-db" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/testutil/mock" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + evmtypes "github.com/evmos/ethermint/x/evm/types" + + altheacfg "github.com/AltheaFoundation/althea-L1/config" ) // Setup initializes a new Althea app. A Nop logger is set in AltheaApp. -func Setup(isCheckTx bool, patchGenesis func(*AltheaApp, GenesisState) GenesisState) *AltheaApp { +func Setup(isCheckTx bool, patchGenesis func(*AltheaApp, simapp.GenesisState) simapp.GenesisState) *AltheaApp { db := dbm.NewMemDB() app := NewAltheaApp(tmlog.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, MakeEncodingConfig(), simapp.EmptyAppOptions{}) if !isCheckTx { @@ -45,7 +60,7 @@ func Setup(isCheckTx bool, patchGenesis func(*AltheaApp, GenesisState) GenesisSt } // DefaultConsensusParams defines the default Tendermint consensus params used in -// EthermintApp testing. +// AltheaApp testing. // nolint: exhaustruct var DefaultConsensusParams = &abci.ConsensusParams{ Block: &abci.BlockParams{ @@ -63,3 +78,159 @@ var DefaultConsensusParams = &abci.ConsensusParams{ }, }, } + +var ValidatorPrivKey cryptotypes.PrivKey +var ValidatorPubKey cryptotypes.PubKey + +// Setup initializes a new AltheaApp. A Nop logger is set in AltheaApp. +func NewSetup(isCheckTx bool, patchGenesis func(*AltheaApp, simapp.GenesisState) simapp.GenesisState) *AltheaApp { + return SetupWithDB(isCheckTx, patchGenesis, dbm.NewMemDB()) +} + +// SetupWithDB initializes a new AltheaApp. A Nop logger is set in AltheaApp. +func SetupWithDB(isCheckTx bool, patchGenesis func(*AltheaApp, simapp.GenesisState) simapp.GenesisState, db dbm.DB) *AltheaApp { + app := NewAltheaApp( + tmlog.NewNopLogger(), + db, + nil, + true, + map[int64]bool{}, + DefaultNodeHome, + 5, + MakeEncodingConfig(), + simapp.EmptyAppOptions{}, + ) + if !isCheckTx { + // init chain must be called to stop deliverState from being nil + genesisState := NewTestGenesisState(app.AppCodec()) + if patchGenesis != nil { + genesisState = patchGenesis(app, genesisState) + } + + stateBytes, err := json.MarshalIndent(genesisState, "", " ") + if err != nil { + panic(err) + } + + // Initialize the chain + app.InitChain( + abci.RequestInitChain{ + ChainId: "althea_7357-1", + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: DefaultConsensusParams, + AppStateBytes: stateBytes, + }, + ) + } + + return app +} + +// NewTestGenesisState generate genesis state with single validator +func NewTestGenesisState(codec codec.Codec) simapp.GenesisState { + privVal := mock.NewPV() + ValidatorPrivKey = privVal.PrivKey + pubKey, err := privVal.GetPubKey() + ValidatorPubKey = ValidatorPrivKey.PubKey() + if err != nil { + panic(err) + } + // create validator set with single validator + validator := tmtypes.NewValidator(pubKey, 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + + // generate genesis account + senderPrivKey := secp256k1.GenPrivKey() + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(altheacfg.BaseDenom, sdk.NewInt(100000000000000))), + } + + genesisState := NewDefaultGenesisState() + return genesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance) +} + +func genesisStateWithValSet(codec codec.Codec, genesisState simapp.GenesisState, + valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, + balances ...banktypes.Balance, +) simapp.GenesisState { + mintGenesis := minttypes.DefaultGenesisState() + mintGenesis.Params.MintDenom = altheacfg.BaseDenom + genesisState[minttypes.ModuleName] = codec.MustMarshalJSON(mintGenesis) + + evmGenesis := evmtypes.DefaultGenesisState() + evmGenesis.Params.EvmDenom = altheacfg.BaseDenom + genesisState[evmtypes.ModuleName] = codec.MustMarshalJSON(evmGenesis) + + // set genesis accounts + authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs) + genAccs, err := authtypes.UnpackAccounts(authGenesis.Accounts) + if err != nil { + panic(err) + } + genAccs = append(genAccs, authtypes.NewEmptyModuleAccount(authtypes.FeeCollectorName)) + authGenesis.Accounts, err = authtypes.PackAccounts(genAccs) + if err != nil { + panic(err) + } + genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis) + + validators := make([]stakingtypes.Validator, 0, len(valSet.Validators)) + delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators)) + + bondAmt := sdk.DefaultPowerReduction + + for _, val := range valSet.Validators { + pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey) + if err != nil { + panic(err) + } + pkAny, err := codectypes.NewAnyWithValue(pk) + if err != nil { + panic(err) + } + validator := stakingtypes.Validator{ + OperatorAddress: sdk.ValAddress(val.Address).String(), + ConsensusPubkey: pkAny, + Jailed: false, + Status: stakingtypes.Bonded, + Tokens: bondAmt, + DelegatorShares: sdk.OneDec(), + Description: stakingtypes.Description{}, + UnbondingHeight: int64(0), + UnbondingTime: time.Unix(0, 0).UTC(), + Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), + MinSelfDelegation: sdk.ZeroInt(), + } + validators = append(validators, validator) + delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec())) + } + // set validators and delegations + stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations) + stakingGenesis.Params.BondDenom = altheacfg.BaseDenom + genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON(stakingGenesis) + + totalSupply := sdk.NewCoins() + for _, b := range balances { + // add genesis acc tokens to total supply + totalSupply = totalSupply.Add(b.Coins...) + } + + for range delegations { + // add delegated tokens to total supply + totalSupply = totalSupply.Add(sdk.NewCoin(altheacfg.BaseDenom, bondAmt)) + } + + // add bonded amount to bonded pool module account + balances = append(balances, banktypes.Balance{ + Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), + Coins: sdk.Coins{sdk.NewCoin(altheacfg.BaseDenom, bondAmt)}, + }) + + // update total supply + bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{}) + genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis) + + return genesisState +} diff --git a/go.mod b/go.mod index 658cbde3..99a006bb 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.22.0 toolchain go1.22.7 require ( - github.com/Canto-Network/Canto/v6 v6.0.1 github.com/cosmos/cosmos-sdk v0.46.17 github.com/cosmos/ibc-go/v6 v6.3.1 github.com/evmos/ethermint v0.22.3 @@ -45,6 +44,8 @@ require ( github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 + github.com/onsi/ginkgo/v2 v2.9.2 + github.com/onsi/gomega v1.27.6 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 github.com/spf13/cast v1.7.0 @@ -60,17 +61,22 @@ require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/iam v1.1.6 // indirect cloud.google.com/go/storage v1.38.0 // indirect + github.com/allegro/bigcache v1.2.1 // indirect github.com/aws/aws-sdk-go v1.44.122 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bufbuild/protocompile v0.14.1 // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/cosmos/gogoproto v1.4.7 // indirect + github.com/gin-gonic/gin v1.8.1 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect + github.com/go-playground/validator/v10 v10.11.1 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/goccy/go-json v0.9.11 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-cmp v0.6.0 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.3 // indirect @@ -79,7 +85,6 @@ require ( github.com/hashicorp/go-safetemp v1.0.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/leodido/go-urn v1.2.1 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -92,7 +97,6 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/sjson v1.2.5 // indirect - github.com/ugorji/go/codec v1.2.7 // indirect github.com/ulikunitz/xz v0.5.10 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect @@ -101,6 +105,7 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/api v0.171.0 // indirect google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect @@ -117,7 +122,7 @@ require ( github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect github.com/Workiva/go-datastructures v1.1.5 // indirect - github.com/armon/go-metrics v0.4.1 // indirect + github.com/armon/go-metrics v0.4.1 github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/btcsuite/btcd v0.24.2 // indirect diff --git a/go.sum b/go.sum index df18a798..bcdbd677 100644 --- a/go.sum +++ b/go.sum @@ -199,8 +199,6 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo87o= github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= -github.com/AltheaFoundation/canto/v6 v6.0.1 h1:3NaThdYw6AZD2bf12bz8Qa3beXDbe0a5pNDB0lAitv4= -github.com/AltheaFoundation/canto/v6 v6.0.1/go.mod h1:CaaiFJ+WEL09j7JTI58JNBrd9p0d7a54eTt61a+nEDk= github.com/AltheaFoundation/ethermint v0.22.3 h1:NlGZmFveXsFtiOFiTXiEwyA5qTbatJtleWL2yx5h/Ow= github.com/AltheaFoundation/ethermint v0.22.3/go.mod h1:Pu0VyapSeMO2o7LlvHVn2ir+P9RuUxhIiIv6VYaFivw= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= @@ -857,6 +855,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -1025,6 +1024,7 @@ github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -1088,6 +1088,8 @@ github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= @@ -1212,8 +1214,8 @@ github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:s github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= @@ -1307,6 +1309,7 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= @@ -1387,6 +1390,7 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= diff --git a/testutil/fund.go b/testutil/fund.go new file mode 100644 index 00000000..018f1cfd --- /dev/null +++ b/testutil/fund.go @@ -0,0 +1,29 @@ +package testutil + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" +) + +// FundAccount is a utility function that funds an account by minting and +// sending the coins to the address. This should be used for testing purposes +// only! +func FundAccount(bankKeeper bankkeeper.Keeper, ctx sdk.Context, addr sdk.AccAddress, amounts sdk.Coins) error { + if err := bankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { + return err + } + + return bankKeeper.SendCoinsFromModuleToAccount(ctx, minttypes.ModuleName, addr, amounts) +} + +// FundModuleAccount is a utility function that funds a module account by +// minting and sending the coins to the address. This should be used for testing +// purposes only! +func FundModuleAccount(bankKeeper bankkeeper.Keeper, ctx sdk.Context, recipientMod string, amounts sdk.Coins) error { + if err := bankKeeper.MintCoins(ctx, minttypes.ModuleName, amounts); err != nil { + return err + } + + return bankKeeper.SendCoinsFromModuleToModule(ctx, minttypes.ModuleName, recipientMod, amounts) +} diff --git a/testutil/network/doc.go b/testutil/network/doc.go new file mode 100644 index 00000000..9e44f371 --- /dev/null +++ b/testutil/network/doc.go @@ -0,0 +1,65 @@ +/* +Package network implements and exposes a fully operational in-process Tendermint +test network that consists of at least one or potentially many validators. This +test network can be used primarily for integration tests or unit test suites. + +The test network utilizes SimApp as the ABCI application and uses all the modules +defined in the Cosmos SDK. An in-process test network can be configured with any +number of validators as well as account funds and even custom genesis state. + +When creating a test network, a series of Validator objects are returned. Each +Validator object has useful information such as their address and public key. A +Validator will also provide its RPC, P2P, and API addresses that can be useful +for integration testing. In addition, a Tendermint local RPC client is also provided +which can be handy for making direct RPC calls to Tendermint. + +Note, due to limitations in concurrency and the design of the RPC layer in +Tendermint, only the first Validator object will have an RPC and API client +exposed. Due to this exact same limitation, only a single test network can exist +at a time. A caller must be certain it calls Cleanup after it no longer needs +the network. + +A typical testing flow might look like the following: + + type IntegrationTestSuite struct { + suite.Suite + + cfg testutil.Config + network *testutil.Network + } + + func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + + cfg := testutil.DefaultConfig() + cfg.NumValidators = 1 + + s.cfg = cfg + s.network = testutil.New(s.T(), cfg) + + _, err := s.network.WaitForHeight(1) + s.Require().NoError(err) + } + + func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + + // This is important and must be called to ensure other tests can create + // a network! + s.network.Cleanup() + } + + func (s *IntegrationTestSuite) TestQueryBalancesRequestHandlerFn() { + val := s.network.Validators[0] + baseURL := val.APIAddress + + // Use baseURL to make API HTTP requests or use val.RPCClient to make direct + // Tendermint RPC calls. + // ... + } + + func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) + } +*/ +package network diff --git a/testutil/network/network.go b/testutil/network/network.go new file mode 100644 index 00000000..269d161e --- /dev/null +++ b/testutil/network/network.go @@ -0,0 +1,694 @@ +package network + +import ( + "bufio" + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "os" + "path/filepath" + "strings" + "sync" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/spf13/cobra" + tmcfg "github.com/tendermint/tendermint/config" + tmflags "github.com/tendermint/tendermint/libs/cli/flags" + "github.com/tendermint/tendermint/libs/log" + tmrand "github.com/tendermint/tendermint/libs/rand" + "github.com/tendermint/tendermint/node" + tmclient "github.com/tendermint/tendermint/rpc/client" + dbm "github.com/tendermint/tm-db" + "google.golang.org/grpc" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/server/api" + srvconfig "github.com/cosmos/cosmos-sdk/server/config" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/evmos/ethermint/crypto/hd" + + "github.com/evmos/ethermint/server/config" + ethermint "github.com/evmos/ethermint/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + + althea "github.com/AltheaFoundation/althea-L1/app" + "github.com/AltheaFoundation/althea-L1/app/params" +) + +// package-wide network lock to only allow one test network at a time +var lock = new(sync.Mutex) + +// AppConstructor defines a function which accepts a network configuration and +// creates an ABCI Application to provide to Tendermint. +type AppConstructor = func(val Validator) servertypes.Application + +// Config defines the necessary configuration used to bootstrap and start an +// in-process local testing network. +type Config struct { + KeyringOptions []keyring.Option // keyring configuration options + Codec codec.Codec + LegacyAmino *codec.LegacyAmino // TODO: Remove! + InterfaceRegistry codectypes.InterfaceRegistry + TxConfig client.TxConfig + AccountRetriever client.AccountRetriever + AppConstructor AppConstructor // the ABCI application constructor + GenesisState simapp.GenesisState // custom gensis state to provide + TimeoutCommit time.Duration // the consensus commitment timeout + AccountTokens sdk.Int // the amount of unique validator tokens (e.g. 1000node0) + StakingTokens sdk.Int // the amount of tokens each validator has available to stake + BondedTokens sdk.Int // the amount of tokens each validator stakes + NumValidators int // the total number of validators to create and bond + ChainID string // the network chain-id + BondDenom string // the staking bond denomination + MinGasPrices string // the minimum gas prices each validator will accept + PruningStrategy string // the pruning strategy each validator will have + SigningAlgo string // signing algorithm for keys + RPCAddress string // RPC listen address (including port) + JSONRPCAddress string // JSON-RPC listen address (including port) + APIAddress string // REST API listen address (including port) + GRPCAddress string // GRPC server listen address (including port) + EnableTMLogging bool // enable Tendermint logging to STDOUT + CleanupDir bool // remove base temporary directory during cleanup + PrintMnemonic bool // print the mnemonic of first validator as log output for testing +} + +// DefaultConfig returns a sane default configuration suitable for nearly all +// testing requirements. +func DefaultConfig() Config { + encCfg := althea.MakeEncodingConfig() + + return Config{ + Codec: encCfg.Codec, + TxConfig: encCfg.TxConfig, + LegacyAmino: encCfg.Amino, + InterfaceRegistry: encCfg.InterfaceRegistry, + AccountRetriever: authtypes.AccountRetriever{}, + AppConstructor: NewAppConstructor(encCfg), + GenesisState: althea.ModuleBasics.DefaultGenesis(encCfg.Codec), + TimeoutCommit: 2 * time.Second, + ChainID: fmt.Sprintf("canto_%d-1", tmrand.Int63n(9999999999999)+1), + NumValidators: 4, + BondDenom: ethermint.AttoPhoton, + MinGasPrices: fmt.Sprintf("0.000006%s", ethermint.AttoPhoton), + AccountTokens: sdk.TokensFromConsensusPower(1000, ethermint.PowerReduction), + StakingTokens: sdk.TokensFromConsensusPower(500, ethermint.PowerReduction), + BondedTokens: sdk.TokensFromConsensusPower(100, ethermint.PowerReduction), + PruningStrategy: pruningtypes.PruningOptionNothing, + CleanupDir: true, + SigningAlgo: string(hd.EthSecp256k1Type), + KeyringOptions: []keyring.Option{hd.EthSecp256k1Option()}, + PrintMnemonic: false, + } +} + +// NewAppConstructor returns a new canto AppConstructor +func NewAppConstructor(encodingCfg params.EncodingConfig) AppConstructor { + return func(val Validator) servertypes.Application { + return althea.NewAltheaApp( + val.Ctx.Logger, dbm.NewMemDB(), nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0, + encodingCfg, + simapp.EmptyAppOptions{}, + baseapp.SetPruning(pruningtypes.NewPruningOptionsFromString(val.AppConfig.Pruning)), + baseapp.SetMinGasPrices(val.AppConfig.MinGasPrices), + ) + } +} + +type ( + // Network defines a local in-process testing network using SimApp. It can be + // configured to start any number of validators, each with its own RPC and API + // clients. Typically, this test network would be used in client and integration + // testing where user input is expected. + // + // Note, due to Tendermint constraints in regards to RPC functionality, there + // may only be one test network running at a time. Thus, any caller must be + // sure to Cleanup after testing is finished in order to allow other tests + // to create networks. In addition, only the first validator will have a valid + // RPC and API server/client. + Network struct { + Logger Logger + BaseDir string + Validators []*Validator + + Config Config + } + + // Validator defines an in-process Tendermint validator node. Through this object, + // a client can make RPC and API calls and interact with any client command + // or handler. + Validator struct { + AppConfig *config.Config + ClientCtx client.Context + Ctx *server.Context + Dir string + NodeID string + PubKey cryptotypes.PubKey + Moniker string + APIAddress string + RPCAddress string + P2PAddress string + Address sdk.AccAddress + ValAddress sdk.ValAddress + RPCClient tmclient.Client + JSONRPCClient *ethclient.Client + + tmNode *node.Node + api *api.Server + grpc *grpc.Server + grpcWeb *http.Server + jsonrpc *http.Server + jsonrpcDone chan struct{} + } +) + +// Logger is a network logger interface that exposes testnet-level Log() methods for an in-process testing network +// This is not to be confused with logging that may happen at an individual node or validator level +type Logger interface { + Log(args ...interface{}) + Logf(format string, args ...interface{}) +} + +var ( + _ Logger = (*testing.T)(nil) + _ Logger = (*CLILogger)(nil) +) + +type CLILogger struct { + cmd *cobra.Command +} + +func (s CLILogger) Log(args ...interface{}) { + s.cmd.Println(args...) +} + +func (s CLILogger) Logf(format string, args ...interface{}) { + s.cmd.Printf(format, args...) +} + +func NewCLILogger(cmd *cobra.Command) CLILogger { + return CLILogger{cmd} +} + +// New creates a new Network for integration tests or in-process testnets run via the CLI +func New(l Logger, baseDir string, cfg Config) (*Network, error) { + // only one caller/test can create and use a network at a time + l.Log("acquiring test network lock") + lock.Lock() + + if !ethermint.IsValidChainID(cfg.ChainID) { + return nil, fmt.Errorf("invalid chain-id: %s", cfg.ChainID) + } + + network := &Network{ + Logger: l, + BaseDir: baseDir, + Validators: make([]*Validator, cfg.NumValidators), + Config: cfg, + } + + l.Logf("preparing test network with chain-id \"%s\"\n", cfg.ChainID) + + monikers := make([]string, cfg.NumValidators) + nodeIDs := make([]string, cfg.NumValidators) + valPubKeys := make([]cryptotypes.PubKey, cfg.NumValidators) + + var ( + genAccounts []authtypes.GenesisAccount + genBalances []banktypes.Balance + genFiles []string + ) + + buf := bufio.NewReader(os.Stdin) + + // generate private keys, node IDs, and initial transactions + for i := 0; i < cfg.NumValidators; i++ { + appCfg := config.DefaultConfig() + appCfg.Pruning = cfg.PruningStrategy + appCfg.MinGasPrices = cfg.MinGasPrices + appCfg.API.Enable = true + appCfg.API.Swagger = false + appCfg.Telemetry.Enabled = false + appCfg.Telemetry.GlobalLabels = [][]string{{"chain_id", cfg.ChainID}} + + ctx := server.NewDefaultContext() + tmCfg := ctx.Config + tmCfg.Consensus.TimeoutCommit = cfg.TimeoutCommit + + // Only allow the first validator to expose an RPC, API and gRPC + // server/client due to Tendermint in-process constraints. + apiAddr := "" + tmCfg.RPC.ListenAddress = "" + appCfg.GRPC.Enable = false + appCfg.GRPCWeb.Enable = false + apiListenAddr := "" + if i == 0 { + if cfg.APIAddress != "" { + apiListenAddr = cfg.APIAddress + } else { + var err error + apiListenAddr, _, err = server.FreeTCPAddr() + if err != nil { + return nil, err + } + } + + appCfg.API.Address = apiListenAddr + apiURL, err := url.Parse(apiListenAddr) + if err != nil { + return nil, err + } + apiAddr = fmt.Sprintf("http://%s:%s", apiURL.Hostname(), apiURL.Port()) + + if cfg.RPCAddress != "" { + tmCfg.RPC.ListenAddress = cfg.RPCAddress + } else { + rpcAddr, _, err := server.FreeTCPAddr() + if err != nil { + return nil, err + } + tmCfg.RPC.ListenAddress = rpcAddr + } + + if cfg.GRPCAddress != "" { + appCfg.GRPC.Address = cfg.GRPCAddress + } else { + _, grpcPort, err := server.FreeTCPAddr() + if err != nil { + return nil, err + } + appCfg.GRPC.Address = fmt.Sprintf("0.0.0.0:%s", grpcPort) + } + appCfg.GRPC.Enable = true + + _, grpcWebPort, err := server.FreeTCPAddr() + if err != nil { + return nil, err + } + appCfg.GRPCWeb.Address = fmt.Sprintf("0.0.0.0:%s", grpcWebPort) + appCfg.GRPCWeb.Enable = true + + if cfg.JSONRPCAddress != "" { + appCfg.JSONRPC.Address = cfg.JSONRPCAddress + } else { + _, jsonRPCPort, err := server.FreeTCPAddr() + if err != nil { + return nil, err + } + appCfg.JSONRPC.Address = fmt.Sprintf("0.0.0.0:%s", jsonRPCPort) + } + appCfg.JSONRPC.Enable = true + appCfg.JSONRPC.API = config.GetAPINamespaces() + } + + logger := log.NewNopLogger() + if cfg.EnableTMLogging { + logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + logger, _ = tmflags.ParseLogLevel("info", logger, tmcfg.DefaultLogLevel) + } + + ctx.Logger = logger + + nodeDirName := fmt.Sprintf("node%d", i) + nodeDir := filepath.Join(network.BaseDir, nodeDirName, "cantod") + clientDir := filepath.Join(network.BaseDir, nodeDirName, "cantocli") + gentxsDir := filepath.Join(network.BaseDir, "gentxs") + + err := os.MkdirAll(filepath.Join(nodeDir, "config"), 0o750) + if err != nil { + return nil, err + } + + err = os.MkdirAll(clientDir, 0o750) + if err != nil { + return nil, err + } + + tmCfg.SetRoot(nodeDir) + tmCfg.Moniker = nodeDirName + monikers[i] = nodeDirName + + proxyAddr, _, err := server.FreeTCPAddr() + if err != nil { + return nil, err + } + tmCfg.ProxyApp = proxyAddr + + p2pAddr, _, err := server.FreeTCPAddr() + if err != nil { + return nil, err + } + tmCfg.P2P.ListenAddress = p2pAddr + tmCfg.P2P.AddrBookStrict = false + tmCfg.P2P.AllowDuplicateIP = true + + nodeID, pubKey, err := genutil.InitializeNodeValidatorFiles(tmCfg) + if err != nil { + return nil, err + } + nodeIDs[i] = nodeID + valPubKeys[i] = pubKey + + kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.Codec, cfg.KeyringOptions...) + if err != nil { + return nil, err + } + + keyringAlgos, _ := kb.SupportedAlgorithms() + algo, err := keyring.NewSigningAlgoFromString(cfg.SigningAlgo, keyringAlgos) + if err != nil { + return nil, err + } + + addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, "", true, algo) + if err != nil { + return nil, err + } + + // if PrintMnemonic is set to true, we print the first validator node's secret to the network's logger + // for debugging and manual testing + if cfg.PrintMnemonic && i == 0 { + printMnemonic(l, secret) + } + + info := map[string]string{"secret": secret} + infoBz, err := json.Marshal(info) + if err != nil { + return nil, err + } + + // save private key seed words + err = WriteFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, infoBz) + if err != nil { + return nil, err + } + + balances := sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), cfg.AccountTokens), + sdk.NewCoin(cfg.BondDenom, cfg.StakingTokens), + ) + + genFiles = append(genFiles, tmCfg.GenesisFile()) + genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: balances.Sort()}) + genAccounts = append(genAccounts, ðermint.EthAccount{ + BaseAccount: authtypes.NewBaseAccount(addr, nil, 0, 0), + CodeHash: common.BytesToHash(evmtypes.EmptyCodeHash).Hex(), + }) + + commission, err := sdk.NewDecFromStr("0.5") + if err != nil { + return nil, err + } + + createValMsg, err := stakingtypes.NewMsgCreateValidator( + sdk.ValAddress(addr), + valPubKeys[i], + sdk.NewCoin(cfg.BondDenom, cfg.BondedTokens), + stakingtypes.NewDescription(nodeDirName, "", "", "", ""), + stakingtypes.NewCommissionRates(commission, sdk.OneDec(), sdk.OneDec()), + sdk.OneInt(), + ) + if err != nil { + return nil, err + } + + p2pURL, err := url.Parse(p2pAddr) + if err != nil { + return nil, err + } + + memo := fmt.Sprintf("%s@%s:%s", nodeIDs[i], p2pURL.Hostname(), p2pURL.Port()) + fee := sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, sdk.NewInt(0))) + txBuilder := cfg.TxConfig.NewTxBuilder() + err = txBuilder.SetMsgs(createValMsg) + if err != nil { + return nil, err + } + txBuilder.SetFeeAmount(fee) // Arbitrary fee + txBuilder.SetGasLimit(1000000) // Need at least 100386 + txBuilder.SetMemo(memo) + + txFactory := tx.Factory{} + txFactory = txFactory. + WithChainID(cfg.ChainID). + WithMemo(memo). + WithKeybase(kb). + WithTxConfig(cfg.TxConfig) + + if err := tx.Sign(txFactory, nodeDirName, txBuilder, true); err != nil { + return nil, err + } + + txBz, err := cfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx()) + if err != nil { + return nil, err + } + + if err := WriteFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz); err != nil { + return nil, err + } + + customAppTemplate, _ := config.AppConfig(ethermint.AttoPhoton) + srvconfig.SetConfigTemplate(customAppTemplate) + srvconfig.WriteConfigFile(filepath.Join(nodeDir, "config/app.toml"), appCfg) + + ctx.Viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) + ctx.Viper.SetConfigFile(filepath.Join(nodeDir, "config/app.toml")) + err = ctx.Viper.ReadInConfig() + if err != nil { + return nil, err + } + + clientCtx := client.Context{}. + WithKeyringDir(clientDir). + WithKeyring(kb). + WithHomeDir(tmCfg.RootDir). + WithChainID(cfg.ChainID). + WithInterfaceRegistry(cfg.InterfaceRegistry). + WithCodec(cfg.Codec). + WithLegacyAmino(cfg.LegacyAmino). + WithTxConfig(cfg.TxConfig). + WithAccountRetriever(cfg.AccountRetriever) + + network.Validators[i] = &Validator{ + AppConfig: appCfg, + ClientCtx: clientCtx, + Ctx: ctx, + Dir: filepath.Join(network.BaseDir, nodeDirName), + NodeID: nodeID, + PubKey: pubKey, + Moniker: nodeDirName, + RPCAddress: tmCfg.RPC.ListenAddress, + P2PAddress: tmCfg.P2P.ListenAddress, + APIAddress: apiAddr, + Address: addr, + ValAddress: sdk.ValAddress(addr), + } + } + + err := initGenFiles(cfg, genAccounts, genBalances, genFiles) + if err != nil { + return nil, err + } + err = collectGenFiles(cfg, network.Validators, network.BaseDir) + if err != nil { + return nil, err + } + + l.Log("starting test network...") + for _, v := range network.Validators { + err := startInProcess(cfg, v) + if err != nil { + return nil, err + } + } + + l.Log("started test network") + + // Ensure we cleanup incase any test was abruptly halted (e.g. SIGINT) as any + // defer in a test would not be called. + server.TrapSignal(network.Cleanup) + + return network, nil +} + +// LatestHeight returns the latest height of the network or an error if the +// query fails or no validators exist. +func (n *Network) LatestHeight() (int64, error) { + if len(n.Validators) == 0 { + return 0, errors.New("no validators available") + } + + status, err := n.Validators[0].RPCClient.Status(context.Background()) + if err != nil { + return 0, err + } + + return status.SyncInfo.LatestBlockHeight, nil +} + +// WaitForHeight performs a blocking check where it waits for a block to be +// committed after a given block. If that height is not reached within a timeout, +// an error is returned. Regardless, the latest height queried is returned. +func (n *Network) WaitForHeight(h int64) (int64, error) { + return n.WaitForHeightWithTimeout(h, 10*time.Second) +} + +// WaitForHeightWithTimeout is the same as WaitForHeight except the caller can +// provide a custom timeout. +func (n *Network) WaitForHeightWithTimeout(h int64, t time.Duration) (int64, error) { + ticker := time.NewTicker(time.Second) + timeout := time.After(t) + + if len(n.Validators) == 0 { + return 0, errors.New("no validators available") + } + + var latestHeight int64 + val := n.Validators[0] + + for { + select { + case <-timeout: + ticker.Stop() + return latestHeight, errors.New("timeout exceeded waiting for block") + case <-ticker.C: + status, err := val.RPCClient.Status(context.Background()) + if err == nil && status != nil { + latestHeight = status.SyncInfo.LatestBlockHeight + if latestHeight >= h { + return latestHeight, nil + } + } + } + } +} + +// WaitForNextBlock waits for the next block to be committed, returning an error +// upon failure. +func (n *Network) WaitForNextBlock() error { + lastBlock, err := n.LatestHeight() + if err != nil { + return err + } + + _, err = n.WaitForHeight(lastBlock + 1) + if err != nil { + return err + } + + return err +} + +// Cleanup removes the root testing (temporary) directory and stops both the +// Tendermint and API services. It allows other callers to create and start +// test networks. This method must be called when a test is finished, typically +// in a defer. +func (n *Network) Cleanup() { + defer func() { + lock.Unlock() + n.Logger.Log("released test network lock") + }() + + n.Logger.Log("cleaning up test network...") + + for _, v := range n.Validators { + if v.tmNode != nil && v.tmNode.IsRunning() { + _ = v.tmNode.Stop() + } + + if v.api != nil { + _ = v.api.Close() + } + + if v.grpc != nil { + v.grpc.Stop() + if v.grpcWeb != nil { + _ = v.grpcWeb.Close() + } + } + + if v.jsonrpc != nil { + shutdownCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second) + defer cancelFn() + + if err := v.jsonrpc.Shutdown(shutdownCtx); err != nil { + v.tmNode.Logger.Error("HTTP server shutdown produced a warning", "error", err.Error()) + } else { + v.tmNode.Logger.Info("HTTP server shut down, waiting 5 sec") + select { + case <-time.Tick(5 * time.Second): + case <-v.jsonrpcDone: + } + } + } + } + + if n.Config.CleanupDir { + _ = os.RemoveAll(n.BaseDir) + } + + n.Logger.Log("finished cleaning up test network") +} + +// printMnemonic prints a provided mnemonic seed phrase on a network logger +// for debugging and manual testing +func printMnemonic(l Logger, secret string) { + lines := []string{ + "THIS MNEMONIC IS FOR TESTING PURPOSES ONLY", + "DO NOT USE IN PRODUCTION", + "", + strings.Join(strings.Fields(secret)[0:8], " "), + strings.Join(strings.Fields(secret)[8:16], " "), + strings.Join(strings.Fields(secret)[16:24], " "), + } + + lineLengths := make([]int, len(lines)) + for i, line := range lines { + lineLengths[i] = len(line) + } + + maxLineLength := 0 + for _, lineLen := range lineLengths { + if lineLen > maxLineLength { + maxLineLength = lineLen + } + } + + l.Log("\n") + l.Log(strings.Repeat("+", maxLineLength+8)) + for _, line := range lines { + l.Logf("++ %s ++\n", centerText(line, maxLineLength)) + } + l.Log(strings.Repeat("+", maxLineLength+8)) + l.Log("\n") +} + +// centerText centers text across a fixed width, filling either side with whitespace buffers +func centerText(text string, width int) string { + textLen := len(text) + leftBuffer := strings.Repeat(" ", (width-textLen)/2) + rightBuffer := strings.Repeat(" ", (width-textLen)/2+(width-textLen)%2) + + return fmt.Sprintf("%s%s%s", leftBuffer, text, rightBuffer) +} diff --git a/testutil/network/network_test.go b/testutil/network/network_test.go new file mode 100644 index 00000000..030e158f --- /dev/null +++ b/testutil/network/network_test.go @@ -0,0 +1,64 @@ +//go:build norace +// +build norace + +package network_test + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/suite" + + "github.com/ethereum/go-ethereum/ethclient" + "github.com/evmos/ethermint/server/config" + "github.com/evmos/ethermint/testutil/network" + + cantonetwork "github.com/AltheaFoundation/althea-L1/testutil/network" +) + +type IntegrationTestSuite struct { + suite.Suite + + network *network.Network +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + + var err error + cfg := cantonetwork.DefaultConfig() + cfg.JSONRPCAddress = config.DefaultJSONRPCAddress + cfg.NumValidators = 1 + + s.network, err = network.New(s.T(), s.T().TempDir(), cfg) + s.Require().NoError(err) + s.Require().NotNil(s.network) + + _, err = s.network.WaitForHeight(2) + s.Require().NoError(err) + + if s.network.Validators[0].JSONRPCClient == nil { + address := fmt.Sprintf("http://%s", s.network.Validators[0].AppConfig.JSONRPC.Address) + s.network.Validators[0].JSONRPCClient, err = ethclient.Dial(address) + s.Require().NoError(err) + } +} + +func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +func (s *IntegrationTestSuite) TestNetwork_Liveness() { + h, err := s.network.WaitForHeightWithTimeout(10, time.Minute) + s.Require().NoError(err, "expected to reach 10 blocks; got %d", h) + + latestHeight, err := s.network.LatestHeight() + s.Require().NoError(err, "latest height failed") + s.Require().GreaterOrEqual(latestHeight, h) +} + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} diff --git a/testutil/network/util.go b/testutil/network/util.go new file mode 100644 index 00000000..928ab49c --- /dev/null +++ b/testutil/network/util.go @@ -0,0 +1,256 @@ +package network + +import ( + "encoding/json" + "fmt" + "path/filepath" + "time" + + "github.com/ethereum/go-ethereum/ethclient" + tmos "github.com/tendermint/tendermint/libs/os" + "github.com/tendermint/tendermint/node" + "github.com/tendermint/tendermint/p2p" + pvm "github.com/tendermint/tendermint/privval" + "github.com/tendermint/tendermint/proxy" + "github.com/tendermint/tendermint/rpc/client/local" + "github.com/tendermint/tendermint/types" + tmtime "github.com/tendermint/tendermint/types/time" + + "github.com/cosmos/cosmos-sdk/server/api" + servergrpc "github.com/cosmos/cosmos-sdk/server/grpc" + srvtypes "github.com/cosmos/cosmos-sdk/server/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + "github.com/evmos/ethermint/server" + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +func startInProcess(cfg Config, val *Validator) error { + logger := val.Ctx.Logger + tmCfg := val.Ctx.Config + tmCfg.Instrumentation.Prometheus = false + + if err := val.AppConfig.ValidateBasic(); err != nil { + return err + } + + nodeKey, err := p2p.LoadOrGenNodeKey(tmCfg.NodeKeyFile()) + if err != nil { + return err + } + + app := cfg.AppConstructor(*val) + + genDocProvider := node.DefaultGenesisDocProviderFunc(tmCfg) + tmNode, err := node.NewNode( + tmCfg, + pvm.LoadOrGenFilePV(tmCfg.PrivValidatorKeyFile(), tmCfg.PrivValidatorStateFile()), + nodeKey, + proxy.NewLocalClientCreator(app), + genDocProvider, + node.DefaultDBProvider, + node.DefaultMetricsProvider(tmCfg.Instrumentation), + logger.With("module", val.Moniker), + ) + if err != nil { + return err + } + + if err := tmNode.Start(); err != nil { + return err + } + + val.tmNode = tmNode + + if val.RPCAddress != "" { + val.RPCClient = local.New(tmNode) + } + + // We'll need a RPC client if the validator exposes a gRPC or REST endpoint. + if val.APIAddress != "" || val.AppConfig.GRPC.Enable { + val.ClientCtx = val.ClientCtx. + WithClient(val.RPCClient) + + // Add the tx service in the gRPC router. + app.RegisterTxService(val.ClientCtx) + + // Add the tendermint queries service in the gRPC router. + app.RegisterTendermintService(val.ClientCtx) + } + + if val.AppConfig.API.Enable && val.APIAddress != "" { + apiSrv := api.New(val.ClientCtx, logger.With("module", "api-server")) + app.RegisterAPIRoutes(apiSrv, val.AppConfig.API) + + errCh := make(chan error) + + go func() { + if err := apiSrv.Start(val.AppConfig.Config); err != nil { + errCh <- err + } + }() + + select { + case err := <-errCh: + return err + case <-time.After(srvtypes.ServerStartTime): // assume server started successfully + } + + val.api = apiSrv + } + + if val.AppConfig.GRPC.Enable { + grpcSrv, err := servergrpc.StartGRPCServer(val.ClientCtx, app, val.AppConfig.GRPC) + if err != nil { + return err + } + + val.grpc = grpcSrv + + if val.AppConfig.GRPCWeb.Enable { + val.grpcWeb, err = servergrpc.StartGRPCWeb(grpcSrv, val.AppConfig.Config) + if err != nil { + return err + } + } + } + + if val.AppConfig.JSONRPC.Enable && val.AppConfig.JSONRPC.Address != "" { + if val.Ctx == nil || val.Ctx.Viper == nil { + return fmt.Errorf("validator %s context is nil", val.Moniker) + } + + tmEndpoint := "/websocket" + tmRPCAddr := fmt.Sprintf("tcp://%s", val.AppConfig.GRPC.Address) + + val.jsonrpc, val.jsonrpcDone, err = server.StartJSONRPC(val.Ctx, val.ClientCtx, tmRPCAddr, tmEndpoint, val.AppConfig, nil) + if err != nil { + return err + } + + address := fmt.Sprintf("http://%s", val.AppConfig.JSONRPC.Address) + + val.JSONRPCClient, err = ethclient.Dial(address) + if err != nil { + return fmt.Errorf("failed to dial JSON-RPC at %s: %w", val.AppConfig.JSONRPC.Address, err) + } + } + + return nil +} + +func collectGenFiles(cfg Config, vals []*Validator, outputDir string) error { + genTime := tmtime.Now() + + for i := 0; i < cfg.NumValidators; i++ { + tmCfg := vals[i].Ctx.Config + + nodeDir := filepath.Join(outputDir, vals[i].Moniker, "cantod") + gentxsDir := filepath.Join(outputDir, "gentxs") + + tmCfg.Moniker = vals[i].Moniker + tmCfg.SetRoot(nodeDir) + + initCfg := genutiltypes.NewInitConfig(cfg.ChainID, gentxsDir, vals[i].NodeID, vals[i].PubKey) + + genFile := tmCfg.GenesisFile() + genDoc, err := types.GenesisDocFromFile(genFile) + if err != nil { + return err + } + + appState, err := genutil.GenAppStateFromConfig(cfg.Codec, cfg.TxConfig, + tmCfg, initCfg, *genDoc, banktypes.GenesisBalancesIterator{}) + if err != nil { + return err + } + + // overwrite each validator's genesis file to have a canonical genesis time + if err := genutil.ExportGenesisFileWithTime(genFile, cfg.ChainID, nil, appState, genTime); err != nil { + return err + } + } + + return nil +} + +func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance, genFiles []string) error { + // set the accounts in the genesis state + var authGenState authtypes.GenesisState + cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[authtypes.ModuleName], &authGenState) + + accounts, err := authtypes.PackAccounts(genAccounts) + if err != nil { + return err + } + + authGenState.Accounts = append(authGenState.Accounts, accounts...) + cfg.GenesisState[authtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&authGenState) + + // set the balances in the genesis state + var bankGenState banktypes.GenesisState + bankGenState.Balances = genBalances + cfg.GenesisState[banktypes.ModuleName] = cfg.Codec.MustMarshalJSON(&bankGenState) + + var stakingGenState stakingtypes.GenesisState + cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[stakingtypes.ModuleName], &stakingGenState) + + stakingGenState.Params.BondDenom = cfg.BondDenom + cfg.GenesisState[stakingtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&stakingGenState) + + var govGenState govv1beta1.GenesisState + cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[govtypes.ModuleName], &govGenState) + + govGenState.DepositParams.MinDeposit[0].Denom = cfg.BondDenom + cfg.GenesisState[govtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&govGenState) + + var crisisGenState crisistypes.GenesisState + cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[crisistypes.ModuleName], &crisisGenState) + + crisisGenState.ConstantFee.Denom = cfg.BondDenom + cfg.GenesisState[crisistypes.ModuleName] = cfg.Codec.MustMarshalJSON(&crisisGenState) + + var evmGenState evmtypes.GenesisState + cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[evmtypes.ModuleName], &evmGenState) + + evmGenState.Params.EvmDenom = cfg.BondDenom + cfg.GenesisState[evmtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&evmGenState) + + appGenStateJSON, err := json.MarshalIndent(cfg.GenesisState, "", " ") + if err != nil { + return err + } + + genDoc := types.GenesisDoc{ + ChainID: cfg.ChainID, + AppState: appGenStateJSON, + Validators: nil, + } + + // generate empty genesis files for each validator and save + for i := 0; i < cfg.NumValidators; i++ { + if err := genDoc.SaveAs(genFiles[i]); err != nil { + return err + } + } + + return nil +} + +func WriteFile(name string, dir string, contents []byte) error { + file := filepath.Join(dir, name) + + err := tmos.EnsureDir(dir, 0o755) + if err != nil { + return err + } + + return tmos.WriteFile(file, contents, 0o644) +} diff --git a/x/erc20/client/cli/query.go b/x/erc20/client/cli/query.go new file mode 100644 index 00000000..a99ebbb1 --- /dev/null +++ b/x/erc20/client/cli/query.go @@ -0,0 +1,128 @@ +package cli + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// GetQueryCmd returns the parent command for all erc20 CLI query commands +func GetQueryCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the erc20 module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand( + GetTokenPairsCmd(), + GetTokenPairCmd(), + GetParamsCmd(), + ) + return cmd +} + +// GetTokenPairsCmd queries all registered token pairs +func GetTokenPairsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "token-pairs", + Short: "Gets registered token pairs", + Long: "Gets registered token pairs", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + pageReq, err := client.ReadPageRequest(cmd.Flags()) + if err != nil { + return err + } + + req := &types.QueryTokenPairsRequest{ + Pagination: pageReq, + } + + res, err := queryClient.TokenPairs(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetTokenPairsCmd queries a registered token pair +func GetTokenPairCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "token-pair [token]", + Short: "Get a registered token pair", + Long: "Get a registered token pair", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryTokenPairRequest{ + Token: args[0], + } + + res, err := queryClient.TokenPair(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetParamsCmd queries erc20 module params +func GetParamsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Gets erc20 params", + Long: "Gets erc20 params", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + req := &types.QueryParamsRequest{} + + res, err := queryClient.Params(context.Background(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/erc20/client/cli/tx.go b/x/erc20/client/cli/tx.go new file mode 100644 index 00000000..a41a7166 --- /dev/null +++ b/x/erc20/client/cli/tx.go @@ -0,0 +1,363 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "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/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/gov/client/cli" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + + "github.com/ethereum/go-ethereum/common" + + ethermint "github.com/evmos/ethermint/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// NewTxCmd returns a root CLI command handler for erc20 transaction commands +func NewTxCmd() *cobra.Command { + txCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "erc20 subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + txCmd.AddCommand( + NewConvertCoinCmd(), + NewConvertERC20Cmd(), + ) + return txCmd +} + +// NewConvertCoinCmd returns a CLI command handler for converting a Cosmos coin +func NewConvertCoinCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "convert-coin [coin] [receiver_hex]", + Short: "Convert a Cosmos coin to ERC20. When the receiver [optional] is omitted, the ERC20 tokens are transferred to the sender.", + Args: cobra.RangeArgs(1, 2), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + coin, err := sdk.ParseCoinNormalized(args[0]) + if err != nil { + return err + } + + var receiver string + sender := cliCtx.GetFromAddress() + + if len(args) == 2 { + receiver = args[1] + if err := ethermint.ValidateAddress(receiver); err != nil { + return fmt.Errorf("invalid receiver hex address %w", err) + } + } else { + receiver = common.BytesToAddress(sender).Hex() + } + + msg := &types.MsgConvertCoin{ + Coin: coin, + Receiver: receiver, + Sender: sender.String(), + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewConvertERC20Cmd returns a CLI command handler for converting an ERC20 +func NewConvertERC20Cmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "convert-erc20 [contract-address] [amount] [receiver]", + Short: "Convert an ERC20 token to Cosmos coin. When the receiver [optional] is omitted, the Cosmos coins are transferred to the sender.", + Args: cobra.RangeArgs(2, 3), + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + contract := args[0] + if err := ethermint.ValidateAddress(contract); err != nil { + return fmt.Errorf("invalid ERC20 contract address %w", err) + } + + amount, ok := sdk.NewIntFromString(args[1]) + if !ok { + return fmt.Errorf("invalid amount %s", args[1]) + } + + from := common.BytesToAddress(cliCtx.GetFromAddress().Bytes()) + + receiver := cliCtx.GetFromAddress() + if len(args) == 3 { + receiver, err = sdk.AccAddressFromBech32(args[2]) + if err != nil { + return err + } + } + + msg := &types.MsgConvertERC20{ + ContractAddress: contract, + Amount: amount, + Receiver: receiver.String(), + Sender: from.Hex(), + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(cliCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// NewRegisterCoinProposalCmd implements the command to submit a community-pool-spend proposal +func NewRegisterCoinProposalCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "register-coin [metadata]", + Args: cobra.ExactArgs(1), + Short: "Submit a register coin proposal", + Long: `Submit a proposal to register a Cosmos coin to the erc20 along with an initial deposit. +Upon passing, the +The proposal details must be supplied via a JSON file.`, + Example: fmt.Sprintf(`$ %s tx gov submit-proposal register-coin --from= + +Where metadata.json contains (example): + +{ + "description": "The native staking and governance token of the Osmosis chain", + "denom_units": [ + { + "denom": "ibc/", + "exponent": 0, + "aliases": ["ibcuosmo"] + }, + { + "denom": "OSMO", + "exponent": 6 + } + ], + "base": "ibc/", + "display": "OSMO", + "name": "Osmo", + "symbol": "OSMO" +}`, version.AppName, + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + title, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return err + } + + description, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return err + } + + depositStr, err := cmd.Flags().GetString(cli.FlagDeposit) + if err != nil { + return err + } + + deposit, err := sdk.ParseCoinsNormalized(depositStr) + if err != nil { + return err + } + + metadata, err := ParseMetadata(clientCtx.Codec, args[0]) + if err != nil { + return err + } + + from := clientCtx.GetFromAddress() + + content := types.NewRegisterCoinProposal(title, description, metadata) + + msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, from) + if err != nil { + return err + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(cli.FlagTitle, "", "title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "description of proposal") + cmd.Flags().String(cli.FlagDeposit, "1acanto", "deposit of proposal") + if err := cmd.MarkFlagRequired(cli.FlagTitle); err != nil { + panic(err) + } + if err := cmd.MarkFlagRequired(cli.FlagDescription); err != nil { + panic(err) + } + if err := cmd.MarkFlagRequired(cli.FlagDeposit); err != nil { + panic(err) + } + return cmd +} + +// NewRegisterERC20ProposalCmd implements the command to submit a community-pool-spend proposal +func NewRegisterERC20ProposalCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "register-erc20 [erc20-address]", + Args: cobra.ExactArgs(1), + Short: "Submit a proposal to register an ERC20 token", + Long: "Submit a proposal to register an ERC20 token to the erc20 along with an initial deposit.", + Example: fmt.Sprintf("$ %s tx gov submit-proposal register-erc20 --from=", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + title, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return err + } + + description, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return err + } + + depositStr, err := cmd.Flags().GetString(cli.FlagDeposit) + if err != nil { + return err + } + + deposit, err := sdk.ParseCoinsNormalized(depositStr) + if err != nil { + return err + } + + erc20Addr := args[0] + from := clientCtx.GetFromAddress() + content := types.NewRegisterERC20Proposal(title, description, erc20Addr) + + msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, from) + if err != nil { + return err + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(cli.FlagTitle, "", "title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "description of proposal") + cmd.Flags().String(cli.FlagDeposit, "1acanto", "deposit of proposal") + if err := cmd.MarkFlagRequired(cli.FlagTitle); err != nil { + panic(err) + } + if err := cmd.MarkFlagRequired(cli.FlagDescription); err != nil { + panic(err) + } + if err := cmd.MarkFlagRequired(cli.FlagDeposit); err != nil { + panic(err) + } + return cmd +} + +// NewToggleTokenConversionProposalCmd implements the command to submit a community-pool-spend proposal +func NewToggleTokenConversionProposalCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "toggle-token-conversion [token]", + Args: cobra.ExactArgs(1), + Short: "Submit a toggle token conversion proposal", + Long: "Submit a proposal to toggle the conversion of a token pair along with an initial deposit.", + Example: fmt.Sprintf("$ %s tx gov submit-proposal toggle-token-conversion --from=", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + title, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return err + } + + description, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return err + } + + depositStr, err := cmd.Flags().GetString(cli.FlagDeposit) + if err != nil { + return err + } + + deposit, err := sdk.ParseCoinsNormalized(depositStr) + if err != nil { + return err + } + + from := clientCtx.GetFromAddress() + token := args[0] + content := types.NewToggleTokenConversionProposal(title, description, token) + + msg, err := govv1beta1.NewMsgSubmitProposal(content, deposit, from) + if err != nil { + return err + } + + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().String(cli.FlagTitle, "", "title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "description of proposal") + cmd.Flags().String(cli.FlagDeposit, "1acanto", "deposit of proposal") + if err := cmd.MarkFlagRequired(cli.FlagTitle); err != nil { + panic(err) + } + if err := cmd.MarkFlagRequired(cli.FlagDescription); err != nil { + panic(err) + } + if err := cmd.MarkFlagRequired(cli.FlagDeposit); err != nil { + panic(err) + } + return cmd +} diff --git a/x/erc20/client/cli/utils.go b/x/erc20/client/cli/utils.go new file mode 100644 index 00000000..f9f77de3 --- /dev/null +++ b/x/erc20/client/cli/utils.go @@ -0,0 +1,25 @@ +package cli + +import ( + "io/ioutil" + "path/filepath" + + "github.com/cosmos/cosmos-sdk/codec" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// ParseRegisterCoinProposal reads and parses a ParseRegisterCoinProposal from a file. +func ParseMetadata(cdc codec.JSONCodec, metadataFile string) (banktypes.Metadata, error) { + metadata := banktypes.Metadata{} + + contents, err := ioutil.ReadFile(filepath.Clean(metadataFile)) + if err != nil { + return metadata, err + } + + if err = cdc.UnmarshalJSON(contents, &metadata); err != nil { + return metadata, err + } + + return metadata, nil +} diff --git a/x/erc20/client/proposal_handler.go b/x/erc20/client/proposal_handler.go new file mode 100644 index 00000000..04e81e99 --- /dev/null +++ b/x/erc20/client/proposal_handler.go @@ -0,0 +1,13 @@ +package client + +import ( + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + + "github.com/AltheaFoundation/althea-L1/x/erc20/client/cli" +) + +var ( + RegisterCoinProposalHandler = govclient.NewProposalHandler(cli.NewRegisterCoinProposalCmd) + RegisterERC20ProposalHandler = govclient.NewProposalHandler(cli.NewRegisterERC20ProposalCmd) + ToggleTokenConversionProposalHandler = govclient.NewProposalHandler(cli.NewToggleTokenConversionProposalCmd) +) diff --git a/x/erc20/genesis.go b/x/erc20/genesis.go new file mode 100644 index 00000000..1ca47c0b --- /dev/null +++ b/x/erc20/genesis.go @@ -0,0 +1,40 @@ +package erc20 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + + "github.com/AltheaFoundation/althea-L1/x/erc20/keeper" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// InitGenesis import module genesis +func InitGenesis( + ctx sdk.Context, + k keeper.Keeper, + accountKeeper authkeeper.AccountKeeper, + data types.GenesisState, +) { + k.SetParams(ctx, data.Params) + + // ensure erc20 module account is set on genesis + if acc := accountKeeper.GetModuleAccount(ctx, types.ModuleName); acc == nil { + // NOTE: shouldn't occur + panic("the erc20 module account has not been set") + } + + for _, pair := range data.TokenPairs { + id := pair.GetID() + k.SetTokenPair(ctx, pair) + k.SetDenomMap(ctx, pair.Denom, id) + k.SetERC20Map(ctx, pair.GetERC20Contract(), id) + } +} + +// ExportGenesis export module status +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { + return &types.GenesisState{ + Params: k.GetParams(ctx), + TokenPairs: k.GetTokenPairs(ctx), + } +} diff --git a/x/erc20/genesis_test.go b/x/erc20/genesis_test.go new file mode 100644 index 00000000..bebe536b --- /dev/null +++ b/x/erc20/genesis_test.go @@ -0,0 +1,160 @@ +package erc20_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + "github.com/tendermint/tendermint/crypto/tmhash" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmversion "github.com/tendermint/tendermint/proto/tendermint/version" + "github.com/tendermint/tendermint/version" + + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + + feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" + + althea "github.com/AltheaFoundation/althea-L1/app" + "github.com/AltheaFoundation/althea-L1/x/erc20" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +type GenesisTestSuite struct { + suite.Suite + ctx sdk.Context + app *althea.AltheaApp +} + +func TestGenesisTestSuite(t *testing.T) { + suite.Run(t, new(GenesisTestSuite)) +} + +func (suite *GenesisTestSuite) SetupTest() { + // init app + suite.app = althea.NewSetup(false, func(aa *althea.AltheaApp, gs simapp.GenesisState) simapp.GenesisState { + // setup feemarketGenesis params + feemarketGenesis := feemarkettypes.DefaultGenesisState() + feemarketGenesis.Params.EnableHeight = 1 + feemarketGenesis.Params.NoBaseFee = false + gs[feemarkettypes.ModuleName] = aa.AppCodec().MustMarshalJSON(feemarketGenesis) + return gs + }) + + suite.ctx = suite.app.BaseApp.NewContext(false, tmproto.Header{ + Height: 1, + ChainID: "althea_7357-1", + Time: time.Now().UTC(), + ProposerAddress: althea.ValidatorPubKey.Address().Bytes(), + + Version: tmversion.Consensus{ + Block: version.BlockProtocol, + }, + LastBlockId: tmproto.BlockID{ + Hash: tmhash.Sum([]byte("block_id")), + PartSetHeader: tmproto.PartSetHeader{ + Total: 11, + Hash: tmhash.Sum([]byte("partset_header")), + }, + }, + AppHash: tmhash.Sum([]byte("app")), + DataHash: tmhash.Sum([]byte("data")), + EvidenceHash: tmhash.Sum([]byte("evidence")), + ValidatorsHash: tmhash.Sum([]byte("validators")), + NextValidatorsHash: tmhash.Sum([]byte("next_validators")), + ConsensusHash: tmhash.Sum([]byte("consensus")), + LastResultsHash: tmhash.Sum([]byte("last_result")), + }) +} + +func (suite *GenesisTestSuite) TestERC20InitGenesis() { + testCases := []struct { + name string + genesisState types.GenesisState + }{ + { + "empty genesis", + types.GenesisState{}, + }, + { + "default genesis", + *types.DefaultGenesisState(), + }, + { + "custom genesis", + types.NewGenesisState( + types.DefaultParams(), + []types.TokenPair{ + { + Erc20Address: "0x5dCA2483280D9727c80b5518faC4556617fb19ZZ", + Denom: "coin", + Enabled: true, + ContractOwner: types.OWNER_MODULE, + }, + }), + }, + } + + for _, tc := range testCases { + + suite.Require().NotPanics(func() { + erc20.InitGenesis(suite.ctx, *suite.app.Erc20Keeper, *suite.app.AccountKeeper, tc.genesisState) + }) + params := suite.app.Erc20Keeper.GetParams(suite.ctx) + + tokenPairs := suite.app.Erc20Keeper.GetTokenPairs(suite.ctx) + suite.Require().Equal(tc.genesisState.Params, params) + if len(tokenPairs) > 0 { + suite.Require().Equal(tc.genesisState.TokenPairs, tokenPairs) + } else { + suite.Require().Len(tc.genesisState.TokenPairs, 0) + } + } +} + +func (suite *GenesisTestSuite) TestErc20ExportGenesis() { + testGenCases := []struct { + name string + genesisState types.GenesisState + }{ + { + "empty genesis", + types.GenesisState{}, + }, + { + "default genesis", + *types.DefaultGenesisState(), + }, + { + "custom genesis", + types.NewGenesisState( + types.DefaultParams(), + []types.TokenPair{ + { + Erc20Address: "0x5dCA2483280D9727c80b5518faC4556617fb19ZZ", + Denom: "coin", + Enabled: true, + ContractOwner: types.OWNER_MODULE, + }, + }), + }, + } + + for _, tc := range testGenCases { + erc20.InitGenesis(suite.ctx, *suite.app.Erc20Keeper, *suite.app.AccountKeeper, tc.genesisState) + suite.Require().NotPanics(func() { + genesisExported := erc20.ExportGenesis(suite.ctx, *suite.app.Erc20Keeper) + params := suite.app.Erc20Keeper.GetParams(suite.ctx) + suite.Require().Equal(genesisExported.Params, params) + + tokenPairs := suite.app.Erc20Keeper.GetTokenPairs(suite.ctx) + if len(tokenPairs) > 0 { + suite.Require().Equal(genesisExported.TokenPairs, tokenPairs) + } else { + suite.Require().Len(genesisExported.TokenPairs, 0) + } + }) + // } + } +} diff --git a/x/erc20/handler.go b/x/erc20/handler.go new file mode 100644 index 00000000..0ad2c3ca --- /dev/null +++ b/x/erc20/handler.go @@ -0,0 +1,27 @@ +package erc20 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// NewHandler defines the erc20 module handler instance +func NewHandler(server types.MsgServer) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case *types.MsgConvertCoin: + res, err := server.ConvertCoin(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgConvertERC20: + res, err := server.ConvertERC20(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + default: + err := sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) + return nil, err + } + } +} diff --git a/x/erc20/keeper/evm.go b/x/erc20/keeper/evm.go new file mode 100644 index 00000000..5ded21dd --- /dev/null +++ b/x/erc20/keeper/evm.go @@ -0,0 +1,241 @@ +package keeper + +import ( + "encoding/json" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "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/evmos/ethermint/server/config" + evmtypes "github.com/evmos/ethermint/x/evm/types" + + "github.com/AltheaFoundation/althea-L1/contracts" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// DeployERC20Contract creates and deploys an ERC20 contract on the EVM with the +// erc20 module account as owner. +func (k Keeper) DeployERC20Contract( + ctx sdk.Context, + coinMetadata banktypes.Metadata, +) (common.Address, error) { + decimals := uint8(0) + if len(coinMetadata.DenomUnits) > 0 { + decimalsIdx := len(coinMetadata.DenomUnits) - 1 + decimals = uint8(coinMetadata.DenomUnits[decimalsIdx].Exponent) + } + ctorArgs, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack( + "", + coinMetadata.Name, + coinMetadata.Symbol, + decimals, + ) + if err != nil { + return common.Address{}, sdkerrors.Wrapf(types.ErrABIPack, "coin metadata is invalid %s: %s", coinMetadata.Name, err.Error()) + } + + data := make([]byte, len(contracts.ERC20MinterBurnerDecimalsContract.Bin)+len(ctorArgs)) + copy(data[:len(contracts.ERC20MinterBurnerDecimalsContract.Bin)], contracts.ERC20MinterBurnerDecimalsContract.Bin) + copy(data[len(contracts.ERC20MinterBurnerDecimalsContract.Bin):], ctorArgs) + + nonce, err := k.accountKeeper.GetSequence(ctx, types.ModuleAddress.Bytes()) + if err != nil { + return common.Address{}, err + } + + contractAddr := crypto.CreateAddress(types.ModuleAddress, nonce) + _, err = k.CallEVMWithData(ctx, types.ModuleAddress, nil, data, true) + if err != nil { + return common.Address{}, sdkerrors.Wrapf(err, "failed to deploy contract for %s", coinMetadata.Name) + } + + return contractAddr, nil +} + +// QueryERC20 returns the data of a deployed ERC20 contract +func (k Keeper) QueryERC20( + ctx sdk.Context, + contract common.Address, +) (types.ERC20Data, error) { + var ( + nameRes types.ERC20StringResponse + symbolRes types.ERC20StringResponse + decimalRes types.ERC20Uint8Response + ) + + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + + // Name + res, err := k.CallEVM(ctx, erc20, types.ModuleAddress, contract, false, "name") + if err != nil { + return types.ERC20Data{}, err + } + + if err := erc20.UnpackIntoInterface(&nameRes, "name", res.Ret); err != nil { + return types.ERC20Data{}, sdkerrors.Wrapf( + types.ErrABIUnpack, "failed to unpack name: %s", err.Error(), + ) + } + + // Symbol + res, err = k.CallEVM(ctx, erc20, types.ModuleAddress, contract, false, "symbol") + if err != nil { + return types.ERC20Data{}, err + } + + if err := erc20.UnpackIntoInterface(&symbolRes, "symbol", res.Ret); err != nil { + return types.ERC20Data{}, sdkerrors.Wrapf( + types.ErrABIUnpack, "failed to unpack symbol: %s", err.Error(), + ) + } + + // Decimals + res, err = k.CallEVM(ctx, erc20, types.ModuleAddress, contract, false, "decimals") + if err != nil { + return types.ERC20Data{}, err + } + + if err := erc20.UnpackIntoInterface(&decimalRes, "decimals", res.Ret); err != nil { + return types.ERC20Data{}, sdkerrors.Wrapf( + types.ErrABIUnpack, "failed to unpack decimals: %s", err.Error(), + ) + } + + return types.NewERC20Data(nameRes.Value, symbolRes.Value, decimalRes.Value), nil +} + +// BalanceOf queries an account's balance for a given ERC20 contract +func (k Keeper) BalanceOf( + ctx sdk.Context, + abi abi.ABI, + contract, account common.Address, +) *big.Int { + res, err := k.CallEVM(ctx, abi, types.ModuleAddress, contract, false, "balanceOf", account) + if err != nil { + return nil + } + + unpacked, err := abi.Unpack("balanceOf", res.Ret) + if err != nil || len(unpacked) == 0 { + return nil + } + + balance, ok := unpacked[0].(*big.Int) + if !ok { + return nil + } + + return balance +} + +// CallEVM performs a smart contract method call using given args +func (k Keeper) CallEVM( + ctx sdk.Context, + abi abi.ABI, + from, contract common.Address, + commit bool, + method string, + args ...interface{}, +) (*evmtypes.MsgEthereumTxResponse, error) { + data, err := abi.Pack(method, args...) + if err != nil { + return nil, sdkerrors.Wrap( + types.ErrABIPack, + sdkerrors.Wrap(err, "failed to create transaction data").Error(), + ) + } + + resp, err := k.CallEVMWithData(ctx, from, &contract, data, commit) + if err != nil { + return nil, sdkerrors.Wrapf(err, "contract call failed: method '%s', contract '%s'", method, contract) + } + return resp, nil +} + +// CallEVMWithData performs a smart contract method call using contract data +func (k Keeper) CallEVMWithData( + ctx sdk.Context, + from common.Address, + contract *common.Address, + data []byte, + commit bool, +) (*evmtypes.MsgEthereumTxResponse, error) { + nonce, err := k.accountKeeper.GetSequence(ctx, from.Bytes()) + if err != nil { + return nil, err + } + + gasCap := config.DefaultGasCap + if commit { + args, err := json.Marshal(evmtypes.TransactionArgs{ + From: &from, + To: contract, + Data: (*hexutil.Bytes)(&data), + }) + if err != nil { + return nil, sdkerrors.Wrapf(sdkerrors.ErrJSONMarshal, "failed to marshal tx args: %s", err.Error()) + } + + gasRes, err := k.evmKeeper.EstimateGas(sdk.WrapSDKContext(ctx), &evmtypes.EthCallRequest{ + Args: args, + GasCap: config.DefaultGasCap, + }) + if err != nil { + return nil, err + } + gasCap = gasRes.Gas + } + + msg := ethtypes.NewMessage( + from, + contract, + nonce, + big.NewInt(0), // amount + gasCap, // gasLimit + big.NewInt(0), // gasFeeCap + big.NewInt(0), // gasTipCap + big.NewInt(0), // gasPrice + data, + ethtypes.AccessList{}, // AccessList + !commit, // isFake + ) + + res, err := k.evmKeeper.ApplyMessage(ctx, msg, evmtypes.NewNoOpTracer(), commit) + if err != nil { + return nil, err + } + + if res.Failed() { + return nil, sdkerrors.Wrap(evmtypes.ErrVMExecution, res.VmError) + } + + return res, nil +} + +// monitorApprovalEvent returns an error if the given transactions logs include +// an unexpected `Approval` event +func (k Keeper) monitorApprovalEvent(res *evmtypes.MsgEthereumTxResponse) error { + if res == nil || len(res.Logs) == 0 { + return nil + } + + logApprovalSig := []byte("Approval(address,address,uint256)") + logApprovalSigHash := crypto.Keccak256Hash(logApprovalSig) + + for _, log := range res.Logs { + if log.Topics[0] == logApprovalSigHash.Hex() { + return sdkerrors.Wrapf( + types.ErrUnexpectedEvent, "unexpected Approval event", + ) + } + } + + return nil +} diff --git a/x/erc20/keeper/evm_hooks.go b/x/erc20/keeper/evm_hooks.go new file mode 100644 index 00000000..2736224d --- /dev/null +++ b/x/erc20/keeper/evm_hooks.go @@ -0,0 +1,157 @@ +package keeper + +import ( + "bytes" + // nolint: typecheck + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + ethtypes "github.com/ethereum/go-ethereum/core/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + + "github.com/AltheaFoundation/althea-L1/contracts" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +var _ evmtypes.EvmHooks = Hooks{} + +// Hooks wrapper struct for erc20 keeper +type Hooks struct { + k Keeper +} + +// Return the wrapper struct +func (k Keeper) Hooks() Hooks { + return Hooks{k} +} + +// PostTxProcessing implements EvmHooks.PostTxProcessing. The EVM hooks allows +// users to convert ERC20s to Cosmos Coins by sending an Ethereum tx transfer to +// the module account address. This hook applies to both token pairs that have +// been registered through a native Cosmos coin or an ERC20 token. If token pair +// has been registered with: +// - coin -> burn tokens and transfer escrowed coins on module to sender +// - token -> escrow tokens on module account and mint & transfer coins to sender +// +// Note that the PostTxProcessing hook is only called by sending an EVM +// transaction that triggers `ApplyTransaction`. A cosmos tx with a +// `ConvertERC20` msg does not trigger the hook as it only calls `ApplyMessage`. +func (h Hooks) PostTxProcessing( + ctx sdk.Context, + msg core.Message, + receipt *ethtypes.Receipt, +) error { + params := h.k.GetParams(ctx) + if !params.EnableErc20 || !params.EnableEVMHook { + // no error is returned to avoid reverting the tx and allow for other post + // processing txs to pass and + return nil + } + + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + + for i, log := range receipt.Logs { + // Note: the `Transfer` event contains 3 topics (id, from, to) + if len(log.Topics) != 3 { + continue + } + + // Check if event is included in ERC20 + eventID := log.Topics[0] + event, err := erc20.EventByID(eventID) + if err != nil { + continue + } + + // Check if event is a `Transfer` event. + if event.Name != types.ERC20EventTransfer { + h.k.Logger(ctx).Info("emitted event", "name", event.Name, "signature", event.Sig) + continue + } + + transferEvent, err := erc20.Unpack(event.Name, log.Data) + if err != nil { + h.k.Logger(ctx).Error("failed to unpack transfer event", "error", err.Error()) + continue + } + + if len(transferEvent) == 0 { + continue + } + + tokens, ok := transferEvent[0].(*big.Int) + // safety check and ignore if amount not positive + if !ok || tokens == nil || tokens.Sign() != 1 { + continue + } + + // Check that the contract is a registered token pair + contractAddr := log.Address + id := h.k.GetERC20Map(ctx, contractAddr) + if len(id) == 0 { + continue + } + + pair, found := h.k.GetTokenPair(ctx, id) + if !found { + continue + } + + // Check if tokens are sent to module address + to := common.BytesToAddress(log.Topics[2].Bytes()) + if !bytes.Equal(to.Bytes(), types.ModuleAddress.Bytes()) { + continue + } + + // Check that conversion for the pair is enabled. Fail + if !pair.Enabled { + // continue to allow transfers for the ERC20 in case the token pair is + // disabled + h.k.Logger(ctx).Debug( + "ERC20 token -> Cosmos coin conversion is disabled for pair", + "coin", pair.Denom, "contract", pair.Erc20Address, + ) + continue + } + + // create the corresponding sdk.Coin that is paired with ERC20 + coins := sdk.Coins{{Denom: pair.Denom, Amount: sdk.NewIntFromBigInt(tokens)}} + + // Perform token conversion. We can now assume that the sender of a + // registered token wants to mint a Cosmos coin. + switch pair.ContractOwner { + case types.OWNER_MODULE: + _, err = h.k.CallEVM(ctx, erc20, types.ModuleAddress, contractAddr, true, "burn", tokens) + case types.OWNER_EXTERNAL: + err = h.k.bankKeeper.MintCoins(ctx, types.ModuleName, coins) + default: + err = types.ErrUndefinedOwner + } + + if err != nil { + h.k.Logger(ctx).Debug( + "failed to process EVM hook for ER20 -> coin conversion", + "coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(), + ) + continue + } + + // Only need last 20 bytes from log.topics + from := common.BytesToAddress(log.Topics[1].Bytes()) + recipient := sdk.AccAddress(from.Bytes()) + + // transfer the tokens from ModuleAccount to sender address + if err := h.k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, coins); err != nil { + h.k.Logger(ctx).Debug( + "failed to process EVM hook for ER20 -> coin conversion", + "tx-hash", receipt.TxHash.Hex(), "log-idx", i, + "coin", pair.Denom, "contract", pair.Erc20Address, "error", err.Error(), + ) + continue + } + } + + return nil +} diff --git a/x/erc20/keeper/evm_hooks_test.go b/x/erc20/keeper/evm_hooks_test.go new file mode 100644 index 00000000..174dc2e8 --- /dev/null +++ b/x/erc20/keeper/evm_hooks_test.go @@ -0,0 +1,431 @@ +package keeper_test + +import ( + "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/AltheaFoundation/althea-L1/contracts" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" + "github.com/evmos/ethermint/tests" +) + +// ensureHooksSet tries to set the hooks on EVMKeeper, this will fail if the erc20 hook is already set +func (suite *KeeperTestSuite) ensureHooksSet() { + // TODO: PR to Ethermint to add the functionality `GetHooks` or `areHooksSet` to avoid catching a panic + defer func() { + err := recover() + suite.Require().NotNil(err) + }() + suite.app.EvmKeeper.SetHooks(suite.app.Erc20Keeper.Hooks()) +} + +func (suite *KeeperTestSuite) TestEvmHooksRegisteredERC20() { + testCases := []struct { + name string + malleate func(common.Address) + result bool + }{ + { + "correct execution", + func(contractAddr common.Address) { + _, err := suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contractAddr) + suite.Require().NoError(err) + + // Mint 10 tokens to suite.address (owner) + _ = suite.MintERC20Token(contractAddr, suite.address, suite.address, big.NewInt(10)) + suite.Commit() + + // Burn the 10 tokens of suite.address (owner) + _ = suite.TransferERC20TokenToModule(contractAddr, suite.address, big.NewInt(10)) + }, + true, + }, + { + "unregistered pair", + func(contractAddr common.Address) { + // Mint 10 tokens to suite.address (owner) + _ = suite.MintERC20Token(contractAddr, suite.address, suite.address, big.NewInt(10)) + suite.Commit() + + // Burn the 10 tokens of suite.address (owner) + _ = suite.TransferERC20TokenToModule(contractAddr, suite.address, big.NewInt(10)) + }, + false, + }, + { + "wrong event", + func(contractAddr common.Address) { + _, err := suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contractAddr) + suite.Require().NoError(err) + + // Mint 10 tokens to suite.address (owner) + _ = suite.MintERC20Token(contractAddr, suite.address, suite.address, big.NewInt(10)) + }, + false, + }, + { + "Pair is disabled", + func(contractAddr common.Address) { + pair, err := suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contractAddr) + suite.Require().NoError(err) + + pair.Enabled = false + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, *pair) + // Mint 10 tokens to suite.address (owner) + _ = suite.MintERC20Token(contractAddr, suite.address, suite.address, big.NewInt(10)) + suite.Commit() + + // Burn the 10 tokens of suite.address (owner) + _ = suite.TransferERC20TokenToModule(contractAddr, suite.address, big.NewInt(10)) + }, + false, + }, + { + "Pair is incorrectly loaded", + func(contractAddr common.Address) { + pair, err := suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contractAddr) + suite.Require().NoError(err) + + suite.app.Erc20Keeper.DeleteTokenPair(suite.ctx, *pair) + + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, pair.GetID()) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, pair.GetERC20Contract(), pair.GetID()) + // Mint 10 tokens to suite.address (owner) + _ = suite.MintERC20Token(contractAddr, suite.address, suite.address, big.NewInt(10)) + suite.Commit() + + // Burn the 10 tokens of suite.address (owner) + _ = suite.TransferERC20TokenToModule(contractAddr, suite.address, big.NewInt(10)) + }, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + + suite.ensureHooksSet() + + contractAddr, err := suite.DeployContract("coin test erc20", "token", erc20Decimals) + suite.Require().NoError(err) + suite.Commit() + + tc.malleate(contractAddr) + + balance := suite.app.BankKeeper.GetBalance(suite.ctx, sdk.AccAddress(suite.address.Bytes()), types.CreateDenom(contractAddr.String())) + suite.Commit() + if tc.result { + // Check if the execution was successful + suite.Require().Equal(int64(10), balance.Amount.Int64()) + } else { + // Check that no changes were made to the account + suite.Require().Equal(int64(0), balance.Amount.Int64()) + } + }) + } + suite.mintFeeCollector = false +} + +func (suite *KeeperTestSuite) TestEvmHooksRegisteredCoin() { + testCases := []struct { + name string + mint int64 + burn int64 + reconvert int64 + + result bool + }{ + {"correct execution", 100, 10, 5, true}, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + + suite.ensureHooksSet() + + metadata, pair := suite.setupRegisterCoin() + suite.Require().NotNil(metadata) + suite.Require().NotNil(pair) + + sender := sdk.AccAddress(suite.address.Bytes()) + contractAddr := common.HexToAddress(pair.Erc20Address) + + coins := sdk.NewCoins(sdk.NewCoin(cosmosTokenBase, sdk.NewInt(tc.mint))) + suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins) + suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, sender, coins) + + convertCoin := types.NewMsgConvertCoin( + sdk.NewCoin(cosmosTokenBase, sdk.NewInt(tc.burn)), + suite.address, + sender, + ) + + ctx := sdk.WrapSDKContext(suite.ctx) + _, err := suite.app.Erc20Keeper.ConvertCoin(ctx, convertCoin) + suite.Require().NoError(err, tc.name) + suite.Commit() + + balance := suite.BalanceOf(common.HexToAddress(pair.Erc20Address), suite.address) + cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, metadata.Base) + suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn).Int64()) + suite.Require().Equal(balance, big.NewInt(tc.burn)) + + // Burn the 10 tokens of suite.address (owner) + _ = suite.TransferERC20TokenToModule(contractAddr, suite.address, big.NewInt(tc.reconvert)) + + balance = suite.BalanceOf(common.HexToAddress(pair.Erc20Address), suite.address) + cosmosBalance = suite.app.BankKeeper.GetBalance(suite.ctx, sender, metadata.Base) + + if tc.result { + // Check if the execution was successful + suite.Require().NoError(err) + suite.Require().Equal(cosmosBalance.Amount, sdk.NewInt(tc.mint-tc.burn+tc.reconvert)) + } else { + // Check that no changes were made to the account + suite.Require().Error(err) + suite.Require().Equal(cosmosBalance.Amount, sdk.NewInt(tc.mint-tc.burn)) + } + }) + } + suite.mintFeeCollector = false +} + +func (suite *KeeperTestSuite) TestPostTxProcessing() { + var ( + receipt *ethtypes.Receipt + pair *types.TokenPair + ) + + msg := ethtypes.NewMessage( + types.ModuleAddress, + &common.Address{}, + 0, + big.NewInt(0), // amount + uint64(0), // gasLimit + big.NewInt(0), // gasFeeCap + big.NewInt(0), // gasTipCap + big.NewInt(0), // gasPrice + []byte{}, + ethtypes.AccessList{}, // AccessList + true, // checkNonce + ) + + account := tests.GenerateAddress() + + transferData := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + transferData[31] = uint8(10) + erc20 := contracts.ERC20BurnableContract.ABI + + transferEvent := erc20.Events["Transfer"] + + testCases := []struct { + name string + malleate func() + expConversion bool + }{ + { + "Empty logs", + func() { + log := ethtypes.Log{} + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + false, + }, + { + "No log data", + func() { + topics := []common.Hash{transferEvent.ID, account.Hash(), types.ModuleAddress.Hash()} + log := ethtypes.Log{ + Topics: topics, + } + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + false, + }, + { + "Non recognized event", + func() { + topics := []common.Hash{{}, account.Hash(), account.Hash()} + log := ethtypes.Log{ + Topics: topics, + Data: transferData, + } + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + false, + }, + { + "Non transfer event", + func() { + aprovalEvent := erc20.Events["Approval"] + topics := []common.Hash{aprovalEvent.ID, account.Hash(), account.Hash()} + log := ethtypes.Log{ + Topics: topics, + Data: transferData, + } + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + false, + }, + { + "No log address", + func() { + topics := []common.Hash{transferEvent.ID, account.Hash(), types.ModuleAddress.Hash()} + log := ethtypes.Log{ + Topics: topics, + Data: transferData, + } + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + false, + }, + { + "No data on topic", + func() { + topics := []common.Hash{transferEvent.ID} + log := ethtypes.Log{ + Topics: topics, + Data: transferData, + } + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + false, + }, + { + "transfer to non-evm-module account", + func() { + contractAddr, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + suite.Commit() + + _, err = suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contractAddr) + suite.Require().NoError(err) + + topics := []common.Hash{transferEvent.ID, account.Hash(), account.Hash()} + log := ethtypes.Log{ + Topics: topics, + Data: transferData, + Address: contractAddr, + } + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + false, + }, + { + "correct burn", + func() { + contractAddr, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + suite.Commit() + + pair, err = suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contractAddr) + suite.Require().NoError(err) + + topics := []common.Hash{transferEvent.ID, account.Hash(), types.ModuleAddress.Hash()} + log := ethtypes.Log{ + Topics: topics, + Data: transferData, + Address: contractAddr, + } + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + true, + }, + { + "Unspecified Owner", + func() { + contractAddr, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + suite.Commit() + + pair, err := suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contractAddr) + suite.Require().NoError(err) + + pair.ContractOwner = types.OWNER_UNSPECIFIED + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, *pair) + + topics := []common.Hash{transferEvent.ID, account.Hash(), types.ModuleAddress.Hash()} + log := ethtypes.Log{ + Topics: topics, + Data: transferData, + Address: contractAddr, + } + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + false, + }, + { + "Fail Evm", + func() { + contractAddr, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + suite.Commit() + + pair, err := suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contractAddr) + suite.Require().NoError(err) + + pair.ContractOwner = types.OWNER_MODULE + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, *pair) + + topics := []common.Hash{transferEvent.ID, account.Hash(), types.ModuleAddress.Hash()} + log := ethtypes.Log{ + Topics: topics, + Data: transferData, + Address: contractAddr, + } + receipt = ðtypes.Receipt{ + Logs: []*ethtypes.Log{&log}, + } + }, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + suite.ensureHooksSet() + + tc.malleate() + + err := suite.app.Erc20Keeper.Hooks().PostTxProcessing(suite.ctx, msg, receipt) + suite.Require().NoError(err) + + if tc.expConversion { + sender := sdk.AccAddress(account.Bytes()) + cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, pair.Denom) + + transferEvent, err := erc20.Unpack("Transfer", transferData) + suite.Require().NoError(err) + + tokens, _ := transferEvent[0].(*big.Int) + suite.Require().Equal(cosmosBalance.Amount.String(), tokens.String()) + } + }) + } + suite.mintFeeCollector = false +} diff --git a/x/erc20/keeper/evm_test.go b/x/erc20/keeper/evm_test.go new file mode 100644 index 00000000..7cc7391e --- /dev/null +++ b/x/erc20/keeper/evm_test.go @@ -0,0 +1,386 @@ +package keeper_test + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/evmos/ethermint/tests" + evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/stretchr/testify/mock" + + "github.com/AltheaFoundation/althea-L1/contracts" + "github.com/AltheaFoundation/althea-L1/x/erc20/keeper" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +func (suite *KeeperTestSuite) TestQueryERC20() { + var contract common.Address + testCases := []struct { + name string + malleate func() + res bool + }{ + { + "erc20 not deployed", + func() { contract = common.Address{} }, + false, + }, + { + "ok", + func() { contract, _ = suite.DeployContract("coin", "token", erc20Decimals) }, + true, + }, + } + for _, tc := range testCases { + suite.SetupTest() // reset + + tc.malleate() + + res, err := suite.app.Erc20Keeper.QueryERC20(suite.ctx, contract) + if tc.res { + suite.Require().NoError(err) + suite.Require().Equal( + types.ERC20Data{Name: "coin", Symbol: "token", Decimals: erc20Decimals}, + res, + ) + } else { + suite.Require().Error(err) + } + } +} + +func (suite *KeeperTestSuite) TestBalanceOf() { + var mockEVMKeeper *MockEVMKeeper + contract := tests.GenerateAddress() + testCases := []struct { + name string + malleate func() + expBalance int64 + res bool + }{ + { + "Failed to call Evm", + func() { + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + }, + int64(0), + false, + }, + { + "Incorrect res", + func() { + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() + }, + int64(0), + false, + }, + { + "Correct Execution", + func() { + balance := make([]uint8, 32) + balance[31] = uint8(10) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + }, + int64(10), + true, + }, + } + for _, tc := range testCases { + suite.SetupTest() // reset + mockEVMKeeper = &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + tc.malleate() + + abi := contracts.ERC20BurnableContract.ABI + balance := suite.app.Erc20Keeper.BalanceOf(suite.ctx, abi, contract, tests.GenerateAddress()) + if tc.res { + suite.Require().Equal(balance.Int64(), tc.expBalance) + } else { + suite.Require().Nil(balance) + } + } +} + +func (suite *KeeperTestSuite) TestCallEVM() { + testCases := []struct { + name string + method string + expPass bool + }{ + { + "unknown method", + "", + false, + }, + { + "pass", + "balanceOf", + true, + }, + } + for _, tc := range testCases { + suite.SetupTest() // reset + + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + contract, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + account := tests.GenerateAddress() + + res, err := suite.app.Erc20Keeper.CallEVM(suite.ctx, erc20, types.ModuleAddress, contract, true, tc.method, account) + if tc.expPass { + suite.Require().IsTypef(&evmtypes.MsgEthereumTxResponse{}, res, tc.name) + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + } +} + +func (suite *KeeperTestSuite) TestCallEVMWithData() { + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + testCases := []struct { + name string + from common.Address + malleate func() ([]byte, *common.Address) + expPass bool + }{ + { + "unknown method", + types.ModuleAddress, + func() ([]byte, *common.Address) { + contract, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + account := tests.GenerateAddress() + data, _ := erc20.Pack("", account) + return data, &contract + }, + false, + }, + { + "pass", + types.ModuleAddress, + func() ([]byte, *common.Address) { + contract, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + account := tests.GenerateAddress() + data, _ := erc20.Pack("balanceOf", account) + return data, &contract + }, + true, + }, + { + "fail empty data", + types.ModuleAddress, + func() ([]byte, *common.Address) { + contract, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + return []byte{}, &contract + }, + false, + }, + + { + "fail empty sender", + common.Address{}, + func() ([]byte, *common.Address) { + contract, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + return []byte{}, &contract + }, + false, + }, + { + "deploy", + types.ModuleAddress, + func() ([]byte, *common.Address) { + ctorArgs, _ := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("", "test", "test", uint8(18)) + data := append(contracts.ERC20MinterBurnerDecimalsContract.Bin, ctorArgs...) + return data, nil + }, + true, + }, + { + "fail deploy", + types.ModuleAddress, + func() ([]byte, *common.Address) { + params := suite.app.EvmKeeper.GetParams(suite.ctx) + params.EnableCreate = false + suite.app.EvmKeeper.SetParams(suite.ctx, params) + ctorArgs, _ := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("", "test", "test", uint8(18)) + data := append(contracts.ERC20MinterBurnerDecimalsContract.Bin, ctorArgs...) + return data, nil + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + data, contract := tc.malleate() + + res, err := suite.app.Erc20Keeper.CallEVMWithData(suite.ctx, tc.from, contract, data, true) + if tc.expPass { + suite.Require().IsTypef(&evmtypes.MsgEthereumTxResponse{}, res, tc.name) + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestForceFail() { + var mockEVMKeeper *MockEVMKeeper + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + testCases := []struct { + name string + malleate func() + commit bool + expPass bool + }{ + { + "Force estimate gas error", + func() { + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced EstimateGas error")) + }, + true, + false, + }, + { + "Force ApplyMessage error", + func() { + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + }, + true, + false, + }, + { + "Force ApplyMessage failed", + func() { + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{VmError: "SomeError"}, nil) + }, + true, + false, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + mockEVMKeeper = &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + tc.malleate() + + contract, err := suite.DeployContract("coin", "token", erc20Decimals) + suite.Require().NoError(err) + account := tests.GenerateAddress() + data, _ := erc20.Pack("balanceOf", account) + + res, err := suite.app.Erc20Keeper.CallEVMWithData(suite.ctx, types.ModuleAddress, &contract, data, tc.commit) + if tc.expPass { + suite.Require().IsTypef(&evmtypes.MsgEthereumTxResponse{}, res, tc.name) + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryERC20ForceFail() { + var mockEVMKeeper *MockEVMKeeper + contract := tests.GenerateAddress() + testCases := []struct { + name string + malleate func() + res bool + }{ + { + "Failed to call Evm", + func() { + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + }, + false, + }, + { + "Incorrect res", + func() { + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() + }, + false, + }, + { + "Correct res for name - incorrect for symbol", + func() { + ret := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 67, 111, 105, 110, 32, 84, 111, 107, 101, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{VmError: "Error"}, nil).Once() + }, + false, + }, + { + "incorrect symbol res", + func() { + ret := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 67, 111, 105, 110, 32, 84, 111, 107, 101, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() + }, + false, + }, + { + "Correct res for name - incorrect for symbol", + func() { + ret := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 67, 111, 105, 110, 32, 84, 111, 107, 101, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + retSymbol := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 67, 84, 75, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: retSymbol}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{VmError: "Error"}, nil).Once() + }, + false, + }, + { + "incorrect symbol res", + func() { + ret := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 67, 111, 105, 110, 32, 84, 111, 107, 101, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + retSymbol := []uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 67, 84, 75, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: ret}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: retSymbol}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: []uint8{0, 0}}, nil).Once() + }, + false, + }, + } + for _, tc := range testCases { + suite.SetupTest() // reset + mockEVMKeeper = &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + tc.malleate() + + res, err := suite.app.Erc20Keeper.QueryERC20(suite.ctx, contract) + if tc.res { + suite.Require().NoError(err) + suite.Require().Equal( + types.ERC20Data{Name: "coin", Symbol: "token", Decimals: erc20Decimals}, + res, + ) + } else { + suite.Require().Error(err) + } + } +} diff --git a/x/erc20/keeper/grpc_query.go b/x/erc20/keeper/grpc_query.go new file mode 100644 index 00000000..4c318be7 --- /dev/null +++ b/x/erc20/keeper/grpc_query.go @@ -0,0 +1,85 @@ +package keeper + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + ethermint "github.com/evmos/ethermint/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +var _ types.QueryServer = Keeper{} + +// TokenPairs returns all registered pairs +func (k Keeper) TokenPairs(c context.Context, req *types.QueryTokenPairsRequest) (*types.QueryTokenPairsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + var pairs []types.TokenPair + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPair) + + pageRes, err := query.Paginate(store, req.Pagination, func(_, value []byte) error { + var pair types.TokenPair + if err := k.cdc.Unmarshal(value, &pair); err != nil { + return err + } + pairs = append(pairs, pair) + return nil + }) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + return &types.QueryTokenPairsResponse{ + TokenPairs: pairs, + Pagination: pageRes, + }, nil +} + +// TokenPair returns a given registered token pair +func (k Keeper) TokenPair(c context.Context, req *types.QueryTokenPairRequest) (*types.QueryTokenPairResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + // check if the token is a hex address, if not, check if it is a valid SDK + // denom + if err := ethermint.ValidateAddress(req.Token); err != nil { + if err := sdk.ValidateDenom(req.Token); err != nil { + return nil, status.Errorf( + codes.InvalidArgument, + "invalid format for token %s, should be either hex ('0x...') cosmos denom", req.Token, + ) + } + } + + id := k.GetTokenPairID(ctx, req.Token) + + if len(id) == 0 { + return nil, status.Errorf(codes.NotFound, "token pair with token '%s'", req.Token) + } + + pair, found := k.GetTokenPair(ctx, id) + if !found { + return nil, status.Errorf(codes.NotFound, "token pair with token '%s'", req.Token) + } + + return &types.QueryTokenPairResponse{TokenPair: pair}, nil +} + +// Params returns the params of the erc20 module +func (k Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + params := k.GetParams(ctx) + return &types.QueryParamsResponse{Params: params}, nil +} diff --git a/x/erc20/keeper/grpc_query_test.go b/x/erc20/keeper/grpc_query_test.go new file mode 100644 index 00000000..9da65f57 --- /dev/null +++ b/x/erc20/keeper/grpc_query_test.go @@ -0,0 +1,170 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/evmos/ethermint/tests" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +func (suite *KeeperTestSuite) TestTokenPairs() { + var ( + req *types.QueryTokenPairsRequest + expRes *types.QueryTokenPairsResponse + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "no pairs registered", + func() { + req = &types.QueryTokenPairsRequest{} + expRes = &types.QueryTokenPairsResponse{Pagination: &query.PageResponse{}} + }, + true, + }, + { + "1 pair registered w/pagination", + func() { + req = &types.QueryTokenPairsRequest{ + Pagination: &query.PageRequest{Limit: 10, CountTotal: true}, + } + pair := types.NewTokenPair(tests.GenerateAddress(), "coin", true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + + expRes = &types.QueryTokenPairsResponse{ + Pagination: &query.PageResponse{Total: 1}, + TokenPairs: []types.TokenPair{pair}, + } + }, + true, + }, + { + "2 pairs registered wo/pagination", + func() { + req = &types.QueryTokenPairsRequest{} + pair := types.NewTokenPair(tests.GenerateAddress(), "coin", true, types.OWNER_MODULE) + pair2 := types.NewTokenPair(tests.GenerateAddress(), "coin2", true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair2) + + expRes = &types.QueryTokenPairsResponse{ + Pagination: &query.PageResponse{Total: 2}, + TokenPairs: []types.TokenPair{pair, pair2}, + } + }, + true, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + ctx := sdk.WrapSDKContext(suite.ctx) + tc.malleate() + + res, err := suite.queryClient.TokenPairs(ctx, req) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expRes.Pagination, res.Pagination) + suite.Require().ElementsMatch(expRes.TokenPairs, res.TokenPairs) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestTokenPair() { + var ( + req *types.QueryTokenPairRequest + expRes *types.QueryTokenPairResponse + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "invalid token address", + func() { + req = &types.QueryTokenPairRequest{} + expRes = &types.QueryTokenPairResponse{} + }, + false, + }, + { + "token pair not found", + func() { + req = &types.QueryTokenPairRequest{ + Token: tests.GenerateAddress().Hex(), + } + expRes = &types.QueryTokenPairResponse{} + }, + false, + }, + { + "token pair found", + func() { + addr := tests.GenerateAddress() + pair := types.NewTokenPair(addr, "coin", true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, addr, pair.GetID()) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, pair.GetID()) + + req = &types.QueryTokenPairRequest{ + Token: pair.Erc20Address, + } + expRes = &types.QueryTokenPairResponse{TokenPair: pair} + }, + true, + }, + { + "token pair not found - with erc20 existant", + func() { + addr := tests.GenerateAddress() + pair := types.NewTokenPair(addr, "coin", true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, addr, pair.GetID()) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, pair.GetID()) + + req = &types.QueryTokenPairRequest{ + Token: pair.Erc20Address, + } + expRes = &types.QueryTokenPairResponse{TokenPair: pair} + }, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + ctx := sdk.WrapSDKContext(suite.ctx) + tc.malleate() + + res, err := suite.queryClient.TokenPair(ctx, req) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expRes, res) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestQueryParams() { + ctx := sdk.WrapSDKContext(suite.ctx) + expParams := types.DefaultParams() + + res, err := suite.queryClient.Params(ctx, &types.QueryParamsRequest{}) + suite.Require().NoError(err) + suite.Require().Equal(expParams, res.Params) +} diff --git a/x/erc20/keeper/integration_test.go b/x/erc20/keeper/integration_test.go new file mode 100644 index 00000000..5b00c064 --- /dev/null +++ b/x/erc20/keeper/integration_test.go @@ -0,0 +1,302 @@ +package keeper_test + +import ( + "math/big" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + + "github.com/ethereum/go-ethereum/common" + + "github.com/evmos/ethermint/crypto/ethsecp256k1" + "github.com/evmos/ethermint/encoding" + ethermint "github.com/evmos/ethermint/types" + + "github.com/AltheaFoundation/althea-L1/testutil" + + althea "github.com/AltheaFoundation/althea-L1/app" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +var _ = Describe("Performing EVM transactions", Ordered, func() { + BeforeEach(func() { + s.SetupTest() + + params := s.app.Erc20Keeper.GetParams(s.ctx) + params.EnableEVMHook = true + params.EnableErc20 = true + s.app.Erc20Keeper.SetParams(s.ctx, params) + }) + + // Epoch mechanism for triggering allocation and distribution + Context("with the ERC20 module and EVM Hook disabled", func() { + BeforeEach(func() { + params := s.app.Erc20Keeper.GetParams(s.ctx) + params.EnableEVMHook = false + params.EnableErc20 = false + s.app.Erc20Keeper.SetParams(s.ctx, params) + }) + It("should be successful", func() { + _, err := s.DeployContract("coin", "token", erc20Decimals) + Expect(err).To(BeNil()) + }) + }) + + Context("with the ERC20 module disabled", func() { + BeforeEach(func() { + params := s.app.Erc20Keeper.GetParams(s.ctx) + params.EnableErc20 = false + s.app.Erc20Keeper.SetParams(s.ctx, params) + }) + It("should be successful", func() { + _, err := s.DeployContract("coin", "token", erc20Decimals) + Expect(err).To(BeNil()) + }) + }) + + Context("with the EVMHook disabled", func() { + BeforeEach(func() { + params := s.app.Erc20Keeper.GetParams(s.ctx) + params.EnableEVMHook = false + s.app.Erc20Keeper.SetParams(s.ctx, params) + }) + It("should be successful", func() { + _, err := s.DeployContract("coin", "token", erc20Decimals) + Expect(err).To(BeNil()) + }) + }) + + Context("with the ERC20 module and EVM Hook enabled", func() { + It("should be successful", func() { + _, err := s.DeployContract("coin", "token", erc20Decimals) + Expect(err).To(BeNil()) + }) + }) +}) + +var _ = Describe("ERC20: Converting", Ordered, func() { + var ( + pair *types.TokenPair + coin sdk.Coin + moduleAcc sdk.AccAddress + amt = sdk.NewInt(100) + priv *ethsecp256k1.PrivKey + addr common.Address + accAddr sdk.AccAddress + ) + + BeforeEach(func() { + s.SetupTest() + priv, _ = ethsecp256k1.GenerateKey() + addrBz := priv.PubKey().Address().Bytes() + accAddr = sdk.AccAddress(addrBz) + addr = common.BytesToAddress(addrBz) + moduleAcc = s.app.AccountKeeper.GetModuleAccount(s.ctx, types.ModuleName).GetAddress() + + }) + + Context("with a registered coin", func() { + BeforeEach(func() { + _, pair = s.setupRegisterCoin() + coin = sdk.NewCoin(pair.Denom, amt) + + // denom := s.app.ClaimsKeeper.GetParams(s.ctx).ClaimsDenom + denom := "aalthea" + + err := testutil.FundAccount(s.app.BankKeeper, s.ctx, accAddr, sdk.NewCoins(sdk.NewCoin(denom, sdk.TokensFromConsensusPower(100, ethermint.PowerReduction)))) + s.Require().NoError(err) + err = testutil.FundAccount(s.app.BankKeeper, s.ctx, accAddr, sdk.NewCoins(coin)) + s.Require().NoError(err) + }) + + Describe("a Cosmos coin into an ERC20 token", func() { + BeforeEach(func() { + convertCoin(priv, coin) + }) + + It("should decrease coins on the sender account", func() { + balanceCoin := s.app.BankKeeper.GetBalance(s.ctx, accAddr, pair.Denom) + Expect(balanceCoin.IsZero()).To(BeTrue()) + }) + + It("should escrow coins on the module account", func() { + balanceCoin := s.app.BankKeeper.GetBalance(s.ctx, moduleAcc, pair.Denom) + Expect(balanceCoin).To(Equal(coin)) + }) + + It("should mint tokens and send to receiver", func() { + balanceERC20 := s.BalanceOf(pair.GetERC20Contract(), addr).(*big.Int) + Expect(balanceERC20.Int64()).To(Equal(amt.Int64())) + }) + }) + + Describe("an ERC20 token into a Cosmos coin", func() { + BeforeEach(func() { + convertCoin(priv, coin) + s.Commit() + convertERC20(priv, amt, pair.GetERC20Contract()) + }) + + It("should increase coins on the sender account", func() { + balanceCoin := s.app.BankKeeper.GetBalance(s.ctx, accAddr, pair.Denom) + Expect(balanceCoin).To(Equal(coin)) + }) + + It("should unescrow coins on the module account", func() { + balanceCoin := s.app.BankKeeper.GetBalance(s.ctx, moduleAcc, pair.Denom) + Expect(balanceCoin.IsZero()).To(BeTrue()) + }) + + It("should burn the receiver's token", func() { + balanceERC20 := s.BalanceOf(pair.GetERC20Contract(), addr).(*big.Int) + Expect(balanceERC20.Int64()).To(Equal(int64(0))) + }) + }) + }) + + Context("with a registered ERC20", func() { + BeforeEach(func() { + contract := s.setupRegisterERC20Pair(contractMinterBurner) + id := s.app.Erc20Keeper.GetTokenPairID(s.ctx, contract.String()) + *pair, _ = s.app.Erc20Keeper.GetTokenPair(s.ctx, id) + coin = sdk.NewCoin(pair.Denom, amt) + + // denom := s.app.ClaimsKeeper.GetParams(s.ctx).ClaimsDenom + denom := "aalthea" //use default denom for claimsDenom + + err := testutil.FundAccount(s.app.BankKeeper, s.ctx, accAddr, sdk.NewCoins(sdk.NewCoin(denom, sdk.NewInt(1000_000_000)))) + s.Require().NoError(err) + + _ = s.MintERC20Token(contract, s.address, addr, big.NewInt(amt.Int64())) + s.Commit() + }) + + Describe("an ERC20 token into a Cosmos coin", func() { + BeforeEach(func() { + convertERC20(priv, amt, pair.GetERC20Contract()) + }) + + It("should decrease tokens on the sender account", func() { + balanceERC20 := s.BalanceOf(pair.GetERC20Contract(), addr).(*big.Int) + Expect(balanceERC20.Int64()).To(Equal(int64(0))) + }) + + It("should escrow tokens on the module account", func() { + moduleAddr := common.BytesToAddress(moduleAcc.Bytes()) + balanceERC20 := s.BalanceOf(pair.GetERC20Contract(), moduleAddr).(*big.Int) + Expect(balanceERC20.Int64()).To(Equal(amt.Int64())) + }) + + It("should send coins to the recevier account", func() { + balanceCoin := s.app.BankKeeper.GetBalance(s.ctx, accAddr, pair.Denom) + Expect(balanceCoin).To(Equal(coin)) + }) + }) + + Describe("a Cosmos coin into an ERC20 token", func() { + BeforeEach(func() { + convertERC20(priv, amt, pair.GetERC20Contract()) + s.Commit() + convertCoin(priv, coin) + }) + + It("should increase tokens on the sender account", func() { + balanceERC20 := s.BalanceOf(pair.GetERC20Contract(), addr).(*big.Int) + Expect(balanceERC20.Int64()).To(Equal(amt.Int64())) + }) + + It("should unescrow tokens on the module account", func() { + moduleAddr := common.BytesToAddress(moduleAcc.Bytes()) + balanceERC20 := s.BalanceOf(pair.GetERC20Contract(), moduleAddr).(*big.Int) + Expect(balanceERC20.Int64()).To(Equal(int64(0))) + }) + + It("should burn coins to the recevier account", func() { + balanceCoin := s.app.BankKeeper.GetBalance(s.ctx, accAddr, pair.Denom) + Expect(balanceCoin.IsZero()).To(BeTrue()) + }) + }) + }) +}) + +func convertCoin(priv *ethsecp256k1.PrivKey, coin sdk.Coin) { + addrBz := priv.PubKey().Address().Bytes() + + convertCoinMsg := types.NewMsgConvertCoin(coin, common.BytesToAddress(addrBz), sdk.AccAddress(addrBz)) + res := deliverTx(priv, convertCoinMsg) + Expect(res.IsOK()).To(BeTrue(), "failed to convert coin: %s", res.Log) +} + +func convertERC20(priv *ethsecp256k1.PrivKey, amt sdk.Int, contract common.Address) { + addrBz := priv.PubKey().Address().Bytes() + + convertERC20Msg := types.NewMsgConvertERC20(amt, sdk.AccAddress(addrBz), contract, common.BytesToAddress(addrBz)) + res := deliverTx(priv, convertERC20Msg) + Expect(res.IsOK()).To(BeTrue(), "failed to convert ERC20: %s", res.Log) +} + +func deliverTx(priv *ethsecp256k1.PrivKey, msgs ...sdk.Msg) abci.ResponseDeliverTx { + encodingConfig := encoding.MakeConfig(althea.ModuleBasics) + accountAddress := sdk.AccAddress(priv.PubKey().Address().Bytes()) + // denom := s.app.ClaimsKeeper.GetParams(s.ctx).ClaimsDenom + denom := "aalthea" + + txBuilder := encodingConfig.TxConfig.NewTxBuilder() + + txBuilder.SetGasLimit(100_000_000) + txBuilder.SetFeeAmount(sdk.Coins{{Denom: denom, Amount: sdk.NewInt(100_000_000)}}) + err := txBuilder.SetMsgs(msgs...) + s.Require().NoError(err) + + seq, err := s.app.AccountKeeper.GetSequence(s.ctx, accountAddress) + s.Require().NoError(err) + + // First round: we gather all the signer infos. We use the "set empty + // signature" hack to do that. + sigV2 := signing.SignatureV2{ + PubKey: priv.PubKey(), + Data: &signing.SingleSignatureData{ + SignMode: encodingConfig.TxConfig.SignModeHandler().DefaultMode(), + Signature: nil, + }, + Sequence: seq, + } + + sigsV2 := []signing.SignatureV2{sigV2} + + err = txBuilder.SetSignatures(sigsV2...) + s.Require().NoError(err) + + // Second round: all signer infos are set, so each signer can sign. + accNumber := s.app.AccountKeeper.GetAccount(s.ctx, accountAddress).GetAccountNumber() + signerData := authsigning.SignerData{ + ChainID: s.ctx.ChainID(), + AccountNumber: accNumber, + Sequence: seq, + } + sigV2, err = tx.SignWithPrivKey( + encodingConfig.TxConfig.SignModeHandler().DefaultMode(), signerData, + txBuilder, priv, encodingConfig.TxConfig, + seq, + ) + s.Require().NoError(err) + + sigsV2 = []signing.SignatureV2{sigV2} + err = txBuilder.SetSignatures(sigsV2...) + s.Require().NoError(err) + + // bz are bytes to be broadcasted over the network + bz, err := encodingConfig.TxConfig.TxEncoder()(txBuilder.GetTx()) + s.Require().NoError(err) + + req := abci.RequestDeliverTx{Tx: bz} + res := s.app.BaseApp.DeliverTx(req) + return res +} diff --git a/x/erc20/keeper/keeper.go b/x/erc20/keeper/keeper.go new file mode 100644 index 00000000..47758afb --- /dev/null +++ b/x/erc20/keeper/keeper.go @@ -0,0 +1,53 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// Keeper of this module maintains collections of erc20. +type Keeper struct { + storeKey storetypes.StoreKey + cdc codec.BinaryCodec + paramstore paramtypes.Subspace + + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper + evmKeeper types.EVMKeeper +} + +// NewKeeper creates new instances of the erc20 Keeper +func NewKeeper( + storeKey storetypes.StoreKey, + cdc codec.BinaryCodec, + ps paramtypes.Subspace, + ak types.AccountKeeper, + bk types.BankKeeper, + evmKeeper types.EVMKeeper, +) Keeper { + // set KeyTable if it has not already been set + if !ps.HasKeyTable() { + ps = ps.WithKeyTable(types.ParamKeyTable()) + } + + return Keeper{ + storeKey: storeKey, + cdc: cdc, + paramstore: ps, + accountKeeper: ak, + bankKeeper: bk, + evmKeeper: evmKeeper, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} diff --git a/x/erc20/keeper/keeper_test.go b/x/erc20/keeper/keeper_test.go new file mode 100644 index 00000000..61f2ecbc --- /dev/null +++ b/x/erc20/keeper/keeper_test.go @@ -0,0 +1,518 @@ +package keeper_test + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + "testing" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/simapp" + 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/common/hexutil" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/tmhash" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmversion "github.com/tendermint/tendermint/proto/tendermint/version" + "github.com/tendermint/tendermint/version" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/evmos/ethermint/app" + "github.com/evmos/ethermint/crypto/ethsecp256k1" + "github.com/evmos/ethermint/encoding" + "github.com/evmos/ethermint/server/config" + "github.com/evmos/ethermint/tests" + "github.com/evmos/ethermint/x/evm/statedb" + evm "github.com/evmos/ethermint/x/evm/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" + + "github.com/AltheaFoundation/althea-L1/contracts" + + althea "github.com/AltheaFoundation/althea-L1/app" + altheacfg "github.com/AltheaFoundation/althea-L1/config" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +type KeeperTestSuite struct { + suite.Suite + + ctx sdk.Context + app *althea.AltheaApp + queryClientEvm evm.QueryClient + queryClient types.QueryClient + address common.Address + clientCtx client.Context + ethSigner ethtypes.Signer + signer keyring.Signer + mintFeeCollector bool +} + +var s *KeeperTestSuite + +func TestKeeperTestSuite(t *testing.T) { + s = new(KeeperTestSuite) + suite.Run(t, s) + + // Run Ginkgo integration tests + RegisterFailHandler(Fail) + RunSpecs(t, "Keeper Suite") +} + +// Test helpers +func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) { + checkTx := false + + // account key + priv, err := ethsecp256k1.GenerateKey() + require.NoError(t, err) + suite.address = common.BytesToAddress(priv.PubKey().Address().Bytes()) + suite.signer = tests.NewSigner(priv) + + // init app + suite.app = althea.NewSetup(checkTx, func(aa *althea.AltheaApp, gs simapp.GenesisState) simapp.GenesisState { + // setup feemarketGenesis params + feemarketGenesis := feemarkettypes.DefaultGenesisState() + feemarketGenesis.Params.EnableHeight = 1 + feemarketGenesis.Params.NoBaseFee = false + feemarketGenesis.Params.BaseFee = sdk.NewInt(1) + + gs[feemarkettypes.ModuleName] = aa.AppCodec().MustMarshalJSON(feemarketGenesis) + + if suite.mintFeeCollector { + // mint some coin to fee collector + coins := sdk.NewCoins(sdk.NewCoin(altheacfg.BaseDenom, sdk.NewInt(int64(params.TxGas)-1))) + balances := []banktypes.Balance{ + { + Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(), + Coins: coins, + }, + } + // update total supply + var bankGenesis banktypes.GenesisState + aa.AppCodec().MustUnmarshalJSON(gs[banktypes.ModuleName], &bankGenesis) + bankGenesis.Balances = append(bankGenesis.Balances, balances...) + bankGenesis.Supply = bankGenesis.Supply.Add(coins...) + gs[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(&bankGenesis) + + } + + return gs + }) + + suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{ + Height: 1, + ChainID: "althea_7357-1", + Time: time.Now().UTC(), + ProposerAddress: althea.ValidatorPubKey.Address().Bytes(), + + Version: tmversion.Consensus{ + Block: version.BlockProtocol, + }, + LastBlockId: tmproto.BlockID{ + Hash: tmhash.Sum([]byte("block_id")), + PartSetHeader: tmproto.PartSetHeader{ + Total: 11, + Hash: tmhash.Sum([]byte("partset_header")), + }, + }, + AppHash: tmhash.Sum([]byte("app")), + DataHash: tmhash.Sum([]byte("data")), + EvidenceHash: tmhash.Sum([]byte("evidence")), + ValidatorsHash: tmhash.Sum([]byte("validators")), + NextValidatorsHash: tmhash.Sum([]byte("next_validators")), + ConsensusHash: tmhash.Sum([]byte("consensus")), + LastResultsHash: tmhash.Sum([]byte("last_result")), + }) + + queryHelperEvm := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry()) + evm.RegisterQueryServer(queryHelperEvm, suite.app.EvmKeeper) + suite.queryClientEvm = evm.NewQueryClient(queryHelperEvm) + + queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, suite.app.Erc20Keeper) + suite.queryClient = types.NewQueryClient(queryHelper) + + encodingConfig := encoding.MakeConfig(app.ModuleBasics) + suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig) + suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()) +} + +func (suite *KeeperTestSuite) SetupTest() { + suite.DoSetupTest(suite.T()) +} + +func (suite *KeeperTestSuite) StateDB() *statedb.StateDB { + return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes()))) +} + +func (suite *KeeperTestSuite) MintFeeBurner(coins sdk.Coins) { + err := suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins) + suite.Require().NoError(err) + err = suite.app.BankKeeper.SendCoinsFromModuleToModule(suite.ctx, types.ModuleName, evmtypes.FeeBurner, coins) + suite.Require().NoError(err) +} + +// DeployContract deploys the ERC20MinterBurnerDecimalsContract. +func (suite *KeeperTestSuite) DeployContract(name, symbol string, decimals uint8) (common.Address, error) { + ctx := sdk.WrapSDKContext(suite.ctx) + chainID := suite.app.EvmKeeper.ChainID() + + ctorArgs, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("", name, symbol, decimals) + if err != nil { + return common.Address{}, err + } + + data := append(contracts.ERC20MinterBurnerDecimalsContract.Bin, ctorArgs...) + args, err := json.Marshal(&evm.TransactionArgs{ + From: &suite.address, + Data: (*hexutil.Bytes)(&data), + }) + if err != nil { + return common.Address{}, err + } + + res, err := suite.queryClientEvm.EstimateGas(ctx, &evm.EthCallRequest{ + Args: args, + GasCap: uint64(config.DefaultGasCap), + }) + if err != nil { + return common.Address{}, err + } + + nonce := suite.app.EvmKeeper.GetNonce(suite.ctx, suite.address) + + erc20DeployTx := evm.NewTxContract( + chainID, + nonce, + nil, // amount + res.Gas, // gasLimit + nil, // gasPrice + suite.app.FeemarketKeeper.GetBaseFee(suite.ctx), + big.NewInt(1), + data, // input + ðtypes.AccessList{}, // accesses + ) + + erc20DeployTx.From = suite.address.Hex() + err = erc20DeployTx.Sign(ethtypes.LatestSignerForChainID(chainID), suite.signer) + if err != nil { + return common.Address{}, err + } + + rsp, err := suite.app.EvmKeeper.EthereumTx(ctx, erc20DeployTx) + if err != nil { + return common.Address{}, err + } + + suite.Require().Empty(rsp.VmError) + return crypto.CreateAddress(suite.address, nonce), nil +} + +func (suite *KeeperTestSuite) DeployContractMaliciousDelayed(name string, symbol string) common.Address { + ctx := sdk.WrapSDKContext(suite.ctx) + chainID := suite.app.EvmKeeper.ChainID() + + ctorArgs, err := contracts.ERC20MaliciousDelayedContract.ABI.Pack("", big.NewInt(1000000000000000000)) + suite.Require().NoError(err) + + data := append(contracts.ERC20MaliciousDelayedContract.Bin, ctorArgs...) + args, err := json.Marshal(&evm.TransactionArgs{ + From: &suite.address, + Data: (*hexutil.Bytes)(&data), + }) + suite.Require().NoError(err) + + res, err := suite.queryClientEvm.EstimateGas(ctx, &evm.EthCallRequest{ + Args: args, + GasCap: uint64(config.DefaultGasCap), + }) + suite.Require().NoError(err) + + nonce := suite.app.EvmKeeper.GetNonce(suite.ctx, suite.address) + + erc20DeployTx := evm.NewTxContract( + chainID, + nonce, + nil, // amount + res.Gas, // gasLimit + nil, // gasPrice + suite.app.FeemarketKeeper.GetBaseFee(suite.ctx), + big.NewInt(1), + data, // input + ðtypes.AccessList{}, // accesses + ) + + erc20DeployTx.From = suite.address.Hex() + err = erc20DeployTx.Sign(ethtypes.LatestSignerForChainID(chainID), suite.signer) + suite.Require().NoError(err) + rsp, err := suite.app.EvmKeeper.EthereumTx(ctx, erc20DeployTx) + suite.Require().NoError(err) + suite.Require().Empty(rsp.VmError) + return crypto.CreateAddress(suite.address, nonce) +} + +func (suite *KeeperTestSuite) DeployContractDirectBalanceManipulation(name string, symbol string) common.Address { + ctx := sdk.WrapSDKContext(suite.ctx) + chainID := suite.app.EvmKeeper.ChainID() + + ctorArgs, err := contracts.ERC20DirectBalanceManipulationContract.ABI.Pack("", big.NewInt(1000000000000000000)) + suite.Require().NoError(err) + + data := append(contracts.ERC20DirectBalanceManipulationContract.Bin, ctorArgs...) + args, err := json.Marshal(&evm.TransactionArgs{ + From: &suite.address, + Data: (*hexutil.Bytes)(&data), + }) + suite.Require().NoError(err) + + res, err := suite.queryClientEvm.EstimateGas(ctx, &evm.EthCallRequest{ + Args: args, + GasCap: uint64(config.DefaultGasCap), + }) + suite.Require().NoError(err) + + nonce := suite.app.EvmKeeper.GetNonce(suite.ctx, suite.address) + + erc20DeployTx := evm.NewTxContract( + chainID, + nonce, + nil, // amount + res.Gas, // gasLimit + nil, // gasPrice + suite.app.FeemarketKeeper.GetBaseFee(suite.ctx), + big.NewInt(1), + data, // input + ðtypes.AccessList{}, // accesses + ) + + erc20DeployTx.From = suite.address.Hex() + err = erc20DeployTx.Sign(ethtypes.LatestSignerForChainID(chainID), suite.signer) + suite.Require().NoError(err) + rsp, err := suite.app.EvmKeeper.EthereumTx(ctx, erc20DeployTx) + suite.Require().NoError(err) + suite.Require().Empty(rsp.VmError) + return crypto.CreateAddress(suite.address, nonce) +} + +func (suite *KeeperTestSuite) Commit() { + _ = suite.app.Commit() + header := suite.ctx.BlockHeader() + header.Height += 1 + suite.app.BeginBlock(abci.RequestBeginBlock{ + Header: header, + }) + + // update ctx + suite.ctx = suite.app.BaseApp.NewContext(false, header) + + queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry()) + evm.RegisterQueryServer(queryHelper, suite.app.EvmKeeper) + suite.queryClientEvm = evm.NewQueryClient(queryHelper) +} + +func (suite *KeeperTestSuite) MintERC20Token(contractAddr, from, to common.Address, amount *big.Int) *evm.MsgEthereumTx { + transferData, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("mint", to, amount) + suite.Require().NoError(err) + return suite.sendTx(contractAddr, from, transferData) +} + +func (suite *KeeperTestSuite) TransferERC20TokenToModule(contractAddr, from common.Address, amount *big.Int) *evm.MsgEthereumTx { + transferData, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("transfer", types.ModuleAddress, amount) + suite.Require().NoError(err) + return suite.sendTx(contractAddr, from, transferData) +} + +func (suite *KeeperTestSuite) GrantERC20Token(contractAddr, from, to common.Address, role_string string) *evm.MsgEthereumTx { + // 0xCc508cD0818C85b8b8a1aB4cEEef8d981c8956A6 MINTER_ROLE + role := crypto.Keccak256([]byte(role_string)) + // needs to be an array not a slice + var v [32]byte + copy(v[:], role) + + transferData, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("grantRole", v, to) + suite.Require().NoError(err) + return suite.sendTx(contractAddr, from, transferData) +} + +func (suite *KeeperTestSuite) sendTx(contractAddr, from common.Address, transferData []byte) *evm.MsgEthereumTx { + ctx := sdk.WrapSDKContext(suite.ctx) + chainID := suite.app.EvmKeeper.ChainID() + + args, err := json.Marshal(&evm.TransactionArgs{To: &contractAddr, From: &from, Data: (*hexutil.Bytes)(&transferData)}) + suite.Require().NoError(err) + res, err := suite.queryClientEvm.EstimateGas(ctx, &evm.EthCallRequest{ + Args: args, + GasCap: uint64(config.DefaultGasCap), + }) + suite.Require().NoError(err) + + nonce := suite.app.EvmKeeper.GetNonce(suite.ctx, suite.address) + + // Mint the max gas to the FeeCollector to ensure balance in case of refund + suite.MintFeeBurner(sdk.NewCoins(sdk.NewCoin(altheacfg.BaseDenom, sdk.NewInt(suite.app.FeemarketKeeper.GetBaseFee(suite.ctx).Int64()*int64(res.Gas))))) + + ercTransferTx := evm.NewTx( + chainID, + nonce, + &contractAddr, + nil, + res.Gas, + nil, + suite.app.FeemarketKeeper.GetBaseFee(suite.ctx), + big.NewInt(1), + transferData, + ðtypes.AccessList{}, // accesses + ) + + ercTransferTx.From = suite.address.Hex() + err = ercTransferTx.Sign(ethtypes.LatestSignerForChainID(chainID), suite.signer) + suite.Require().NoError(err) + rsp, err := suite.app.EvmKeeper.EthereumTx(ctx, ercTransferTx) + suite.Require().NoError(err) + suite.Require().Empty(rsp.VmError) + return ercTransferTx +} + +func (suite *KeeperTestSuite) BalanceOf(contract, account common.Address) interface{} { + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + + res, err := suite.app.Erc20Keeper.CallEVM(suite.ctx, erc20, types.ModuleAddress, contract, false, "balanceOf", account) + if err != nil { + return nil + } + + unpacked, err := erc20.Unpack("balanceOf", res.Ret) + if len(unpacked) == 0 { + return nil + } + + return unpacked[0] +} + +func (suite *KeeperTestSuite) NameOf(contract common.Address) string { + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + + res, err := suite.app.Erc20Keeper.CallEVM(suite.ctx, erc20, types.ModuleAddress, contract, false, "name") + suite.Require().NoError(err) + suite.Require().NotNil(res) + + unpacked, err := erc20.Unpack("name", res.Ret) + suite.Require().NoError(err) + suite.Require().NotEmpty(unpacked) + + return fmt.Sprintf("%v", unpacked[0]) +} + +func (suite *KeeperTestSuite) TransferERC20Token(contractAddr, from, to common.Address, amount *big.Int) *evm.MsgEthereumTx { + transferData, err := contracts.ERC20MinterBurnerDecimalsContract.ABI.Pack("transfer", to, amount) + suite.Require().NoError(err) + return suite.sendTx(contractAddr, from, transferData) +} + +var _ types.EVMKeeper = &MockEVMKeeper{} + +type MockEVMKeeper struct { + mock.Mock +} + +func (m *MockEVMKeeper) GetParams(ctx sdk.Context) evmtypes.Params { + args := m.Called(mock.Anything) + return args.Get(0).(evmtypes.Params) +} + +func (m *MockEVMKeeper) GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) *statedb.Account { + args := m.Called(mock.Anything, mock.Anything) + if args.Get(0) == nil { + return nil + } + return args.Get(0).(*statedb.Account) +} + +func (m *MockEVMKeeper) EstimateGas(c context.Context, req *evmtypes.EthCallRequest) (*evmtypes.EstimateGasResponse, error) { + args := m.Called(mock.Anything, mock.Anything) + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(*evmtypes.EstimateGasResponse), args.Error(1) +} + +func (m *MockEVMKeeper) ApplyMessage(ctx sdk.Context, msg core.Message, tracer vm.EVMLogger, commit bool) (*evmtypes.MsgEthereumTxResponse, error) { + args := m.Called(mock.Anything, mock.Anything, mock.Anything, mock.Anything) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + return args.Get(0).(*evmtypes.MsgEthereumTxResponse), args.Error(1) +} + +var _ types.BankKeeper = &MockBankKeeper{} + +type MockBankKeeper struct { + mock.Mock +} + +func (b *MockBankKeeper) SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error { + args := b.Called(mock.Anything, mock.Anything, mock.Anything, mock.Anything) + return args.Error(0) +} + +func (b *MockBankKeeper) SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error { + args := b.Called(mock.Anything, mock.Anything, mock.Anything, mock.Anything) + return args.Error(0) +} + +func (b *MockBankKeeper) MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { + args := b.Called(mock.Anything, mock.Anything, mock.Anything) + return args.Error(0) +} + +func (b *MockBankKeeper) BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error { + args := b.Called(mock.Anything, mock.Anything, mock.Anything) + return args.Error(0) +} + +func (b *MockBankKeeper) IsSendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool { + args := b.Called(mock.Anything, mock.Anything) + return args.Bool(0) +} + +func (b *MockBankKeeper) BlockedAddr(addr sdk.AccAddress) bool { + args := b.Called(mock.Anything) + return args.Bool(0) +} + +func (b *MockBankKeeper) GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool) { + args := b.Called(mock.Anything, mock.Anything) + return args.Get(0).(banktypes.Metadata), args.Bool(1) +} + +func (b *MockBankKeeper) SetDenomMetaData(ctx sdk.Context, denomMetaData banktypes.Metadata) { +} + +func (b *MockBankKeeper) HasSupply(ctx sdk.Context, denom string) bool { + args := b.Called(mock.Anything, mock.Anything) + return args.Bool(0) +} + +func (b *MockBankKeeper) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + args := b.Called(mock.Anything, mock.Anything) + return args.Get(0).(sdk.Coin) +} diff --git a/x/erc20/keeper/migrations.go b/x/erc20/keeper/migrations.go new file mode 100644 index 00000000..a0185291 --- /dev/null +++ b/x/erc20/keeper/migrations.go @@ -0,0 +1,27 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + v2 "github.com/AltheaFoundation/althea-L1/x/erc20/migrations/v2" +) + +var _ module.MigrationHandler = Migrator{}.Migrate1to2 + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + keeper Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(keeper Keeper) Migrator { + return Migrator{ + keeper: keeper, + } +} + +// Migrate1to2 migrates from consensus version 1 to 2. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return v2.UpdateParams(ctx, &m.keeper.paramstore) +} diff --git a/x/erc20/keeper/mint.go b/x/erc20/keeper/mint.go new file mode 100644 index 00000000..72d07f96 --- /dev/null +++ b/x/erc20/keeper/mint.go @@ -0,0 +1,66 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// MintingEnabled checks that: +// - the global parameter for erc20 conversion is enabled +// - minting is enabled for the given (erc20,coin) token pair +// - recipient address is not on the blocked list +// - bank module transfers are enabled for the Cosmos coin +func (k Keeper) MintingEnabled( + ctx sdk.Context, + sender, receiver sdk.AccAddress, + token string, +) (types.TokenPair, error) { + params := k.GetParams(ctx) + if !params.EnableErc20 { + return types.TokenPair{}, sdkerrors.Wrap( + types.ErrERC20Disabled, "module is currently disabled by governance", + ) + } + + id := k.GetTokenPairID(ctx, token) + if len(id) == 0 { + return types.TokenPair{}, sdkerrors.Wrapf( + types.ErrTokenPairNotFound, "token '%s' not registered by id", token, + ) + } + + pair, found := k.GetTokenPair(ctx, id) + if !found { + return types.TokenPair{}, sdkerrors.Wrapf( + types.ErrTokenPairNotFound, "token '%s' not registered", token, + ) + } + + if !pair.Enabled { + return types.TokenPair{}, sdkerrors.Wrapf( + types.ErrERC20TokenPairDisabled, "minting token '%s' is not enabled by governance", token, + ) + } + + if k.bankKeeper.BlockedAddr(receiver.Bytes()) { + return types.TokenPair{}, sdkerrors.Wrapf( + sdkerrors.ErrUnauthorized, "%s is not allowed to receive transactions", receiver, + ) + } + + // NOTE: ignore amount as only denom is checked on IsSendEnabledCoin + coin := sdk.Coin{Denom: pair.Denom} + + // check if minting to a recipient address other than the sender is enabled + // for for the given coin denom + if !sender.Equals(receiver) && !k.bankKeeper.IsSendEnabledCoin(ctx, coin) { + return types.TokenPair{}, sdkerrors.Wrapf( + banktypes.ErrSendDisabled, "minting '%s' coins to an external address is currently disabled", token, + ) + } + + return pair, nil +} diff --git a/x/erc20/keeper/mint_test.go b/x/erc20/keeper/mint_test.go new file mode 100644 index 00000000..ce39e144 --- /dev/null +++ b/x/erc20/keeper/mint_test.go @@ -0,0 +1,112 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/evmos/ethermint/tests" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +func (suite *KeeperTestSuite) TestMintingEnabled() { + sender := sdk.AccAddress(tests.GenerateAddress().Bytes()) + receiver := sdk.AccAddress(tests.GenerateAddress().Bytes()) + expPair := types.NewTokenPair(tests.GenerateAddress(), "coin", true, types.OWNER_MODULE) + id := expPair.GetID() + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "conversion is disabled globally", + func() { + params := types.DefaultParams() + params.EnableErc20 = false + suite.app.Erc20Keeper.SetParams(suite.ctx, params) + }, + false, + }, + { + "token pair not found", + func() {}, + false, + }, + { + "conversion is disabled for the given pair", + func() { + expPair.Enabled = false + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, expPair) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id) + }, + false, + }, + { + "token transfers are disabled", + func() { + expPair.Enabled = true + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, expPair) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id) + + params := banktypes.DefaultParams() + params.SendEnabled = []*banktypes.SendEnabled{ + {Denom: expPair.Denom, Enabled: false}, + } + suite.app.BankKeeper.SetParams(suite.ctx, params) + }, + false, + }, + { + "token not registered", + func() { + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id) + }, + false, + }, + { + "receiver address is blocked (module account)", + func() { + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, expPair) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id) + + acc := suite.app.AccountKeeper.GetModuleAccount(suite.ctx, types.ModuleName) + receiver = acc.GetAddress() + }, + false, + }, + { + "ok", + func() { + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, expPair) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, expPair.Denom, id) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, expPair.GetERC20Contract(), id) + + receiver = sdk.AccAddress(tests.GenerateAddress().Bytes()) + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + tc.malleate() + + pair, err := suite.app.Erc20Keeper.MintingEnabled(suite.ctx, sender, receiver, expPair.Erc20Address) + if tc.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expPair, pair) + } else { + suite.Require().Error(err) + } + }) + } +} diff --git a/x/erc20/keeper/msg_server.go b/x/erc20/keeper/msg_server.go new file mode 100644 index 00000000..2ad0be99 --- /dev/null +++ b/x/erc20/keeper/msg_server.go @@ -0,0 +1,526 @@ +package keeper + +import ( + "context" + "math/big" + + "github.com/armon/go-metrics" + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/ethereum/go-ethereum/common" + + "github.com/AltheaFoundation/althea-L1/contracts" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +var _ types.MsgServer = &Keeper{} + +// ConvertCoin converts native Cosmos coins into ERC20 tokens for both +// Cosmos-native and ERC20 TokenPair Owners +func (k Keeper) ConvertCoin( + goCtx context.Context, + msg *types.MsgConvertCoin, +) (*types.MsgConvertCoinResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // Error checked during msg validation + receiver := common.HexToAddress(msg.Receiver) + sender := sdk.MustAccAddressFromBech32(msg.Sender) + + pair, err := k.MintingEnabled(ctx, sender, receiver.Bytes(), msg.Coin.Denom) + if err != nil { + return nil, err + } + + // Remove token pair if contract is suicided + erc20 := common.HexToAddress(pair.Erc20Address) + acc := k.evmKeeper.GetAccountWithoutBalance(ctx, erc20) + + if acc == nil || !acc.IsContract() { + k.DeleteTokenPair(ctx, pair) + k.Logger(ctx).Debug( + "deleting selfdestructed token pair from state", + "contract", pair.Erc20Address, + ) + // NOTE: return nil error to persist the changes from the deletion + return nil, nil + } + + // Check ownership and execute conversion + switch { + case pair.IsNativeCoin(): + return k.convertCoinNativeCoin(ctx, pair, msg, receiver, sender) // case 1.1 + case pair.IsNativeERC20(): + return k.convertCoinNativeERC20(ctx, pair, msg, receiver, sender) // case 2.2 + default: + return nil, types.ErrUndefinedOwner + } +} + +// ConvertERC20 converts ERC20 tokens into native Cosmos coins for both +// Cosmos-native and ERC20 TokenPair Owners +func (k Keeper) ConvertERC20( + goCtx context.Context, + msg *types.MsgConvertERC20, +) (*types.MsgConvertERC20Response, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // Error checked during msg validation + receiver := sdk.MustAccAddressFromBech32(msg.Receiver) + sender := common.HexToAddress(msg.Sender) + + pair, err := k.MintingEnabled(ctx, sender.Bytes(), receiver, msg.ContractAddress) + if err != nil { + return nil, err + } + + // Remove token pair if contract is suicided + erc20 := common.HexToAddress(pair.Erc20Address) + acc := k.evmKeeper.GetAccountWithoutBalance(ctx, erc20) + + if acc == nil || !acc.IsContract() { + k.DeleteTokenPair(ctx, pair) + k.Logger(ctx).Debug( + "deleting selfdestructed token pair from state", + "contract", pair.Erc20Address, + ) + // NOTE: return nil error to persist the changes from the deletion + return nil, nil + } + + // Check ownership and execute conversion + switch { + case pair.IsNativeCoin(): + return k.convertERC20NativeCoin(ctx, pair, msg, receiver, sender) // case 1.2 + case pair.IsNativeERC20(): + return k.convertERC20NativeToken(ctx, pair, msg, receiver, sender) // case 2.1 + default: + return nil, types.ErrUndefinedOwner + } +} + +// convertCoinNativeCoin handles the coin conversion for a native Cosmos coin +// token pair: +// - escrow coins on module account +// - mint tokens and send to receiver +// - check if token balance increased by amount +func (k Keeper) convertCoinNativeCoin( + ctx sdk.Context, + pair types.TokenPair, + msg *types.MsgConvertCoin, + receiver common.Address, + sender sdk.AccAddress, +) (*types.MsgConvertCoinResponse, error) { + // NOTE: ignore validation from NewCoin constructor + coins := sdk.Coins{msg.Coin} + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + contract := pair.GetERC20Contract() + balanceToken := k.BalanceOf(ctx, erc20, contract, receiver) + if balanceToken == nil { + return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + + // Escrow coins on module account + err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, coins) + if err != nil { + return nil, sdkerrors.Wrap(err, "failed to escrow coins") + } + + // Mint tokens and send to receiver + _, err = k.CallEVM(ctx, erc20, types.ModuleAddress, contract, true, "mint", receiver, msg.Coin.Amount.BigInt()) + if err != nil { + return nil, err + } + + // Check expected receiver balance after transfer + tokens := msg.Coin.Amount.BigInt() + balanceTokenAfter := k.BalanceOf(ctx, erc20, contract, receiver) + if balanceTokenAfter == nil { + return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + expToken := big.NewInt(0).Add(balanceToken, tokens) + + if r := balanceTokenAfter.Cmp(expToken); r != 0 { + return nil, sdkerrors.Wrapf( + types.ErrBalanceInvariance, + "invalid token balance - expected: %v, actual: %v", expToken, balanceTokenAfter, + ) + } + + defer func() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "coin", "total"}, + 1, + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + telemetry.NewLabel("erc20", pair.Erc20Address), + }, + ) + + if msg.Coin.Amount.IsInt64() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "coin", "amount", "total"}, + float32(msg.Coin.Amount.Int64()), + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + telemetry.NewLabel("erc20", pair.Erc20Address), + }, + ) + } + }() + + ctx.EventManager().EmitEvents( + sdk.Events{ + sdk.NewEvent( + types.EventTypeConvertCoin, + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Coin.Amount.String()), + sdk.NewAttribute(types.AttributeKeyCosmosCoin, msg.Coin.Denom), + sdk.NewAttribute(types.AttributeKeyERC20Token, pair.Erc20Address), + ), + }, + ) + + return &types.MsgConvertCoinResponse{}, nil +} + +// convertERC20NativeCoin handles the erc20 conversion for a native Cosmos coin +// token pair: +// - burn escrowed tokens +// - unescrow coins that have been previously escrowed with ConvertCoin +// - check if coin balance increased by amount +// - check if token balance decreased by amount +func (k Keeper) convertERC20NativeCoin( + ctx sdk.Context, + pair types.TokenPair, + msg *types.MsgConvertERC20, + receiver sdk.AccAddress, + sender common.Address, +) (*types.MsgConvertERC20Response, error) { + // NOTE: coin fields already validated + coins := sdk.Coins{sdk.Coin{Denom: pair.Denom, Amount: msg.Amount}} + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + contract := pair.GetERC20Contract() + balanceCoin := k.bankKeeper.GetBalance(ctx, receiver, pair.Denom) + balanceToken := k.BalanceOf(ctx, erc20, contract, sender) + if balanceToken == nil { + return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + + // Burn escrowed tokens + _, err := k.CallEVM(ctx, erc20, types.ModuleAddress, contract, true, "burnCoins", sender, msg.Amount.BigInt()) + if err != nil { + return nil, err + } + + // Unescrow coins and send to receiver + err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiver, coins) + if err != nil { + return nil, err + } + + // Check expected receiver balance after transfer + balanceCoinAfter := k.bankKeeper.GetBalance(ctx, receiver, pair.Denom) + expCoin := balanceCoin.Add(coins[0]) + if ok := balanceCoinAfter.IsEqual(expCoin); !ok { + return nil, sdkerrors.Wrapf( + types.ErrBalanceInvariance, + "invalid coin balance - expected: %v, actual: %v", + expCoin, balanceCoinAfter, + ) + } + + // Check expected Sender balance after transfer + tokens := coins[0].Amount.BigInt() + balanceTokenAfter := k.BalanceOf(ctx, erc20, contract, sender) + if balanceTokenAfter == nil { + return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + + expToken := big.NewInt(0).Sub(balanceToken, tokens) + if r := balanceTokenAfter.Cmp(expToken); r != 0 { + return nil, sdkerrors.Wrapf( + types.ErrBalanceInvariance, + "invalid token balance - expected: %v, actual: %v", + expToken, balanceTokenAfter, + ) + } + + defer func() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "erc20", "total"}, + 1, + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + telemetry.NewLabel("erc20", pair.Erc20Address), + }, + ) + + if msg.Amount.IsInt64() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "erc20", "amount", "total"}, + float32(msg.Amount.Int64()), + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + telemetry.NewLabel("erc20", pair.Erc20Address), + }, + ) + } + }() + + ctx.EventManager().EmitEvents( + sdk.Events{ + sdk.NewEvent( + types.EventTypeConvertERC20, + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(types.AttributeKeyCosmosCoin, pair.Denom), + sdk.NewAttribute(types.AttributeKeyERC20Token, msg.ContractAddress), + ), + }, + ) + + return &types.MsgConvertERC20Response{}, nil +} + +// convertERC20NativeToken handles the erc20 conversion for a native erc20 token +// pair: +// - escrow tokens on module account +// - mint coins on bank module +// - send minted coins to the receiver +// - check if coin balance increased by amount +// - check if token balance decreased by amount +// - check for unexpected `Approval` event in logs +func (k Keeper) convertERC20NativeToken( + ctx sdk.Context, + pair types.TokenPair, + msg *types.MsgConvertERC20, + receiver sdk.AccAddress, + sender common.Address, +) (*types.MsgConvertERC20Response, error) { + // NOTE: coin fields already validated + coins := sdk.Coins{sdk.Coin{Denom: pair.Denom, Amount: msg.Amount}} + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + contract := pair.GetERC20Contract() + balanceCoin := k.bankKeeper.GetBalance(ctx, receiver, pair.Denom) + balanceToken := k.BalanceOf(ctx, erc20, contract, types.ModuleAddress) + if balanceToken == nil { + return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + + // Escrow tokens on module account + transferData, err := erc20.Pack("transfer", types.ModuleAddress, msg.Amount.BigInt()) + if err != nil { + return nil, err + } + + res, err := k.CallEVMWithData(ctx, sender, &contract, transferData, true) + if err != nil { + return nil, err + } + + // Check evm call response + var unpackedRet types.ERC20BoolResponse + if err := erc20.UnpackIntoInterface(&unpackedRet, "transfer", res.Ret); err != nil { + return nil, err + } + + if !unpackedRet.Value { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "failed to execute transfer") + } + + // Check expected escrow balance after transfer execution + tokens := coins[0].Amount.BigInt() + balanceTokenAfter := k.BalanceOf(ctx, erc20, contract, types.ModuleAddress) + if balanceTokenAfter == nil { + return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + + expToken := big.NewInt(0).Add(balanceToken, tokens) + + if r := balanceTokenAfter.Cmp(expToken); r != 0 { + return nil, sdkerrors.Wrapf( + types.ErrBalanceInvariance, + "invalid token balance - expected: %v, actual: %v", + expToken, balanceTokenAfter, + ) + } + + // Mint coins + if err := k.bankKeeper.MintCoins(ctx, types.ModuleName, coins); err != nil { + return nil, err + } + + // Send minted coins to the receiver + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, receiver, coins); err != nil { + return nil, err + } + + // Check expected receiver balance after transfer + balanceCoinAfter := k.bankKeeper.GetBalance(ctx, receiver, pair.Denom) + expCoin := balanceCoin.Add(coins[0]) + + if ok := balanceCoinAfter.IsEqual(expCoin); !ok { + return nil, sdkerrors.Wrapf( + types.ErrBalanceInvariance, + "invalid coin balance - expected: %v, actual: %v", + expCoin, balanceCoinAfter, + ) + } + + // Check for unexpected `Approval` event in logs + if err := k.monitorApprovalEvent(res); err != nil { + return nil, err + } + + defer func() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "erc20", "total"}, + 1, + []metrics.Label{ + telemetry.NewLabel("coin", pair.Denom), + telemetry.NewLabel("erc20", pair.Erc20Address), + }, + ) + + if msg.Amount.IsInt64() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "erc20", "amount", "total"}, + float32(msg.Amount.Int64()), + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + telemetry.NewLabel("erc20", pair.Erc20Address), + }, + ) + } + }() + + ctx.EventManager().EmitEvents( + sdk.Events{ + sdk.NewEvent( + types.EventTypeConvertERC20, + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), + sdk.NewAttribute(types.AttributeKeyCosmosCoin, pair.Denom), + sdk.NewAttribute(types.AttributeKeyERC20Token, msg.ContractAddress), + ), + }, + ) + + return &types.MsgConvertERC20Response{}, nil +} + +// convertCoinNativeERC20 handles the coin conversion for a native ERC20 token +// pair: +// - escrow Coins on module account +// - unescrow Tokens that have been previously escrowed with ConvertERC20 and send to receiver +// - burn escrowed Coins +// - check if token balance increased by amount +// - check for unexpected `Approval` event in logs +func (k Keeper) convertCoinNativeERC20( + ctx sdk.Context, + pair types.TokenPair, + msg *types.MsgConvertCoin, + receiver common.Address, + sender sdk.AccAddress, +) (*types.MsgConvertCoinResponse, error) { + // NOTE: ignore validation from NewCoin constructor + coins := sdk.Coins{msg.Coin} + + erc20 := contracts.ERC20MinterBurnerDecimalsContract.ABI + contract := pair.GetERC20Contract() + balanceToken := k.BalanceOf(ctx, erc20, contract, receiver) + if balanceToken == nil { + return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + + // Escrow Coins on module account + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, coins); err != nil { + return nil, sdkerrors.Wrap(err, "failed to escrow coins") + } + + // Unescrow Tokens and send to receiver + res, err := k.CallEVM(ctx, erc20, types.ModuleAddress, contract, true, "transfer", receiver, msg.Coin.Amount.BigInt()) + if err != nil { + return nil, err + } + + // Check unpackedRet execution + var unpackedRet types.ERC20BoolResponse + if err := erc20.UnpackIntoInterface(&unpackedRet, "transfer", res.Ret); err != nil { + return nil, err + } + + if !unpackedRet.Value { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "failed to execute unescrow tokens from user") + } + + // Check expected Receiver balance after transfer execution + tokens := msg.Coin.Amount.BigInt() + balanceTokenAfter := k.BalanceOf(ctx, erc20, contract, receiver) + if balanceTokenAfter == nil { + return nil, sdkerrors.Wrap(types.ErrEVMCall, "failed to retrieve balance") + } + + exp := big.NewInt(0).Add(balanceToken, tokens) + + if r := balanceTokenAfter.Cmp(exp); r != 0 { + return nil, sdkerrors.Wrapf( + types.ErrBalanceInvariance, + "invalid token balance - expected: %v, actual: %v", exp, balanceTokenAfter, + ) + } + + // Burn escrowed Coins + err = k.bankKeeper.BurnCoins(ctx, types.ModuleName, coins) + if err != nil { + return nil, sdkerrors.Wrap(err, "failed to burn coins") + } + + // Check for unexpected `Approval` event in logs + if err := k.monitorApprovalEvent(res); err != nil { + return nil, err + } + + defer func() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "coin", "total"}, + 1, + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + telemetry.NewLabel("erc20", pair.Erc20Address), + }, + ) + + if msg.Coin.Amount.IsInt64() { + telemetry.IncrCounterWithLabels( + []string{"tx", "msg", "convert", "coin", "amount", "total"}, + float32(msg.Coin.Amount.Int64()), + []metrics.Label{ + telemetry.NewLabel("denom", pair.Denom), + telemetry.NewLabel("erc20", pair.Erc20Address), + }, + ) + } + }() + + ctx.EventManager().EmitEvents( + sdk.Events{ + sdk.NewEvent( + types.EventTypeConvertCoin, + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver), + sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Coin.Amount.String()), + sdk.NewAttribute(types.AttributeKeyCosmosCoin, msg.Coin.Denom), + sdk.NewAttribute(types.AttributeKeyERC20Token, pair.Erc20Address), + ), + }, + ) + + return &types.MsgConvertCoinResponse{}, nil +} diff --git a/x/erc20/keeper/msg_server_test.go b/x/erc20/keeper/msg_server_test.go new file mode 100644 index 00000000..47d1c2c2 --- /dev/null +++ b/x/erc20/keeper/msg_server_test.go @@ -0,0 +1,1344 @@ +package keeper_test + +import ( + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/mock" + + "github.com/ethereum/go-ethereum/common" + + "github.com/AltheaFoundation/althea-L1/x/erc20/keeper" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" + "github.com/evmos/ethermint/x/evm/statedb" + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +func (suite *KeeperTestSuite) TestConvertCoinNativeCoin() { + testCases := []struct { + name string + mint int64 + burn int64 + malleate func(common.Address) + extra func() + expPass bool + selfdestructed bool + }{ + { + "ok - sufficient funds", + 100, + 10, + func(common.Address) {}, + func() {}, + true, + false, + }, + { + "ok - equal funds", + 10, + 10, + func(common.Address) {}, + func() {}, + true, + false, + }, + { + "ok - suicided contract", + 10, + 10, + func(erc20 common.Address) { + stateDb := suite.StateDB() + ok := stateDb.Suicide(erc20) + suite.Require().True(ok) + suite.Require().NoError(stateDb.Commit()) + }, + func() {}, + true, + true, + }, + { + "fail - insufficient funds", + 0, + 10, + func(common.Address) {}, + func() {}, + false, + false, + }, + { + "fail - minting disabled", + 100, + 10, + func(common.Address) { + params := types.DefaultParams() + params.EnableErc20 = false + suite.app.Erc20Keeper.SetParams(suite.ctx, params) + }, + func() {}, + false, + false, + }, + { + "fail - deleted module account - force fail", 100, 10, func(common.Address) {}, + func() { + acc := suite.app.AccountKeeper.GetAccount(suite.ctx, types.ModuleAddress.Bytes()) + suite.app.AccountKeeper.RemoveAccount(suite.ctx, acc) + }, false, false, + }, + { + "fail - force evm fail", 100, 10, func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, false, false, + }, + { + "fail - force evm balance error", 100, 10, func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + // first balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + // convert coin + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil).Once() + // second balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, fmt.Errorf("third")).Once() + // Extra call on test + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, false, false, + }, + { + "fail - force balance error", 100, 10, func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Times(4) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, false, false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + metadata, pair := suite.setupRegisterCoin() + suite.Require().NotNil(metadata) + erc20 := pair.GetERC20Contract() + tc.malleate(erc20) + suite.Commit() + + ctx := sdk.WrapSDKContext(suite.ctx) + coins := sdk.NewCoins(sdk.NewCoin(cosmosTokenBase, sdk.NewInt(tc.mint))) + sender := sdk.AccAddress(suite.address.Bytes()) + msg := types.NewMsgConvertCoin( + sdk.NewCoin(cosmosTokenBase, sdk.NewInt(tc.burn)), + suite.address, + sender, + ) + + suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins) + suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, sender, coins) + + tc.extra() + res, err := suite.app.Erc20Keeper.ConvertCoin(ctx, msg) + expRes := &types.MsgConvertCoinResponse{} + suite.Commit() + balance := suite.BalanceOf(common.HexToAddress(pair.Erc20Address), suite.address) + cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, metadata.Base) + + if tc.expPass { + suite.Require().NoError(err, tc.name) + + acc := suite.app.EvmKeeper.GetAccountWithoutBalance(suite.ctx, erc20) + if tc.selfdestructed { + suite.Require().Nil(acc, "expected contract to be destroyed") + } else { + suite.Require().NotNil(acc) + } + + if tc.selfdestructed || !acc.IsContract() { + id := suite.app.Erc20Keeper.GetTokenPairID(suite.ctx, erc20.String()) + _, found := suite.app.Erc20Keeper.GetTokenPair(suite.ctx, id) + suite.Require().False(found) + } else { + suite.Require().Equal(expRes, res) + suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn).Int64()) + suite.Require().Equal(balance.(*big.Int).Int64(), big.NewInt(tc.burn).Int64()) + } + } else { + suite.Require().Error(err, tc.name) + } + }) + } + suite.mintFeeCollector = false +} + +func (suite *KeeperTestSuite) TestConvertERC20NativeCoin() { + testCases := []struct { + name string + mint int64 + burn int64 + reconvert int64 + malleate func() + expPass bool + }{ + {"ok - sufficient funds", 100, 10, 5, func() {}, true}, + {"ok - equal funds", 10, 10, 10, func() {}, true}, + {"fail - insufficient funds", 10, 1, 5, func() {}, false}, + {"fail ", 10, 1, -5, func() {}, false}, + { + "fail - deleted module account - force fail", 100, 10, 5, + func() { + acc := suite.app.AccountKeeper.GetAccount(suite.ctx, types.ModuleAddress.Bytes()) + suite.app.AccountKeeper.RemoveAccount(suite.ctx, acc) + }, + false, + }, + { + "fail - force evm fail", 100, 10, 5, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + false, + }, + { + "fail - force fail second balance", 100, 10, 5, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + // first balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + // convert coin + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil).Once() + // second balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, fmt.Errorf("third")).Once() + // Extra call on test + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + false, + }, + { + "fail - force fail second balance", 100, 10, 5, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + // first balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + // convert coin + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil).Once() + // second balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + // Extra call on test + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + false, + }, + { + "fail - force fail unescrow", 100, 10, 5, + func() { + mockBankKeeper := &MockBankKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, mockBankKeeper, suite.app.EvmKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + mockBankKeeper.On("SendCoinsFromModuleToAccount", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("failed to unescrow")) + mockBankKeeper.On("BlockedAddr", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(false) + mockBankKeeper.On("GetBalance", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Coin{Denom: "coin", Amount: sdk.OneInt()}) + }, + false, + }, + { + "fail - force fail balance after transfer", 100, 10, 5, + func() { + mockBankKeeper := &MockBankKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, mockBankKeeper, suite.app.EvmKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + mockBankKeeper.On("SendCoinsFromModuleToAccount", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + mockBankKeeper.On("BlockedAddr", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(false) + mockBankKeeper.On("GetBalance", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Coin{Denom: "acoin", Amount: sdk.OneInt()}) + }, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + metadata, pair := suite.setupRegisterCoin() + suite.Require().NotNil(metadata) + suite.Require().NotNil(pair) + + // Precondition: Convert Coin to ERC20 + coins := sdk.NewCoins(sdk.NewCoin(cosmosTokenBase, sdk.NewInt(tc.mint))) + sender := sdk.AccAddress(suite.address.Bytes()) + suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins) + suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, sender, coins) + msg := types.NewMsgConvertCoin( + sdk.NewCoin(cosmosTokenBase, sdk.NewInt(tc.burn)), + suite.address, + sender, + ) + + ctx := sdk.WrapSDKContext(suite.ctx) + _, err := suite.app.Erc20Keeper.ConvertCoin(ctx, msg) + suite.Require().NoError(err, tc.name) + suite.Commit() + balance := suite.BalanceOf(common.HexToAddress(pair.Erc20Address), suite.address) + cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, metadata.Base) + suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn).Int64()) + suite.Require().Equal(balance, big.NewInt(tc.burn)) + + // Convert ERC20s back to Coins + ctx = sdk.WrapSDKContext(suite.ctx) + contractAddr := common.HexToAddress(pair.Erc20Address) + msgConvertERC20 := types.NewMsgConvertERC20( + sdk.NewInt(tc.reconvert), + sender, + contractAddr, + suite.address, + ) + + tc.malleate() + res, err := suite.app.Erc20Keeper.ConvertERC20(ctx, msgConvertERC20) + expRes := &types.MsgConvertERC20Response{} + suite.Commit() + balance = suite.BalanceOf(contractAddr, suite.address) + cosmosBalance = suite.app.BankKeeper.GetBalance(suite.ctx, sender, pair.Denom) + if tc.expPass { + suite.Require().NoError(err, tc.name) + suite.Require().Equal(expRes, res) + suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn+tc.reconvert).Int64()) + suite.Require().Equal(balance.(*big.Int).Int64(), big.NewInt(tc.burn-tc.reconvert).Int64()) + } else { + suite.Require().Error(err, tc.name) + } + }) + } + suite.mintFeeCollector = false +} + +func (suite *KeeperTestSuite) TestConvertERC20NativeERC20() { + var contractAddr common.Address + var coinName string + + testCases := []struct { + name string + mint int64 + transfer int64 + malleate func(common.Address) + extra func() + contractType int + expPass bool + selfdestructed bool + }{ + { + "ok - sufficient funds", + 100, + 10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + true, + false, + }, + { + "ok - equal funds", + 10, + 10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + true, + false, + }, + { + "ok - equal funds", + 10, + 10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + true, + false, + }, + { + "ok - suicided contract", + 10, + 10, + func(erc20 common.Address) { + stateDb := suite.StateDB() + ok := stateDb.Suicide(erc20) + suite.Require().True(ok) + suite.Require().NoError(stateDb.Commit()) + }, + func() {}, + contractMinterBurner, + true, + true, + }, + { + "fail - insufficient funds - callEVM", + 0, + 10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + false, + false, + }, + { + "fail - minting disabled", + 100, + 10, + func(common.Address) { + params := types.DefaultParams() + params.EnableErc20 = false + suite.app.Erc20Keeper.SetParams(suite.ctx, params) + }, + func() {}, + contractMinterBurner, + false, + false, + }, + { + "fail - direct balance manipulation contract", + 100, + 10, + func(common.Address) {}, + func() {}, + contractDirectBalanceManipulation, + false, + false, + }, + { + "fail - delayed malicious contract", + 10, + 10, + func(common.Address) {}, + func() {}, + contractMaliciousDelayed, + false, + false, + }, + { + "fail - negative transfer contract", + 10, + -10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + false, + false, + }, + { + "fail - no module address", + 100, + 10, + func(common.Address) { + }, + func() { + acc := suite.app.AccountKeeper.GetAccount(suite.ctx, types.ModuleAddress.Bytes()) + suite.app.AccountKeeper.RemoveAccount(suite.ctx, acc) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force evm fail", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force get balance fail", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + balance[31] = uint8(1) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Twice() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced balance error")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force transfer unpack fail", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + contractMinterBurner, + false, + false, + }, + + { + "fail - force invalid transfer fail", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force mint fail", + 100, + 10, + func(common.Address) {}, + func() { + mockBankKeeper := &MockBankKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, mockBankKeeper, suite.app.EvmKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + mockBankKeeper.On("MintCoins", mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("failed to mint")) + mockBankKeeper.On("SendCoinsFromModuleToAccount", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("failed to unescrow")) + mockBankKeeper.On("BlockedAddr", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(false) + mockBankKeeper.On("GetBalance", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Coin{Denom: "coin", Amount: sdk.OneInt()}) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force send minted fail", + 100, + 10, + func(common.Address) {}, + func() { + mockBankKeeper := &MockBankKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, mockBankKeeper, suite.app.EvmKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + mockBankKeeper.On("MintCoins", mock.Anything, mock.Anything, mock.Anything).Return(nil) + mockBankKeeper.On("SendCoinsFromModuleToAccount", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("failed to unescrow")) + mockBankKeeper.On("BlockedAddr", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(false) + mockBankKeeper.On("GetBalance", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Coin{Denom: "coin", Amount: sdk.OneInt()}) + }, + contractMinterBurner, + false, + false, + }, + { + "fail - force bank balance fail", + 100, + 10, + func(common.Address) {}, + func() { + mockBankKeeper := &MockBankKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, mockBankKeeper, suite.app.EvmKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + mockBankKeeper.On("MintCoins", mock.Anything, mock.Anything, mock.Anything).Return(nil) + mockBankKeeper.On("SendCoinsFromModuleToAccount", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + mockBankKeeper.On("BlockedAddr", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(false) + mockBankKeeper.On("GetBalance", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Coin{Denom: coinName, Amount: sdk.NewInt(int64(10))}) + }, + contractMinterBurner, + false, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + + contractAddr = suite.setupRegisterERC20Pair(tc.contractType) + + tc.malleate(contractAddr) + suite.Require().NotNil(contractAddr) + suite.Commit() + + coinName = types.CreateDenom(contractAddr.String()) + sender := sdk.AccAddress(suite.address.Bytes()) + msg := types.NewMsgConvertERC20( + sdk.NewInt(tc.transfer), + sender, + contractAddr, + suite.address, + ) + + suite.MintERC20Token(contractAddr, suite.address, suite.address, big.NewInt(tc.mint)) + suite.Commit() + ctx := sdk.WrapSDKContext(suite.ctx) + + tc.extra() + res, err := suite.app.Erc20Keeper.ConvertERC20(ctx, msg) + + expRes := &types.MsgConvertERC20Response{} + suite.Commit() + balance := suite.BalanceOf(contractAddr, suite.address) + cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, coinName) + if tc.expPass { + suite.Require().NoError(err, tc.name) + + acc := suite.app.EvmKeeper.GetAccountWithoutBalance(suite.ctx, contractAddr) + if tc.selfdestructed { + suite.Require().Nil(acc, "expected contract to be destroyed") + } else { + suite.Require().NotNil(acc) + } + + if tc.selfdestructed || !acc.IsContract() { + id := suite.app.Erc20Keeper.GetTokenPairID(suite.ctx, contractAddr.String()) + _, found := suite.app.Erc20Keeper.GetTokenPair(suite.ctx, id) + suite.Require().False(found) + } else { + suite.Require().Equal(expRes, res) + suite.Require().Equal(cosmosBalance.Amount, sdk.NewInt(tc.transfer)) + suite.Require().Equal(balance.(*big.Int).Int64(), big.NewInt(tc.mint-tc.transfer).Int64()) + } + } else { + suite.Require().Error(err, tc.name) + } + }) + } + suite.mintFeeCollector = false +} + +func (suite *KeeperTestSuite) TestConvertCoinNativeERC20() { + var contractAddr common.Address + + testCases := []struct { + name string + mint int64 + convert int64 + malleate func(common.Address) + extra func() + contractType int + expPass bool + }{ + { + "ok - sufficient funds", + 100, + 10, + func(common.Address) {}, + func() {}, + contractMinterBurner, + true, + }, + { + "ok - equal funds", + 100, + 100, + func(common.Address) {}, + func() {}, + contractMinterBurner, + true, + }, + { + "fail - insufficient funds", + 100, + 200, + func(common.Address) {}, + func() {}, + contractMinterBurner, + false, + }, + { + "fail - direct balance manipulation contract", + 100, + 10, + func(common.Address) {}, + func() {}, + contractDirectBalanceManipulation, + false, + }, + { + "fail - malicious delayed contract", + 100, + 10, + func(common.Address) {}, + func() {}, + contractMaliciousDelayed, + false, + }, + { + "fail - deleted module address - force fail", + 100, + 10, + func(common.Address) {}, + func() { + acc := suite.app.AccountKeeper.GetAccount(suite.ctx, types.ModuleAddress.Bytes()) + suite.app.AccountKeeper.RemoveAccount(suite.ctx, acc) + }, + contractMinterBurner, + false, + }, + { + "fail - force evm fail", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + contractMinterBurner, + false, + }, + { + "fail - force invalid transfer", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + contractMinterBurner, + false, + }, + { + "fail - force fail second balance", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + balance[31] = uint8(1) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Twice() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("fail second balance")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + contractMinterBurner, + false, + }, + { + "fail - force fail transfer", + 100, + 10, + func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + contractMinterBurner, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + contractAddr = suite.setupRegisterERC20Pair(tc.contractType) + suite.Require().NotNil(contractAddr) + + id := suite.app.Erc20Keeper.GetTokenPairID(suite.ctx, contractAddr.String()) + pair, _ := suite.app.Erc20Keeper.GetTokenPair(suite.ctx, id) + coins := sdk.NewCoins(sdk.NewCoin(pair.Denom, sdk.NewInt(tc.mint))) + coinName := types.CreateDenom(contractAddr.String()) + sender := sdk.AccAddress(suite.address.Bytes()) + + // Precondition: Mint Coins to convert on sender account + suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins) + suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, sender, coins) + cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, coinName) + suite.Require().Equal(sdk.NewInt(tc.mint), cosmosBalance.Amount) + + // Precondition: Mint escrow tokens on module account + suite.GrantERC20Token(contractAddr, suite.address, types.ModuleAddress, "MINTER_ROLE") + suite.MintERC20Token(contractAddr, types.ModuleAddress, types.ModuleAddress, big.NewInt(tc.mint)) + tokenBalance := suite.BalanceOf(contractAddr, types.ModuleAddress) + suite.Require().Equal(big.NewInt(tc.mint), tokenBalance) + + tc.malleate(contractAddr) + suite.Commit() + + // Convert Coins back to ERC20s + receiver := suite.address + ctx := sdk.WrapSDKContext(suite.ctx) + msg := types.NewMsgConvertCoin( + sdk.NewCoin(coinName, sdk.NewInt(tc.convert)), + receiver, + sender, + ) + + tc.extra() + res, err := suite.app.Erc20Keeper.ConvertCoin(ctx, msg) + + expRes := &types.MsgConvertCoinResponse{} + suite.Commit() + tokenBalance = suite.BalanceOf(contractAddr, suite.address) + cosmosBalance = suite.app.BankKeeper.GetBalance(suite.ctx, sender, coinName) + if tc.expPass { + suite.Require().NoError(err, tc.name) + suite.Require().Equal(expRes, res) + suite.Require().Equal(sdk.NewInt(tc.mint-tc.convert), cosmosBalance.Amount) + suite.Require().Equal(big.NewInt(tc.convert), tokenBalance.(*big.Int)) + } else { + suite.Require().Error(err, tc.name) + } + }) + } + suite.mintFeeCollector = false +} + +func (suite *KeeperTestSuite) TestWrongPairOwnerERC20NativeCoin() { + testCases := []struct { + name string + mint int64 + burn int64 + reconvert int64 + expPass bool + }{ + {"ok - sufficient funds", 100, 10, 5, true}, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + metadata, pair := suite.setupRegisterCoin() + suite.Require().NotNil(metadata) + suite.Require().NotNil(pair) + + // Precondition: Convert Coin to ERC20 + coins := sdk.NewCoins(sdk.NewCoin(cosmosTokenBase, sdk.NewInt(tc.mint))) + sender := sdk.AccAddress(suite.address.Bytes()) + suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins) + suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, sender, coins) + msg := types.NewMsgConvertCoin( + sdk.NewCoin(cosmosTokenBase, sdk.NewInt(tc.burn)), + suite.address, + sender, + ) + + pair.ContractOwner = types.OWNER_UNSPECIFIED + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, *pair) + + ctx := sdk.WrapSDKContext(suite.ctx) + _, err := suite.app.Erc20Keeper.ConvertCoin(ctx, msg) + suite.Require().Error(err, tc.name) + + // Convert ERC20s back to Coins + ctx = sdk.WrapSDKContext(suite.ctx) + contractAddr := common.HexToAddress(pair.Erc20Address) + msgConvertERC20 := types.NewMsgConvertERC20( + sdk.NewInt(tc.reconvert), + sender, + contractAddr, + suite.address, + ) + + _, err = suite.app.Erc20Keeper.ConvertERC20(ctx, msgConvertERC20) + suite.Require().Error(err, tc.name) + }) + } +} + +func (suite *KeeperTestSuite) TestConvertCoinNativeIBCVoucher() { + testCases := []struct { + name string + mint int64 + burn int64 + malleate func(common.Address) + extra func() + expPass bool + selfdestructed bool + }{ + { + "ok - sufficient funds", + 100, + 10, + func(common.Address) {}, + func() {}, + true, + false, + }, + { + "ok - equal funds", + 10, + 10, + func(common.Address) {}, + func() {}, + true, + false, + }, + { + "ok - suicided contract", + 10, + 10, + func(erc20 common.Address) { + stateDb := suite.StateDB() + ok := stateDb.Suicide(erc20) + suite.Require().True(ok) + suite.Require().NoError(stateDb.Commit()) + }, + func() {}, + true, + true, + }, + { + "fail - insufficient funds", + 0, + 10, + func(common.Address) {}, + func() {}, + false, + false, + }, + { + "fail - minting disabled", + 100, + 10, + func(common.Address) { + params := types.DefaultParams() + params.EnableErc20 = false + suite.app.Erc20Keeper.SetParams(suite.ctx, params) + }, + func() {}, + false, + false, + }, + { + "fail - deleted module account - force fail", 100, 10, func(common.Address) {}, + func() { + acc := suite.app.AccountKeeper.GetAccount(suite.ctx, types.ModuleAddress.Bytes()) + suite.app.AccountKeeper.RemoveAccount(suite.ctx, acc) + }, false, false, + }, + { + "fail - force evm fail", 100, 10, func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, false, false, + }, + { + "fail - force evm balance error", 100, 10, func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + // first balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + // convert coin + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil).Once() + // second balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, fmt.Errorf("third")).Once() + // Extra call on test + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, false, false, + }, + { + "fail - force balance error", 100, 10, func(common.Address) {}, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Times(4) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, false, false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + metadata, pair := suite.setupRegisterIBCVoucher() + suite.Require().NotNil(metadata) + erc20 := pair.GetERC20Contract() + tc.malleate(erc20) + suite.Commit() + + ctx := sdk.WrapSDKContext(suite.ctx) + coins := sdk.NewCoins(sdk.NewCoin(ibcBase, sdk.NewInt(tc.mint))) + sender := sdk.AccAddress(suite.address.Bytes()) + msg := types.NewMsgConvertCoin( + sdk.NewCoin(ibcBase, sdk.NewInt(tc.burn)), + suite.address, + sender, + ) + + suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins) + suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, sender, coins) + + tc.extra() + res, err := suite.app.Erc20Keeper.ConvertCoin(ctx, msg) + expRes := &types.MsgConvertCoinResponse{} + suite.Commit() + balance := suite.BalanceOf(common.HexToAddress(pair.Erc20Address), suite.address) + cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, metadata.Base) + + if tc.expPass { + suite.Require().NoError(err, tc.name) + + acc := suite.app.EvmKeeper.GetAccountWithoutBalance(suite.ctx, erc20) + if tc.selfdestructed { + suite.Require().Nil(acc, "expected contract to be destroyed") + } else { + suite.Require().NotNil(acc) + } + + if tc.selfdestructed || !acc.IsContract() { + id := suite.app.Erc20Keeper.GetTokenPairID(suite.ctx, erc20.String()) + _, found := suite.app.Erc20Keeper.GetTokenPair(suite.ctx, id) + suite.Require().False(found) + } else { + suite.Require().Equal(expRes, res) + suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn).Int64()) + suite.Require().Equal(balance.(*big.Int).Int64(), big.NewInt(tc.burn).Int64()) + } + } else { + suite.Require().Error(err, tc.name) + } + }) + } + suite.mintFeeCollector = false +} + +func (suite *KeeperTestSuite) TestConvertERC20NativeIBCVoucher() { + testCases := []struct { + name string + mint int64 + burn int64 + reconvert int64 + malleate func() + expPass bool + }{ + {"ok - sufficient funds", 100, 10, 5, func() {}, true}, + {"ok - equal funds", 10, 10, 10, func() {}, true}, + {"fail - insufficient funds", 10, 1, 5, func() {}, false}, + {"fail ", 10, 1, -5, func() {}, false}, + { + "fail - deleted module account - force fail", 100, 10, 5, + func() { + acc := suite.app.AccountKeeper.GetAccount(suite.ctx, types.ModuleAddress.Bytes()) + suite.app.AccountKeeper.RemoveAccount(suite.ctx, acc) + }, + false, + }, + { + "fail - force evm fail", 100, 10, 5, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + false, + }, + { + "fail - force fail second balance", 100, 10, 5, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + // first balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + // convert coin + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil).Once() + // second balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, fmt.Errorf("third")).Once() + // Extra call on test + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + false, + }, + { + "fail - force fail second balance", 100, 10, 5, + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + existingAcc := &statedb.Account{Nonce: uint64(1), Balance: common.Big1} + balance := make([]uint8, 32) + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + // first balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + // convert coin + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil).Once() + // second balance of + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{Ret: balance}, nil).Once() + // Extra call on test + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&evmtypes.MsgEthereumTxResponse{}, nil) + mockEVMKeeper.On("GetAccountWithoutBalance", mock.Anything, mock.Anything).Return(existingAcc, nil) + }, + false, + }, + { + "fail - force fail unescrow", 100, 10, 5, + func() { + mockBankKeeper := &MockBankKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, mockBankKeeper, suite.app.EvmKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + mockBankKeeper.On("SendCoinsFromModuleToAccount", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fmt.Errorf("failed to unescrow")) + mockBankKeeper.On("BlockedAddr", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(false) + mockBankKeeper.On("GetBalance", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Coin{Denom: "coin", Amount: sdk.OneInt()}) + }, + false, + }, + { + "fail - force fail balance after transfer", 100, 10, 5, + func() { + mockBankKeeper := &MockBankKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, mockBankKeeper, suite.app.EvmKeeper) + suite.app.Erc20Keeper = &erc20Keeper + + mockBankKeeper.On("SendCoinsFromModuleToAccount", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + mockBankKeeper.On("BlockedAddr", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(false) + mockBankKeeper.On("GetBalance", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sdk.Coin{Denom: ibcBase, Amount: sdk.OneInt()}) + }, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.mintFeeCollector = true + suite.SetupTest() + metadata, pair := suite.setupRegisterIBCVoucher() + suite.Require().NotNil(metadata) + suite.Require().NotNil(pair) + + // Precondition: Convert Coin to ERC20 + coins := sdk.NewCoins(sdk.NewCoin(ibcBase, sdk.NewInt(tc.mint))) + sender := sdk.AccAddress(suite.address.Bytes()) + suite.app.BankKeeper.MintCoins(suite.ctx, types.ModuleName, coins) + suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, types.ModuleName, sender, coins) + msg := types.NewMsgConvertCoin( + sdk.NewCoin(ibcBase, sdk.NewInt(tc.burn)), + suite.address, + sender, + ) + + ctx := sdk.WrapSDKContext(suite.ctx) + _, err := suite.app.Erc20Keeper.ConvertCoin(ctx, msg) + suite.Require().NoError(err, tc.name) + suite.Commit() + balance := suite.BalanceOf(common.HexToAddress(pair.Erc20Address), suite.address) + cosmosBalance := suite.app.BankKeeper.GetBalance(suite.ctx, sender, metadata.Base) + suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn).Int64()) + suite.Require().Equal(balance, big.NewInt(tc.burn)) + + // Convert ERC20s back to Coins + ctx = sdk.WrapSDKContext(suite.ctx) + contractAddr := common.HexToAddress(pair.Erc20Address) + msgConvertERC20 := types.NewMsgConvertERC20( + sdk.NewInt(tc.reconvert), + sender, + contractAddr, + suite.address, + ) + + tc.malleate() + res, err := suite.app.Erc20Keeper.ConvertERC20(ctx, msgConvertERC20) + expRes := &types.MsgConvertERC20Response{} + suite.Commit() + balance = suite.BalanceOf(contractAddr, suite.address) + cosmosBalance = suite.app.BankKeeper.GetBalance(suite.ctx, sender, pair.Denom) + if tc.expPass { + suite.Require().NoError(err, tc.name) + suite.Require().Equal(expRes, res) + suite.Require().Equal(cosmosBalance.Amount.Int64(), sdk.NewInt(tc.mint-tc.burn+tc.reconvert).Int64()) + suite.Require().Equal(balance.(*big.Int).Int64(), big.NewInt(tc.burn-tc.reconvert).Int64()) + } else { + suite.Require().Error(err, tc.name) + } + }) + } + suite.mintFeeCollector = false +} diff --git a/x/erc20/keeper/params.go b/x/erc20/keeper/params.go new file mode 100644 index 00000000..ff5c294e --- /dev/null +++ b/x/erc20/keeper/params.go @@ -0,0 +1,18 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// GetParams returns the total set of erc20 parameters. +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramstore.GetParamSet(ctx, ¶ms) + return params +} + +// SetParams sets the erc20 parameters to the param space. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramstore.SetParamSet(ctx, ¶ms) +} diff --git a/x/erc20/keeper/params_test.go b/x/erc20/keeper/params_test.go new file mode 100644 index 00000000..aee894c1 --- /dev/null +++ b/x/erc20/keeper/params_test.go @@ -0,0 +1,12 @@ +package keeper_test + +import "github.com/AltheaFoundation/althea-L1/x/erc20/types" + +func (suite *KeeperTestSuite) TestParams() { + params := suite.app.Erc20Keeper.GetParams(suite.ctx) + suite.Require().Equal(types.DefaultParams(), params) + params.EnableErc20 = false + suite.app.Erc20Keeper.SetParams(suite.ctx, params) + newParams := suite.app.Erc20Keeper.GetParams(suite.ctx) + suite.Require().Equal(newParams, params) +} diff --git a/x/erc20/keeper/proposals.go b/x/erc20/keeper/proposals.go new file mode 100644 index 00000000..dbbee327 --- /dev/null +++ b/x/erc20/keeper/proposals.go @@ -0,0 +1,216 @@ +package keeper + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/common" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// RegisterCoin deploys an erc20 contract and creates the token pair for the +// existing cosmos coin +func (k Keeper) RegisterCoin( + ctx sdk.Context, + coinMetadata banktypes.Metadata, +) (*types.TokenPair, error) { + // Check if the conversion is globally enabled + params := k.GetParams(ctx) + if !params.EnableErc20 { + return nil, sdkerrors.Wrap( + types.ErrERC20Disabled, "registration is currently disabled by governance", + ) + } + + // Prohibit denominations that contain the evm denom + if strings.Contains(coinMetadata.Base, "CANTO") { + return nil, sdkerrors.Wrapf( + types.ErrEVMDenom, "cannot register the EVM denomination %s", coinMetadata.Base, + ) + } + + // Check if denomination is already registered + if k.IsDenomRegistered(ctx, coinMetadata.Name) { + return nil, sdkerrors.Wrapf( + types.ErrTokenPairAlreadyExists, "coin denomination already registered: %s", coinMetadata.Name, + ) + } + + // Check if the coin exists by ensuring the supply is set + if !k.bankKeeper.HasSupply(ctx, coinMetadata.Base) { + return nil, sdkerrors.Wrapf( + sdkerrors.ErrInvalidCoins, "base denomination '%s' cannot have a supply of 0", coinMetadata.Base, + ) + } + + if err := k.verifyMetadata(ctx, coinMetadata); err != nil { + return nil, sdkerrors.Wrapf( + types.ErrInternalTokenPair, "coin metadata is invalid %s", coinMetadata.Name, + ) + } + + addr, err := k.DeployERC20Contract(ctx, coinMetadata) + if err != nil { + return nil, sdkerrors.Wrap( + err, "failed to create wrapped coin denom metadata for ERC20", + ) + } + + pair := types.NewTokenPair(addr, coinMetadata.Base, true, types.OWNER_MODULE) + k.SetTokenPair(ctx, pair) + k.SetDenomMap(ctx, pair.Denom, pair.GetID()) + k.SetERC20Map(ctx, common.HexToAddress(pair.Erc20Address), pair.GetID()) + + return &pair, nil +} + +// RegisterERC20 creates a Cosmos coin and registers the token pair between the +// coin and the ERC20 +func (k Keeper) RegisterERC20( + ctx sdk.Context, + contract common.Address, +) (*types.TokenPair, error) { + // Check if the conversion is globally enabled + params := k.GetParams(ctx) + if !params.EnableErc20 { + return nil, sdkerrors.Wrap( + types.ErrERC20Disabled, "registration is currently disabled by governance", + ) + } + + // Check if ERC20 is already registered + if k.IsERC20Registered(ctx, contract) { + return nil, sdkerrors.Wrapf( + types.ErrTokenPairAlreadyExists, "token ERC20 contract already registered: %s", contract.String(), + ) + } + + metadata, err := k.CreateCoinMetadata(ctx, contract) + if err != nil { + return nil, sdkerrors.Wrap( + err, "failed to create wrapped coin denom metadata for ERC20", + ) + } + + pair := types.NewTokenPair(contract, metadata.Name, true, types.OWNER_EXTERNAL) + k.SetTokenPair(ctx, pair) + k.SetDenomMap(ctx, pair.Denom, pair.GetID()) + k.SetERC20Map(ctx, common.HexToAddress(pair.Erc20Address), pair.GetID()) + return &pair, nil +} + +// CreateCoinMetadata generates the metadata to represent the ERC20 token on +// canto. +func (k Keeper) CreateCoinMetadata( + ctx sdk.Context, + contract common.Address, +) (*banktypes.Metadata, error) { + strContract := contract.String() + + erc20Data, err := k.QueryERC20(ctx, contract) + if err != nil { + return nil, err + } + + // Check if metadata already exists + _, found := k.bankKeeper.GetDenomMetaData(ctx, types.CreateDenom(strContract)) + if found { + return nil, sdkerrors.Wrap( + types.ErrInternalTokenPair, "denom metadata already registered", + ) + } + + if k.IsDenomRegistered(ctx, types.CreateDenom(strContract)) { + return nil, sdkerrors.Wrapf( + types.ErrInternalTokenPair, "coin denomination already registered: %s", erc20Data.Name, + ) + } + + // base denomination + base := types.CreateDenom(strContract) + + // create a bank denom metadata based on the ERC20 token ABI details + // metadata name is should always be the contract since it's the key + // to the bank store + metadata := banktypes.Metadata{ + Description: types.CreateDenomDescription(strContract), + Base: base, + // NOTE: Denom units MUST be increasing + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: base, + Exponent: 0, + }, + }, + Name: types.CreateDenom(strContract), + Symbol: erc20Data.Symbol, + Display: base, + } + + // only append metadata if decimals > 0, otherwise validation fails + if erc20Data.Decimals > 0 { + nameSanitized := types.SanitizeERC20Name(erc20Data.Name) + metadata.DenomUnits = append( + metadata.DenomUnits, + &banktypes.DenomUnit{ + Denom: nameSanitized, + Exponent: uint32(erc20Data.Decimals), + }, + ) + metadata.Display = nameSanitized + } + + if err := metadata.Validate(); err != nil { + return nil, sdkerrors.Wrapf( + err, "ERC20 token data is invalid for contract %s", strContract, + ) + } + + k.bankKeeper.SetDenomMetaData(ctx, metadata) + + return &metadata, nil +} + +// ToggleConversion toggles conversion for a given token pair +func (k Keeper) ToggleConversion( + ctx sdk.Context, + token string, +) (types.TokenPair, error) { + id := k.GetTokenPairID(ctx, token) + if len(id) == 0 { + return types.TokenPair{}, sdkerrors.Wrapf( + types.ErrTokenPairNotFound, "token '%s' not registered by id", token, + ) + } + + pair, found := k.GetTokenPair(ctx, id) + if !found { + return types.TokenPair{}, sdkerrors.Wrapf( + types.ErrTokenPairNotFound, "token '%s' not registered", token, + ) + } + + pair.Enabled = !pair.Enabled + + k.SetTokenPair(ctx, pair) + return pair, nil +} + +// verifyMetadata verifies if the metadata matches the existing one, if not it +// sets it to the store +func (k Keeper) verifyMetadata( + ctx sdk.Context, + coinMetadata banktypes.Metadata, +) error { + meta, found := k.bankKeeper.GetDenomMetaData(ctx, coinMetadata.Base) + if !found { + k.bankKeeper.SetDenomMetaData(ctx, coinMetadata) + return nil + } + + // If it already existed, check that is equal to what is stored + return types.EqualMetadata(meta, coinMetadata) +} diff --git a/x/erc20/keeper/proposals_test.go b/x/erc20/keeper/proposals_test.go new file mode 100644 index 00000000..7910fe8c --- /dev/null +++ b/x/erc20/keeper/proposals_test.go @@ -0,0 +1,473 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/stretchr/testify/mock" + + "github.com/ethereum/go-ethereum/common" + + "github.com/evmos/ethermint/tests" + evmtypes "github.com/evmos/ethermint/x/evm/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/keeper" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +const ( + contractMinterBurner = iota + 1 + contractDirectBalanceManipulation + contractMaliciousDelayed +) + +const ( + erc20Name = "Coin Token" + erc20Symbol = "CTKN" + erc20Decimals = uint8(18) + cosmosTokenBase = "acoin" + cosmosTokenDisplay = "coin" + cosmosDecimals = uint8(6) + defaultExponent = uint32(18) + zeroExponent = uint32(0) + ibcBase = "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2" +) + +func (suite *KeeperTestSuite) setupRegisterERC20Pair(contractType int) common.Address { + var contract common.Address + // Deploy contract + switch contractType { + case contractDirectBalanceManipulation: + contract = suite.DeployContractDirectBalanceManipulation(erc20Name, erc20Symbol) + case contractMaliciousDelayed: + contract = suite.DeployContractMaliciousDelayed(erc20Name, erc20Symbol) + default: + contract, _ = suite.DeployContract(erc20Name, erc20Symbol, erc20Decimals) + } + suite.Commit() + + _, err := suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contract) + suite.Require().NoError(err) + return contract +} + +func (suite *KeeperTestSuite) setupRegisterCoin() (banktypes.Metadata, *types.TokenPair) { + validMetadata := banktypes.Metadata{ + Description: "description of the token", + Base: cosmosTokenBase, + // NOTE: Denom units MUST be increasing + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: cosmosTokenBase, + Exponent: 0, + }, + { + Denom: cosmosTokenBase[1:], + Exponent: uint32(18), + }, + }, + Name: cosmosTokenBase, + Symbol: erc20Symbol, + Display: cosmosTokenBase, + } + + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(validMetadata.Base, 1)}) + suite.Require().NoError(err) + + // pair := types.NewTokenPair(contractAddr, cosmosTokenBase, true, types.OWNER_MODULE) + pair, err := suite.app.Erc20Keeper.RegisterCoin(suite.ctx, validMetadata) + suite.Require().NoError(err) + suite.Commit() + return validMetadata, pair +} + +func (suite *KeeperTestSuite) setupRegisterIBCVoucher() (banktypes.Metadata, *types.TokenPair) { + suite.SetupTest() + + validMetadata := banktypes.Metadata{ + Description: "ATOM IBC voucher (channel 14)", + Base: ibcBase, + // NOTE: Denom units MUST be increasing + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: ibcBase, + Exponent: 0, + }, + }, + Name: "ATOM channel-14", + Symbol: "ibcATOM-14", + Display: ibcBase, + } + + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(validMetadata.Base, 1)}) + suite.Require().NoError(err) + + // pair := types.NewTokenPair(contractAddr, cosmosTokenBase, true, types.OWNER_MODULE) + pair, err := suite.app.Erc20Keeper.RegisterCoin(suite.ctx, validMetadata) + suite.Require().NoError(err) + suite.Commit() + return validMetadata, pair +} + +func (suite KeeperTestSuite) TestRegisterCoin() { + metadata := banktypes.Metadata{ + Description: "description", + Base: cosmosTokenBase, + // NOTE: Denom units MUST be increasing + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: cosmosTokenBase, + Exponent: 0, + }, + { + Denom: cosmosTokenDisplay, + Exponent: defaultExponent, + }, + }, + Name: cosmosTokenBase, + Symbol: erc20Symbol, + Display: cosmosTokenDisplay, + } + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "conversion is disabled globally", + func() { + params := types.DefaultParams() + params.EnableErc20 = false + suite.app.Erc20Keeper.SetParams(suite.ctx, params) + }, + false, + }, + { + "denom already registered", + func() { + regPair := types.NewTokenPair(tests.GenerateAddress(), metadata.Base, true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, regPair.Denom, regPair.GetID()) + suite.Commit() + }, + false, + }, + { + "token doesn't have supply", + func() { + }, + false, + }, + { + "metadata different that stored", + func() { + metadata.Base = cosmosTokenBase + validMetadata := banktypes.Metadata{ + Description: "description", + Base: cosmosTokenBase, + // NOTE: Denom units MUST be increasing + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: cosmosTokenBase, + Exponent: 0, + }, + { + Denom: cosmosTokenDisplay, + Exponent: uint32(18), + }, + }, + Name: erc20Name, + Symbol: erc20Symbol, + Display: cosmosTokenDisplay, + } + + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(validMetadata.Base, 1)}) + suite.Require().NoError(err) + suite.app.BankKeeper.SetDenomMetaData(suite.ctx, validMetadata) + }, + false, + }, + { + "evm denom registration - CANTO", + func() { + metadata.Base = "CANTO" + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(metadata.Base, 1)}) + suite.Require().NoError(err) + }, + false, + }, + { + "evm denom registration - CANTO", + func() { + metadata.Base = "CANTO" + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(metadata.Base, 1)}) + suite.Require().NoError(err) + }, + false, + }, + { + "evm denom registration - aCANTO", + func() { + metadata.Base = "aCANTO" + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(metadata.Base, 1)}) + suite.Require().NoError(err) + }, + false, + }, + { + "evm denom registration - wCANTO", + func() { + metadata.Base = "wCANTO" + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(metadata.Base, 1)}) + suite.Require().NoError(err) + }, + false, + }, + { + "ok", + func() { + metadata.Base = cosmosTokenBase + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(metadata.Base, 1)}) + suite.Require().NoError(err) + }, + true, + }, + { + "force fail evm", + func() { + metadata.Base = cosmosTokenBase + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(metadata.Base, 1)}) + suite.Require().NoError(err) + + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + }, + false, + }, + { + "force delete module account evm", + func() { + metadata.Base = cosmosTokenBase + err := suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, sdk.Coins{sdk.NewInt64Coin(metadata.Base, 1)}) + suite.Require().NoError(err) + + acc := suite.app.AccountKeeper.GetAccount(suite.ctx, types.ModuleAddress.Bytes()) + suite.app.AccountKeeper.RemoveAccount(suite.ctx, acc) + }, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + tc.malleate() + + pair, err := suite.app.Erc20Keeper.RegisterCoin(suite.ctx, metadata) + suite.Commit() + + expPair := &types.TokenPair{ + Erc20Address: "0x80b5a32E4F032B2a058b4F29EC95EEfEEB87aDcd", + Denom: "acoin", + Enabled: true, + ContractOwner: 1, + } + + if tc.expPass { + suite.Require().NoError(err, tc.name) + suite.Require().Equal(pair, expPair) + } else { + suite.Require().Error(err, tc.name) + } + }) + } +} + +func (suite KeeperTestSuite) TestRegisterERC20() { + var ( + contractAddr common.Address + pair types.TokenPair + ) + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "conversion is disabled globally", + func() { + params := types.DefaultParams() + params.EnableErc20 = false + suite.app.Erc20Keeper.SetParams(suite.ctx, params) + }, + false, + }, + { + "token ERC20 already registered", + func() { + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, pair.GetERC20Contract(), pair.GetID()) + }, + false, + }, + { + "denom already registered", + func() { + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, pair.GetID()) + }, + false, + }, + { + "meta data already stored", + func() { + suite.app.Erc20Keeper.CreateCoinMetadata(suite.ctx, contractAddr) + }, + false, + }, + { + "ok", + func() {}, + true, + }, + { + "force fail evm", + func() { + mockEVMKeeper := &MockEVMKeeper{} + sp, found := suite.app.ParamsKeeper.GetSubspace(types.ModuleName) + suite.Require().True(found) + erc20Keeper := keeper.NewKeeper(suite.app.GetKey("erc20"), suite.app.AppCodec(), sp, suite.app.AccountKeeper, suite.app.BankKeeper, mockEVMKeeper) + suite.app.Erc20Keeper = &erc20Keeper + mockEVMKeeper.On("EstimateGas", mock.Anything, mock.Anything).Return(&evmtypes.EstimateGasResponse{Gas: uint64(200)}, nil) + mockEVMKeeper.On("ApplyMessage", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("forced ApplyMessage error")) + }, + false, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + var err error + contractAddr, err = suite.DeployContract(erc20Name, erc20Symbol, cosmosDecimals) + suite.Require().NoError(err) + suite.Commit() + coinName := types.CreateDenom(contractAddr.String()) + pair = types.NewTokenPair(contractAddr, coinName, true, types.OWNER_EXTERNAL) + + tc.malleate() + + _, err = suite.app.Erc20Keeper.RegisterERC20(suite.ctx, contractAddr) + metadata, found := suite.app.BankKeeper.GetDenomMetaData(suite.ctx, coinName) + if tc.expPass { + suite.Require().NoError(err, tc.name) + // Metadata variables + suite.Require().True(found) + suite.Require().Equal(coinName, metadata.Base) + suite.Require().Equal(coinName, metadata.Name) + suite.Require().Equal(types.SanitizeERC20Name(erc20Name), metadata.Display) + suite.Require().Equal(erc20Symbol, metadata.Symbol) + // Denom units + suite.Require().Equal(len(metadata.DenomUnits), 2) + suite.Require().Equal(coinName, metadata.DenomUnits[0].Denom) + suite.Require().Equal(uint32(zeroExponent), metadata.DenomUnits[0].Exponent) + suite.Require().Equal(types.SanitizeERC20Name(erc20Name), metadata.DenomUnits[1].Denom) + // Custom exponent at contract creation matches coin with token + suite.Require().Equal(metadata.DenomUnits[1].Exponent, uint32(cosmosDecimals)) + } else { + suite.Require().Error(err, tc.name) + } + }) + } +} + +func (suite *KeeperTestSuite) TestRegisterIBCVoucher() { + suite.setupRegisterIBCVoucher() +} + +func (suite KeeperTestSuite) TestToggleConverision() { + var ( + contractAddr common.Address + id []byte + pair types.TokenPair + ) + + testCases := []struct { + name string + malleate func() + expPass bool + conversionEnabled bool + }{ + { + "token not registered", + func() { + contractAddr, err := suite.DeployContract(erc20Name, erc20Symbol, erc20Decimals) + suite.Require().NoError(err) + suite.Commit() + pair = types.NewTokenPair(contractAddr, cosmosTokenBase, true, types.OWNER_MODULE) + }, + false, + false, + }, + { + "token not registered - pair not found", + func() { + contractAddr, err := suite.DeployContract(erc20Name, erc20Symbol, erc20Decimals) + suite.Require().NoError(err) + suite.Commit() + pair = types.NewTokenPair(contractAddr, cosmosTokenBase, true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, common.HexToAddress(pair.Erc20Address), pair.GetID()) + }, + false, + false, + }, + { + "disable conversion", + func() { + contractAddr = suite.setupRegisterERC20Pair(contractMinterBurner) + id = suite.app.Erc20Keeper.GetTokenPairID(suite.ctx, contractAddr.String()) + pair, _ = suite.app.Erc20Keeper.GetTokenPair(suite.ctx, id) + }, + true, + false, + }, + { + "disable and enable conversion", + func() { + contractAddr = suite.setupRegisterERC20Pair(contractMinterBurner) + id = suite.app.Erc20Keeper.GetTokenPairID(suite.ctx, contractAddr.String()) + pair, _ = suite.app.Erc20Keeper.GetTokenPair(suite.ctx, id) + pair, _ = suite.app.Erc20Keeper.ToggleConversion(suite.ctx, contractAddr.String()) + }, + true, + true, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + tc.malleate() + + var err error + pair, err = suite.app.Erc20Keeper.ToggleConversion(suite.ctx, contractAddr.String()) + // Request the pair using the GetPairToken func to make sure that is updated on the db + pair, _ = suite.app.Erc20Keeper.GetTokenPair(suite.ctx, id) + if tc.expPass { + suite.Require().NoError(err, tc.name) + if tc.conversionEnabled { + suite.Require().True(pair.Enabled) + } else { + suite.Require().False(pair.Enabled) + } + } else { + suite.Require().Error(err, tc.name) + } + }) + } +} diff --git a/x/erc20/keeper/token_pairs.go b/x/erc20/keeper/token_pairs.go new file mode 100644 index 00000000..702ca05a --- /dev/null +++ b/x/erc20/keeper/token_pairs.go @@ -0,0 +1,129 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// GetTokenPairs - get all registered token tokenPairs +func (k Keeper) GetTokenPairs(ctx sdk.Context) []types.TokenPair { + tokenPairs := []types.TokenPair{} + + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, types.KeyPrefixTokenPair) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var tokenPair types.TokenPair + k.cdc.MustUnmarshal(iterator.Value(), &tokenPair) + + tokenPairs = append(tokenPairs, tokenPair) + } + + return tokenPairs +} + +// GetTokenPairID returns the pair id from either of the registered tokens. +func (k Keeper) GetTokenPairID(ctx sdk.Context, token string) []byte { + if common.IsHexAddress(token) { + addr := common.HexToAddress(token) + return k.GetERC20Map(ctx, addr) + } + return k.GetDenomMap(ctx, token) +} + +// GetTokenPair - get registered token pair from the identifier +func (k Keeper) GetTokenPair(ctx sdk.Context, id []byte) (types.TokenPair, bool) { + if id == nil { + return types.TokenPair{}, false + } + + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPair) + var tokenPair types.TokenPair + bz := store.Get(id) + if len(bz) == 0 { + return types.TokenPair{}, false + } + + k.cdc.MustUnmarshal(bz, &tokenPair) + return tokenPair, true +} + +// SetTokenPair stores a token pair +func (k Keeper) SetTokenPair(ctx sdk.Context, tokenPair types.TokenPair) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPair) + key := tokenPair.GetID() + bz := k.cdc.MustMarshal(&tokenPair) + store.Set(key, bz) +} + +// DeleteTokenPair removes a token pair. +func (k Keeper) DeleteTokenPair(ctx sdk.Context, tokenPair types.TokenPair) { + id := tokenPair.GetID() + k.deleteTokenPair(ctx, id) + k.deleteERC20Map(ctx, tokenPair.GetERC20Contract()) + k.deleteDenomMap(ctx, tokenPair.Denom) +} + +// deleteTokenPair deletes the token pair for the given id +func (k Keeper) deleteTokenPair(ctx sdk.Context, id []byte) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPair) + store.Delete(id) +} + +// GetERC20Map returns the token pair id for the given address +func (k Keeper) GetERC20Map(ctx sdk.Context, erc20 common.Address) []byte { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPairByERC20) + return store.Get(erc20.Bytes()) +} + +// GetDenomMap returns the token pair id for the given denomination +func (k Keeper) GetDenomMap(ctx sdk.Context, denom string) []byte { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPairByDenom) + return store.Get([]byte(denom)) +} + +// SetERC20Map sets the token pair id for the given address +func (k Keeper) SetERC20Map(ctx sdk.Context, erc20 common.Address, id []byte) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPairByERC20) + store.Set(erc20.Bytes(), id) +} + +// deleteERC20Map deletes the token pair id for the given address +func (k Keeper) deleteERC20Map(ctx sdk.Context, erc20 common.Address) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPairByERC20) + store.Delete(erc20.Bytes()) +} + +// SetDenomMap sets the token pair id for the denomination +func (k Keeper) SetDenomMap(ctx sdk.Context, denom string, id []byte) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPairByDenom) + store.Set([]byte(denom), id) +} + +// deleteDenomMap deletes the token pair id for the given denom +func (k Keeper) deleteDenomMap(ctx sdk.Context, denom string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPairByDenom) + store.Delete([]byte(denom)) +} + +// IsTokenPairRegistered - check if registered token tokenPair is registered +func (k Keeper) IsTokenPairRegistered(ctx sdk.Context, id []byte) bool { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPair) + return store.Has(id) +} + +// IsERC20Registered check if registered ERC20 token is registered +func (k Keeper) IsERC20Registered(ctx sdk.Context, erc20 common.Address) bool { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPairByERC20) + return store.Has(erc20.Bytes()) +} + +// IsDenomRegistered check if registered coin denom is registered +func (k Keeper) IsDenomRegistered(ctx sdk.Context, denom string) bool { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTokenPairByDenom) + return store.Has([]byte(denom)) +} diff --git a/x/erc20/keeper/token_pairs_test.go b/x/erc20/keeper/token_pairs_test.go new file mode 100644 index 00000000..56f44543 --- /dev/null +++ b/x/erc20/keeper/token_pairs_test.go @@ -0,0 +1,234 @@ +package keeper_test + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/evmos/ethermint/tests" + + altheaconfig "github.com/AltheaFoundation/althea-L1/config" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +func (suite *KeeperTestSuite) TestGetTokenPairs() { + var expRes []types.TokenPair + + testCases := []struct { + name string + malleate func() + }{ + { + "no pair registered", func() { expRes = []types.TokenPair{} }, + }, + { + "1 pair registered", + func() { + pair := types.NewTokenPair(tests.GenerateAddress(), "coin", true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + + expRes = []types.TokenPair{pair} + }, + }, + { + "2 pairs registered", + func() { + pair := types.NewTokenPair(tests.GenerateAddress(), "coin", true, types.OWNER_MODULE) + pair2 := types.NewTokenPair(tests.GenerateAddress(), "coin2", true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair2) + + expRes = []types.TokenPair{pair, pair2} + }, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.name), func() { + suite.SetupTest() // reset + + tc.malleate() + res := suite.app.Erc20Keeper.GetTokenPairs(suite.ctx) + + suite.Require().ElementsMatch(expRes, res, tc.name) + }) + } +} + +func (suite *KeeperTestSuite) TestGetTokenPairID() { + pair := types.NewTokenPair(tests.GenerateAddress(), altheaconfig.BaseDenom, true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + + testCases := []struct { + name string + token string + expId []byte + }{ + {"nil token", "", nil}, + {"valid hex token", tests.GenerateAddress().Hex(), []byte{}}, + {"valid hex token", tests.GenerateAddress().String(), []byte{}}, + } + for _, tc := range testCases { + id := suite.app.Erc20Keeper.GetTokenPairID(suite.ctx, tc.token) + if id != nil { + suite.Require().Equal(tc.expId, id, tc.name) + } else { + suite.Require().Nil(id) + } + } +} + +func (suite *KeeperTestSuite) TestGetTokenPair() { + pair := types.NewTokenPair(tests.GenerateAddress(), altheaconfig.BaseDenom, true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + + testCases := []struct { + name string + id []byte + ok bool + }{ + {"nil id", nil, false}, + {"valid id", pair.GetID(), true}, + {"pair not found", []byte{}, false}, + } + for _, tc := range testCases { + p, found := suite.app.Erc20Keeper.GetTokenPair(suite.ctx, tc.id) + if tc.ok { + suite.Require().True(found, tc.name) + suite.Require().Equal(pair, p, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} + +func (suite *KeeperTestSuite) TestDeleteTokenPair() { + pair := types.NewTokenPair(tests.GenerateAddress(), altheaconfig.BaseDenom, true, types.OWNER_MODULE) + id := pair.GetID() + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, pair.GetERC20Contract(), id) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, id) + + testCases := []struct { + name string + id []byte + malleate func() + ok bool + }{ + {"nil id", nil, func() {}, false}, + {"pair not found", []byte{}, func() {}, false}, + {"valid id", id, func() {}, true}, + { + "detete tokenpair", + id, + func() { + suite.app.Erc20Keeper.DeleteTokenPair(suite.ctx, pair) + }, + false, + }, + } + for _, tc := range testCases { + tc.malleate() + p, found := suite.app.Erc20Keeper.GetTokenPair(suite.ctx, tc.id) + if tc.ok { + suite.Require().True(found, tc.name) + suite.Require().Equal(pair, p, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} + +func (suite *KeeperTestSuite) TestIsTokenPairRegistered() { + pair := types.NewTokenPair(tests.GenerateAddress(), altheaconfig.BaseDenom, true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + + testCases := []struct { + name string + id []byte + ok bool + }{ + {"valid id", pair.GetID(), true}, + {"pair not found", []byte{}, false}, + } + for _, tc := range testCases { + found := suite.app.Erc20Keeper.IsTokenPairRegistered(suite.ctx, tc.id) + if tc.ok { + suite.Require().True(found, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} + +func (suite *KeeperTestSuite) TestIsERC20Registered() { + addr := tests.GenerateAddress() + pair := types.NewTokenPair(addr, "coin", true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, addr, pair.GetID()) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, pair.GetID()) + + testCases := []struct { + name string + erc20 common.Address + malleate func() + ok bool + }{ + {"nil erc20 address", common.Address{}, func() {}, false}, + {"valid erc20 address", pair.GetERC20Contract(), func() {}, true}, + { + "deleted erc20 map", + pair.GetERC20Contract(), + func() { + suite.app.Erc20Keeper.DeleteTokenPair(suite.ctx, pair) + }, + false, + }, + } + for _, tc := range testCases { + tc.malleate() + + found := suite.app.Erc20Keeper.IsERC20Registered(suite.ctx, tc.erc20) + + if tc.ok { + suite.Require().True(found, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} + +func (suite *KeeperTestSuite) TestIsDenomRegistered() { + addr := tests.GenerateAddress() + pair := types.NewTokenPair(addr, "coin", true, types.OWNER_MODULE) + suite.app.Erc20Keeper.SetTokenPair(suite.ctx, pair) + suite.app.Erc20Keeper.SetERC20Map(suite.ctx, addr, pair.GetID()) + suite.app.Erc20Keeper.SetDenomMap(suite.ctx, pair.Denom, pair.GetID()) + + testCases := []struct { + name string + denom string + malleate func() + ok bool + }{ + {"empty denom", "", func() {}, false}, + {"valid denom", pair.GetDenom(), func() {}, true}, + { + "deleted denom map", + pair.GetDenom(), + func() { + suite.app.Erc20Keeper.DeleteTokenPair(suite.ctx, pair) + }, + false, + }, + } + for _, tc := range testCases { + tc.malleate() + + found := suite.app.Erc20Keeper.IsDenomRegistered(suite.ctx, tc.denom) + + if tc.ok { + suite.Require().True(found, tc.name) + } else { + suite.Require().False(found, tc.name) + } + } +} diff --git a/x/erc20/migrations/v2/migration.go b/x/erc20/migrations/v2/migration.go new file mode 100644 index 00000000..2d42a4da --- /dev/null +++ b/x/erc20/migrations/v2/migration.go @@ -0,0 +1,21 @@ +package v2 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// UpdateParams updates the module parameters EnableERC20 and EnableEMVHook +// values to true. +func UpdateParams(ctx sdk.Context, paramstore *paramtypes.Subspace) error { + if !paramstore.HasKeyTable() { + ps := paramstore.WithKeyTable(types.ParamKeyTable()) + paramstore = &ps + } + + paramstore.Set(ctx, types.ParamStoreKeyEnableErc20, true) + paramstore.Set(ctx, types.ParamStoreKeyEnableEVMHook, true) + return nil +} diff --git a/x/erc20/migrations/v2/migration_test.go b/x/erc20/migrations/v2/migration_test.go new file mode 100644 index 00000000..3a0b0c86 --- /dev/null +++ b/x/erc20/migrations/v2/migration_test.go @@ -0,0 +1,54 @@ +package v2_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/evmos/ethermint/encoding" + + althea "github.com/AltheaFoundation/althea-L1/app" + v2 "github.com/AltheaFoundation/althea-L1/x/erc20/migrations/v2" + erc20types "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +func TestUpdateParams(t *testing.T) { + encCfg := encoding.MakeConfig(althea.ModuleBasics) + erc20Key := sdk.NewKVStoreKey(erc20types.StoreKey) + tErc20Key := sdk.NewTransientStoreKey(fmt.Sprintf("%s_test", erc20types.StoreKey)) + ctx := testutil.DefaultContext(erc20Key, tErc20Key) + paramstore := paramtypes.NewSubspace( + encCfg.Codec, encCfg.Amino, erc20Key, tErc20Key, "erc20", + ) + paramstore = paramstore.WithKeyTable(erc20types.ParamKeyTable()) + require.True(t, paramstore.HasKeyTable()) + + // check no params + require.False(t, paramstore.Has(ctx, erc20types.ParamStoreKeyEnableErc20)) + require.False(t, paramstore.Has(ctx, erc20types.ParamStoreKeyEnableEVMHook)) + + // Run migrations + err := v2.UpdateParams(ctx, ¶mstore) + require.NoError(t, err) + + // Make sure the params are set + require.True(t, paramstore.Has(ctx, erc20types.ParamStoreKeyEnableErc20)) + require.True(t, paramstore.Has(ctx, erc20types.ParamStoreKeyEnableEVMHook)) + + var enableERC20, enableEVMHook bool + + // Make sure the new params are set + require.NotPanics(t, func() { + paramstore.Get(ctx, erc20types.ParamStoreKeyEnableErc20, &enableERC20) + paramstore.Get(ctx, erc20types.ParamStoreKeyEnableEVMHook, &enableEVMHook) + }) + + // check the params are updated + require.True(t, enableERC20) + require.True(t, enableEVMHook) +} diff --git a/x/erc20/module.go b/x/erc20/module.go new file mode 100644 index 00000000..948158cb --- /dev/null +++ b/x/erc20/module.go @@ -0,0 +1,181 @@ +package erc20 + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/client/cli" + "github.com/AltheaFoundation/althea-L1/x/erc20/keeper" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// type check to ensure the interface is properly implemented +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleSimulation = AppModule{} +) + +// app module Basics object +type AppModuleBasic struct{} + +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec performs a no-op as the erc20 doesn't support Amino encoding +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +// ConsensusVersion returns the consensus state-breaking version for the module. +func (AppModuleBasic) ConsensusVersion() uint64 { + return 2 +} + +// RegisterInterfaces registers interfaces and implementations of the erc20 module. +func (AppModuleBasic) RegisterInterfaces(interfaceRegistry codectypes.InterfaceRegistry) { + types.RegisterInterfaces(interfaceRegistry) +} + +// DefaultGenesis returns default genesis state as raw bytes for the erc20 +// module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesisState()) +} + +func (b AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var genesisState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genesisState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + + return genesisState.Validate() +} + +// RegisterRESTRoutes performs a no-op as the erc20 module doesn't expose REST +// endpoints +func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) {} + +func (b AppModuleBasic) RegisterGRPCGatewayRoutes(c client.Context, serveMux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), serveMux, types.NewQueryClient(c)); err != nil { + panic(err) + } +} + +// GetTxCmd returns the root tx command for the erc20 module. +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.NewTxCmd() +} + +// GetQueryCmd returns no root query command for the erc20 module. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper + ak authkeeper.AccountKeeper +} + +// NewAppModule creates a new AppModule Object +func NewAppModule( + k keeper.Keeper, + ak authkeeper.AccountKeeper, +) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + keeper: k, + ak: ak, + } +} + +func (AppModule) Name() string { + return types.ModuleName +} + +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {} + +func (am AppModule) NewHandler() sdk.Handler { + return NewHandler(am.keeper) +} + +func (am AppModule) Route() sdk.Route { + return sdk.NewRoute(types.RouterKey, am.NewHandler()) +} + +func (am AppModule) QuerierRoute() string { + return types.RouterKey +} + +func (am AppModule) LegacyQuerierHandler(amino *codec.LegacyAmino) sdk.Querier { + return nil +} + +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), am.keeper) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + + migrator := keeper.NewMigrator(am.keeper) + + // NOTE: the migrations below will only run if the consensus version has changed + // since the last release + + // register v1 -> v2 migration + if err := cfg.RegisterMigration(types.ModuleName, 1, migrator.Migrate1to2); err != nil { + panic(fmt.Errorf("failed to migrate %s to v2: %w", types.ModuleName, err)) + } +} + +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) { +} + +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + + cdc.MustUnmarshalJSON(data, &genesisState) + InitGenesis(ctx, am.keeper, am.ak, genesisState) + return []abci.ValidatorUpdate{} +} + +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(gs) +} + +func (am AppModule) GenerateGenesisState(input *module.SimulationState) { +} + +func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { + return []simtypes.WeightedProposalContent{} +} + +func (am AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange { + return []simtypes.ParamChange{} +} + +func (am AppModule) RegisterStoreDecoder(decoderRegistry sdk.StoreDecoderRegistry) { +} + +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + return []simtypes.WeightedOperation{} +} diff --git a/x/erc20/proposal_handler.go b/x/erc20/proposal_handler.go new file mode 100644 index 00000000..1e4b15d9 --- /dev/null +++ b/x/erc20/proposal_handler.go @@ -0,0 +1,77 @@ +package erc20 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/ethereum/go-ethereum/common" + + "github.com/AltheaFoundation/althea-L1/x/erc20/keeper" + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// NewErc20ProposalHandler creates a governance handler to manage new proposal types. +func NewErc20ProposalHandler(k *keeper.Keeper) govv1beta1.Handler { + return func(ctx sdk.Context, content govv1beta1.Content) error { + switch c := content.(type) { + case *types.RegisterCoinProposal: + return handleRegisterCoinProposal(ctx, k, c) + case *types.RegisterERC20Proposal: + return handleRegisterERC20Proposal(ctx, k, c) + case *types.ToggleTokenConversionProposal: + return handleToggleConversionProposal(ctx, k, c) + + default: + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s proposal content type: %T", types.ModuleName, c) + } + } +} + +func handleRegisterCoinProposal(ctx sdk.Context, k *keeper.Keeper, p *types.RegisterCoinProposal) error { + pair, err := k.RegisterCoin(ctx, p.Metadata) + if err != nil { + return err + } + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeRegisterCoin, + sdk.NewAttribute(types.AttributeKeyCosmosCoin, pair.Denom), + sdk.NewAttribute(types.AttributeKeyERC20Token, pair.Erc20Address), + ), + ) + + return nil +} + +func handleRegisterERC20Proposal(ctx sdk.Context, k *keeper.Keeper, p *types.RegisterERC20Proposal) error { + pair, err := k.RegisterERC20(ctx, common.HexToAddress(p.Erc20Address)) + if err != nil { + return err + } + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeRegisterERC20, + sdk.NewAttribute(types.AttributeKeyCosmosCoin, pair.Denom), + sdk.NewAttribute(types.AttributeKeyERC20Token, pair.Erc20Address), + ), + ) + + return nil +} + +func handleToggleConversionProposal(ctx sdk.Context, k *keeper.Keeper, p *types.ToggleTokenConversionProposal) error { + pair, err := k.ToggleConversion(ctx, p.Token) + if err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeToggleTokenConversion, + sdk.NewAttribute(types.AttributeKeyCosmosCoin, pair.Denom), + sdk.NewAttribute(types.AttributeKeyERC20Token, pair.Erc20Address), + ), + ) + + return nil +} diff --git a/x/erc20/types/codec.go b/x/erc20/types/codec.go new file mode 100644 index 00000000..20cec806 --- /dev/null +++ b/x/erc20/types/codec.go @@ -0,0 +1,60 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" +) + +var ( + amino = codec.NewLegacyAmino() + + // ModuleCdc references the global erc20 module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding. + // + // The actual codec used for serialization should be provided to modules/erc20 and + // defined at the application level. + ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + + // AminoCdc is a amino codec created to support amino JSON compatible msgs. + AminoCdc = codec.NewAminoCodec(amino) +) + +const ( + // Amino names + convertERC20Name = "canto/MsgConvertERC20" + convertCoinName = "canto/MsgConvertCoin" +) + +// NOTE: This is required for the GetSignBytes function +func init() { + RegisterLegacyAminoCodec(amino) + amino.Seal() +} + +// RegisterInterfaces register implementations +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgConvertCoin{}, + &MsgConvertERC20{}, + ) + registry.RegisterImplementations( + (*govv1beta1.Content)(nil), + &RegisterCoinProposal{}, + &RegisterERC20Proposal{}, + &ToggleTokenConversionProposal{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +// RegisterLegacyAminoCodec registers the necessary x/erc20 interfaces and +// concrete types on the provided LegacyAmino codec. These types are used for +// Amino JSON serialization and EIP-712 compatibility. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgConvertERC20{}, convertERC20Name, nil) + cdc.RegisterConcrete(&MsgConvertCoin{}, convertCoinName, nil) +} diff --git a/x/erc20/types/erc20.pb.go b/x/erc20/types/erc20.pb.go new file mode 100644 index 00000000..0563b16e --- /dev/null +++ b/x/erc20/types/erc20.pb.go @@ -0,0 +1,1401 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: canto/erc20/v1/erc20.proto + +package types + +import ( + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/x/bank/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 + +// Owner enumerates the ownership of a ERC20 contract. +type Owner int32 + +const ( + // OWNER_UNSPECIFIED defines an invalid/undefined owner. + OWNER_UNSPECIFIED Owner = 0 + // OWNER_MODULE erc20 is owned by the erc20 module account. + OWNER_MODULE Owner = 1 + // EXTERNAL erc20 is owned by an external account. + OWNER_EXTERNAL Owner = 2 +) + +var Owner_name = map[int32]string{ + 0: "OWNER_UNSPECIFIED", + 1: "OWNER_MODULE", + 2: "OWNER_EXTERNAL", +} + +var Owner_value = map[string]int32{ + "OWNER_UNSPECIFIED": 0, + "OWNER_MODULE": 1, + "OWNER_EXTERNAL": 2, +} + +func (x Owner) String() string { + return proto.EnumName(Owner_name, int32(x)) +} + +func (Owner) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_5c364669f6882b8b, []int{0} +} + +// TokenPair defines an instance that records a pairing consisting of a native +// Cosmos Coin and an ERC20 token address. +type TokenPair struct { + // address of ERC20 contract token + Erc20Address string `protobuf:"bytes,1,opt,name=erc20_address,json=erc20Address,proto3" json:"erc20_address,omitempty"` + // cosmos base denomination to be mapped to + Denom string `protobuf:"bytes,2,opt,name=denom,proto3" json:"denom,omitempty"` + // shows token mapping enable status + Enabled bool `protobuf:"varint,3,opt,name=enabled,proto3" json:"enabled,omitempty"` + // ERC20 owner address ENUM (0 invalid, 1 ModuleAccount, 2 external address) + ContractOwner Owner `protobuf:"varint,4,opt,name=contract_owner,json=contractOwner,proto3,enum=canto.erc20.v1.Owner" json:"contract_owner,omitempty"` +} + +func (m *TokenPair) Reset() { *m = TokenPair{} } +func (m *TokenPair) String() string { return proto.CompactTextString(m) } +func (*TokenPair) ProtoMessage() {} +func (*TokenPair) Descriptor() ([]byte, []int) { + return fileDescriptor_5c364669f6882b8b, []int{0} +} +func (m *TokenPair) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TokenPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TokenPair.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 *TokenPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_TokenPair.Merge(m, src) +} +func (m *TokenPair) XXX_Size() int { + return m.Size() +} +func (m *TokenPair) XXX_DiscardUnknown() { + xxx_messageInfo_TokenPair.DiscardUnknown(m) +} + +var xxx_messageInfo_TokenPair proto.InternalMessageInfo + +func (m *TokenPair) GetErc20Address() string { + if m != nil { + return m.Erc20Address + } + return "" +} + +func (m *TokenPair) GetDenom() string { + if m != nil { + return m.Denom + } + return "" +} + +func (m *TokenPair) GetEnabled() bool { + if m != nil { + return m.Enabled + } + return false +} + +func (m *TokenPair) GetContractOwner() Owner { + if m != nil { + return m.ContractOwner + } + return OWNER_UNSPECIFIED +} + +// RegisterCoinProposal is a gov Content type to register a token pair for a +// native Cosmos coin. +type RegisterCoinProposal struct { + // title of the proposal + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // proposal description + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // metadata of the native Cosmos coin + Metadata types.Metadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata"` +} + +func (m *RegisterCoinProposal) Reset() { *m = RegisterCoinProposal{} } +func (m *RegisterCoinProposal) String() string { return proto.CompactTextString(m) } +func (*RegisterCoinProposal) ProtoMessage() {} +func (*RegisterCoinProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_5c364669f6882b8b, []int{1} +} +func (m *RegisterCoinProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RegisterCoinProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RegisterCoinProposal.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 *RegisterCoinProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_RegisterCoinProposal.Merge(m, src) +} +func (m *RegisterCoinProposal) XXX_Size() int { + return m.Size() +} +func (m *RegisterCoinProposal) XXX_DiscardUnknown() { + xxx_messageInfo_RegisterCoinProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_RegisterCoinProposal proto.InternalMessageInfo + +func (m *RegisterCoinProposal) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *RegisterCoinProposal) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *RegisterCoinProposal) GetMetadata() types.Metadata { + if m != nil { + return m.Metadata + } + return types.Metadata{} +} + +// RegisterERC20Proposal is a gov Content type to register a token pair for an +// ERC20 token +type RegisterERC20Proposal struct { + // title of the proposa string title = 1; + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // proposal description + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // contract address of ERC20 token + Erc20Address string `protobuf:"bytes,3,opt,name=erc20address,proto3" json:"erc20address,omitempty"` +} + +func (m *RegisterERC20Proposal) Reset() { *m = RegisterERC20Proposal{} } +func (m *RegisterERC20Proposal) String() string { return proto.CompactTextString(m) } +func (*RegisterERC20Proposal) ProtoMessage() {} +func (*RegisterERC20Proposal) Descriptor() ([]byte, []int) { + return fileDescriptor_5c364669f6882b8b, []int{2} +} +func (m *RegisterERC20Proposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RegisterERC20Proposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RegisterERC20Proposal.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 *RegisterERC20Proposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_RegisterERC20Proposal.Merge(m, src) +} +func (m *RegisterERC20Proposal) XXX_Size() int { + return m.Size() +} +func (m *RegisterERC20Proposal) XXX_DiscardUnknown() { + xxx_messageInfo_RegisterERC20Proposal.DiscardUnknown(m) +} + +var xxx_messageInfo_RegisterERC20Proposal proto.InternalMessageInfo + +func (m *RegisterERC20Proposal) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *RegisterERC20Proposal) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *RegisterERC20Proposal) GetErc20Address() string { + if m != nil { + return m.Erc20Address + } + return "" +} + +// ToggleTokenConversionProposal is a gov Content type to toggle the conversion +// of a token pair. +type ToggleTokenConversionProposal struct { + // title of the proposal + Title string `protobuf:"bytes,1,opt,name=Title,proto3" json:"Title,omitempty"` + // proposal description + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // token identifier can be either the hex contract address of the ERC20 or the + // Cosmos base denomination + Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"` +} + +func (m *ToggleTokenConversionProposal) Reset() { *m = ToggleTokenConversionProposal{} } +func (m *ToggleTokenConversionProposal) String() string { return proto.CompactTextString(m) } +func (*ToggleTokenConversionProposal) ProtoMessage() {} +func (*ToggleTokenConversionProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_5c364669f6882b8b, []int{3} +} +func (m *ToggleTokenConversionProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ToggleTokenConversionProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ToggleTokenConversionProposal.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 *ToggleTokenConversionProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_ToggleTokenConversionProposal.Merge(m, src) +} +func (m *ToggleTokenConversionProposal) XXX_Size() int { + return m.Size() +} +func (m *ToggleTokenConversionProposal) XXX_DiscardUnknown() { + xxx_messageInfo_ToggleTokenConversionProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_ToggleTokenConversionProposal proto.InternalMessageInfo + +func (m *ToggleTokenConversionProposal) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *ToggleTokenConversionProposal) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *ToggleTokenConversionProposal) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func init() { + proto.RegisterEnum("canto.erc20.v1.Owner", Owner_name, Owner_value) + proto.RegisterType((*TokenPair)(nil), "canto.erc20.v1.TokenPair") + proto.RegisterType((*RegisterCoinProposal)(nil), "canto.erc20.v1.RegisterCoinProposal") + proto.RegisterType((*RegisterERC20Proposal)(nil), "canto.erc20.v1.RegisterERC20Proposal") + proto.RegisterType((*ToggleTokenConversionProposal)(nil), "canto.erc20.v1.ToggleTokenConversionProposal") +} + +func init() { proto.RegisterFile("canto/erc20/v1/erc20.proto", fileDescriptor_5c364669f6882b8b) } + +var fileDescriptor_5c364669f6882b8b = []byte{ + // 499 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x93, 0x41, 0x6b, 0xdb, 0x3e, + 0x18, 0xc6, 0xad, 0x36, 0xfd, 0xff, 0x5b, 0xb5, 0x0d, 0x99, 0x48, 0x20, 0x04, 0xea, 0x86, 0xec, + 0x12, 0x06, 0xb3, 0x9b, 0xec, 0x36, 0x06, 0xa3, 0x75, 0x3d, 0xc8, 0x68, 0x93, 0xe0, 0xb9, 0x6c, + 0xec, 0x12, 0x64, 0x5b, 0x78, 0x26, 0x89, 0xde, 0x20, 0x69, 0xee, 0xfa, 0x0d, 0x76, 0xdc, 0x65, + 0xf7, 0xc1, 0xf6, 0x61, 0x7a, 0xec, 0x71, 0xa7, 0x31, 0x92, 0xcb, 0x3e, 0xc6, 0xb0, 0xe4, 0x8c, + 0xf4, 0x36, 0xd8, 0x4d, 0xcf, 0xf3, 0xbe, 0x96, 0x7e, 0x7e, 0x1f, 0x09, 0xb7, 0x62, 0xca, 0x15, + 0xb8, 0x4c, 0xc4, 0xfd, 0x13, 0x37, 0xef, 0x99, 0x85, 0xb3, 0x10, 0xa0, 0x80, 0x54, 0x75, 0xcd, + 0x31, 0x56, 0xde, 0x6b, 0xd5, 0x53, 0x48, 0x41, 0x97, 0xdc, 0x62, 0x65, 0xba, 0x5a, 0x76, 0x0c, + 0x72, 0x0e, 0xd2, 0x8d, 0x28, 0x9f, 0xba, 0x79, 0x2f, 0x62, 0x8a, 0xf6, 0xb4, 0x30, 0xf5, 0xce, + 0x37, 0x84, 0xf7, 0x42, 0x98, 0x32, 0x3e, 0xa6, 0x99, 0x20, 0x0f, 0xf1, 0xa1, 0xde, 0x6f, 0x42, + 0x93, 0x44, 0x30, 0x29, 0x9b, 0xa8, 0x8d, 0xba, 0x7b, 0xc1, 0x81, 0x36, 0x4f, 0x8d, 0x47, 0xea, + 0x78, 0x27, 0x61, 0x1c, 0xe6, 0xcd, 0x2d, 0x5d, 0x34, 0x82, 0x34, 0xf1, 0xff, 0x8c, 0xd3, 0x68, + 0xc6, 0x92, 0xe6, 0x76, 0x1b, 0x75, 0x77, 0x83, 0xb5, 0x24, 0xcf, 0x70, 0x35, 0x06, 0xae, 0x04, + 0x8d, 0xd5, 0x04, 0xae, 0x39, 0x13, 0xcd, 0x4a, 0x1b, 0x75, 0xab, 0xfd, 0x86, 0x73, 0xff, 0x0f, + 0x9c, 0x51, 0x51, 0x0c, 0x0e, 0xd7, 0xcd, 0x5a, 0x3e, 0xad, 0xfc, 0xfa, 0x72, 0x8c, 0x3a, 0x9f, + 0x11, 0xae, 0x07, 0x2c, 0xcd, 0xa4, 0x62, 0xc2, 0x83, 0x8c, 0x8f, 0x05, 0x2c, 0x40, 0xd2, 0x59, + 0x01, 0xa3, 0x32, 0x35, 0x63, 0x25, 0xa9, 0x11, 0xa4, 0x8d, 0xf7, 0x13, 0x26, 0x63, 0x91, 0x2d, + 0x54, 0x06, 0xbc, 0x04, 0xdd, 0xb4, 0xc8, 0x73, 0xbc, 0x3b, 0x67, 0x8a, 0x26, 0x54, 0x51, 0xcd, + 0xbb, 0xdf, 0x3f, 0x72, 0xcc, 0xa8, 0x1c, 0x3d, 0x9d, 0x72, 0x54, 0xce, 0x65, 0xd9, 0x74, 0x56, + 0xb9, 0xfd, 0x71, 0x6c, 0x05, 0x7f, 0x3e, 0xd2, 0x5c, 0x56, 0xe7, 0x06, 0x37, 0xd6, 0x58, 0x7e, + 0xe0, 0xf5, 0x4f, 0xfe, 0x99, 0xab, 0x83, 0xcd, 0xb0, 0xd7, 0x01, 0x6c, 0x6f, 0x04, 0x50, 0x7a, + 0xe5, 0xd1, 0x12, 0x1f, 0x85, 0x90, 0xa6, 0x33, 0xa6, 0xe3, 0xf3, 0x80, 0xe7, 0x4c, 0xc8, 0x0c, + 0xee, 0x8d, 0x26, 0xdc, 0x44, 0x08, 0xff, 0x12, 0xa1, 0x40, 0x2f, 0xb6, 0x2c, 0xcf, 0x36, 0xc2, + 0xe4, 0xf0, 0xe8, 0x25, 0xde, 0xd1, 0xb1, 0x90, 0x06, 0x7e, 0x30, 0x7a, 0x3d, 0xf4, 0x83, 0xc9, + 0xd5, 0xf0, 0xd5, 0xd8, 0xf7, 0x06, 0x2f, 0x06, 0xfe, 0x79, 0xcd, 0x22, 0x35, 0x7c, 0x60, 0xec, + 0xcb, 0xd1, 0xf9, 0xd5, 0x85, 0x5f, 0x43, 0x84, 0xe0, 0xaa, 0x71, 0xfc, 0x37, 0xa1, 0x1f, 0x0c, + 0x4f, 0x2f, 0x6a, 0x5b, 0xad, 0xca, 0xc7, 0xaf, 0xb6, 0x75, 0x36, 0xb8, 0x5d, 0xda, 0xe8, 0x6e, + 0x69, 0xa3, 0x9f, 0x4b, 0x1b, 0x7d, 0x5a, 0xd9, 0xd6, 0xdd, 0xca, 0xb6, 0xbe, 0xaf, 0x6c, 0xeb, + 0xad, 0x9b, 0x66, 0xea, 0xdd, 0xfb, 0xc8, 0x89, 0x61, 0xee, 0x7a, 0xc5, 0x1d, 0x79, 0x3c, 0x64, + 0xea, 0x1a, 0xc4, 0xd4, 0x28, 0x37, 0xef, 0xbb, 0x1f, 0xca, 0x47, 0xa1, 0x6e, 0x16, 0x4c, 0x46, + 0xff, 0xe9, 0xcb, 0xfc, 0xe4, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x29, 0x55, 0xba, 0x56, 0x30, + 0x03, 0x00, 0x00, +} + +func (this *TokenPair) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*TokenPair) + if !ok { + that2, ok := that.(TokenPair) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Erc20Address != that1.Erc20Address { + return false + } + if this.Denom != that1.Denom { + return false + } + if this.Enabled != that1.Enabled { + return false + } + if this.ContractOwner != that1.ContractOwner { + return false + } + return true +} +func (this *ToggleTokenConversionProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ToggleTokenConversionProposal) + if !ok { + that2, ok := that.(ToggleTokenConversionProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.Token != that1.Token { + return false + } + return true +} +func (m *TokenPair) 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 *TokenPair) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TokenPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ContractOwner != 0 { + i = encodeVarintErc20(dAtA, i, uint64(m.ContractOwner)) + i-- + dAtA[i] = 0x20 + } + if m.Enabled { + i-- + if m.Enabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if len(m.Denom) > 0 { + i -= len(m.Denom) + copy(dAtA[i:], m.Denom) + i = encodeVarintErc20(dAtA, i, uint64(len(m.Denom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Erc20Address) > 0 { + i -= len(m.Erc20Address) + copy(dAtA[i:], m.Erc20Address) + i = encodeVarintErc20(dAtA, i, uint64(len(m.Erc20Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RegisterCoinProposal) 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 *RegisterCoinProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RegisterCoinProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintErc20(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintErc20(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 = encodeVarintErc20(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RegisterERC20Proposal) 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 *RegisterERC20Proposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RegisterERC20Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Erc20Address) > 0 { + i -= len(m.Erc20Address) + copy(dAtA[i:], m.Erc20Address) + i = encodeVarintErc20(dAtA, i, uint64(len(m.Erc20Address))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintErc20(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 = encodeVarintErc20(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ToggleTokenConversionProposal) 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 *ToggleTokenConversionProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ToggleTokenConversionProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Token) > 0 { + i -= len(m.Token) + copy(dAtA[i:], m.Token) + i = encodeVarintErc20(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 = encodeVarintErc20(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 = encodeVarintErc20(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintErc20(dAtA []byte, offset int, v uint64) int { + offset -= sovErc20(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *TokenPair) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Erc20Address) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + l = len(m.Denom) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + if m.Enabled { + n += 2 + } + if m.ContractOwner != 0 { + n += 1 + sovErc20(uint64(m.ContractOwner)) + } + return n +} + +func (m *RegisterCoinProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + l = m.Metadata.Size() + n += 1 + l + sovErc20(uint64(l)) + return n +} + +func (m *RegisterERC20Proposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + l = len(m.Erc20Address) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + return n +} + +func (m *ToggleTokenConversionProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + l = len(m.Token) + if l > 0 { + n += 1 + l + sovErc20(uint64(l)) + } + return n +} + +func sovErc20(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozErc20(x uint64) (n int) { + return sovErc20(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *TokenPair) 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 ErrIntOverflowErc20 + } + 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: TokenPair: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TokenPair: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Erc20Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Erc20Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Enabled = bool(v != 0) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractOwner", wireType) + } + m.ContractOwner = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ContractOwner |= Owner(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipErc20(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthErc20 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RegisterCoinProposal) 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 ErrIntOverflowErc20 + } + 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: RegisterCoinProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RegisterCoinProposal: 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 ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.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 ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipErc20(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthErc20 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RegisterERC20Proposal) 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 ErrIntOverflowErc20 + } + 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: RegisterERC20Proposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RegisterERC20Proposal: 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 ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.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 ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Erc20Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Erc20Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipErc20(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthErc20 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ToggleTokenConversionProposal) 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 ErrIntOverflowErc20 + } + 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: ToggleTokenConversionProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ToggleTokenConversionProposal: 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 ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.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 ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.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 ErrIntOverflowErc20 + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthErc20 + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthErc20 + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Token = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipErc20(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthErc20 + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipErc20(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, ErrIntOverflowErc20 + } + 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, ErrIntOverflowErc20 + } + 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, ErrIntOverflowErc20 + } + 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, ErrInvalidLengthErc20 + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupErc20 + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthErc20 + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthErc20 = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowErc20 = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupErc20 = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/erc20/types/errors.go b/x/erc20/types/errors.go new file mode 100644 index 00000000..09e61938 --- /dev/null +++ b/x/erc20/types/errors.go @@ -0,0 +1,21 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" +) + +// errors +var ( + ErrERC20Disabled = errorsmod.Register(ModuleName, 2, "erc20 module is disabled") + ErrInternalTokenPair = errorsmod.Register(ModuleName, 3, "internal ethereum token mapping error") + ErrTokenPairNotFound = errorsmod.Register(ModuleName, 4, "token pair not found") + ErrTokenPairAlreadyExists = errorsmod.Register(ModuleName, 5, "token pair already exists") + ErrUndefinedOwner = errorsmod.Register(ModuleName, 6, "undefined owner of contract pair") + ErrBalanceInvariance = errorsmod.Register(ModuleName, 7, "post transfer balance invariant failed") + ErrUnexpectedEvent = errorsmod.Register(ModuleName, 8, "unexpected event") + ErrABIPack = errorsmod.Register(ModuleName, 9, "contract ABI pack failed") + ErrABIUnpack = errorsmod.Register(ModuleName, 10, "contract ABI unpack failed") + ErrEVMDenom = errorsmod.Register(ModuleName, 11, "EVM denomination registration") + ErrEVMCall = errorsmod.Register(ModuleName, 12, "EVM call unexpected error") + ErrERC20TokenPairDisabled = errorsmod.Register(ModuleName, 13, "erc20 token pair is disabled") +) diff --git a/x/erc20/types/events.go b/x/erc20/types/events.go new file mode 100644 index 00000000..867e5ca1 --- /dev/null +++ b/x/erc20/types/events.go @@ -0,0 +1,33 @@ +package types + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" +) + +// erc20 events +const ( + EventTypeTokenLock = "token_lock" + EventTypeTokenUnlock = "token_unlock" + EventTypeMint = "mint" + EventTypeConvertCoin = "convert_coin" + EventTypeConvertERC20 = "convert_erc20" + EventTypeBurn = "burn" + EventTypeRegisterCoin = "register_coin" + EventTypeRegisterERC20 = "register_erc20" + EventTypeToggleTokenConversion = "toggle_token_conversion" // #nosec + + AttributeKeyCosmosCoin = "cosmos_coin" + AttributeKeyERC20Token = "erc20_token" // #nosec + AttributeKeyReceiver = "receiver" + + ERC20EventTransfer = "Transfer" +) + +// Event type for Transfer(address from, address to, uint256 value) +type LogTransfer struct { + From common.Address + To common.Address + Tokens *big.Int +} diff --git a/x/erc20/types/evm.go b/x/erc20/types/evm.go new file mode 100644 index 00000000..4e8e7dea --- /dev/null +++ b/x/erc20/types/evm.go @@ -0,0 +1,33 @@ +package types + +// ERC20Data represents the ERC20 token details used to map +// the token to a Cosmos Coin +type ERC20Data struct { + Name string + Symbol string + Decimals uint8 +} + +// ERC20StringResponse defines the string value from the call response +type ERC20StringResponse struct { + Value string +} + +// ERC20Uint8Response defines the uint8 value from the call response +type ERC20Uint8Response struct { + Value uint8 +} + +// ERC20BoolResponse defines the bool value from the call response +type ERC20BoolResponse struct { + Value bool +} + +// NewERC20Data creates a new ERC20Data instance +func NewERC20Data(name, symbol string, decimals uint8) ERC20Data { + return ERC20Data{ + Name: name, + Symbol: symbol, + Decimals: decimals, + } +} diff --git a/x/erc20/types/evm_test.go b/x/erc20/types/evm_test.go new file mode 100644 index 00000000..83605b6d --- /dev/null +++ b/x/erc20/types/evm_test.go @@ -0,0 +1,13 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNewERC20Data(t *testing.T) { + data := NewERC20Data("test", "ERC20", uint8(18)) + exp := ERC20Data(ERC20Data{Name: "test", Symbol: "ERC20", Decimals: 0x12}) + require.Equal(t, exp, data) +} diff --git a/x/erc20/types/genesis.go b/x/erc20/types/genesis.go new file mode 100644 index 00000000..dab7227c --- /dev/null +++ b/x/erc20/types/genesis.go @@ -0,0 +1,44 @@ +package types + +import "fmt" + +// NewGenesisState creates a new genesis state. +func NewGenesisState(params Params, pairs []TokenPair) GenesisState { + return GenesisState{ + Params: params, + TokenPairs: pairs, + } +} + +// DefaultGenesisState sets default evm genesis state with empty accounts and +// default params and chain config values. +func DefaultGenesisState() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + seenErc20 := make(map[string]bool) + seenDenom := make(map[string]bool) + + for _, b := range gs.TokenPairs { + if seenErc20[b.Erc20Address] { + return fmt.Errorf("token ERC20 contract duplicated on genesis '%s'", b.Erc20Address) + } + if seenDenom[b.Denom] { + return fmt.Errorf("coin denomination duplicated on genesis: '%s'", b.Denom) + } + + if err := b.Validate(); err != nil { + return err + } + + seenErc20[b.Erc20Address] = true + seenDenom[b.Denom] = true + } + + return gs.Params.Validate() +} diff --git a/x/erc20/types/genesis.pb.go b/x/erc20/types/genesis.pb.go new file mode 100644 index 00000000..cda92dba --- /dev/null +++ b/x/erc20/types/genesis.pb.go @@ -0,0 +1,598 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: canto/erc20/v1/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 + +// GenesisState defines the module's genesis state. +type GenesisState struct { + // module parameters + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + // registered token pairs + TokenPairs []TokenPair `protobuf:"bytes,2,rep,name=token_pairs,json=tokenPairs,proto3" json:"token_pairs"` +} + +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_6af5bf0eee46eaa1, []int{0} +} +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) GetTokenPairs() []TokenPair { + if m != nil { + return m.TokenPairs + } + return nil +} + +// Params defines the erc20 module params +type Params struct { + // parameter to enable the conversion of Cosmos coins <--> ERC20 tokens. + EnableErc20 bool `protobuf:"varint,1,opt,name=enable_erc20,json=enableErc20,proto3" json:"enable_erc20,omitempty"` + // parameter to enable the EVM hook that converts an ERC20 token to a Cosmos + // Coin by transferring the Tokens through a MsgEthereumTx to the + // ModuleAddress Ethereum address. + EnableEVMHook bool `protobuf:"varint,2,opt,name=enable_evm_hook,json=enableEvmHook,proto3" json:"enable_evm_hook,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_6af5bf0eee46eaa1, []int{1} +} +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) GetEnableErc20() bool { + if m != nil { + return m.EnableErc20 + } + return false +} + +func (m *Params) GetEnableEVMHook() bool { + if m != nil { + return m.EnableEVMHook + } + return false +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "canto.erc20.v1.GenesisState") + proto.RegisterType((*Params)(nil), "canto.erc20.v1.Params") +} + +func init() { proto.RegisterFile("canto/erc20/v1/genesis.proto", fileDescriptor_6af5bf0eee46eaa1) } + +var fileDescriptor_6af5bf0eee46eaa1 = []byte{ + // 311 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x49, 0x4e, 0xcc, 0x2b, + 0xc9, 0xd7, 0x4f, 0x2d, 0x4a, 0x36, 0x32, 0xd0, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, + 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x03, 0xcb, 0xea, 0x81, 0x65, 0xf5, + 0xca, 0x0c, 0xa5, 0xa4, 0xd0, 0x54, 0x43, 0x24, 0xc0, 0x6a, 0xa5, 0x44, 0xd2, 0xf3, 0xd3, 0xf3, + 0xc1, 0x4c, 0x7d, 0x10, 0x0b, 0x22, 0xaa, 0xd4, 0xc6, 0xc8, 0xc5, 0xe3, 0x0e, 0x31, 0x33, 0xb8, + 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x84, 0x8b, 0xad, 0x20, 0xb1, 0x28, 0x31, 0xb7, 0x58, 0x82, 0x51, + 0x81, 0x51, 0x83, 0xdb, 0x48, 0x4c, 0x0f, 0xd5, 0x0e, 0xbd, 0x00, 0xb0, 0xac, 0x13, 0xcb, 0x89, + 0x7b, 0xf2, 0x0c, 0x41, 0x50, 0xb5, 0x42, 0x0e, 0x5c, 0xdc, 0x25, 0xf9, 0xd9, 0xa9, 0x79, 0xf1, + 0x05, 0x89, 0x99, 0x45, 0xc5, 0x12, 0x4c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 0x92, 0xe8, 0x5a, 0x43, + 0x40, 0x4a, 0x02, 0x12, 0x33, 0x8b, 0xa0, 0xba, 0xb9, 0x4a, 0x60, 0x02, 0xc5, 0x4a, 0x69, 0x5c, + 0x6c, 0x10, 0x93, 0x85, 0x14, 0xb9, 0x78, 0x52, 0xf3, 0x12, 0x93, 0x72, 0x52, 0xe3, 0xc1, 0x1a, + 0xc1, 0xee, 0xe0, 0x08, 0xe2, 0x86, 0x88, 0xb9, 0x82, 0x84, 0x84, 0x2c, 0xb9, 0xf8, 0x61, 0x4a, + 0xca, 0x72, 0xe3, 0x33, 0xf2, 0xf3, 0xb3, 0x25, 0x98, 0x40, 0xaa, 0x9c, 0x04, 0x1f, 0xdd, 0x93, + 0xe7, 0x75, 0x85, 0xa8, 0x0c, 0xf3, 0xf5, 0xc8, 0xcf, 0xcf, 0x0e, 0xe2, 0x85, 0x6a, 0x2c, 0xcb, + 0x05, 0x71, 0x9d, 0x3c, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, + 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x4a, 0x3f, + 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0xdf, 0x19, 0xe4, 0x70, 0x5d, 0xbf, + 0xd4, 0x92, 0xf2, 0xfc, 0xa2, 0x6c, 0x08, 0x4f, 0xbf, 0xcc, 0x48, 0xbf, 0x02, 0x1a, 0xb4, 0x25, + 0x95, 0x05, 0xa9, 0xc5, 0x49, 0x6c, 0xe0, 0x20, 0x34, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x05, + 0x60, 0x6f, 0xf6, 0xa4, 0x01, 0x00, 0x00, +} + +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.TokenPairs) > 0 { + for iNdEx := len(m.TokenPairs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TokenPairs[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 (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 m.EnableEVMHook { + i-- + if m.EnableEVMHook { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if m.EnableErc20 { + i-- + if m.EnableErc20 { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + 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 *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.TokenPairs) > 0 { + for _, e := range m.TokenPairs { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.EnableErc20 { + n += 2 + } + if m.EnableEVMHook { + n += 2 + } + 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 *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 TokenPairs", 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.TokenPairs = append(m.TokenPairs, TokenPair{}) + if err := m.TokenPairs[len(m.TokenPairs)-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 (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 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EnableErc20", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.EnableErc20 = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EnableEVMHook", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.EnableEVMHook = bool(v != 0) + 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/erc20/types/genesis_test.go b/x/erc20/types/genesis_test.go new file mode 100644 index 00000000..a3997232 --- /dev/null +++ b/x/erc20/types/genesis_test.go @@ -0,0 +1,148 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/suite" +) + +type GenesisTestSuite struct { + suite.Suite +} + +func (suite *GenesisTestSuite) SetupTest() { +} + +func TestGenesisTestSuite(t *testing.T) { + suite.Run(t, new(GenesisTestSuite)) +} + +func (suite *GenesisTestSuite) TestValidateGenesis() { + newGen := NewGenesisState(DefaultParams(), []TokenPair{}) + + testCases := []struct { + name string + genState *GenesisState + expPass bool + }{ + { + name: "valid genesis constructor", + genState: &newGen, + expPass: true, + }, + { + name: "default", + genState: DefaultGenesisState(), + expPass: true, + }, + { + name: "valid genesis", + genState: &GenesisState{ + Params: DefaultParams(), + TokenPairs: []TokenPair{}, + }, + expPass: true, + }, + { + name: "valid genesis - with tokens pairs", + genState: &GenesisState{ + Params: DefaultParams(), + TokenPairs: []TokenPair{ + { + Erc20Address: "0xdac17f958d2ee523a2206206994597c13d831ec7", + Denom: "usdt", + Enabled: true, + }, + }, + }, + expPass: true, + }, + { + name: "invalid genesis - duplicated token pair", + genState: &GenesisState{ + Params: DefaultParams(), + TokenPairs: []TokenPair{ + { + Erc20Address: "0xdac17f958d2ee523a2206206994597c13d831ec7", + Denom: "usdt", + Enabled: true, + }, + { + Erc20Address: "0xdac17f958d2ee523a2206206994597c13d831ec7", + Denom: "usdt", + Enabled: true, + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis - duplicated token pair", + genState: &GenesisState{ + Params: DefaultParams(), + TokenPairs: []TokenPair{ + { + Erc20Address: "0xdac17f958d2ee523a2206206994597c13d831ec7", + Denom: "usdt", + Enabled: true, + }, + { + Erc20Address: "0xdac17f958d2ee523a2206206994597c13d831ec7", + Denom: "usdt2", + Enabled: true, + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis - duplicated token pair", + genState: &GenesisState{ + Params: DefaultParams(), + TokenPairs: []TokenPair{ + { + Erc20Address: "0xdac17f958d2ee523a2206206994597c13d831ec7", + Denom: "usdt", + Enabled: true, + }, + { + Erc20Address: "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", + Denom: "usdt", + Enabled: true, + }, + }, + }, + expPass: false, + }, + { + name: "invalid genesis - invalid token pair", + genState: &GenesisState{ + Params: DefaultParams(), + TokenPairs: []TokenPair{ + { + Erc20Address: "0xinvalidaddress", + Denom: "bad", + Enabled: true, + }, + }, + }, + expPass: false, + }, + { + // Voting period cant be zero + name: "empty genesis", + genState: &GenesisState{}, + expPass: true, + }, + } + + for _, tc := range testCases { + tc := tc + err := tc.genState.Validate() + if tc.expPass { + suite.Require().NoError(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +} diff --git a/x/erc20/types/interfaces.go b/x/erc20/types/interfaces.go new file mode 100644 index 00000000..497106ab --- /dev/null +++ b/x/erc20/types/interfaces.go @@ -0,0 +1,43 @@ +package types + +import ( + context "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + 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/evmos/ethermint/x/evm/statedb" + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +// AccountKeeper defines the expected interface needed to retrieve account info. +type AccountKeeper interface { + GetModuleAddress(moduleName string) sdk.AccAddress + GetSequence(sdk.Context, sdk.AccAddress) (uint64, error) +} + +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + IsSendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool + BlockedAddr(addr sdk.AccAddress) bool + GetDenomMetaData(ctx sdk.Context, denom string) (banktypes.Metadata, bool) + SetDenomMetaData(ctx sdk.Context, denomMetaData banktypes.Metadata) + HasSupply(ctx sdk.Context, denom string) bool + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin +} + +// EVMKeeper defines the expected EVM keeper interface used on erc20 +type EVMKeeper interface { + GetParams(ctx sdk.Context) evmtypes.Params + GetAccountWithoutBalance(ctx sdk.Context, addr common.Address) *statedb.Account + EstimateGas(c context.Context, req *evmtypes.EthCallRequest) (*evmtypes.EstimateGasResponse, error) + ApplyMessage(ctx sdk.Context, msg core.Message, tracer vm.EVMLogger, commit bool) (*evmtypes.MsgEthereumTxResponse, error) +} diff --git a/x/erc20/types/keys.go b/x/erc20/types/keys.go new file mode 100644 index 00000000..65c4346a --- /dev/null +++ b/x/erc20/types/keys.go @@ -0,0 +1,39 @@ +package types + +import ( + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" +) + +// constants +const ( + // module name + ModuleName = "erc20" + + // StoreKey to be used when creating the KVStore + StoreKey = ModuleName + + // RouterKey to be used for message routing + RouterKey = ModuleName +) + +// ModuleAddress is the native module address for EVM +var ModuleAddress common.Address + +func init() { + ModuleAddress = common.BytesToAddress(authtypes.NewModuleAddress(ModuleName).Bytes()) +} + +// prefix bytes for the EVM persistent store +const ( + prefixTokenPair = iota + 1 + prefixTokenPairByERC20 + prefixTokenPairByDenom +) + +// KVStore key prefixes +var ( + KeyPrefixTokenPair = []byte{prefixTokenPair} + KeyPrefixTokenPairByERC20 = []byte{prefixTokenPairByERC20} + KeyPrefixTokenPairByDenom = []byte{prefixTokenPairByDenom} +) diff --git a/x/erc20/types/msg.go b/x/erc20/types/msg.go new file mode 100644 index 00000000..3ad959df --- /dev/null +++ b/x/erc20/types/msg.go @@ -0,0 +1,111 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + "github.com/ethereum/go-ethereum/common" +) + +var ( + _ sdk.Msg = &MsgConvertCoin{} + _ sdk.Msg = &MsgConvertERC20{} +) + +const ( + TypeMsgConvertCoin = "convert_coin" + TypeMsgConvertERC20 = "convert_ERC20" +) + +// NewMsgConvertCoin creates a new instance of MsgConvertCoin +func NewMsgConvertCoin(coin sdk.Coin, receiver common.Address, sender sdk.AccAddress) *MsgConvertCoin { // nolint: interfacer + return &MsgConvertCoin{ + Coin: coin, + Receiver: receiver.Hex(), + Sender: sender.String(), + } +} + +// Route should return the name of the module +func (msg MsgConvertCoin) Route() string { return RouterKey } + +// Type should return the action +func (msg MsgConvertCoin) Type() string { return TypeMsgConvertCoin } + +// ValidateBasic runs stateless checks on the message +func (msg MsgConvertCoin) ValidateBasic() error { + if err := ValidateErc20Denom(msg.Coin.Denom); err != nil { + if err := ibctransfertypes.ValidateIBCDenom(msg.Coin.Denom); err != nil { + return err + } + } + + if !msg.Coin.Amount.IsPositive() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "cannot mint a non-positive amount") + } + _, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return sdkerrors.Wrap(err, "invalid sender address") + } + if !common.IsHexAddress(msg.Receiver) { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid receiver hex address %s", msg.Receiver) + } + return nil +} + +// GetSignBytes encodes the message for signing +func (msg MsgConvertCoin) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) +} + +// GetSigners defines whose signature is required +func (msg MsgConvertCoin) GetSigners() []sdk.AccAddress { + addr := sdk.MustAccAddressFromBech32(msg.Sender) + return []sdk.AccAddress{addr} +} + +// NewMsgConvertERC20 creates a new instance of MsgConvertERC20 +func NewMsgConvertERC20(amount sdk.Int, receiver sdk.AccAddress, contract, sender common.Address) *MsgConvertERC20 { // nolint: interfacer + return &MsgConvertERC20{ + ContractAddress: contract.String(), + Amount: amount, + Receiver: receiver.String(), + Sender: sender.Hex(), + } +} + +// Route should return the name of the module +func (msg MsgConvertERC20) Route() string { return RouterKey } + +// Type should return the action +func (msg MsgConvertERC20) Type() string { return TypeMsgConvertERC20 } + +// ValidateBasic runs stateless checks on the message +func (msg MsgConvertERC20) ValidateBasic() error { + if !common.IsHexAddress(msg.ContractAddress) { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid contract hex address '%s'", msg.ContractAddress) + } + if !msg.Amount.IsPositive() { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "cannot mint a non-positive amount") + } + _, err := sdk.AccAddressFromBech32(msg.Receiver) + if err != nil { + return sdkerrors.Wrap(err, "invalid receiver address") + } + if !common.IsHexAddress(msg.Sender) { + return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid sender hex address %s", msg.Sender) + } + return nil +} + +// GetSignBytes encodes the message for signing +func (msg MsgConvertERC20) GetSignBytes() []byte { + return sdk.MustSortJSON(AminoCdc.MustMarshalJSON(&msg)) +} + +// GetSigners defines whose signature is required +func (msg MsgConvertERC20) GetSigners() []sdk.AccAddress { + addr := common.HexToAddress(msg.Sender) + return []sdk.AccAddress{addr.Bytes()} +} diff --git a/x/erc20/types/msg_test.go b/x/erc20/types/msg_test.go new file mode 100644 index 00000000..952bad8b --- /dev/null +++ b/x/erc20/types/msg_test.go @@ -0,0 +1,247 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/evmos/ethermint/tests" + + "github.com/ethereum/go-ethereum/common" +) + +type MsgsTestSuite struct { + suite.Suite +} + +func TestMsgsTestSuite(t *testing.T) { + suite.Run(t, new(MsgsTestSuite)) +} + +func (suite *MsgsTestSuite) TestMsgConvertCoinGetters() { + msgInvalid := MsgConvertCoin{} + msg := NewMsgConvertCoin( + sdk.NewCoin("test", sdk.NewInt(100)), + tests.GenerateAddress(), + sdk.AccAddress(tests.GenerateAddress().Bytes()), + ) + suite.Require().Equal(RouterKey, msg.Route()) + suite.Require().Equal(TypeMsgConvertCoin, msg.Type()) + suite.Require().NotNil(msgInvalid.GetSignBytes()) + suite.Require().NotNil(msg.GetSigners()) +} + +func (suite *MsgsTestSuite) TestMsgConvertCoinNew() { + testCases := []struct { + msg string + coin sdk.Coin + receiver common.Address + sender sdk.AccAddress + expectPass bool + }{ + { + "msg convert coin - pass", + sdk.NewCoin("test", sdk.NewInt(100)), + tests.GenerateAddress(), + sdk.AccAddress(tests.GenerateAddress().Bytes()), + true, + }, + } + + for i, tc := range testCases { + tx := NewMsgConvertCoin(tc.coin, tc.receiver, tc.sender) + err := tx.ValidateBasic() + + if tc.expectPass { + suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg) + } + } +} + +func (suite *MsgsTestSuite) TestMsgConvertCoin() { + testCases := []struct { + msg string + coin sdk.Coin + receiver string + sender string + expectPass bool + }{ + { + "invalid denom", + sdk.Coin{ + Denom: "", + Amount: sdk.NewInt(100), + }, + "0x0000", + tests.GenerateAddress().String(), + false, + }, + { + "negative coin amount", + sdk.Coin{ + Denom: "coin", + Amount: sdk.NewInt(-100), + }, + "0x0000", + tests.GenerateAddress().String(), + false, + }, + { + "msg convert coin - invalid sender", + sdk.NewCoin("coin", sdk.NewInt(100)), + tests.GenerateAddress().String(), + "cantoinvalid", + false, + }, + { + "msg convert coin - invalid receiver", + sdk.NewCoin("coin", sdk.NewInt(100)), + "0x0000", + sdk.AccAddress(tests.GenerateAddress().Bytes()).String(), + false, + }, + { + "msg convert coin - pass", + sdk.NewCoin("coin", sdk.NewInt(100)), + tests.GenerateAddress().String(), + sdk.AccAddress(tests.GenerateAddress().Bytes()).String(), + true, + }, + { + "msg convert coin - pass with `erc20/` denom", + sdk.NewCoin("erc20/0xdac17f958d2ee523a2206206994597c13d831ec7", sdk.NewInt(100)), + tests.GenerateAddress().String(), + sdk.AccAddress(tests.GenerateAddress().Bytes()).String(), + true, + }, + { + "msg convert coin - pass with `ibc/{hash}` denom", + sdk.NewCoin("ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2", sdk.NewInt(100)), + tests.GenerateAddress().String(), + sdk.AccAddress(tests.GenerateAddress().Bytes()).String(), + true, + }, + } + + for i, tc := range testCases { + tx := MsgConvertCoin{tc.coin, tc.receiver, tc.sender} + err := tx.ValidateBasic() + + if tc.expectPass { + suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg) + } + } +} + +func (suite *MsgsTestSuite) TestMsgConvertERC20Getters() { + msgInvalid := MsgConvertERC20{} + msg := NewMsgConvertERC20( + sdk.NewInt(100), + sdk.AccAddress(tests.GenerateAddress().Bytes()), + tests.GenerateAddress(), + tests.GenerateAddress(), + ) + suite.Require().Equal(RouterKey, msg.Route()) + suite.Require().Equal(TypeMsgConvertERC20, msg.Type()) + suite.Require().NotNil(msgInvalid.GetSignBytes()) + suite.Require().NotNil(msg.GetSigners()) +} + +func (suite *MsgsTestSuite) TestMsgConvertERC20New() { + testCases := []struct { + msg string + amount sdk.Int + receiver sdk.AccAddress + contract common.Address + sender common.Address + expectPass bool + }{ + { + "msg convert erc20 - pass", + sdk.NewInt(100), + sdk.AccAddress(tests.GenerateAddress().Bytes()), + tests.GenerateAddress(), + tests.GenerateAddress(), + true, + }, + } + + for i, tc := range testCases { + tx := NewMsgConvertERC20(tc.amount, tc.receiver, tc.contract, tc.sender) + err := tx.ValidateBasic() + + if tc.expectPass { + suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg) + } + } +} + +func (suite *MsgsTestSuite) TestMsgConvertERC20() { + testCases := []struct { + msg string + amount sdk.Int + receiver string + contract string + sender string + expectPass bool + }{ + { + "invalid contract hex address", + sdk.NewInt(100), + sdk.AccAddress(tests.GenerateAddress().Bytes()).String(), + sdk.AccAddress{}.String(), + tests.GenerateAddress().String(), + false, + }, + { + "negative coin amount", + sdk.NewInt(-100), + sdk.AccAddress(tests.GenerateAddress().Bytes()).String(), + tests.GenerateAddress().String(), + tests.GenerateAddress().String(), + false, + }, + { + "invalid receiver address", + sdk.NewInt(100), + sdk.AccAddress{}.String(), + tests.GenerateAddress().String(), + tests.GenerateAddress().String(), + false, + }, + { + "invalid sender address", + sdk.NewInt(100), + sdk.AccAddress(tests.GenerateAddress().Bytes()).String(), + tests.GenerateAddress().String(), + sdk.AccAddress{}.String(), + false, + }, + { + "msg convert erc20 - pass", + sdk.NewInt(100), + sdk.AccAddress(tests.GenerateAddress().Bytes()).String(), + tests.GenerateAddress().String(), + tests.GenerateAddress().String(), + true, + }, + } + + for i, tc := range testCases { + tx := MsgConvertERC20{tc.contract, tc.amount, tc.receiver, tc.sender} + err := tx.ValidateBasic() + + if tc.expectPass { + suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg) + } + } +} diff --git a/x/erc20/types/params.go b/x/erc20/types/params.go new file mode 100644 index 00000000..8d91a6e2 --- /dev/null +++ b/x/erc20/types/params.go @@ -0,0 +1,57 @@ +package types + +import ( + fmt "fmt" + + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +// Parameter store key +var ( + ParamStoreKeyEnableErc20 = []byte("EnableErc20") + ParamStoreKeyEnableEVMHook = []byte("EnableEVMHook") +) + +var _ paramtypes.ParamSet = &Params{} + +// ParamKeyTable returns the parameter key table. +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new Params object +func NewParams( + enableErc20 bool, + enableEVMHook bool, +) Params { + return Params{ + EnableErc20: enableErc20, + EnableEVMHook: enableEVMHook, + } +} + +func DefaultParams() Params { + return Params{ + EnableErc20: true, + EnableEVMHook: true, + } +} + +func validateBool(i interface{}) error { + _, ok := i.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + + return nil +} + +// ParamSetPairs returns the parameter set pairs. +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(ParamStoreKeyEnableErc20, &p.EnableErc20, validateBool), + paramtypes.NewParamSetPair(ParamStoreKeyEnableEVMHook, &p.EnableEVMHook, validateBool), + } +} + +func (p Params) Validate() error { return nil } diff --git a/x/erc20/types/params_test.go b/x/erc20/types/params_test.go new file mode 100644 index 00000000..3b6bb56a --- /dev/null +++ b/x/erc20/types/params_test.go @@ -0,0 +1,55 @@ +package types + +import ( + "testing" + + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/stretchr/testify/suite" +) + +type ParamsTestSuite struct { + suite.Suite +} + +func TestParamsTestSuite(t *testing.T) { + suite.Run(t, new(ParamsTestSuite)) +} + +func (suite *ParamsTestSuite) TestParamKeyTable() { + suite.Require().IsType(paramtypes.KeyTable{}, ParamKeyTable()) +} + +func (suite *ParamsTestSuite) TestParamsValidate() { + testCases := []struct { + name string + params Params + expError bool + }{ + {"default", DefaultParams(), false}, + { + "valid", + NewParams(true, true), + false, + }, + { + "empty", + Params{}, + false, + }, + } + + for _, tc := range testCases { + err := tc.params.Validate() + + if tc.expError { + suite.Require().Error(err, tc.name) + } else { + suite.Require().NoError(err, tc.name) + } + } +} + +func (suite *ParamsTestSuite) TestParamsValidatePriv() { + suite.Require().Error(validateBool(1)) + suite.Require().NoError(validateBool(true)) +} diff --git a/x/erc20/types/proposal.go b/x/erc20/types/proposal.go new file mode 100644 index 00000000..741eef99 --- /dev/null +++ b/x/erc20/types/proposal.go @@ -0,0 +1,163 @@ +package types + +import ( + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + ethermint "github.com/evmos/ethermint/types" +) + +// constants +const ( + ProposalTypeRegisterCoin string = "RegisterCoin" + ProposalTypeRegisterERC20 string = "RegisterERC20" + ProposalTypeToggleTokenConversion string = "ToggleTokenConversion" // #nosec +) + +// Implements Proposal Interface +var ( + _ govv1beta1.Content = &RegisterCoinProposal{} + _ govv1beta1.Content = &RegisterERC20Proposal{} + _ govv1beta1.Content = &ToggleTokenConversionProposal{} +) + +func init() { + govv1beta1.RegisterProposalType(ProposalTypeRegisterCoin) + govv1beta1.RegisterProposalType(ProposalTypeRegisterERC20) + govv1beta1.RegisterProposalType(ProposalTypeToggleTokenConversion) +} + +// CreateDenomDescription generates a string with the coin description +func CreateDenomDescription(address string) string { + return fmt.Sprintf("Cosmos coin token representation of %s", address) +} + +// CreateDenom generates a string the module name plus the address to avoid conflicts with names staring with a number +func CreateDenom(address string) string { + return fmt.Sprintf("%s/%s", ModuleName, address) +} + +// NewRegisterCoinProposal returns new instance of RegisterCoinProposal +func NewRegisterCoinProposal(title, description string, coinMetadata banktypes.Metadata) govv1beta1.Content { + return &RegisterCoinProposal{ + Title: title, + Description: description, + Metadata: coinMetadata, + } +} + +// ProposalRoute returns router key for this proposal +func (*RegisterCoinProposal) ProposalRoute() string { return RouterKey } + +// ProposalType returns proposal type for this proposal +func (*RegisterCoinProposal) ProposalType() string { + return ProposalTypeRegisterCoin +} + +// ValidateBasic performs a stateless check of the proposal fields +func (rtbp *RegisterCoinProposal) ValidateBasic() error { + if err := rtbp.Metadata.Validate(); err != nil { + return err + } + + if err := ibctransfertypes.ValidateIBCDenom(rtbp.Metadata.Base); err != nil { + return err + } + + if err := validateIBCVoucherMetadata(rtbp.Metadata); err != nil { + return err + } + + return govv1beta1.ValidateAbstract(rtbp) +} + +// validateIBCVoucherMetadata checks that the coin metadata fields are consistent +// with an IBC voucher denomination. +func validateIBCVoucherMetadata(metadata banktypes.Metadata) error { + // Check ibc/ denom + denomSplit := strings.SplitN(metadata.Base, "/", 2) + + if denomSplit[0] == metadata.Base && strings.TrimSpace(metadata.Base) != "" { + // Not IBC + return nil + } + + if len(denomSplit) != 2 || denomSplit[0] != ibctransfertypes.DenomPrefix { + // NOTE: should be unaccessible (covered on ValidateIBCDenom) + return fmt.Errorf("invalid metadata. %s denomination should be prefixed with the format 'ibc/", metadata.Base) + } + + return nil +} + +// ValidateErc20Denom checks if a denom is a valid erc20/ +// denomination +func ValidateErc20Denom(denom string) error { + denomSplit := strings.SplitN(denom, "/", 2) + + if len(denomSplit) != 2 || denomSplit[0] != ModuleName { + return fmt.Errorf("invalid denom. %s denomination should be prefixed with the format 'erc20/", denom) + } + + return ethermint.ValidateAddress(denomSplit[1]) +} + +// NewRegisterERC20Proposal returns new instance of RegisterERC20Proposal +func NewRegisterERC20Proposal(title, description, erc20Addr string) govv1beta1.Content { + return &RegisterERC20Proposal{ + Title: title, + Description: description, + Erc20Address: erc20Addr, + } +} + +// ProposalRoute returns router key for this proposal +func (*RegisterERC20Proposal) ProposalRoute() string { return RouterKey } + +// ProposalType returns proposal type for this proposal +func (*RegisterERC20Proposal) ProposalType() string { + return ProposalTypeRegisterERC20 +} + +// ValidateBasic performs a stateless check of the proposal fields +func (rtbp *RegisterERC20Proposal) ValidateBasic() error { + if err := ethermint.ValidateAddress(rtbp.Erc20Address); err != nil { + return sdkerrors.Wrap(err, "ERC20 address") + } + return govv1beta1.ValidateAbstract(rtbp) +} + +// NewToggleTokenConversionProposal returns new instance of ToggleTokenConversionProposal +func NewToggleTokenConversionProposal(title, description string, token string) govv1beta1.Content { + return &ToggleTokenConversionProposal{ + Title: title, + Description: description, + Token: token, + } +} + +// ProposalRoute returns router key for this proposal +func (*ToggleTokenConversionProposal) ProposalRoute() string { return RouterKey } + +// ProposalType returns proposal type for this proposal +func (*ToggleTokenConversionProposal) ProposalType() string { + return ProposalTypeToggleTokenConversion +} + +// ValidateBasic performs a stateless check of the proposal fields +func (ttcp *ToggleTokenConversionProposal) ValidateBasic() error { + // check if the token is a hex address, if not, check if it is a valid SDK + // denom + if err := ethermint.ValidateAddress(ttcp.Token); err != nil { + if err := sdk.ValidateDenom(ttcp.Token); err != nil { + return err + } + } + + return govv1beta1.ValidateAbstract(ttcp) +} diff --git a/x/erc20/types/proposal_test.go b/x/erc20/types/proposal_test.go new file mode 100644 index 00000000..ecb58936 --- /dev/null +++ b/x/erc20/types/proposal_test.go @@ -0,0 +1,279 @@ +package types + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/evmos/ethermint/tests" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" +) + +type ProposalTestSuite struct { + suite.Suite +} + +func TestProposalTestSuite(t *testing.T) { + suite.Run(t, new(ProposalTestSuite)) +} + +func (suite *ProposalTestSuite) TestKeysTypes() { + suite.Require().Equal("erc20", (&RegisterCoinProposal{}).ProposalRoute()) + suite.Require().Equal("RegisterCoin", (&RegisterCoinProposal{}).ProposalType()) + suite.Require().Equal("erc20", (&RegisterERC20Proposal{}).ProposalRoute()) + suite.Require().Equal("RegisterERC20", (&RegisterERC20Proposal{}).ProposalType()) + suite.Require().Equal("erc20", (&ToggleTokenConversionProposal{}).ProposalRoute()) + suite.Require().Equal("ToggleTokenConversion", (&ToggleTokenConversionProposal{}).ProposalType()) +} + +func (suite *ProposalTestSuite) TestCreateDenomDescription() { + testCases := []struct { + name string + denom string + expString string + }{ + { + "with valid address", + "0xdac17f958d2ee523a2206206994597c13d831ec7", + "Cosmos coin token representation of 0xdac17f958d2ee523a2206206994597c13d831ec7", + }, + { + "with empty string", + "", + "Cosmos coin token representation of ", + }, + } + for _, tc := range testCases { + desc := CreateDenomDescription(tc.denom) + suite.Require().Equal(desc, tc.expString) + } +} + +func (suite *ProposalTestSuite) TestCreateDenom() { + testCases := []struct { + name string + denom string + expString string + }{ + { + "with valid address", + "0xdac17f958d2ee523a2206206994597c13d831ec7", + "erc20/0xdac17f958d2ee523a2206206994597c13d831ec7", + }, + { + "with empty string", + "", + "erc20/", + }, + } + for _, tc := range testCases { + desc := CreateDenom(tc.denom) + suite.Require().Equal(desc, tc.expString) + } +} + +func (suite *ProposalTestSuite) TestValidateErc20Denom() { + testCases := []struct { + name string + denom string + expPass bool + }{ + { + "- instead of /", + "erc20-0xdac17f958d2ee523a2206206994597c13d831ec7", + false, + }, + { + "without /", + "conversionCoin", + false, + }, + { + "// instead of /", + "erc20//0xdac17f958d2ee523a2206206994597c13d831ec7", + false, + }, + { + "multiple /", + "erc20/0xdac17f958d2ee523a2206206994597c13d831ec7/test", + false, + }, + { + "pass", + "erc20/0xdac17f958d2ee523a2206206994597c13d831ec7", + true, + }, + } + for _, tc := range testCases { + err := ValidateErc20Denom(tc.denom) + + if tc.expPass { + suite.Require().Nil(err, tc.name) + } else { + suite.Require().Error(err, tc.name) + } + } +} + +func (suite *ProposalTestSuite) TestRegisterERC20Proposal() { + testCases := []struct { + msg string + title string + description string + pair TokenPair + expectPass bool + }{ + // Valid tests + {msg: "Register token pair - valid pair enabled", title: "test", description: "test desc", pair: TokenPair{tests.GenerateAddress().String(), "test", true, OWNER_MODULE}, expectPass: true}, + {msg: "Register token pair - valid pair dissabled", title: "test", description: "test desc", pair: TokenPair{tests.GenerateAddress().String(), "test", false, OWNER_MODULE}, expectPass: true}, + // Missing params valid + {msg: "Register token pair - invalid missing title ", title: "", description: "test desc", pair: TokenPair{tests.GenerateAddress().String(), "test", false, OWNER_MODULE}, expectPass: false}, + {msg: "Register token pair - invalid missing description ", title: "test", description: "", pair: TokenPair{tests.GenerateAddress().String(), "test", false, OWNER_MODULE}, expectPass: false}, + // Invalid address + {msg: "Register token pair - invalid address (no hex)", title: "test", description: "test desc", pair: TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19ZZ", "test", true, OWNER_MODULE}, expectPass: false}, + {msg: "Register token pair - invalid address (invalid length 1)", title: "test", description: "test desc", pair: TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19", "test", true, OWNER_MODULE}, expectPass: false}, + {msg: "Register token pair - invalid address (invalid length 2)", title: "test", description: "test desc", pair: TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb194FFF", "test", true, OWNER_MODULE}, expectPass: false}, + {msg: "Register token pair - invalid address (invalid prefix)", title: "test", description: "test desc", pair: TokenPair{"1x5dCA2483280D9727c80b5518faC4556617fb19F", "test", true, OWNER_MODULE}, expectPass: false}, + } + + for i, tc := range testCases { + tx := NewRegisterERC20Proposal(tc.title, tc.description, tc.pair.Erc20Address) + err := tx.ValidateBasic() + + if tc.expectPass { + suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg) + } + } +} + +func createFullMetadata(denom, symbol, name string) banktypes.Metadata { + return banktypes.Metadata{ + Description: "desc", + Base: denom, + // NOTE: Denom units MUST be increasing + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: denom, + Exponent: 0, + }, + { + Denom: symbol, + Exponent: uint32(18), + }, + }, + Name: name, + Symbol: symbol, + Display: denom, + } +} + +func createMetadata(denom, symbol string) banktypes.Metadata { + return createFullMetadata(denom, symbol, denom) +} + +func (suite *ProposalTestSuite) TestRegisterCoinProposal() { + validMetadata := banktypes.Metadata{ + Description: "desc", + Base: "coin", + // NOTE: Denom units MUST be increasing + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "coin", + Exponent: 0, + }, + { + Denom: "coin2", + Exponent: uint32(18), + }, + }, + Name: "coin", + Symbol: "token", + Display: "coin", + } + + validIBCDenom := "ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2" + validIBCSymbol := "ATOM" + validIBCName := "Atom" + + testCases := []struct { + msg string + title string + description string + metadata banktypes.Metadata + expectPass bool + }{ + // Valid tests + {msg: "Register token pair - valid pair enabled", title: "test", description: "test desc", metadata: validMetadata, expectPass: true}, + {msg: "Register token pair - valid pair dissabled", title: "test", description: "test desc", metadata: validMetadata, expectPass: true}, + + // Invalid Regex (denom) + {msg: "Register token pair - invalid starts with number", title: "test", description: "test desc", metadata: createMetadata("1test", "test"), expectPass: false}, + {msg: "Register token pair - invalid char '('", title: "test", description: "test desc", metadata: createMetadata("(test", "test"), expectPass: false}, + {msg: "Register token pair - invalid char '^'", title: "test", description: "test desc", metadata: createMetadata("^test", "test"), expectPass: false}, + // Invalid length + {msg: "Register token pair - invalid length token (0)", title: "test", description: "test desc", metadata: createMetadata("", "test"), expectPass: false}, + {msg: "Register token pair - invalid length token (1)", title: "test", description: "test desc", metadata: createMetadata("a", "test"), expectPass: false}, + {msg: "Register token pair - invalid length token (128)", title: "test", description: "test desc", metadata: createMetadata(strings.Repeat("a", 129), "test"), expectPass: false}, + {msg: "Register token pair - invalid length title (140)", title: strings.Repeat("a", govv1beta1.MaxTitleLength+1), description: "test desc", metadata: validMetadata, expectPass: false}, + {msg: "Register token pair - invalid length description (5000)", title: "title", description: strings.Repeat("a", govv1beta1.MaxDescriptionLength+1), metadata: validMetadata, expectPass: false}, + + // Ibc + {msg: "Register token pair - ibc", title: "test", description: "test desc", metadata: createFullMetadata(validIBCDenom, validIBCSymbol, validIBCName), expectPass: true}, + {msg: "Register token pair - ibc invalid denom", title: "test", description: "test desc", metadata: createFullMetadata("ibc/", validIBCSymbol, validIBCName), expectPass: false}, + } + + for i, tc := range testCases { + tx := NewRegisterCoinProposal(tc.title, tc.description, tc.metadata) + err := tx.ValidateBasic() + + if tc.expectPass { + suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg) + } + } +} + +func (suite *ProposalTestSuite) TestToggleTokenConversionProposal() { + testCases := []struct { + msg string + title string + description string + token string + expectPass bool + }{ + {msg: "Enable token conversion proposal - valid denom", title: "test", description: "test desc", token: "test", expectPass: true}, + {msg: "Enable token conversion proposal - valid address", title: "test", description: "test desc", token: "0x5dCA2483280D9727c80b5518faC4556617fb194F", expectPass: true}, + {msg: "Enable token conversion proposal - invalid address", title: "test", description: "test desc", token: "0x123", expectPass: false}, + + // Invalid missing params + {msg: "Enable token conversion proposal - valid missing title", title: "", description: "test desc", token: "test", expectPass: false}, + {msg: "Enable token conversion proposal - valid missing description", title: "test", description: "", token: "test", expectPass: false}, + {msg: "Enable token conversion proposal - invalid missing token", title: "test", description: "test desc", token: "", expectPass: false}, + + // Invalid regex + {msg: "Enable token conversion proposal - invalid denom", title: "test", description: "test desc", token: "^test", expectPass: false}, + // Invalid length + {msg: "Enable token conversion proposal - invalid length (1)", title: "test", description: "test desc", token: "a", expectPass: false}, + {msg: "Enable token conversion proposal - invalid length (128)", title: "test", description: "test desc", token: strings.Repeat("a", 129), expectPass: false}, + + {msg: "Enable token conversion proposal - invalid length title (140)", title: strings.Repeat("a", govv1beta1.MaxTitleLength+1), description: "test desc", token: "test", expectPass: false}, + {msg: "Enable token conversion proposal - invalid length description (5000)", title: "title", description: strings.Repeat("a", govv1beta1.MaxDescriptionLength+1), token: "test", expectPass: false}, + } + + for i, tc := range testCases { + tx := NewToggleTokenConversionProposal(tc.title, tc.description, tc.token) + err := tx.ValidateBasic() + + if tc.expectPass { + suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg) + } + } +} diff --git a/x/erc20/types/query.pb.go b/x/erc20/types/query.pb.go new file mode 100644 index 00000000..8ecfcfc1 --- /dev/null +++ b/x/erc20/types/query.pb.go @@ -0,0 +1,1399 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: canto/erc20/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + query "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/gogo/protobuf/gogoproto" + 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 + +// QueryTokenPairsRequest is the request type for the Query/TokenPairs RPC +// method. +type QueryTokenPairsRequest struct { + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryTokenPairsRequest) Reset() { *m = QueryTokenPairsRequest{} } +func (m *QueryTokenPairsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTokenPairsRequest) ProtoMessage() {} +func (*QueryTokenPairsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a1d7327008f799c8, []int{0} +} +func (m *QueryTokenPairsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTokenPairsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTokenPairsRequest.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 *QueryTokenPairsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTokenPairsRequest.Merge(m, src) +} +func (m *QueryTokenPairsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTokenPairsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTokenPairsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTokenPairsRequest proto.InternalMessageInfo + +func (m *QueryTokenPairsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryTokenPairsResponse is the response type for the Query/TokenPairs RPC +// method. +type QueryTokenPairsResponse struct { + TokenPairs []TokenPair `protobuf:"bytes,1,rep,name=token_pairs,json=tokenPairs,proto3" json:"token_pairs"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryTokenPairsResponse) Reset() { *m = QueryTokenPairsResponse{} } +func (m *QueryTokenPairsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTokenPairsResponse) ProtoMessage() {} +func (*QueryTokenPairsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a1d7327008f799c8, []int{1} +} +func (m *QueryTokenPairsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTokenPairsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTokenPairsResponse.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 *QueryTokenPairsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTokenPairsResponse.Merge(m, src) +} +func (m *QueryTokenPairsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTokenPairsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTokenPairsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTokenPairsResponse proto.InternalMessageInfo + +func (m *QueryTokenPairsResponse) GetTokenPairs() []TokenPair { + if m != nil { + return m.TokenPairs + } + return nil +} + +func (m *QueryTokenPairsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryTokenPairRequest is the request type for the Query/TokenPair RPC method. +type QueryTokenPairRequest struct { + // token identifier can be either the hex contract address of the ERC20 or the + // Cosmos base denomination + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` +} + +func (m *QueryTokenPairRequest) Reset() { *m = QueryTokenPairRequest{} } +func (m *QueryTokenPairRequest) String() string { return proto.CompactTextString(m) } +func (*QueryTokenPairRequest) ProtoMessage() {} +func (*QueryTokenPairRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a1d7327008f799c8, []int{2} +} +func (m *QueryTokenPairRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTokenPairRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTokenPairRequest.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 *QueryTokenPairRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTokenPairRequest.Merge(m, src) +} +func (m *QueryTokenPairRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryTokenPairRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTokenPairRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTokenPairRequest proto.InternalMessageInfo + +func (m *QueryTokenPairRequest) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +// QueryTokenPairResponse is the response type for the Query/TokenPair RPC +// method. +type QueryTokenPairResponse struct { + TokenPair TokenPair `protobuf:"bytes,1,opt,name=token_pair,json=tokenPair,proto3" json:"token_pair"` +} + +func (m *QueryTokenPairResponse) Reset() { *m = QueryTokenPairResponse{} } +func (m *QueryTokenPairResponse) String() string { return proto.CompactTextString(m) } +func (*QueryTokenPairResponse) ProtoMessage() {} +func (*QueryTokenPairResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a1d7327008f799c8, []int{3} +} +func (m *QueryTokenPairResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryTokenPairResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryTokenPairResponse.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 *QueryTokenPairResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryTokenPairResponse.Merge(m, src) +} +func (m *QueryTokenPairResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryTokenPairResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryTokenPairResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryTokenPairResponse proto.InternalMessageInfo + +func (m *QueryTokenPairResponse) GetTokenPair() TokenPair { + if m != nil { + return m.TokenPair + } + return TokenPair{} +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_a1d7327008f799c8, []int{4} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.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 *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response type for the Query/Params RPC +// method. +type QueryParamsResponse struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a1d7327008f799c8, []int{5} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.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 *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*QueryTokenPairsRequest)(nil), "canto.erc20.v1.QueryTokenPairsRequest") + proto.RegisterType((*QueryTokenPairsResponse)(nil), "canto.erc20.v1.QueryTokenPairsResponse") + proto.RegisterType((*QueryTokenPairRequest)(nil), "canto.erc20.v1.QueryTokenPairRequest") + proto.RegisterType((*QueryTokenPairResponse)(nil), "canto.erc20.v1.QueryTokenPairResponse") + proto.RegisterType((*QueryParamsRequest)(nil), "canto.erc20.v1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "canto.erc20.v1.QueryParamsResponse") +} + +func init() { proto.RegisterFile("canto/erc20/v1/query.proto", fileDescriptor_a1d7327008f799c8) } + +var fileDescriptor_a1d7327008f799c8 = []byte{ + // 511 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x53, 0x4f, 0x6b, 0x13, 0x41, + 0x14, 0xcf, 0xb4, 0x36, 0x90, 0x17, 0xf0, 0x30, 0xc6, 0x18, 0x57, 0x5d, 0xcb, 0x86, 0xa6, 0x45, + 0xe9, 0x8c, 0x59, 0x3d, 0x8b, 0x54, 0x50, 0x44, 0x90, 0x18, 0x3c, 0x88, 0x17, 0x9d, 0x84, 0x61, + 0x5d, 0x6a, 0x66, 0x36, 0x3b, 0x93, 0x68, 0x11, 0x2f, 0xbd, 0x88, 0x37, 0xc1, 0xaf, 0xe0, 0x87, + 0xe9, 0xb1, 0xe0, 0xc5, 0x93, 0x48, 0xe2, 0x07, 0x91, 0x9d, 0x99, 0x6c, 0xba, 0xdb, 0x92, 0xdc, + 0x76, 0xde, 0xbc, 0xdf, 0xbf, 0xf7, 0x66, 0xc1, 0x1b, 0x32, 0xa1, 0x25, 0xe5, 0xe9, 0x30, 0xbc, + 0x47, 0xa7, 0x5d, 0x3a, 0x9e, 0xf0, 0xf4, 0x88, 0x24, 0xa9, 0xd4, 0x12, 0x5f, 0x36, 0x77, 0xc4, + 0xdc, 0x91, 0x69, 0xd7, 0xbb, 0x33, 0x94, 0x6a, 0x24, 0x15, 0x1d, 0x30, 0xc5, 0x6d, 0x23, 0x9d, + 0x76, 0x07, 0x5c, 0xb3, 0x2e, 0x4d, 0x58, 0x14, 0x0b, 0xa6, 0x63, 0x29, 0x2c, 0xd6, 0xbb, 0x59, + 0xe2, 0x8d, 0xb8, 0xe0, 0x2a, 0x56, 0xee, 0xb6, 0xac, 0x6a, 0x25, 0x1c, 0x32, 0x92, 0x32, 0xfa, + 0xc0, 0x29, 0x4b, 0x62, 0xca, 0x84, 0x90, 0xda, 0xd0, 0x2e, 0x90, 0x8d, 0x48, 0x46, 0xd2, 0x7c, + 0xd2, 0xec, 0xcb, 0x56, 0x83, 0x77, 0xd0, 0x7c, 0x99, 0xf9, 0x79, 0x25, 0x0f, 0xb9, 0xe8, 0xb1, + 0x38, 0x55, 0x7d, 0x3e, 0x9e, 0x70, 0xa5, 0xf1, 0x13, 0x80, 0xa5, 0xb7, 0x16, 0xda, 0x46, 0x7b, + 0xf5, 0xb0, 0x43, 0x6c, 0x10, 0x92, 0x05, 0x21, 0x36, 0xb1, 0x0b, 0x42, 0x7a, 0x2c, 0xe2, 0x0e, + 0xdb, 0x3f, 0x83, 0x0c, 0x7e, 0x22, 0xb8, 0x76, 0x4e, 0x42, 0x25, 0x52, 0x28, 0x8e, 0x1f, 0x41, + 0x5d, 0x67, 0xd5, 0xb7, 0x49, 0x56, 0x6e, 0xa1, 0xed, 0xcd, 0xbd, 0x7a, 0x78, 0x9d, 0x14, 0xa7, + 0x47, 0x72, 0xe0, 0xc1, 0xa5, 0x93, 0x3f, 0xb7, 0x2b, 0x7d, 0xd0, 0x39, 0x13, 0x7e, 0x5a, 0x70, + 0xb9, 0x61, 0x5c, 0xee, 0xae, 0x75, 0x69, 0xe5, 0x0b, 0x36, 0xf7, 0xe1, 0x6a, 0xd1, 0xe5, 0x62, + 0x0e, 0x0d, 0xd8, 0x32, 0x7a, 0x66, 0x04, 0xb5, 0xbe, 0x3d, 0x04, 0xaf, 0xcb, 0x73, 0xcb, 0x33, + 0x3d, 0x04, 0x58, 0x66, 0x72, 0x73, 0x5b, 0x1b, 0xa9, 0x96, 0x47, 0x0a, 0x1a, 0x80, 0x0d, 0x73, + 0x8f, 0xa5, 0x6c, 0xb4, 0xd8, 0x46, 0xf0, 0x1c, 0xae, 0x14, 0xaa, 0x4e, 0xec, 0x01, 0x54, 0x13, + 0x53, 0x71, 0x42, 0xcd, 0xb2, 0x90, 0xed, 0x77, 0x2a, 0xae, 0x37, 0xfc, 0xb6, 0x09, 0x5b, 0x86, + 0x0d, 0x1f, 0x23, 0x80, 0xe5, 0x5e, 0x70, 0xa7, 0x0c, 0xbf, 0xf8, 0x6d, 0x78, 0xbb, 0x6b, 0xfb, + 0xac, 0xbf, 0xa0, 0x7d, 0xfc, 0xeb, 0xdf, 0x8f, 0x8d, 0x5b, 0xf8, 0x06, 0x2d, 0xbd, 0xdb, 0x33, + 0x6b, 0xc7, 0x5f, 0x11, 0xd4, 0x72, 0x2c, 0xde, 0x59, 0xcd, 0xbd, 0xb0, 0xd0, 0x59, 0xd7, 0xe6, + 0x1c, 0xdc, 0x35, 0x0e, 0x76, 0x70, 0x7b, 0x85, 0x03, 0xfa, 0xd9, 0x1c, 0xbe, 0xe0, 0x31, 0x54, + 0xed, 0xc0, 0x70, 0x70, 0x21, 0x7d, 0x61, 0x27, 0x5e, 0x7b, 0x65, 0x8f, 0xd3, 0xf7, 0x8d, 0x7e, + 0x0b, 0x37, 0xcb, 0xfa, 0x76, 0x17, 0x07, 0xcf, 0x4e, 0x66, 0x3e, 0x3a, 0x9d, 0xf9, 0xe8, 0xef, + 0xcc, 0x47, 0xdf, 0xe7, 0x7e, 0xe5, 0x74, 0xee, 0x57, 0x7e, 0xcf, 0xfd, 0xca, 0x1b, 0x1a, 0xc5, + 0xfa, 0xfd, 0x64, 0x40, 0x86, 0x72, 0x44, 0x1f, 0x67, 0xd8, 0xfd, 0x17, 0x5c, 0x7f, 0x94, 0xe9, + 0xa1, 0x3d, 0xd1, 0x69, 0x48, 0x3f, 0x39, 0x3a, 0x7d, 0x94, 0x70, 0x35, 0xa8, 0x9a, 0x5f, 0xfa, + 0xfe, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xca, 0x31, 0xa5, 0x0a, 0x9a, 0x04, 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 { + // TokenPairs retrieves registered token pairs + TokenPairs(ctx context.Context, in *QueryTokenPairsRequest, opts ...grpc.CallOption) (*QueryTokenPairsResponse, error) + // TokenPair retrieves a registered token pair + TokenPair(ctx context.Context, in *QueryTokenPairRequest, opts ...grpc.CallOption) (*QueryTokenPairResponse, error) + // Params retrieves the erc20 module params + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) TokenPairs(ctx context.Context, in *QueryTokenPairsRequest, opts ...grpc.CallOption) (*QueryTokenPairsResponse, error) { + out := new(QueryTokenPairsResponse) + err := c.cc.Invoke(ctx, "/canto.erc20.v1.Query/TokenPairs", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) TokenPair(ctx context.Context, in *QueryTokenPairRequest, opts ...grpc.CallOption) (*QueryTokenPairResponse, error) { + out := new(QueryTokenPairResponse) + err := c.cc.Invoke(ctx, "/canto.erc20.v1.Query/TokenPair", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/canto.erc20.v1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // TokenPairs retrieves registered token pairs + TokenPairs(context.Context, *QueryTokenPairsRequest) (*QueryTokenPairsResponse, error) + // TokenPair retrieves a registered token pair + TokenPair(context.Context, *QueryTokenPairRequest) (*QueryTokenPairResponse, error) + // Params retrieves the erc20 module params + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) TokenPairs(ctx context.Context, req *QueryTokenPairsRequest) (*QueryTokenPairsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TokenPairs not implemented") +} +func (*UnimplementedQueryServer) TokenPair(ctx context.Context, req *QueryTokenPairRequest) (*QueryTokenPairResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TokenPair not implemented") +} +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_TokenPairs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTokenPairsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TokenPairs(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/canto.erc20.v1.Query/TokenPairs", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TokenPairs(ctx, req.(*QueryTokenPairsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_TokenPair_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryTokenPairRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).TokenPair(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/canto.erc20.v1.Query/TokenPair", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).TokenPair(ctx, req.(*QueryTokenPairRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/canto.erc20.v1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "canto.erc20.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "TokenPairs", + Handler: _Query_TokenPairs_Handler, + }, + { + MethodName: "TokenPair", + Handler: _Query_TokenPair_Handler, + }, + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "canto/erc20/v1/query.proto", +} + +func (m *QueryTokenPairsRequest) 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 *QueryTokenPairsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTokenPairsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryTokenPairsResponse) 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 *QueryTokenPairsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTokenPairsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.TokenPairs) > 0 { + for iNdEx := len(m.TokenPairs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TokenPairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryTokenPairRequest) 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 *QueryTokenPairRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTokenPairRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Token) > 0 { + i -= len(m.Token) + copy(dAtA[i:], m.Token) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Token))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryTokenPairResponse) 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 *QueryTokenPairResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryTokenPairResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.TokenPair.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryParamsRequest) 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 *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) 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 *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + 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 *QueryTokenPairsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryTokenPairsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TokenPairs) > 0 { + for _, e := range m.TokenPairs { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryTokenPairRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Token) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryTokenPairResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.TokenPair.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + 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 *QueryTokenPairsRequest) 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: QueryTokenPairsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTokenPairsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + 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 *QueryTokenPairsResponse) 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: QueryTokenPairsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTokenPairsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenPairs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenPairs = append(m.TokenPairs, TokenPair{}) + if err := m.TokenPairs[len(m.TokenPairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + 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 *QueryTokenPairRequest) 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: QueryTokenPairRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTokenPairRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + 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 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.Token = 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 *QueryTokenPairResponse) 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: QueryTokenPairResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryTokenPairResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenPair", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TokenPair.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + 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 *QueryParamsRequest) 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: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + 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 *QueryParamsResponse) 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: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: 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 ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := 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/erc20/types/query.pb.gw.go b/x/erc20/types/query.pb.gw.go new file mode 100644 index 00000000..586ccbf0 --- /dev/null +++ b/x/erc20/types/query.pb.gw.go @@ -0,0 +1,337 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: canto/erc20/v1/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_TokenPairs_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_TokenPairs_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTokenPairsRequest + 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_TokenPairs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.TokenPairs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TokenPairs_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTokenPairsRequest + 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_TokenPairs_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.TokenPairs(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_TokenPair_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTokenPairRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["token"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "token") + } + + protoReq.Token, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "token", err) + } + + msg, err := client.TokenPair(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_TokenPair_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryTokenPairRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["token"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "token") + } + + protoReq.Token, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "token", err) + } + + msg, err := server.TokenPair(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(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_TokenPairs_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_TokenPairs_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_TokenPairs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TokenPair_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_TokenPair_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_TokenPair_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Params_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_Params_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_Params_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_TokenPairs_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_TokenPairs_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_TokenPairs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_TokenPair_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_TokenPair_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_TokenPair_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Params_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_Params_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_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_TokenPairs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"canto", "erc20", "v1", "token_pairs"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_TokenPair_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"canto", "erc20", "v1", "token_pairs", "token"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"canto", "erc20", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Query_TokenPairs_0 = runtime.ForwardResponseMessage + + forward_Query_TokenPair_0 = runtime.ForwardResponseMessage + + forward_Query_Params_0 = runtime.ForwardResponseMessage +) diff --git a/x/erc20/types/token_pair.go b/x/erc20/types/token_pair.go new file mode 100644 index 00000000..2fcb5fe3 --- /dev/null +++ b/x/erc20/types/token_pair.go @@ -0,0 +1,54 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + ethermint "github.com/evmos/ethermint/types" + "github.com/tendermint/tendermint/crypto/tmhash" +) + +// NewTokenPair returns an instance of TokenPair +func NewTokenPair(erc20Address common.Address, denom string, enabled bool, contractOwner Owner) TokenPair { + return TokenPair{ + Erc20Address: erc20Address.String(), + Denom: denom, + Enabled: true, + ContractOwner: contractOwner, + } +} + +// GetID returns the SHA256 hash of the ERC20 address and denomination +func (tp TokenPair) GetID() []byte { + id := tp.Erc20Address + "|" + tp.Denom + return tmhash.Sum([]byte(id)) +} + +// GetErc20Contract casts the hex string address of the ERC20 to common.Address +func (tp TokenPair) GetERC20Contract() common.Address { + return common.HexToAddress(tp.Erc20Address) +} + +// Validate performs a stateless validation of a TokenPair +func (tp TokenPair) Validate() error { + if err := sdk.ValidateDenom(tp.Denom); err != nil { + return err + } + + if err := ethermint.ValidateAddress(tp.Erc20Address); err != nil { + return err + } + + return nil +} + +// IsNativeCoin returns true if the owner of the ERC20 contract is the +// erc20 module account +func (tp TokenPair) IsNativeCoin() bool { + return tp.ContractOwner == OWNER_MODULE +} + +// IsNativeERC20 returns true if the owner of the ERC20 contract not the +// erc20 module account +func (tp TokenPair) IsNativeERC20() bool { + return tp.ContractOwner == OWNER_EXTERNAL +} diff --git a/x/erc20/types/token_pair_test.go b/x/erc20/types/token_pair_test.go new file mode 100644 index 00000000..42358196 --- /dev/null +++ b/x/erc20/types/token_pair_test.go @@ -0,0 +1,159 @@ +package types + +import ( + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/suite" + "github.com/tendermint/tendermint/crypto/tmhash" + + "github.com/evmos/ethermint/tests" +) + +type TokenPairTestSuite struct { + suite.Suite +} + +func TestTokenPairSuite(t *testing.T) { + suite.Run(t, new(TokenPairTestSuite)) +} + +func (suite *TokenPairTestSuite) TestTokenPairNew() { + testCases := []struct { + msg string + erc20Address common.Address + denom string + enabled bool + owner Owner + expectPass bool + }{ + {msg: "Register token pair - invalid starts with number", erc20Address: tests.GenerateAddress(), denom: "1test", enabled: true, owner: OWNER_MODULE, expectPass: false}, + {msg: "Register token pair - invalid char '('", erc20Address: tests.GenerateAddress(), denom: "(test", enabled: true, owner: OWNER_MODULE, expectPass: false}, + {msg: "Register token pair - invalid char '^'", erc20Address: tests.GenerateAddress(), denom: "^test", enabled: true, owner: OWNER_MODULE, expectPass: false}, + // TODO: (guille) should the "\" be allowed to support unicode names? + {msg: "Register token pair - invalid char '\\'", erc20Address: tests.GenerateAddress(), denom: "-test", enabled: true, owner: OWNER_MODULE, expectPass: false}, + // Invalid length + {msg: "Register token pair - invalid length token (0)", erc20Address: tests.GenerateAddress(), denom: "", enabled: true, owner: OWNER_MODULE, expectPass: false}, + {msg: "Register token pair - invalid length token (1)", erc20Address: tests.GenerateAddress(), denom: "a", enabled: true, owner: OWNER_MODULE, expectPass: false}, + {msg: "Register token pair - invalid length token (128)", erc20Address: tests.GenerateAddress(), denom: strings.Repeat("a", 129), enabled: true, owner: OWNER_MODULE, expectPass: false}, + {msg: "Register token pair - pass", erc20Address: tests.GenerateAddress(), denom: "test", enabled: true, owner: OWNER_MODULE, expectPass: true}, + } + + for i, tc := range testCases { + tp := NewTokenPair(tc.erc20Address, tc.denom, tc.enabled, tc.owner) + err := tp.Validate() + + if tc.expectPass { + suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg) + } + } +} + +func (suite *TokenPairTestSuite) TestTokenPair() { + testCases := []struct { + msg string + pair TokenPair + expectPass bool + }{ + {msg: "Register token pair - invalid address (no hex)", pair: TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19ZZ", "test", true, OWNER_MODULE}, expectPass: false}, + {msg: "Register token pair - invalid address (invalid length 1)", pair: TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb19", "test", true, OWNER_MODULE}, expectPass: false}, + {msg: "Register token pair - invalid address (invalid length 2)", pair: TokenPair{"0x5dCA2483280D9727c80b5518faC4556617fb194FFF", "test", true, OWNER_MODULE}, expectPass: false}, + {msg: "pass", pair: TokenPair{tests.GenerateAddress().String(), "test", true, OWNER_MODULE}, expectPass: true}, + } + + for i, tc := range testCases { + err := tc.pair.Validate() + + if tc.expectPass { + suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg) + } else { + suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg) + } + } +} + +func (suite *TokenPairTestSuite) TestGetID() { + addr := tests.GenerateAddress() + denom := "test" + pair := NewTokenPair(addr, denom, true, OWNER_MODULE) + id := pair.GetID() + expID := tmhash.Sum([]byte(addr.String() + "|" + denom)) + suite.Require().Equal(expID, id) +} + +func (suite *TokenPairTestSuite) TestGetERC20Contract() { + expAddr := tests.GenerateAddress() + denom := "test" + pair := NewTokenPair(expAddr, denom, true, OWNER_MODULE) + addr := pair.GetERC20Contract() + suite.Require().Equal(expAddr, addr) +} + +func (suite *TokenPairTestSuite) TestIsNativeCoin() { + testCases := []struct { + name string + pair TokenPair + expectPass bool + }{ + { + "no owner", + TokenPair{tests.GenerateAddress().String(), "test", true, OWNER_UNSPECIFIED}, + false, + }, + { + "external ERC20 owner", + TokenPair{tests.GenerateAddress().String(), "test", true, OWNER_EXTERNAL}, + false, + }, + { + "pass", + TokenPair{tests.GenerateAddress().String(), "test", true, OWNER_MODULE}, + true, + }, + } + + for _, tc := range testCases { + res := tc.pair.IsNativeCoin() + if tc.expectPass { + suite.Require().True(res, tc.name) + } else { + suite.Require().False(res, tc.name) + } + } +} + +func (suite *TokenPairTestSuite) TestIsNativeERC20() { + testCases := []struct { + name string + pair TokenPair + expectPass bool + }{ + { + "no owner", + TokenPair{tests.GenerateAddress().String(), "test", true, OWNER_UNSPECIFIED}, + false, + }, + { + "module owner", + TokenPair{tests.GenerateAddress().String(), "test", true, OWNER_MODULE}, + false, + }, + { + "pass", + TokenPair{tests.GenerateAddress().String(), "test", true, OWNER_EXTERNAL}, + true, + }, + } + + for _, tc := range testCases { + res := tc.pair.IsNativeERC20() + if tc.expectPass { + suite.Require().True(res, tc.name) + } else { + suite.Require().False(res, tc.name) + } + } +} diff --git a/x/erc20/types/tx.pb.go b/x/erc20/types/tx.pb.go new file mode 100644 index 00000000..6e410e2b --- /dev/null +++ b/x/erc20/types/tx.pb.go @@ -0,0 +1,1140 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: canto/erc20/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + 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 + +// MsgConvertCoin defines a Msg to convert a native Cosmos coin to a ERC20 token +type MsgConvertCoin struct { + // Cosmos coin which denomination is registered in a token pair. The coin + // amount defines the amount of coins to convert. + Coin types.Coin `protobuf:"bytes,1,opt,name=coin,proto3" json:"coin"` + // recipient hex address to receive ERC20 token + Receiver string `protobuf:"bytes,2,opt,name=receiver,proto3" json:"receiver,omitempty"` + // cosmos bech32 address from the owner of the given Cosmos coins + Sender string `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"` +} + +func (m *MsgConvertCoin) Reset() { *m = MsgConvertCoin{} } +func (m *MsgConvertCoin) String() string { return proto.CompactTextString(m) } +func (*MsgConvertCoin) ProtoMessage() {} +func (*MsgConvertCoin) Descriptor() ([]byte, []int) { + return fileDescriptor_3cff33f93a8dd3e5, []int{0} +} +func (m *MsgConvertCoin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConvertCoin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConvertCoin.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 *MsgConvertCoin) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConvertCoin.Merge(m, src) +} +func (m *MsgConvertCoin) XXX_Size() int { + return m.Size() +} +func (m *MsgConvertCoin) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConvertCoin.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConvertCoin proto.InternalMessageInfo + +func (m *MsgConvertCoin) GetCoin() types.Coin { + if m != nil { + return m.Coin + } + return types.Coin{} +} + +func (m *MsgConvertCoin) GetReceiver() string { + if m != nil { + return m.Receiver + } + return "" +} + +func (m *MsgConvertCoin) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +// MsgConvertCoinResponse returns no fields +type MsgConvertCoinResponse struct { +} + +func (m *MsgConvertCoinResponse) Reset() { *m = MsgConvertCoinResponse{} } +func (m *MsgConvertCoinResponse) String() string { return proto.CompactTextString(m) } +func (*MsgConvertCoinResponse) ProtoMessage() {} +func (*MsgConvertCoinResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_3cff33f93a8dd3e5, []int{1} +} +func (m *MsgConvertCoinResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConvertCoinResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConvertCoinResponse.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 *MsgConvertCoinResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConvertCoinResponse.Merge(m, src) +} +func (m *MsgConvertCoinResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgConvertCoinResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConvertCoinResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConvertCoinResponse proto.InternalMessageInfo + +// MsgConvertERC20 defines a Msg to convert a ERC20 token to a native Cosmos +// coin. +type MsgConvertERC20 struct { + // ERC20 token contract address registered in a token pair + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // amount of ERC20 tokens to convert + Amount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount"` + // bech32 address to receive native Cosmos coins + Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` + // sender hex address from the owner of the given ERC20 tokens + Sender string `protobuf:"bytes,4,opt,name=sender,proto3" json:"sender,omitempty"` +} + +func (m *MsgConvertERC20) Reset() { *m = MsgConvertERC20{} } +func (m *MsgConvertERC20) String() string { return proto.CompactTextString(m) } +func (*MsgConvertERC20) ProtoMessage() {} +func (*MsgConvertERC20) Descriptor() ([]byte, []int) { + return fileDescriptor_3cff33f93a8dd3e5, []int{2} +} +func (m *MsgConvertERC20) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConvertERC20) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConvertERC20.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 *MsgConvertERC20) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConvertERC20.Merge(m, src) +} +func (m *MsgConvertERC20) XXX_Size() int { + return m.Size() +} +func (m *MsgConvertERC20) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConvertERC20.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConvertERC20 proto.InternalMessageInfo + +func (m *MsgConvertERC20) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *MsgConvertERC20) GetReceiver() string { + if m != nil { + return m.Receiver + } + return "" +} + +func (m *MsgConvertERC20) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +// MsgConvertERC20Response returns no fields +type MsgConvertERC20Response struct { +} + +func (m *MsgConvertERC20Response) Reset() { *m = MsgConvertERC20Response{} } +func (m *MsgConvertERC20Response) String() string { return proto.CompactTextString(m) } +func (*MsgConvertERC20Response) ProtoMessage() {} +func (*MsgConvertERC20Response) Descriptor() ([]byte, []int) { + return fileDescriptor_3cff33f93a8dd3e5, []int{3} +} +func (m *MsgConvertERC20Response) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgConvertERC20Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgConvertERC20Response.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 *MsgConvertERC20Response) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgConvertERC20Response.Merge(m, src) +} +func (m *MsgConvertERC20Response) XXX_Size() int { + return m.Size() +} +func (m *MsgConvertERC20Response) XXX_DiscardUnknown() { + xxx_messageInfo_MsgConvertERC20Response.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgConvertERC20Response proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgConvertCoin)(nil), "canto.erc20.v1.MsgConvertCoin") + proto.RegisterType((*MsgConvertCoinResponse)(nil), "canto.erc20.v1.MsgConvertCoinResponse") + proto.RegisterType((*MsgConvertERC20)(nil), "canto.erc20.v1.MsgConvertERC20") + proto.RegisterType((*MsgConvertERC20Response)(nil), "canto.erc20.v1.MsgConvertERC20Response") +} + +func init() { proto.RegisterFile("canto/erc20/v1/tx.proto", fileDescriptor_3cff33f93a8dd3e5) } + +var fileDescriptor_3cff33f93a8dd3e5 = []byte{ + // 460 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x52, 0xc1, 0x6e, 0x13, 0x31, + 0x10, 0xcd, 0x26, 0x51, 0x44, 0x5d, 0xd4, 0x22, 0x0b, 0xb5, 0xe9, 0x0a, 0x6d, 0x42, 0x0e, 0x6d, + 0x38, 0xd4, 0xd3, 0x6c, 0xbf, 0x80, 0x44, 0x20, 0xf5, 0x50, 0x0e, 0x7b, 0xe4, 0x52, 0x39, 0x8e, + 0xb5, 0xac, 0x4a, 0x3c, 0x2b, 0xdb, 0x5d, 0xda, 0x0b, 0x87, 0x1e, 0x39, 0x21, 0xf1, 0x33, 0x7c, + 0x42, 0x8f, 0x95, 0xb8, 0x20, 0x0e, 0x15, 0x4a, 0xf8, 0x10, 0xb4, 0xf6, 0x36, 0x74, 0x41, 0x2d, + 0xa7, 0xf5, 0xcc, 0x7b, 0xfb, 0xfc, 0xe6, 0x8d, 0xc9, 0xb6, 0xe0, 0xca, 0x22, 0x48, 0x2d, 0xe2, + 0x03, 0x28, 0x46, 0x60, 0xcf, 0x59, 0xae, 0xd1, 0x22, 0xdd, 0x70, 0x00, 0x73, 0x00, 0x2b, 0x46, + 0xe1, 0xb3, 0x14, 0x31, 0x7d, 0x2f, 0x81, 0xe7, 0x19, 0x70, 0xa5, 0xd0, 0x72, 0x9b, 0xa1, 0x32, + 0x9e, 0x1d, 0x3e, 0x4d, 0x31, 0x45, 0x77, 0x84, 0xf2, 0x54, 0x75, 0x23, 0x81, 0x66, 0x8e, 0x06, + 0xa6, 0xdc, 0x48, 0x28, 0x46, 0x53, 0x69, 0xf9, 0x08, 0x04, 0x66, 0xca, 0xe3, 0x83, 0x0b, 0xb2, + 0x71, 0x6c, 0xd2, 0x09, 0xaa, 0x42, 0x6a, 0x3b, 0xc1, 0x4c, 0xd1, 0x43, 0xd2, 0x2e, 0xf1, 0x6e, + 0xd0, 0x0f, 0x86, 0xeb, 0xf1, 0x0e, 0xf3, 0x02, 0xac, 0x14, 0x60, 0x95, 0x00, 0x2b, 0x89, 0xe3, + 0xf6, 0xd5, 0x4d, 0xaf, 0x91, 0x38, 0x32, 0x0d, 0xc9, 0x23, 0x2d, 0x85, 0xcc, 0x0a, 0xa9, 0xbb, + 0xcd, 0x7e, 0x30, 0x5c, 0x4b, 0x56, 0x35, 0xdd, 0x22, 0x1d, 0x23, 0xd5, 0x4c, 0xea, 0x6e, 0xcb, + 0x21, 0x55, 0x35, 0xe8, 0x92, 0xad, 0xfa, 0xd5, 0x89, 0x34, 0x39, 0x2a, 0x23, 0x07, 0x5f, 0x03, + 0xb2, 0xf9, 0x07, 0x7a, 0x95, 0x4c, 0xe2, 0x03, 0xfa, 0x82, 0x3c, 0x11, 0xa8, 0xac, 0xe6, 0xc2, + 0x9e, 0xf0, 0xd9, 0x4c, 0x4b, 0x63, 0x9c, 0xc5, 0xb5, 0x64, 0xf3, 0xb6, 0xff, 0xd2, 0xb7, 0xe9, + 0x6b, 0xd2, 0xe1, 0x73, 0x3c, 0x53, 0xd6, 0x5b, 0x19, 0xb3, 0xd2, 0xe8, 0x8f, 0x9b, 0xde, 0x6e, + 0x9a, 0xd9, 0x77, 0x67, 0x53, 0x26, 0x70, 0x0e, 0x55, 0x2c, 0xfe, 0xb3, 0x6f, 0x66, 0xa7, 0x60, + 0x2f, 0x72, 0x69, 0xd8, 0x91, 0xb2, 0x49, 0xf5, 0x77, 0x6d, 0xa8, 0xd6, 0xbd, 0x43, 0xb5, 0x6b, + 0x43, 0xed, 0x90, 0xed, 0xbf, 0x9c, 0xdf, 0x4e, 0x15, 0x7f, 0x6a, 0x92, 0xd6, 0xb1, 0x49, 0xe9, + 0x47, 0xb2, 0x7e, 0x37, 0xef, 0x88, 0xd5, 0xd7, 0xcc, 0xea, 0xa1, 0x84, 0xbb, 0x0f, 0xe3, 0xab, + 0xd0, 0xf6, 0x2e, 0xbf, 0xfd, 0xfa, 0xd2, 0x7c, 0x4e, 0x7b, 0xf0, 0xcf, 0x7b, 0x02, 0xe1, 0xf9, + 0x27, 0x6e, 0x57, 0x97, 0x01, 0x79, 0x5c, 0x8b, 0xb6, 0x77, 0xff, 0x0d, 0x8e, 0x10, 0xee, 0xfd, + 0x87, 0xb0, 0xf2, 0x30, 0x74, 0x1e, 0x06, 0xb4, 0xff, 0x80, 0x07, 0xd7, 0x1b, 0x1f, 0x5d, 0x2d, + 0xa2, 0xe0, 0x7a, 0x11, 0x05, 0x3f, 0x17, 0x51, 0xf0, 0x79, 0x19, 0x35, 0xae, 0x97, 0x51, 0xe3, + 0xfb, 0x32, 0x6a, 0xbc, 0x85, 0x3b, 0x5b, 0x9a, 0x94, 0x2a, 0xfb, 0x6f, 0xa4, 0xfd, 0x80, 0xfa, + 0xd4, 0x57, 0x50, 0xc4, 0x70, 0x5e, 0x09, 0xbb, 0x95, 0x4d, 0x3b, 0xee, 0x25, 0x1f, 0xfe, 0x0e, + 0x00, 0x00, 0xff, 0xff, 0x25, 0x8c, 0x33, 0x42, 0x48, 0x03, 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 { + // ConvertCoin mints a ERC20 representation of the native Cosmos coin denom + // that is registered on the token mapping. + ConvertCoin(ctx context.Context, in *MsgConvertCoin, opts ...grpc.CallOption) (*MsgConvertCoinResponse, error) + // ConvertERC20 mints a native Cosmos coin representation of the ERC20 token + // contract that is registered on the token mapping. + ConvertERC20(ctx context.Context, in *MsgConvertERC20, opts ...grpc.CallOption) (*MsgConvertERC20Response, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) ConvertCoin(ctx context.Context, in *MsgConvertCoin, opts ...grpc.CallOption) (*MsgConvertCoinResponse, error) { + out := new(MsgConvertCoinResponse) + err := c.cc.Invoke(ctx, "/canto.erc20.v1.Msg/ConvertCoin", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ConvertERC20(ctx context.Context, in *MsgConvertERC20, opts ...grpc.CallOption) (*MsgConvertERC20Response, error) { + out := new(MsgConvertERC20Response) + err := c.cc.Invoke(ctx, "/canto.erc20.v1.Msg/ConvertERC20", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // ConvertCoin mints a ERC20 representation of the native Cosmos coin denom + // that is registered on the token mapping. + ConvertCoin(context.Context, *MsgConvertCoin) (*MsgConvertCoinResponse, error) + // ConvertERC20 mints a native Cosmos coin representation of the ERC20 token + // contract that is registered on the token mapping. + ConvertERC20(context.Context, *MsgConvertERC20) (*MsgConvertERC20Response, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) ConvertCoin(ctx context.Context, req *MsgConvertCoin) (*MsgConvertCoinResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConvertCoin not implemented") +} +func (*UnimplementedMsgServer) ConvertERC20(ctx context.Context, req *MsgConvertERC20) (*MsgConvertERC20Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method ConvertERC20 not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_ConvertCoin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgConvertCoin) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ConvertCoin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/canto.erc20.v1.Msg/ConvertCoin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ConvertCoin(ctx, req.(*MsgConvertCoin)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ConvertERC20_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgConvertERC20) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ConvertERC20(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/canto.erc20.v1.Msg/ConvertERC20", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ConvertERC20(ctx, req.(*MsgConvertERC20)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "canto.erc20.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ConvertCoin", + Handler: _Msg_ConvertCoin_Handler, + }, + { + MethodName: "ConvertERC20", + Handler: _Msg_ConvertERC20_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "canto/erc20/v1/tx.proto", +} + +func (m *MsgConvertCoin) 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 *MsgConvertCoin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConvertCoin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0x1a + } + if len(m.Receiver) > 0 { + i -= len(m.Receiver) + copy(dAtA[i:], m.Receiver) + i = encodeVarintTx(dAtA, i, uint64(len(m.Receiver))) + i-- + dAtA[i] = 0x12 + } + { + size, err := m.Coin.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 *MsgConvertCoinResponse) 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 *MsgConvertCoinResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConvertCoinResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgConvertERC20) 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 *MsgConvertERC20) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConvertERC20) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0x22 + } + if len(m.Receiver) > 0 { + i -= len(m.Receiver) + copy(dAtA[i:], m.Receiver) + i = encodeVarintTx(dAtA, i, uint64(len(m.Receiver))) + i-- + dAtA[i] = 0x1a + } + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgConvertERC20Response) 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 *MsgConvertERC20Response) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgConvertERC20Response) 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 *MsgConvertCoin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Coin.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Receiver) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgConvertCoinResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgConvertERC20) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Receiver) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgConvertERC20Response) 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 *MsgConvertCoin) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConvertCoin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConvertCoin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Coin", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Coin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConvertCoinResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConvertCoinResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConvertCoinResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConvertERC20) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConvertERC20: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConvertERC20: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + 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.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + 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 + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgConvertERC20Response) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgConvertERC20Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgConvertERC20Response: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func 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/erc20/types/tx.pb.gw.go b/x/erc20/types/tx.pb.gw.go new file mode 100644 index 00000000..8b7f2ba7 --- /dev/null +++ b/x/erc20/types/tx.pb.gw.go @@ -0,0 +1,254 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: canto/erc20/v1/tx.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_Msg_ConvertCoin_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_ConvertCoin_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgConvertCoin + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_ConvertCoin_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ConvertCoin(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_ConvertCoin_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgConvertCoin + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_ConvertCoin_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ConvertCoin(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Msg_ConvertERC20_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_ConvertERC20_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgConvertERC20 + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_ConvertERC20_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ConvertERC20(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_ConvertERC20_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgConvertERC20 + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_ConvertERC20_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ConvertERC20(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterMsgHandlerServer registers the http handlers for service Msg to "mux". +// UnaryRPC :call MsgServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMsgHandlerFromEndpoint instead. +func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MsgServer) error { + + mux.Handle("GET", pattern_Msg_ConvertCoin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Msg_ConvertCoin_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_ConvertCoin_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Msg_ConvertERC20_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Msg_ConvertERC20_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_ConvertERC20_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterMsgHandlerFromEndpoint is same as RegisterMsgHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterMsgHandlerFromEndpoint(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 RegisterMsgHandler(ctx, mux, conn) +} + +// RegisterMsgHandler registers the http handlers for service Msg to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterMsgHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterMsgHandlerClient(ctx, mux, NewMsgClient(conn)) +} + +// RegisterMsgHandlerClient registers the http handlers for service Msg +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MsgClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MsgClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "MsgClient" to call the correct interceptors. +func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MsgClient) error { + + mux.Handle("GET", pattern_Msg_ConvertCoin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Msg_ConvertCoin_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_ConvertCoin_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Msg_ConvertERC20_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Msg_ConvertERC20_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_ConvertERC20_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Msg_ConvertCoin_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"canto", "erc20", "v1", "tx", "convert_coin"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Msg_ConvertERC20_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"canto", "erc20", "v1", "tx", "convert_erc20"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Msg_ConvertCoin_0 = runtime.ForwardResponseMessage + + forward_Msg_ConvertERC20_0 = runtime.ForwardResponseMessage +) diff --git a/x/erc20/types/utils.go b/x/erc20/types/utils.go new file mode 100644 index 00000000..d3c4e304 --- /dev/null +++ b/x/erc20/types/utils.go @@ -0,0 +1,83 @@ +package types + +import ( + "fmt" + "regexp" + "strings" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +const ( + // (?m)^(\d+) remove leading numbers + reLeadingNumbers = `(?m)^(\d+)` + // ^[^A-Za-z] forces first chars to be letters + // [^a-zA-Z0-9/-] deletes special characters + reDnmString = `^[^A-Za-z]|[^a-zA-Z0-9/-]` +) + +func removeLeadingNumbers(str string) string { + re := regexp.MustCompile(reLeadingNumbers) + return re.ReplaceAllString(str, "") +} + +func removeSpecialChars(str string) string { + re := regexp.MustCompile(reDnmString) + return re.ReplaceAllString(str, "") +} + +// recursively remove every invalid prefix +func removeInvalidPrefixes(str string) string { + if strings.HasPrefix(str, "ibc/") { + return removeInvalidPrefixes(str[4:]) + } + if strings.HasPrefix(str, "erc20/") { + return removeInvalidPrefixes(str[6:]) + } + return str +} + +// SanitizeERC20Name enforces 128 max string length, deletes leading numbers +// removes special characters (except /) and spaces from the ERC20 name +func SanitizeERC20Name(name string) string { + name = removeLeadingNumbers(name) + name = removeSpecialChars(name) + if len(name) > 128 { + name = name[:128] + } + name = removeInvalidPrefixes(name) + return name +} + +// EqualMetadata checks if all the fields of the provided coin metadata are equal. +func EqualMetadata(a, b banktypes.Metadata) error { + if a.Base == b.Base && a.Description == b.Description && a.Display == b.Display && a.Name == b.Name && a.Symbol == b.Symbol { + if len(a.DenomUnits) != len(b.DenomUnits) { + return fmt.Errorf("metadata provided has different denom units from stored, %d ≠ %d", len(a.DenomUnits), len(b.DenomUnits)) + } + + for i, v := range a.DenomUnits { + if (v.Exponent != b.DenomUnits[i].Exponent) || (v.Denom != b.DenomUnits[i].Denom) || !EqualStringSlice(v.Aliases, b.DenomUnits[i].Aliases) { + return fmt.Errorf("metadata provided has different denom unit from stored, %s ≠ %s", a.DenomUnits[i], b.DenomUnits[i]) + } + } + + return nil + } + return fmt.Errorf("metadata provided is different from stored") +} + +// EqualStringSlice checks if two string slices are equal. +func EqualStringSlice(aliasesA, aliasesB []string) bool { + if len(aliasesA) != len(aliasesB) { + return false + } + + for i := 0; i < len(aliasesA); i++ { + if aliasesA[i] != aliasesB[i] { + return false + } + } + + return true +} diff --git a/x/erc20/types/utils_test.go b/x/erc20/types/utils_test.go new file mode 100644 index 00000000..4790709e --- /dev/null +++ b/x/erc20/types/utils_test.go @@ -0,0 +1,249 @@ +package types + +import ( + "strings" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/require" +) + +func TestSanitizeERC20Name(t *testing.T) { + testCases := []struct { + name string + erc20Name string + expErc20Name string + expectPass bool + }{ + {"name contains 'Special Characters'", "*Special _ []{}||*¼^% &Token", "SpecialToken", true}, + {"name contains 'Special Numbers'", "*20", "20", false}, + {"name contains 'Spaces'", " Spaces Token", "SpacesToken", true}, + {"name contains 'Leading Numbers'", "12313213 Number Coin", "NumberCoin", true}, + {"name contains 'Numbers in the middle'", " Other Erc20 Coin ", "OtherErc20Coin", true}, + {"name contains '/'", "USD/Coin", "USD/Coin", true}, + {"name contains '/'", "/SlashCoin", "SlashCoin", true}, + {"name contains '/'", "O/letter", "O/letter", true}, + {"name contains '/'", "Ot/2letters", "Ot/2letters", true}, + {"name contains '/'", "ibc/valid", "valid", true}, + {"name contains '/'", "erc20/valid", "valid", true}, + {"name contains '/'", "ibc/erc20/valid", "valid", true}, + {"name contains '/'", "ibc/erc20/ibc/valid", "valid", true}, + {"name contains '/'", "ibc/erc20/ibc/20invalid", "20invalid", false}, + {"name contains '/'", "123/leadingslash", "leadingslash", true}, + {"name contains '-'", "Dash-Coin", "Dash-Coin", true}, + {"really long word", strings.Repeat("a", 150), strings.Repeat("a", 128), true}, + {"single word name: Token", "Token", "Token", true}, + {"single word name: Coin", "Coin", "Coin", true}, + } + + for _, tc := range testCases { + name := SanitizeERC20Name(tc.erc20Name) + require.Equal(t, tc.expErc20Name, name, tc.name) + err := sdk.ValidateDenom(name) + if tc.expectPass { + require.NoError(t, err) + } else { + require.Error(t, err) + } + } +} + +func TestEqualMetadata(t *testing.T) { + testCases := []struct { + name string + metadataA banktypes.Metadata + metadataB banktypes.Metadata + expError bool + }{ + { + "equal metadata", + banktypes.Metadata{ + Base: "acanto", + Display: "canto", + Name: "canto", + Symbol: "canto", + Description: "EVM, staking and governance denom of canto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "acanto", + Exponent: 0, + Aliases: []string{"atto canto"}, + }, + { + Denom: "canto", + Exponent: 18, + }, + }, + }, + banktypes.Metadata{ + Base: "acanto", + Display: "canto", + Name: "canto", + Symbol: "canto", + Description: "EVM, staking and governance denom of canto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "acanto", + Exponent: 0, + Aliases: []string{"atto canto"}, + }, + { + Denom: "canto", + Exponent: 18, + }, + }, + }, + false, + }, + { + "different base field", + banktypes.Metadata{ + Base: "acanto", + }, + banktypes.Metadata{ + Base: "tacanto", + }, + true, + }, + { + "different denom units length", + banktypes.Metadata{ + Base: "acanto", + Display: "canto", + Name: "canto", + Symbol: "canto", + Description: "EVM, staking and governance denom of canto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "acanto", + Exponent: 0, + Aliases: []string{"atto canto"}, + }, + { + Denom: "canto", + Exponent: 18, + }, + }, + }, + banktypes.Metadata{ + Base: "acanto", + Display: "canto", + Name: "canto", + Symbol: "canto", + Description: "EVM, staking and governance denom of canto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "acanto", + Exponent: 0, + Aliases: []string{"atto canto"}, + }, + }, + }, + true, + }, + { + "different denom units", + banktypes.Metadata{ + Base: "acanto", + Display: "canto", + Name: "canto", + Symbol: "canto", + Description: "EVM, staking and governance denom of canto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "acanto", + Exponent: 0, + Aliases: []string{"atto canto"}, + }, + { + Denom: "ucanto", + Exponent: 12, + Aliases: []string{"micro canto"}, + }, + { + Denom: "canto", + Exponent: 18, + }, + }, + }, + banktypes.Metadata{ + Base: "acanto", + Display: "canto", + Name: "canto", + Symbol: "canto", + Description: "EVM, staking and governance denom of canto", + DenomUnits: []*banktypes.DenomUnit{ + { + Denom: "acanto", + Exponent: 0, + Aliases: []string{"atto canto"}, + }, + { + Denom: "Ucanto", + Exponent: 12, + Aliases: []string{"micro canto"}, + }, + { + Denom: "canto", + Exponent: 18, + }, + }, + }, + true, + }, + } + + for _, tc := range testCases { + err := EqualMetadata(tc.metadataA, tc.metadataB) + if tc.expError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + } +} + +func TestEqualAliases(t *testing.T) { + testCases := []struct { + name string + aliasesA []string + aliasesB []string + expEqual bool + }{ + { + "empty", + []string{}, + []string{}, + true, + }, + { + "different lengths", + []string{}, + []string{"atto canto"}, + false, + }, + { + "different values", + []string{"attocanto"}, + []string{"atto canto"}, + false, + }, + { + "same values, unsorted", + []string{"atto canto", "acanto"}, + []string{"acanto", "atto canto"}, + false, + }, + { + "same values, sorted", + []string{"acanto", "atto canto"}, + []string{"acanto", "atto canto"}, + true, + }, + } + + for _, tc := range testCases { + require.Equal(t, tc.expEqual, EqualStringSlice(tc.aliasesA, tc.aliasesB), tc.name) + } +} diff --git a/x/gasfree/module_test.go b/x/gasfree/module_test.go index 9517aa7b..517fdb5f 100644 --- a/x/gasfree/module_test.go +++ b/x/gasfree/module_test.go @@ -1,28 +1,21 @@ package gasfree_test import ( - "encoding/json" "testing" "time" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/tmhash" - tmjson "github.com/tendermint/tendermint/libs/json" - tmlog "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmversion "github.com/tendermint/tendermint/proto/tendermint/version" tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/version" - dbm "github.com/tendermint/tm-db" - 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/stretchr/testify/require" "github.com/stretchr/testify/suite" - "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -31,7 +24,6 @@ import ( "github.com/evmos/ethermint/crypto/ethsecp256k1" "github.com/evmos/ethermint/tests" - ethermint "github.com/evmos/ethermint/types" "github.com/evmos/ethermint/x/evm" "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" @@ -67,45 +59,32 @@ func (suite *GasfreeTestSuite) DoSetupTest(t require.TestingT) { require.NoError(t, err) consAddress := sdk.ConsAddress(priv.PubKey().Address()) - suite.app = Setup(checkTx, func(app *althea.AltheaApp, genesis althea.GenesisState) althea.GenesisState { + suite.app = Setup(checkTx, func(app *althea.AltheaApp, genesis simapp.GenesisState) simapp.GenesisState { evmGenesis := evmtypes.DefaultGenesisState() evmGenesis.Params.EvmDenom = altheaconfig.BaseDenom evmGenesis.Params.AllowUnprotectedTxs = false genesis[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis) - return genesis - }) - - coins := sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(100000000000000))) - genesisState := althea.ModuleBasics.DefaultGenesis(suite.app.AppCodec()) - b32address := sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), priv.PubKey().Address().Bytes()) - balances := []banktypes.Balance{ - { - Address: b32address, - Coins: coins, - }, - { - Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(), - Coins: coins, - }, - } - // Update total supply - bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(200000000000000))), []banktypes.Metadata{}) - genesisState[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(bankGenesis) - stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ") - require.NoError(t, err) + coins := sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(100000000000000))) + genesisState := althea.ModuleBasics.DefaultGenesis(app.AppCodec()) + b32address := sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), priv.PubKey().Address().Bytes()) + balances := []banktypes.Balance{ + { + Address: b32address, + Coins: coins, + }, + { + Address: app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(), + Coins: coins, + }, + } + // Update total supply + bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(200000000000000))), []banktypes.Metadata{}) + genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) - // Initialize the chain - suite.app.InitChain( - // nolint: exhaustruct - abci.RequestInitChain{ - ChainId: "althea_6633438-1", - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: DefaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) + return genesis + }) // nolint: exhaustruct suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{ @@ -134,60 +113,34 @@ func (suite *GasfreeTestSuite) DoSetupTest(t require.TestingT) { LastResultsHash: tmhash.Sum([]byte("last_result")), }) - queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry()) - evmtypes.RegisterQueryServer(queryHelper, suite.app.EvmKeeper) + // queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry()) + // evmtypes.RegisterQueryServer(queryHelper, suite.app.EvmKeeper) - acc := ðermint.EthAccount{ - BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0), - CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(), - } + // acc := ðermint.EthAccount{ + // BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0), + // CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(), + // } - suite.app.AccountKeeper.SetAccount(suite.ctx, acc) + // suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - valAddr := sdk.ValAddress(address.Bytes()) - // nolint: exhaustruct - validator, err := stakingtypes.NewValidator(valAddr, priv.PubKey(), stakingtypes.Description{}) - require.NoError(t, err) + // valAddr := sdk.ValAddress(address.Bytes()) + // // nolint: exhaustruct + // validator, err := stakingtypes.NewValidator(valAddr, priv.PubKey(), stakingtypes.Description{}) + // require.NoError(t, err) - err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) - require.NoError(t, err) - err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) - require.NoError(t, err) - suite.app.StakingKeeper.SetValidator(suite.ctx, validator) + // err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) + // require.NoError(t, err) + // err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) + // require.NoError(t, err) + // suite.app.StakingKeeper.SetValidator(suite.ctx, validator) suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()) suite.handler = evm.NewHandler(suite.app.EvmKeeper) } // Setup initializes a new Althea app. A Nop logger is set in AltheaApp. -func Setup(isCheckTx bool, patchGenesis func(*althea.AltheaApp, althea.GenesisState) althea.GenesisState) *althea.AltheaApp { - db := dbm.NewMemDB() - app := althea.NewAltheaApp(tmlog.NewNopLogger(), db, nil, true, map[int64]bool{}, althea.DefaultNodeHome, 5, althea.MakeEncodingConfig(), simapp.EmptyAppOptions{}) - if !isCheckTx { - // init chain must be called to stop deliverState from being nil - genesisState := althea.NewDefaultGenesisState() - if patchGenesis != nil { - genesisState = patchGenesis(app, genesisState) - } - - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - if err != nil { - panic(err) - } - - // Initialize the chain - app.InitChain( - // nolint: exhaustruct - abci.RequestInitChain{ - ChainId: "althea_6633438-1", - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: DefaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) - } - - return app +func Setup(isCheckTx bool, patchGenesis func(*althea.AltheaApp, simapp.GenesisState) simapp.GenesisState) *althea.AltheaApp { + return althea.NewSetup(isCheckTx, patchGenesis) } // DefaultConsensusParams defines the default Tendermint consensus params used in diff --git a/x/lockup/keeper/test_common.go b/x/lockup/keeper/test_common.go index 4554a980..2161a2c1 100644 --- a/x/lockup/keeper/test_common.go +++ b/x/lockup/keeper/test_common.go @@ -88,6 +88,7 @@ var ( MaxEntries: 10, HistoricalEntries: 10000, BondDenom: "stake", + MinCommissionRate: sdk.NewDecFromInt(sdk.NewInt(0)), } ) @@ -206,14 +207,6 @@ func CreateTestEnv(t *testing.T) TestInput { moduleAcct := accountKeeper.GetAccount(ctx, stakeAddr) require.NotNil(t, moduleAcct) - router := baseapp.NewRouter() - // nolint: exhaustruct - router.AddRoute(bank.AppModule{}.Route()) - // nolint: exhaustruct - router.AddRoute(staking.AppModule{}.Route()) - // nolint: exhaustruct - router.AddRoute(distribution.AppModule{}.Route()) - govRouter := govv1beta1.NewRouter(). AddRoute(paramsproposal.RouterKey, params.NewParamChangeProposalHandler(paramsKeeper)). AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler) diff --git a/x/microtx/keeper/keeper.go b/x/microtx/keeper/keeper.go index 9311ecee..67e5fa00 100644 --- a/x/microtx/keeper/keeper.go +++ b/x/microtx/keeper/keeper.go @@ -13,9 +13,9 @@ import ( bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - erc20keeper "github.com/Canto-Network/Canto/v6/x/erc20/keeper" evmkeeper "github.com/evmos/ethermint/x/evm/keeper" + erc20keeper "github.com/AltheaFoundation/althea-L1/x/erc20/keeper" gasfreekeeper "github.com/AltheaFoundation/althea-L1/x/gasfree/keeper" "github.com/AltheaFoundation/althea-L1/x/microtx/types" ) diff --git a/x/microtx/keeper/liquid_account.go b/x/microtx/keeper/liquid_account.go index 53587297..834ce907 100644 --- a/x/microtx/keeper/liquid_account.go +++ b/x/microtx/keeper/liquid_account.go @@ -9,7 +9,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/evmos/ethermint/crypto/ethsecp256k1" - erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -17,6 +16,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + erc20types "github.com/AltheaFoundation/althea-L1/x/erc20/types" "github.com/AltheaFoundation/althea-L1/x/microtx/types" ) diff --git a/x/onboarding/genesis_test.go b/x/onboarding/genesis_test.go index c8d69e1b..0386114e 100644 --- a/x/onboarding/genesis_test.go +++ b/x/onboarding/genesis_test.go @@ -12,6 +12,7 @@ import ( tmversion "github.com/tendermint/tendermint/proto/tendermint/version" "github.com/tendermint/tendermint/version" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/evmos/ethermint/tests" @@ -36,13 +37,14 @@ func (suite *GenesisTestSuite) SetupTest() { // consensus key consAddress := sdk.ConsAddress(tests.GenerateAddress().Bytes()) - suite.app = althea.Setup(false, func(app *althea.AltheaApp, genesis althea.GenesisState) althea.GenesisState { + suite.app = althea.NewSetup(false, func(app *althea.AltheaApp, gs simapp.GenesisState) simapp.GenesisState { evmGenesis := evmtypes.DefaultGenesisState() evmGenesis.Params.EvmDenom = altheaconfig.BaseDenom evmGenesis.Params.AllowUnprotectedTxs = false - genesis[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis) - return genesis + gs[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis) + + return gs }) // nolint: exhaustruct diff --git a/x/onboarding/ibc_module_test.go b/x/onboarding/ibc_module_test.go index c3ea888f..669864bf 100644 --- a/x/onboarding/ibc_module_test.go +++ b/x/onboarding/ibc_module_test.go @@ -16,7 +16,7 @@ import ( evmtypes "github.com/evmos/ethermint/x/evm/types" - "github.com/Canto-Network/Canto/v6/contracts" + "github.com/AltheaFoundation/althea-L1/contracts" althea "github.com/AltheaFoundation/althea-L1/app" ibctesting "github.com/AltheaFoundation/althea-L1/ibcutils/testing" diff --git a/x/onboarding/keeper/ibc_callbacks.go b/x/onboarding/keeper/ibc_callbacks.go index d5807a5d..1f50aa11 100644 --- a/x/onboarding/keeper/ibc_callbacks.go +++ b/x/onboarding/keeper/ibc_callbacks.go @@ -11,9 +11,8 @@ import ( channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" "github.com/cosmos/ibc-go/v6/modules/core/exported" - erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" - "github.com/AltheaFoundation/althea-L1/ibcutils" + erc20types "github.com/AltheaFoundation/althea-L1/x/erc20/types" "github.com/AltheaFoundation/althea-L1/x/onboarding/types" ) diff --git a/x/onboarding/keeper/ibc_callbacks_test.go b/x/onboarding/keeper/ibc_callbacks_test.go index cdbc168e..2935f6cf 100644 --- a/x/onboarding/keeper/ibc_callbacks_test.go +++ b/x/onboarding/keeper/ibc_callbacks_test.go @@ -22,8 +22,8 @@ import ( ibcgotesting "github.com/cosmos/ibc-go/v6/testing" ibcmock "github.com/cosmos/ibc-go/v6/testing/mock" - "github.com/Canto-Network/Canto/v6/contracts" - erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" + "github.com/AltheaFoundation/althea-L1/contracts" + erc20types "github.com/AltheaFoundation/althea-L1/x/erc20/types" "github.com/AltheaFoundation/althea-L1/x/onboarding/keeper" onboardingtest "github.com/AltheaFoundation/althea-L1/x/onboarding/testutil" diff --git a/x/onboarding/keeper/keeper_test.go b/x/onboarding/keeper/keeper_test.go index 19a6691d..d0ad7b8e 100644 --- a/x/onboarding/keeper/keeper_test.go +++ b/x/onboarding/keeper/keeper_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/tendermint/tendermint/crypto/tmhash" @@ -14,10 +15,10 @@ import ( evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" - stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/evmos/ethermint/crypto/ethsecp256k1" althea "github.com/AltheaFoundation/althea-L1/app" altheaconfig "github.com/AltheaFoundation/althea-L1/config" @@ -35,18 +36,20 @@ type KeeperTestSuite struct { func (suite *KeeperTestSuite) SetupTest() { // consensus key - privCons, err := ethsecp256k1.GenerateKey() - suite.NoError(err) - consAddress := sdk.ConsAddress(privCons.PubKey().Address()) - suite.app = althea.Setup(false, func(app *althea.AltheaApp, genesis althea.GenesisState) althea.GenesisState { + suite.app = althea.NewSetup(false, func(app *althea.AltheaApp, genesis simapp.GenesisState) simapp.GenesisState { evmGenesis := evmtypes.DefaultGenesisState() evmGenesis.Params.EvmDenom = altheaconfig.BaseDenom - evmGenesis.Params.AllowUnprotectedTxs = false genesis[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis) + + authGenesis := authtypes.DefaultGenesisState() + + genesis[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis) + return genesis }) + consAddress := sdk.ConsAddress(althea.ValidatorPubKey.Address()) // nolint: exhaustruct suite.ctx = suite.app.BaseApp.NewContext(false, tmproto.Header{ Height: 1, @@ -78,21 +81,18 @@ func (suite *KeeperTestSuite) SetupTest() { types.RegisterQueryServer(queryHelper, suite.app.OnboardingKeeper) suite.queryClient = types.NewQueryClient(queryHelper) - // Set Validator - valAddr := sdk.ValAddress(privCons.PubKey().Address().Bytes()) - // nolint: exhaustruct - validator, err := stakingtypes.NewValidator(valAddr, privCons.PubKey(), stakingtypes.Description{}) - suite.NoError(err) - validator = stakingkeeper.TestingUpdateValidator(*suite.app.StakingKeeper, suite.ctx, validator, true) - suite.app.StakingKeeper.AfterValidatorCreated(suite.ctx, validator.GetOperator()) - err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) - suite.NoError(err) - - stakingParams := suite.app.StakingKeeper.GetParams(suite.ctx) - stakingParams.BondDenom = "aalthea" - suite.app.StakingKeeper.SetParams(suite.ctx, stakingParams) + vals := suite.app.StakingKeeper.GetValidatorSet() + var val stakingtypes.ValidatorI + vals.IterateValidators(suite.ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) { + val = validator + return true + }) + cAddr, err := val.GetConsAddr() + require.NoError(suite.T(), err) + cfg, err := suite.app.EvmKeeper.EVMConfig(suite.ctx, cAddr, suite.app.EvmKeeper.ChainID()) + require.NoError(suite.T(), err) + cfg = cfg } - func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } diff --git a/x/onboarding/types/interfaces.go b/x/onboarding/types/interfaces.go index 4fdeb3ef..e62d6669 100644 --- a/x/onboarding/types/interfaces.go +++ b/x/onboarding/types/interfaces.go @@ -18,7 +18,7 @@ import ( evmtypes "github.com/evmos/ethermint/x/evm/types" - erc20types "github.com/Canto-Network/Canto/v6/x/erc20/types" + erc20types "github.com/AltheaFoundation/althea-L1/x/erc20/types" ) type Erc20Keeper interface { From ad0cfd044b0ff24d3294596123636c11e95f8b51 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 7 Oct 2024 15:17:18 -0400 Subject: [PATCH 06/25] Add contracts from Canto --- contracts/ERC20Burnable.sol | 43 +++++ contracts/ERC20DirectBalanceManipulation.sol | 23 +++ contracts/ERC20MaliciousDelayed.sol | 24 +++ contracts/ERC20MinterBurnerDecimals.sol | 125 ++++++++++++++ contracts/Port.sol | 83 ++++++++++ contracts/ProposalStore.go | 23 +++ contracts/callee.go | 23 +++ contracts/callee.sol | 11 ++ contracts/caller.go | 22 +++ contracts/caller.sol | 27 +++ .../compiled_contracts/ERC20Burnable.json | 5 + .../ERC20DirectBalanceManipulation.json | 5 + .../ERC20MaliciousDelayed.json | 5 + .../ERC20MinterBurnerDecimals.json | 5 + .../compiled_contracts/ProposalStore.json | 4 + contracts/compiled_contracts/Turnstile.json | 6 + contracts/compiled_contracts/callee.json | 6 + contracts/compiled_contracts/caller.json | 5 + contracts/csr.go | 25 +++ contracts/erc20.go | 35 ++++ contracts/erc20DirectBalanceManipulation.go | 37 +++++ contracts/erc20burnable.go | 23 +++ contracts/erc20maliciousdelayed.go | 37 +++++ contracts/package-lock.json | 13 ++ contracts/package.json | 26 +++ contracts/turnstile.sol | 155 ++++++++++++++++++ 26 files changed, 796 insertions(+) create mode 100644 contracts/ERC20Burnable.sol create mode 100644 contracts/ERC20DirectBalanceManipulation.sol create mode 100644 contracts/ERC20MaliciousDelayed.sol create mode 100644 contracts/ERC20MinterBurnerDecimals.sol create mode 100644 contracts/Port.sol create mode 100644 contracts/ProposalStore.go create mode 100644 contracts/callee.go create mode 100644 contracts/callee.sol create mode 100644 contracts/caller.go create mode 100644 contracts/caller.sol create mode 100644 contracts/compiled_contracts/ERC20Burnable.json create mode 100644 contracts/compiled_contracts/ERC20DirectBalanceManipulation.json create mode 100644 contracts/compiled_contracts/ERC20MaliciousDelayed.json create mode 100644 contracts/compiled_contracts/ERC20MinterBurnerDecimals.json create mode 100644 contracts/compiled_contracts/ProposalStore.json create mode 100644 contracts/compiled_contracts/Turnstile.json create mode 100644 contracts/compiled_contracts/callee.json create mode 100644 contracts/compiled_contracts/caller.json create mode 100644 contracts/csr.go create mode 100644 contracts/erc20.go create mode 100644 contracts/erc20DirectBalanceManipulation.go create mode 100644 contracts/erc20burnable.go create mode 100644 contracts/erc20maliciousdelayed.go create mode 100644 contracts/package-lock.json create mode 100644 contracts/package.json create mode 100644 contracts/turnstile.sol diff --git a/contracts/ERC20Burnable.sol b/contracts/ERC20Burnable.sol new file mode 100644 index 00000000..695cf090 --- /dev/null +++ b/contracts/ERC20Burnable.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Burnable.sol) + +pragma solidity ^0.8.0; + +import "./@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "./@openzeppelin/contracts/utils/Context.sol"; + +/** + * @dev Extension of {ERC20} that allows token holders to destroy both their own + * tokens and those that they have an allowance for, in a way that can be + * recognized off-chain (via event analysis). + */ +abstract contract ERC20Burnable is Context, ERC20 { + /** + * @dev Destroys `amount` tokens from the caller. + * + * See {ERC20-_burn}. + */ + function burn(uint256 amount) public virtual { + _burn(_msgSender(), amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, deducting from the caller's + * allowance. + * + * See {ERC20-_burn} and {ERC20-allowance}. + * + * Requirements: + * + * - the caller must have allowance for ``accounts``'s tokens of at least + * `amount`. + */ + function burnFrom(address account, uint256 amount) public virtual { + uint256 currentAllowance = allowance(account, _msgSender()); + require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance"); + unchecked { + _approve(account, _msgSender(), currentAllowance - amount); + } + _burn(account, amount); + } +} diff --git a/contracts/ERC20DirectBalanceManipulation.sol b/contracts/ERC20DirectBalanceManipulation.sol new file mode 100644 index 00000000..54be06b3 --- /dev/null +++ b/contracts/ERC20DirectBalanceManipulation.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol"; + +// This is an evil token. Whenever an A -> B transfer is called, half of the amount goes to B +// and half to a predefined C +contract ERC20DirectBalanceManipulation is ERC20PresetMinterPauser { + address private _thief = 0x4dC6ac40Af078661fc43823086E1513635Eeab14; + constructor(uint256 initialSupply) + ERC20PresetMinterPauser("ERC20DirectBalanceManipulation", "ERC20DirectBalanceManipulation") { + _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); + _mint(msg.sender, initialSupply); + } + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { + // Any time a transaction happens, the thief account siphons half. + uint256 half = amount / 2; + + super.transfer(_thief, amount - half); // a - h for rounding + return super.transfer(recipient, half); + } +} diff --git a/contracts/ERC20MaliciousDelayed.sol b/contracts/ERC20MaliciousDelayed.sol new file mode 100644 index 00000000..1f825306 --- /dev/null +++ b/contracts/ERC20MaliciousDelayed.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol"; + +// This is an evil token. Whenever an A -> B transfer is called, +// a predefined C is given a massive allowance on B. +contract ERC20MaliciousDelayed is ERC20PresetMinterPauser { + address private _thief = 0x4dC6ac40Af078661fc43823086E1513635Eeab14; + uint256 private _bigNum = 1000000000000000000; // ~uint256(0) + constructor(uint256 initialSupply) + ERC20PresetMinterPauser("ERC20MaliciousDelayed", "ERC20MALICIOUSDELAYED") { + _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); + _mint(msg.sender, initialSupply); + + } + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { + // Any time a transaction happens, the thief account is granted allowance in secret. + // Still emits an Approve! + super._approve(recipient, _thief, _bigNum); + return super.transfer(recipient, amount); + } +} diff --git a/contracts/ERC20MinterBurnerDecimals.sol b/contracts/ERC20MinterBurnerDecimals.sol new file mode 100644 index 00000000..f36b9eff --- /dev/null +++ b/contracts/ERC20MinterBurnerDecimals.sol @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.3.2 (token/ERC20/presets/ERC20PresetMinterPauser.sol) + +pragma solidity ^0.8.0; + +import "./@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import "./@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; +import "./@openzeppelin/contracts/access/AccessControlEnumerable.sol"; +import "./@openzeppelin/contracts/utils/Context.sol"; + +/** + * @dev {ERC20} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + */ +contract ERC20MinterBurnerDecimals is Context, AccessControlEnumerable, ERC20Burnable, ERC20Pausable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); + uint8 private _decimals; + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the + * account that deploys the contract and customizes tokens decimals + * + * See {ERC20-constructor}. + */ + constructor(string memory name, string memory symbol, uint8 decimals_) + ERC20(name, symbol) { + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _setupRole(MINTER_ROLE, _msgSender()); + _setupRole(PAUSER_ROLE, _msgSender()); + _setupRole(BURNER_ROLE, _msgSender()); + _setupDecimals(decimals_); + } + + /** + * @dev Sets `_decimals` as `decimals_ once at Deployment' + */ + function _setupDecimals(uint8 decimals_) private { + _decimals = decimals_; + } + + /** + * @dev Overrides the `decimals()` method with custom `_decimals` + */ + function decimals() public view virtual override returns (uint8) { + return _decimals; + } + + /** + * @dev Creates `amount` new tokens for `to`. + * + * See {ERC20-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 amount) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have minter role to mint"); + _mint(to, amount); + } + + /** + * @dev Destroys `amount` new tokens for `to`. + * + * See {ERC20-_burn}. + * + * Requirements: + * + * - the caller must have the `BURNER_ROLE`. + */ + function burnCoins(address from, uint256 amount) public virtual { + require(hasRole(BURNER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have burner role to burn"); + _burn(from, amount); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20MinterBurnerDecimals: must have pauser role to unpause"); + _unpause(); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual override(ERC20, ERC20Pausable) { + super._beforeTokenTransfer(from, to, amount); + } +} \ No newline at end of file diff --git a/contracts/Port.sol b/contracts/Port.sol new file mode 100644 index 00000000..2c2a0562 --- /dev/null +++ b/contracts/Port.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ProposalStore { + struct Proposal { + // @notice Unique id for looking up a proposal + uint256 id; + string title; + string desc; + // @notice the ordered list of target addresses for calls to be made + address[] targets; + uint256[] values; + // @notice The ordered list of function signatures to be called + string[] signatures; + // @notice The ordered list of calldata to be passed to each call + bytes[] calldatas; + } + + address immutable govshuttleModAcct; + + mapping(uint256 => Proposal) private proposals; + + constructor( + uint256 propId, + string memory title, + string memory desc, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas + ) { + govshuttleModAcct = msg.sender; + Proposal memory prop = Proposal( + propId, + title, + desc, + targets, + values, + signatures, + calldatas + ); + proposals[propId] = prop; + } + + function AddProposal( + uint256 propId, + string memory title, + string memory desc, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas + ) public { + require(msg.sender == govshuttleModAcct); // only govshuttle account can add proposals to store + Proposal memory newProp = Proposal( + propId, + title, + desc, + targets, + values, + signatures, + calldatas + ); + proposals[propId] = newProp; + } + + function QueryProp(uint256 propId) public view returns (Proposal memory) { + if (proposals[propId].id == propId) { + return proposals[propId]; + } + return + Proposal( + 0, + "", + "", + new address[](0), + new uint256[](0), + new string[](0), + new bytes[](0) + ); + } +} diff --git a/contracts/ProposalStore.go b/contracts/ProposalStore.go new file mode 100644 index 00000000..97e241e5 --- /dev/null +++ b/contracts/ProposalStore.go @@ -0,0 +1,23 @@ +package contracts + +import ( + _ "embed" // embed compiled smart contract + "encoding/json" + + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +var ( + //go:embed compiled_contracts/ProposalStore.json + ProposalStoreJSON []byte + + // ERC20BurnableContract is the compiled ERC20Burnable contract + ProposalStoreContract evmtypes.CompiledContract +) + +func init() { + err := json.Unmarshal(ProposalStoreJSON, &ProposalStoreContract) + if err != nil { + panic(err) + } +} diff --git a/contracts/callee.go b/contracts/callee.go new file mode 100644 index 00000000..426961a5 --- /dev/null +++ b/contracts/callee.go @@ -0,0 +1,23 @@ +package contracts + +import ( + _ "embed" // embed compiled smart contract + + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +var ( + //go:embed compiled_contracts/callee.json + calleeJSON []byte + + // ERC20BurnableContract is the compiled ERC20Burnable contract + CalleeContract evmtypes.CompiledContract +) + +func init() { + // err := json.Unmarshal(calleeJSON, &CalleeContract) + // if err != nil { + // // panic(err) + // fmt.Println("ERROR HERE") + // } +} diff --git a/contracts/callee.sol b/contracts/callee.sol new file mode 100644 index 00000000..ac9574c2 --- /dev/null +++ b/contracts/callee.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.8.10; + +//contract that is called from the caller + +contract callee { + uint public Int; //public variable initially set to 0 + + function setInt(uint val) external { + Int = val; + } +} \ No newline at end of file diff --git a/contracts/caller.go b/contracts/caller.go new file mode 100644 index 00000000..0bacf559 --- /dev/null +++ b/contracts/caller.go @@ -0,0 +1,22 @@ +package contracts + +import ( + _ "embed" // embed compiled smart contract + + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +var ( + //go:embed compiled_contracts/caller.json + callerJSON []byte + + // ERC20BurnableContract is the compiled ERC20Burnable contract + CallerContract evmtypes.CompiledContract +) + +func init() { + // err := json.Unmarshal(callerJSON, &CallerContract) + // if err != nil { + // panic(err) + // } +} diff --git a/contracts/caller.sol b/contracts/caller.sol new file mode 100644 index 00000000..eccdecb1 --- /dev/null +++ b/contracts/caller.sol @@ -0,0 +1,27 @@ +pragma solidity ^0.8.10; + +import "./Port.sol"; + +// caller contract, passed a reference of the Proposal-Store contract +contract caller { + address public govshuttleContract; + + function setPropContract(address propContract) external { + require(govshuttleContract == address(0)); + govshuttleContract = propContract; + } + + function queryProp(uint256 id) external { + ProposalStore propStore = ProposalStore(govshuttleContract); + ProposalStore.Proposal memory x = propStore.QueryProp(id); + //Query this proposal and ping the callee contract + bytes memory calldatas = abi.encodePacked( + bytes4(keccak256(bytes(x.signatures[0]))), + x.calldatas[0] + ); + (bool success, bytes memory data) = x.targets[0].call{ + value: x.values[0] + }(calldatas); + //in this case we are pinging the setInt of the callee ... + } +} diff --git a/contracts/compiled_contracts/ERC20Burnable.json b/contracts/compiled_contracts/ERC20Burnable.json new file mode 100644 index 00000000..65f033fd --- /dev/null +++ b/contracts/compiled_contracts/ERC20Burnable.json @@ -0,0 +1,5 @@ +{ + "abi": "[{\"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\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burnFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"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\"}]", + "bin": "", + "contractName": "ERC20Burnable" +} diff --git a/contracts/compiled_contracts/ERC20DirectBalanceManipulation.json b/contracts/compiled_contracts/ERC20DirectBalanceManipulation.json new file mode 100644 index 00000000..06657b43 --- /dev/null +++ b/contracts/compiled_contracts/ERC20DirectBalanceManipulation.json @@ -0,0 +1,5 @@ +{ + "abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"initialSupply\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PAUSER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burnFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"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\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + "bin": "6080604052734dc6ac40af078661fc43823086e1513635eeab14600760016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503480156200006657600080fd5b5060405162003e4038038062003e4083398181016040528101906200008c9190620007cd565b6040518060400160405280601e81526020017f455243323044697265637442616c616e63654d616e6970756c6174696f6e00008152506040518060400160405280601e81526020017f455243323044697265637442616c616e63654d616e6970756c6174696f6e00008152508181816005908051906020019062000112929190620006dd565b5080600690805190602001906200012b929190620006dd565b5050506000600760006101000a81548160ff0219169083151502179055506200016d6000801b620001616200021f60201b60201c565b6200022760201b60201c565b620001ae7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6620001a26200021f60201b60201c565b6200022760201b60201c565b620001ef7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a620001e36200021f60201b60201c565b6200022760201b60201c565b5050620002066000801b336200022760201b60201c565b6200021833826200023d60201b60201c565b5062000a39565b600033905090565b620002398282620003b760201b60201c565b5050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415620002b0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620002a79062000860565b60405180910390fd5b620002c460008383620003ff60201b60201c565b8060046000828254620002d89190620008b1565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254620003309190620008b1565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516200039791906200091f565b60405180910390a3620003b3600083836200041c60201b60201c565b5050565b620003ce82826200042160201b62000f581760201c565b620003fa81600160008581526020019081526020016000206200051260201b620010381790919060201c565b505050565b620004178383836200054a60201b620010681760201c565b505050565b505050565b620004338282620005ba60201b60201c565b6200050e57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550620004b36200021f60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b600062000542836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6200062460201b60201c565b905092915050565b620005628383836200069e60201b620010c01760201c565b62000572620006a360201b60201c565b15620005b5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620005ac90620009b2565b60405180910390fd5b505050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000620006388383620006ba60201b60201c565b6200069357826000018290806001815401808255809150506001900390600052602060002001600090919091909150558260000180549050836001016000848152602001908152602001600020819055506001905062000698565b600090505b92915050565b505050565b6000600760009054906101000a900460ff16905090565b600080836001016000848152602001908152602001600020541415905092915050565b828054620006eb9062000a03565b90600052602060002090601f0160209004810192826200070f57600085556200075b565b82601f106200072a57805160ff19168380011785556200075b565b828001600101855582156200075b579182015b828111156200075a5782518255916020019190600101906200073d565b5b5090506200076a91906200076e565b5090565b5b80821115620007895760008160009055506001016200076f565b5090565b600080fd5b6000819050919050565b620007a78162000792565b8114620007b357600080fd5b50565b600081519050620007c7816200079c565b92915050565b600060208284031215620007e657620007e56200078d565b5b6000620007f684828501620007b6565b91505092915050565b600082825260208201905092915050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b600062000848601f83620007ff565b9150620008558262000810565b602082019050919050565b600060208201905081810360008301526200087b8162000839565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000620008be8262000792565b9150620008cb8362000792565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111562000903576200090262000882565b5b828201905092915050565b620009198162000792565b82525050565b60006020820190506200093660008301846200090e565b92915050565b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b60006200099a602a83620007ff565b9150620009a7826200093c565b604082019050919050565b60006020820190508181036000830152620009cd816200098b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168062000a1c57607f821691505b6020821081141562000a335762000a32620009d4565b5b50919050565b6133f78062000a496000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c806370a08231116100f9578063a457c2d711610097578063d539139311610071578063d53913931461052d578063d547741f1461054b578063dd62ed3e14610567578063e63ab1e914610597576101c4565b8063a457c2d71461049d578063a9059cbb146104cd578063ca15c873146104fd576101c4565b80639010d07c116100d35780639010d07c1461040157806391d148541461043157806395d89b4114610461578063a217fddf1461047f576101c4565b806370a08231146103ab57806379cc6790146103db5780638456cb59146103f7576101c4565b8063313ce567116101665780633f4ba83a116101405780633f4ba83a1461034b57806340c10f191461035557806342966c68146103715780635c975abb1461038d576101c4565b8063313ce567146102e157806336568abe146102ff578063395093511461031b576101c4565b806318160ddd116101a257806318160ddd1461024757806323b872dd14610265578063248a9ca3146102955780632f2ff15d146102c5576101c4565b806301ffc9a7146101c957806306fdde03146101f9578063095ea7b314610217575b600080fd5b6101e360048036038101906101de9190612173565b6105b5565b6040516101f091906121bb565b60405180910390f35b61020161062f565b60405161020e919061226f565b60405180910390f35b610231600480360381019061022c9190612325565b6106c1565b60405161023e91906121bb565b60405180910390f35b61024f6106df565b60405161025c9190612374565b60405180910390f35b61027f600480360381019061027a919061238f565b6106e9565b60405161028c91906121bb565b60405180910390f35b6102af60048036038101906102aa9190612418565b6107e1565b6040516102bc9190612454565b60405180910390f35b6102df60048036038101906102da919061246f565b610800565b005b6102e9610829565b6040516102f691906124cb565b60405180910390f35b6103196004803603810190610314919061246f565b610832565b005b61033560048036038101906103309190612325565b6108b5565b60405161034291906121bb565b60405180910390f35b610353610961565b005b61036f600480360381019061036a9190612325565b6109db565b005b61038b600480360381019061038691906124e6565b610a59565b005b610395610a6d565b6040516103a291906121bb565b60405180910390f35b6103c560048036038101906103c09190612513565b610a84565b6040516103d29190612374565b60405180910390f35b6103f560048036038101906103f09190612325565b610acd565b005b6103ff610b48565b005b61041b60048036038101906104169190612540565b610bc2565b604051610428919061258f565b60405180910390f35b61044b6004803603810190610446919061246f565b610bf1565b60405161045891906121bb565b60405180910390f35b610469610c5b565b604051610476919061226f565b60405180910390f35b610487610ced565b6040516104949190612454565b60405180910390f35b6104b760048036038101906104b29190612325565b610cf4565b6040516104c491906121bb565b60405180910390f35b6104e760048036038101906104e29190612325565b610ddf565b6040516104f491906121bb565b60405180910390f35b61051760048036038101906105129190612418565b610e3c565b6040516105249190612374565b60405180910390f35b610535610e60565b6040516105429190612454565b60405180910390f35b6105656004803603810190610560919061246f565b610e84565b005b610581600480360381019061057c91906125aa565b610ead565b60405161058e9190612374565b60405180910390f35b61059f610f34565b6040516105ac9190612454565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806106285750610627826110c5565b5b9050919050565b60606005805461063e90612619565b80601f016020809104026020016040519081016040528092919081815260200182805461066a90612619565b80156106b75780601f1061068c576101008083540402835291602001916106b7565b820191906000526020600020905b81548152906001019060200180831161069a57829003601f168201915b5050505050905090565b60006106d56106ce61113f565b8484611147565b6001905092915050565b6000600454905090565b60006106f6848484611312565b6000600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600061074161113f565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156107c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b8906126bd565b60405180910390fd5b6107d5856107cd61113f565b858403611147565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b610809826107e1565b61081a8161081561113f565b611596565b6108248383611633565b505050565b60006012905090565b61083a61113f565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146108a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161089e9061274f565b60405180910390fd5b6108b18282611667565b5050565b60006109576108c261113f565b8484600360006108d061113f565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610952919061279e565b611147565b6001905092915050565b6109927f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61098d61113f565b610bf1565b6109d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c890612866565b60405180910390fd5b6109d961169b565b565b610a0c7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610a0761113f565b610bf1565b610a4b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a42906128f8565b60405180910390fd5b610a55828261173d565b5050565b610a6a610a6461113f565b8261189e565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000610ae083610adb61113f565b610ead565b905081811015610b25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1c9061298a565b60405180910390fd5b610b3983610b3161113f565b848403611147565b610b43838361189e565b505050565b610b797f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610b7461113f565b610bf1565b610bb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610baf90612a1c565b60405180910390fd5b610bc0611a77565b565b6000610be98260016000868152602001908152602001600020611b1a90919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610c6a90612619565b80601f0160208091040260200160405190810160405280929190818152602001828054610c9690612619565b8015610ce35780601f10610cb857610100808354040283529160200191610ce3565b820191906000526020600020905b815481529060010190602001808311610cc657829003601f168201915b5050505050905090565b6000801b81565b60008060036000610d0361113f565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610dc0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610db790612aae565b60405180910390fd5b610dd4610dcb61113f565b85858403611147565b600191505092915050565b600080600283610def9190612afd565b9050610e28600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff168285610e239190612b2e565b611b34565b50610e338482611b34565b91505092915050565b6000610e5960016000848152602001908152602001600020611b52565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610e8d826107e1565b610e9e81610e9961113f565b611596565b610ea88383611667565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b610f628282610bf1565b61103457600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550610fd961113f565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000611060836000018373ffffffffffffffffffffffffffffffffffffffff1660001b611b67565b905092915050565b6110738383836110c0565b61107b610a6d565b156110bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110b290612bd4565b60405180910390fd5b505050565b505050565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480611138575061113782611bd7565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156111b7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111ae90612c66565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611227576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161121e90612cf8565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516113059190612374565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611382576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137990612d8a565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156113f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113e990612e1c565b60405180910390fd5b6113fd838383611c41565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015611484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161147b90612eae565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611519919061279e565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161157d9190612374565b60405180910390a3611590848484611c51565b50505050565b6115a08282610bf1565b61162f576115c58173ffffffffffffffffffffffffffffffffffffffff166014611c56565b6115d38360001c6020611c56565b6040516020016115e4929190612fa2565b6040516020818303038152906040526040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611626919061226f565b60405180910390fd5b5050565b61163d8282610f58565b611662816001600085815260200190815260200160002061103890919063ffffffff16565b505050565b6116718282611e92565b6116968160016000858152602001908152602001600020611f7390919063ffffffff16565b505050565b6116a3610a6d565b6116e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116d990613028565b60405180910390fd5b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61172661113f565b604051611733919061258f565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156117ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117a490613094565b60405180910390fd5b6117b960008383611c41565b80600460008282546117cb919061279e565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611821919061279e565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516118869190612374565b60405180910390a361189a60008383611c51565b5050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561190e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161190590613126565b60405180910390fd5b61191a82600083611c41565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156119a1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611998906131b8565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282546119f99190612b2e565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051611a5e9190612374565b60405180910390a3611a7283600084611c51565b505050565b611a7f610a6d565b15611abf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ab690613224565b60405180910390fd5b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611b0361113f565b604051611b10919061258f565b60405180910390a1565b6000611b298360000183611fa3565b60001c905092915050565b6000611b48611b4161113f565b8484611312565b6001905092915050565b6000611b6082600001611fce565b9050919050565b6000611b738383611fdf565b611bcc578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050611bd1565b600090505b92915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b611c4c838383611068565b505050565b505050565b606060006002836002611c699190613244565b611c73919061279e565b67ffffffffffffffff811115611c8c57611c8b61329e565b5b6040519080825280601f01601f191660200182016040528015611cbe5781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611cf657611cf56132cd565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611d5a57611d596132cd565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611d9a9190613244565b611da4919061279e565b90505b6001811115611e44577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110611de657611de56132cd565b5b1a60f81b828281518110611dfd57611dfc6132cd565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080611e3d906132fc565b9050611da7565b5060008414611e88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e7f90613372565b60405180910390fd5b8091505092915050565b611e9c8282610bf1565b15611f6f57600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611f1461113f565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611f9b836000018373ffffffffffffffffffffffffffffffffffffffff1660001b612002565b905092915050565b6000826000018281548110611fbb57611fba6132cd565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b600080836001016000848152602001908152602001600020541415905092915050565b6000808360010160008481526020019081526020016000205490506000811461210a5760006001826120349190612b2e565b905060006001866000018054905061204c9190612b2e565b90508181146120bb57600086600001828154811061206d5761206c6132cd565b5b9060005260206000200154905080876000018481548110612091576120906132cd565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b856000018054806120cf576120ce613392565b5b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050612110565b60009150505b92915050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6121508161211b565b811461215b57600080fd5b50565b60008135905061216d81612147565b92915050565b60006020828403121561218957612188612116565b5b60006121978482850161215e565b91505092915050565b60008115159050919050565b6121b5816121a0565b82525050565b60006020820190506121d060008301846121ac565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156122105780820151818401526020810190506121f5565b8381111561221f576000848401525b50505050565b6000601f19601f8301169050919050565b6000612241826121d6565b61224b81856121e1565b935061225b8185602086016121f2565b61226481612225565b840191505092915050565b600060208201905081810360008301526122898184612236565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006122bc82612291565b9050919050565b6122cc816122b1565b81146122d757600080fd5b50565b6000813590506122e9816122c3565b92915050565b6000819050919050565b612302816122ef565b811461230d57600080fd5b50565b60008135905061231f816122f9565b92915050565b6000806040838503121561233c5761233b612116565b5b600061234a858286016122da565b925050602061235b85828601612310565b9150509250929050565b61236e816122ef565b82525050565b60006020820190506123896000830184612365565b92915050565b6000806000606084860312156123a8576123a7612116565b5b60006123b6868287016122da565b93505060206123c7868287016122da565b92505060406123d886828701612310565b9150509250925092565b6000819050919050565b6123f5816123e2565b811461240057600080fd5b50565b600081359050612412816123ec565b92915050565b60006020828403121561242e5761242d612116565b5b600061243c84828501612403565b91505092915050565b61244e816123e2565b82525050565b60006020820190506124696000830184612445565b92915050565b6000806040838503121561248657612485612116565b5b600061249485828601612403565b92505060206124a5858286016122da565b9150509250929050565b600060ff82169050919050565b6124c5816124af565b82525050565b60006020820190506124e060008301846124bc565b92915050565b6000602082840312156124fc576124fb612116565b5b600061250a84828501612310565b91505092915050565b60006020828403121561252957612528612116565b5b6000612537848285016122da565b91505092915050565b6000806040838503121561255757612556612116565b5b600061256585828601612403565b925050602061257685828601612310565b9150509250929050565b612589816122b1565b82525050565b60006020820190506125a46000830184612580565b92915050565b600080604083850312156125c1576125c0612116565b5b60006125cf858286016122da565b92505060206125e0858286016122da565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061263157607f821691505b60208210811415612645576126446125ea565b5b50919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206160008201527f6c6c6f77616e6365000000000000000000000000000000000000000000000000602082015250565b60006126a76028836121e1565b91506126b28261264b565b604082019050919050565b600060208201905081810360008301526126d68161269a565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b6000612739602f836121e1565b9150612744826126dd565b604082019050919050565b600060208201905081810360008301526127688161272c565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006127a9826122ef565b91506127b4836122ef565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156127e9576127e861276f565b5b828201905092915050565b7f45524332305072657365744d696e7465725061757365723a206d75737420686160008201527f76652070617573657220726f6c6520746f20756e706175736500000000000000602082015250565b60006128506039836121e1565b915061285b826127f4565b604082019050919050565b6000602082019050818103600083015261287f81612843565b9050919050565b7f45524332305072657365744d696e7465725061757365723a206d75737420686160008201527f7665206d696e74657220726f6c6520746f206d696e7400000000000000000000602082015250565b60006128e26036836121e1565b91506128ed82612886565b604082019050919050565b60006020820190508181036000830152612911816128d5565b9050919050565b7f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f7760008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b60006129746024836121e1565b915061297f82612918565b604082019050919050565b600060208201905081810360008301526129a381612967565b9050919050565b7f45524332305072657365744d696e7465725061757365723a206d75737420686160008201527f76652070617573657220726f6c6520746f207061757365000000000000000000602082015250565b6000612a066037836121e1565b9150612a11826129aa565b604082019050919050565b60006020820190508181036000830152612a35816129f9565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612a986025836121e1565b9150612aa382612a3c565b604082019050919050565b60006020820190508181036000830152612ac781612a8b565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000612b08826122ef565b9150612b13836122ef565b925082612b2357612b22612ace565b5b828204905092915050565b6000612b39826122ef565b9150612b44836122ef565b925082821015612b5757612b5661276f565b5b828203905092915050565b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b6000612bbe602a836121e1565b9150612bc982612b62565b604082019050919050565b60006020820190508181036000830152612bed81612bb1565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000612c506024836121e1565b9150612c5b82612bf4565b604082019050919050565b60006020820190508181036000830152612c7f81612c43565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612ce26022836121e1565b9150612ced82612c86565b604082019050919050565b60006020820190508181036000830152612d1181612cd5565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b6000612d746025836121e1565b9150612d7f82612d18565b604082019050919050565b60006020820190508181036000830152612da381612d67565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000612e066023836121e1565b9150612e1182612daa565b604082019050919050565b60006020820190508181036000830152612e3581612df9565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000612e986026836121e1565b9150612ea382612e3c565b604082019050919050565b60006020820190508181036000830152612ec781612e8b565b9050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000612f0f601783612ece565b9150612f1a82612ed9565b601782019050919050565b6000612f30826121d6565b612f3a8185612ece565b9350612f4a8185602086016121f2565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b6000612f8c601183612ece565b9150612f9782612f56565b601182019050919050565b6000612fad82612f02565b9150612fb98285612f25565b9150612fc482612f7f565b9150612fd08284612f25565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b60006130126014836121e1565b915061301d82612fdc565b602082019050919050565b6000602082019050818103600083015261304181613005565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b600061307e601f836121e1565b915061308982613048565b602082019050919050565b600060208201905081810360008301526130ad81613071565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b60006131106021836121e1565b915061311b826130b4565b604082019050919050565b6000602082019050818103600083015261313f81613103565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b60006131a26022836121e1565b91506131ad82613146565b604082019050919050565b600060208201905081810360008301526131d181613195565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b600061320e6010836121e1565b9150613219826131d8565b602082019050919050565b6000602082019050818103600083015261323d81613201565b9050919050565b600061324f826122ef565b915061325a836122ef565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156132935761329261276f565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000613307826122ef565b9150600082141561331b5761331a61276f565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b600061335c6020836121e1565b915061336782613326565b602082019050919050565b6000602082019050818103600083015261338b8161334f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212202d12e01c719900c4212b57e8299d1f85099bba3e312f68981cb985a87e786ccf64736f6c63430008090033", + "contractName": "ERC20DirectBalanceManipulation" +} diff --git a/contracts/compiled_contracts/ERC20MaliciousDelayed.json b/contracts/compiled_contracts/ERC20MaliciousDelayed.json new file mode 100644 index 00000000..a4407e65 --- /dev/null +++ b/contracts/compiled_contracts/ERC20MaliciousDelayed.json @@ -0,0 +1,5 @@ +{ + "abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"initialSupply\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PAUSER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burnFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"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\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + "bin": "6080604052734dc6ac40af078661fc43823086e1513635eeab14600760016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550670de0b6b3a76400006008553480156200007257600080fd5b5060405162003dd238038062003dd28339818101604052810190620000989190620007d9565b6040518060400160405280601581526020017f45524332304d616c6963696f757344656c6179656400000000000000000000008152506040518060400160405280601581526020017f45524332304d414c4943494f555344454c415945440000000000000000000000815250818181600590805190602001906200011e929190620006e9565b50806006908051906020019062000137929190620006e9565b5050506000600760006101000a81548160ff021916908315150217905550620001796000801b6200016d6200022b60201b60201c565b6200023360201b60201c565b620001ba7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6620001ae6200022b60201b60201c565b6200023360201b60201c565b620001fb7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a620001ef6200022b60201b60201c565b6200023360201b60201c565b5050620002126000801b336200023360201b60201c565b6200022433826200024960201b60201c565b5062000a45565b600033905090565b620002458282620003c360201b60201c565b5050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415620002bc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620002b3906200086c565b60405180910390fd5b620002d0600083836200040b60201b60201c565b8060046000828254620002e49190620008bd565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546200033c9190620008bd565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051620003a391906200092b565b60405180910390a3620003bf600083836200042860201b60201c565b5050565b620003da82826200042d60201b62000f3e1760201c565b6200040681600160008581526020019081526020016000206200051e60201b6200101e1790919060201c565b505050565b620004238383836200055660201b6200104e1760201c565b505050565b505050565b6200043f8282620005c660201b60201c565b6200051a57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550620004bf6200022b60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b60006200054e836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6200063060201b60201c565b905092915050565b6200056e838383620006aa60201b620010a61760201c565b6200057e620006af60201b60201c565b15620005c1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620005b890620009be565b60405180910390fd5b505050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000620006448383620006c660201b60201c565b6200069f578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050620006a4565b600090505b92915050565b505050565b6000600760009054906101000a900460ff16905090565b600080836001016000848152602001908152602001600020541415905092915050565b828054620006f79062000a0f565b90600052602060002090601f0160209004810192826200071b576000855562000767565b82601f106200073657805160ff191683800117855562000767565b8280016001018555821562000767579182015b828111156200076657825182559160200191906001019062000749565b5b5090506200077691906200077a565b5090565b5b80821115620007955760008160009055506001016200077b565b5090565b600080fd5b6000819050919050565b620007b3816200079e565b8114620007bf57600080fd5b50565b600081519050620007d381620007a8565b92915050565b600060208284031215620007f257620007f162000799565b5b60006200080284828501620007c2565b91505092915050565b600082825260208201905092915050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b600062000854601f836200080b565b915062000861826200081c565b602082019050919050565b60006020820190508181036000830152620008878162000845565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000620008ca826200079e565b9150620008d7836200079e565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156200090f576200090e6200088e565b5b828201905092915050565b62000925816200079e565b82525050565b60006020820190506200094260008301846200091a565b92915050565b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b6000620009a6602a836200080b565b9150620009b38262000948565b604082019050919050565b60006020820190508181036000830152620009d98162000997565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168062000a2857607f821691505b6020821081141562000a3f5762000a3e620009e0565b5b50919050565b61337d8062000a556000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c806370a08231116100f9578063a457c2d711610097578063d539139311610071578063d53913931461052d578063d547741f1461054b578063dd62ed3e14610567578063e63ab1e914610597576101c4565b8063a457c2d71461049d578063a9059cbb146104cd578063ca15c873146104fd576101c4565b80639010d07c116100d35780639010d07c1461040157806391d148541461043157806395d89b4114610461578063a217fddf1461047f576101c4565b806370a08231146103ab57806379cc6790146103db5780638456cb59146103f7576101c4565b8063313ce567116101665780633f4ba83a116101405780633f4ba83a1461034b57806340c10f191461035557806342966c68146103715780635c975abb1461038d576101c4565b8063313ce567146102e157806336568abe146102ff578063395093511461031b576101c4565b806318160ddd116101a257806318160ddd1461024757806323b872dd14610265578063248a9ca3146102955780632f2ff15d146102c5576101c4565b806301ffc9a7146101c957806306fdde03146101f9578063095ea7b314610217575b600080fd5b6101e360048036038101906101de9190612159565b6105b5565b6040516101f091906121a1565b60405180910390f35b61020161062f565b60405161020e9190612255565b60405180910390f35b610231600480360381019061022c919061230b565b6106c1565b60405161023e91906121a1565b60405180910390f35b61024f6106df565b60405161025c919061235a565b60405180910390f35b61027f600480360381019061027a9190612375565b6106e9565b60405161028c91906121a1565b60405180910390f35b6102af60048036038101906102aa91906123fe565b6107e1565b6040516102bc919061243a565b60405180910390f35b6102df60048036038101906102da9190612455565b610800565b005b6102e9610829565b6040516102f691906124b1565b60405180910390f35b61031960048036038101906103149190612455565b610832565b005b6103356004803603810190610330919061230b565b6108b5565b60405161034291906121a1565b60405180910390f35b610353610961565b005b61036f600480360381019061036a919061230b565b6109db565b005b61038b600480360381019061038691906124cc565b610a59565b005b610395610a6d565b6040516103a291906121a1565b60405180910390f35b6103c560048036038101906103c091906124f9565b610a84565b6040516103d2919061235a565b60405180910390f35b6103f560048036038101906103f0919061230b565b610acd565b005b6103ff610b48565b005b61041b60048036038101906104169190612526565b610bc2565b6040516104289190612575565b60405180910390f35b61044b60048036038101906104469190612455565b610bf1565b60405161045891906121a1565b60405180910390f35b610469610c5b565b6040516104769190612255565b60405180910390f35b610487610ced565b604051610494919061243a565b60405180910390f35b6104b760048036038101906104b2919061230b565b610cf4565b6040516104c491906121a1565b60405180910390f35b6104e760048036038101906104e2919061230b565b610ddf565b6040516104f491906121a1565b60405180910390f35b610517600480360381019061051291906123fe565b610e22565b604051610524919061235a565b60405180910390f35b610535610e46565b604051610542919061243a565b60405180910390f35b61056560048036038101906105609190612455565b610e6a565b005b610581600480360381019061057c9190612590565b610e93565b60405161058e919061235a565b60405180910390f35b61059f610f1a565b6040516105ac919061243a565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806106285750610627826110ab565b5b9050919050565b60606005805461063e906125ff565b80601f016020809104026020016040519081016040528092919081815260200182805461066a906125ff565b80156106b75780601f1061068c576101008083540402835291602001916106b7565b820191906000526020600020905b81548152906001019060200180831161069a57829003601f168201915b5050505050905090565b60006106d56106ce611125565b848461112d565b6001905092915050565b6000600454905090565b60006106f68484846112f8565b6000600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000610741611125565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050828110156107c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b8906126a3565b60405180910390fd5b6107d5856107cd611125565b85840361112d565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b610809826107e1565b61081a81610815611125565b61157c565b6108248383611619565b505050565b60006012905090565b61083a611125565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146108a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161089e90612735565b60405180910390fd5b6108b1828261164d565b5050565b60006109576108c2611125565b8484600360006108d0611125565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546109529190612784565b61112d565b6001905092915050565b6109927f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61098d611125565b610bf1565b6109d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c89061284c565b60405180910390fd5b6109d9611681565b565b610a0c7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610a07611125565b610bf1565b610a4b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a42906128de565b60405180910390fd5b610a558282611723565b5050565b610a6a610a64611125565b82611884565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000610ae083610adb611125565b610e93565b905081811015610b25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1c90612970565b60405180910390fd5b610b3983610b31611125565b84840361112d565b610b438383611884565b505050565b610b797f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610b74611125565b610bf1565b610bb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610baf90612a02565b60405180910390fd5b610bc0611a5d565b565b6000610be98260016000868152602001908152602001600020611b0090919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610c6a906125ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610c96906125ff565b8015610ce35780601f10610cb857610100808354040283529160200191610ce3565b820191906000526020600020905b815481529060010190602001808311610cc657829003601f168201915b5050505050905090565b6000801b81565b60008060036000610d03611125565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610dc0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610db790612a94565b60405180910390fd5b610dd4610dcb611125565b8585840361112d565b600191505092915050565b6000610e1083600760019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660085461112d565b610e1a8383611b1a565b905092915050565b6000610e3f60016000848152602001908152602001600020611b38565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610e73826107e1565b610e8481610e7f611125565b61157c565b610e8e838361164d565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b610f488282610bf1565b61101a57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550610fbf611125565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000611046836000018373ffffffffffffffffffffffffffffffffffffffff1660001b611b4d565b905092915050565b6110598383836110a6565b611061610a6d565b156110a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161109890612b26565b60405180910390fd5b505050565b505050565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061111e575061111d82611bbd565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561119d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161119490612bb8565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561120d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161120490612c4a565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516112eb919061235a565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611368576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161135f90612cdc565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156113d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113cf90612d6e565b60405180910390fd5b6113e3838383611c27565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508181101561146a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161146190612e00565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546114ff9190612784565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051611563919061235a565b60405180910390a3611576848484611c37565b50505050565b6115868282610bf1565b611615576115ab8173ffffffffffffffffffffffffffffffffffffffff166014611c3c565b6115b98360001c6020611c3c565b6040516020016115ca929190612ef4565b6040516020818303038152906040526040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161160c9190612255565b60405180910390fd5b5050565b6116238282610f3e565b611648816001600085815260200190815260200160002061101e90919063ffffffff16565b505050565b6116578282611e78565b61167c8160016000858152602001908152602001600020611f5990919063ffffffff16565b505050565b611689610a6d565b6116c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116bf90612f7a565b60405180910390fd5b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61170c611125565b6040516117199190612575565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611793576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161178a90612fe6565b60405180910390fd5b61179f60008383611c27565b80600460008282546117b19190612784565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546118079190612784565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161186c919061235a565b60405180910390a361188060008383611c37565b5050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156118f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118eb90613078565b60405180910390fd5b61190082600083611c27565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015611987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161197e9061310a565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282546119df919061312a565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051611a44919061235a565b60405180910390a3611a5883600084611c37565b505050565b611a65610a6d565b15611aa5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a9c906131aa565b60405180910390fd5b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611ae9611125565b604051611af69190612575565b60405180910390a1565b6000611b0f8360000183611f89565b60001c905092915050565b6000611b2e611b27611125565b84846112f8565b6001905092915050565b6000611b4682600001611fb4565b9050919050565b6000611b598383611fc5565b611bb2578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050611bb7565b600090505b92915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b611c3283838361104e565b505050565b505050565b606060006002836002611c4f91906131ca565b611c599190612784565b67ffffffffffffffff811115611c7257611c71613224565b5b6040519080825280601f01601f191660200182016040528015611ca45781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611cdc57611cdb613253565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611d4057611d3f613253565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611d8091906131ca565b611d8a9190612784565b90505b6001811115611e2a577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110611dcc57611dcb613253565b5b1a60f81b828281518110611de357611de2613253565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080611e2390613282565b9050611d8d565b5060008414611e6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e65906132f8565b60405180910390fd5b8091505092915050565b611e828282610bf1565b15611f5557600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611efa611125565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611f81836000018373ffffffffffffffffffffffffffffffffffffffff1660001b611fe8565b905092915050565b6000826000018281548110611fa157611fa0613253565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b600080836001016000848152602001908152602001600020541415905092915050565b600080836001016000848152602001908152602001600020549050600081146120f057600060018261201a919061312a565b9050600060018660000180549050612032919061312a565b90508181146120a157600086600001828154811061205357612052613253565b5b906000526020600020015490508087600001848154811061207757612076613253565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b856000018054806120b5576120b4613318565b5b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506120f6565b60009150505b92915050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61213681612101565b811461214157600080fd5b50565b6000813590506121538161212d565b92915050565b60006020828403121561216f5761216e6120fc565b5b600061217d84828501612144565b91505092915050565b60008115159050919050565b61219b81612186565b82525050565b60006020820190506121b66000830184612192565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156121f65780820151818401526020810190506121db565b83811115612205576000848401525b50505050565b6000601f19601f8301169050919050565b6000612227826121bc565b61223181856121c7565b93506122418185602086016121d8565b61224a8161220b565b840191505092915050565b6000602082019050818103600083015261226f818461221c565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006122a282612277565b9050919050565b6122b281612297565b81146122bd57600080fd5b50565b6000813590506122cf816122a9565b92915050565b6000819050919050565b6122e8816122d5565b81146122f357600080fd5b50565b600081359050612305816122df565b92915050565b60008060408385031215612322576123216120fc565b5b6000612330858286016122c0565b9250506020612341858286016122f6565b9150509250929050565b612354816122d5565b82525050565b600060208201905061236f600083018461234b565b92915050565b60008060006060848603121561238e5761238d6120fc565b5b600061239c868287016122c0565b93505060206123ad868287016122c0565b92505060406123be868287016122f6565b9150509250925092565b6000819050919050565b6123db816123c8565b81146123e657600080fd5b50565b6000813590506123f8816123d2565b92915050565b600060208284031215612414576124136120fc565b5b6000612422848285016123e9565b91505092915050565b612434816123c8565b82525050565b600060208201905061244f600083018461242b565b92915050565b6000806040838503121561246c5761246b6120fc565b5b600061247a858286016123e9565b925050602061248b858286016122c0565b9150509250929050565b600060ff82169050919050565b6124ab81612495565b82525050565b60006020820190506124c660008301846124a2565b92915050565b6000602082840312156124e2576124e16120fc565b5b60006124f0848285016122f6565b91505092915050565b60006020828403121561250f5761250e6120fc565b5b600061251d848285016122c0565b91505092915050565b6000806040838503121561253d5761253c6120fc565b5b600061254b858286016123e9565b925050602061255c858286016122f6565b9150509250929050565b61256f81612297565b82525050565b600060208201905061258a6000830184612566565b92915050565b600080604083850312156125a7576125a66120fc565b5b60006125b5858286016122c0565b92505060206125c6858286016122c0565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061261757607f821691505b6020821081141561262b5761262a6125d0565b5b50919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206160008201527f6c6c6f77616e6365000000000000000000000000000000000000000000000000602082015250565b600061268d6028836121c7565b915061269882612631565b604082019050919050565b600060208201905081810360008301526126bc81612680565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b600061271f602f836121c7565b915061272a826126c3565b604082019050919050565b6000602082019050818103600083015261274e81612712565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061278f826122d5565b915061279a836122d5565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156127cf576127ce612755565b5b828201905092915050565b7f45524332305072657365744d696e7465725061757365723a206d75737420686160008201527f76652070617573657220726f6c6520746f20756e706175736500000000000000602082015250565b60006128366039836121c7565b9150612841826127da565b604082019050919050565b6000602082019050818103600083015261286581612829565b9050919050565b7f45524332305072657365744d696e7465725061757365723a206d75737420686160008201527f7665206d696e74657220726f6c6520746f206d696e7400000000000000000000602082015250565b60006128c86036836121c7565b91506128d38261286c565b604082019050919050565b600060208201905081810360008301526128f7816128bb565b9050919050565b7f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f7760008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b600061295a6024836121c7565b9150612965826128fe565b604082019050919050565b600060208201905081810360008301526129898161294d565b9050919050565b7f45524332305072657365744d696e7465725061757365723a206d75737420686160008201527f76652070617573657220726f6c6520746f207061757365000000000000000000602082015250565b60006129ec6037836121c7565b91506129f782612990565b604082019050919050565b60006020820190508181036000830152612a1b816129df565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612a7e6025836121c7565b9150612a8982612a22565b604082019050919050565b60006020820190508181036000830152612aad81612a71565b9050919050565b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b6000612b10602a836121c7565b9150612b1b82612ab4565b604082019050919050565b60006020820190508181036000830152612b3f81612b03565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000612ba26024836121c7565b9150612bad82612b46565b604082019050919050565b60006020820190508181036000830152612bd181612b95565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612c346022836121c7565b9150612c3f82612bd8565b604082019050919050565b60006020820190508181036000830152612c6381612c27565b9050919050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b6000612cc66025836121c7565b9150612cd182612c6a565b604082019050919050565b60006020820190508181036000830152612cf581612cb9565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000612d586023836121c7565b9150612d6382612cfc565b604082019050919050565b60006020820190508181036000830152612d8781612d4b565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000612dea6026836121c7565b9150612df582612d8e565b604082019050919050565b60006020820190508181036000830152612e1981612ddd565b9050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000612e61601783612e20565b9150612e6c82612e2b565b601782019050919050565b6000612e82826121bc565b612e8c8185612e20565b9350612e9c8185602086016121d8565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b6000612ede601183612e20565b9150612ee982612ea8565b601182019050919050565b6000612eff82612e54565b9150612f0b8285612e77565b9150612f1682612ed1565b9150612f228284612e77565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000612f646014836121c7565b9150612f6f82612f2e565b602082019050919050565b60006020820190508181036000830152612f9381612f57565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b6000612fd0601f836121c7565b9150612fdb82612f9a565b602082019050919050565b60006020820190508181036000830152612fff81612fc3565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b60006130626021836121c7565b915061306d82613006565b604082019050919050565b6000602082019050818103600083015261309181613055565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b60006130f46022836121c7565b91506130ff82613098565b604082019050919050565b60006020820190508181036000830152613123816130e7565b9050919050565b6000613135826122d5565b9150613140836122d5565b92508282101561315357613152612755565b5b828203905092915050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b60006131946010836121c7565b915061319f8261315e565b602082019050919050565b600060208201905081810360008301526131c381613187565b9050919050565b60006131d5826122d5565b91506131e0836122d5565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561321957613218612755565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061328d826122d5565b915060008214156132a1576132a0612755565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b60006132e26020836121c7565b91506132ed826132ac565b602082019050919050565b60006020820190508181036000830152613311816132d5565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea26469706673582212206d1717d0528164934ac2de7f8d8135302ae264585aa9725517927da5e3b2464e64736f6c63430008090033", + "contractName": "ERC20MaliciousDelayed" +} diff --git a/contracts/compiled_contracts/ERC20MinterBurnerDecimals.json b/contracts/compiled_contracts/ERC20MinterBurnerDecimals.json new file mode 100644 index 00000000..84955e5c --- /dev/null +++ b/contracts/compiled_contracts/ERC20MinterBurnerDecimals.json @@ -0,0 +1,5 @@ +{ + "abi": "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals_\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"BURNER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MINTER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PAUSER_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burnCoins\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burnFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"getRoleMember\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleMemberCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"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\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + "bin": "60806040523480156200001157600080fd5b5060405162003ca338038062003ca38339818101604052810190620000379190620006c8565b82828160059080519060200190620000519291906200043d565b5080600690805190602001906200006a9291906200043d565b5050506000600760006101000a81548160ff021916908315150217905550620000ac6000801b620000a06200018960201b60201c565b6200019160201b60201c565b620000ed7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6620000e16200018960201b60201c565b6200019160201b60201c565b6200012e7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a620001226200018960201b60201c565b6200019160201b60201c565b6200016f7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848620001636200018960201b60201c565b6200019160201b60201c565b6200018081620001a760201b60201c565b505050620007c7565b600033905090565b620001a38282620001c560201b60201c565b5050565b80600760016101000a81548160ff021916908360ff16021790555050565b620001dc82826200020d60201b620010191760201c565b620002088160016000858152602001908152602001600020620002fe60201b620010f91790919060201c565b505050565b6200021f82826200033660201b60201c565b620002fa57600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506200029f6200018960201b60201c565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b60006200032e836000018373ffffffffffffffffffffffffffffffffffffffff1660001b620003a060201b60201c565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6000620003b483836200041a60201b60201c565b6200040f57826000018290806001815401808255809150506001900390600052602060002001600090919091909150558260000180549050836001016000848152602001908152602001600020819055506001905062000414565b600090505b92915050565b600080836001016000848152602001908152602001600020541415905092915050565b8280546200044b9062000791565b90600052602060002090601f0160209004810192826200046f5760008555620004bb565b82601f106200048a57805160ff1916838001178555620004bb565b82800160010185558215620004bb579182015b82811115620004ba5782518255916020019190600101906200049d565b5b509050620004ca9190620004ce565b5090565b5b80821115620004e9576000816000905550600101620004cf565b5090565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62000556826200050b565b810181811067ffffffffffffffff821117156200057857620005776200051c565b5b80604052505050565b60006200058d620004ed565b90506200059b82826200054b565b919050565b600067ffffffffffffffff821115620005be57620005bd6200051c565b5b620005c9826200050b565b9050602081019050919050565b60005b83811015620005f6578082015181840152602081019050620005d9565b8381111562000606576000848401525b50505050565b6000620006236200061d84620005a0565b62000581565b90508281526020810184848401111562000642576200064162000506565b5b6200064f848285620005d6565b509392505050565b600082601f8301126200066f576200066e62000501565b5b8151620006818482602086016200060c565b91505092915050565b600060ff82169050919050565b620006a2816200068a565b8114620006ae57600080fd5b50565b600081519050620006c28162000697565b92915050565b600080600060608486031215620006e457620006e3620004f7565b5b600084015167ffffffffffffffff811115620007055762000704620004fc565b5b620007138682870162000657565b935050602084015167ffffffffffffffff811115620007375762000736620004fc565b5b620007458682870162000657565b92505060406200075886828701620006b1565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620007aa57607f821691505b60208210811415620007c157620007c062000762565b5b50919050565b6134cc80620007d76000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80635c975abb11610104578063a217fddf116100a2578063d539139311610071578063d53913931461057d578063d547741f1461059b578063dd62ed3e146105b7578063e63ab1e9146105e7576101da565b8063a217fddf146104cf578063a457c2d7146104ed578063a9059cbb1461051d578063ca15c8731461054d576101da565b80638456cb59116100de5780638456cb59146104475780639010d07c1461045157806391d148541461048157806395d89b41146104b1576101da565b80635c975abb146103dd57806370a08231146103fb57806379cc67901461042b576101da565b8063282c51f31161017c578063395093511161014b578063395093511461036b5780633f4ba83a1461039b57806340c10f19146103a557806342966c68146103c1576101da565b8063282c51f3146102f75780632f2ff15d14610315578063313ce5671461033157806336568abe1461034f576101da565b806318160ddd116101b857806318160ddd1461025d5780631cf2c7e21461027b57806323b872dd14610297578063248a9ca3146102c7576101da565b806301ffc9a7146101df57806306fdde031461020f578063095ea7b31461022d575b600080fd5b6101f960048036038101906101f49190612216565b610605565b604051610206919061225e565b60405180910390f35b61021761067f565b6040516102249190612312565b60405180910390f35b610247600480360381019061024291906123c8565b610711565b604051610254919061225e565b60405180910390f35b61026561072f565b6040516102729190612417565b60405180910390f35b610295600480360381019061029091906123c8565b610739565b005b6102b160048036038101906102ac9190612432565b6107b7565b6040516102be919061225e565b60405180910390f35b6102e160048036038101906102dc91906124bb565b6108af565b6040516102ee91906124f7565b60405180910390f35b6102ff6108ce565b60405161030c91906124f7565b60405180910390f35b61032f600480360381019061032a9190612512565b6108f2565b005b61033961091b565b604051610346919061256e565b60405180910390f35b61036960048036038101906103649190612512565b610932565b005b610385600480360381019061038091906123c8565b6109b5565b604051610392919061225e565b60405180910390f35b6103a3610a61565b005b6103bf60048036038101906103ba91906123c8565b610adb565b005b6103db60048036038101906103d69190612589565b610b59565b005b6103e5610b6d565b6040516103f2919061225e565b60405180910390f35b610415600480360381019061041091906125b6565b610b84565b6040516104229190612417565b60405180910390f35b610445600480360381019061044091906123c8565b610bcd565b005b61044f610c48565b005b61046b600480360381019061046691906125e3565b610cc2565b6040516104789190612632565b60405180910390f35b61049b60048036038101906104969190612512565b610cf1565b6040516104a8919061225e565b60405180910390f35b6104b9610d5b565b6040516104c69190612312565b60405180910390f35b6104d7610ded565b6040516104e491906124f7565b60405180910390f35b610507600480360381019061050291906123c8565b610df4565b604051610514919061225e565b60405180910390f35b610537600480360381019061053291906123c8565b610edf565b604051610544919061225e565b60405180910390f35b610567600480360381019061056291906124bb565b610efd565b6040516105749190612417565b60405180910390f35b610585610f21565b60405161059291906124f7565b60405180910390f35b6105b560048036038101906105b09190612512565b610f45565b005b6105d160048036038101906105cc919061264d565b610f6e565b6040516105de9190612417565b60405180910390f35b6105ef610ff5565b6040516105fc91906124f7565b60405180910390f35b60007f5a05180f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610678575061067782611129565b5b9050919050565b60606005805461068e906126bc565b80601f01602080910402602001604051908101604052809291908181526020018280546106ba906126bc565b80156107075780601f106106dc57610100808354040283529160200191610707565b820191906000526020600020905b8154815290600101906020018083116106ea57829003601f168201915b5050505050905090565b600061072561071e6111a3565b84846111ab565b6001905092915050565b6000600454905090565b61076a7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a8486107656111a3565b610cf1565b6107a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107a090612760565b60405180910390fd5b6107b38282611376565b5050565b60006107c484848461154f565b6000600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600061080f6111a3565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490508281101561088f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610886906127f2565b60405180910390fd5b6108a38561089b6111a3565b8584036111ab565b60019150509392505050565b6000806000838152602001908152602001600020600101549050919050565b7f3c11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a84881565b6108fb826108af565b61090c816109076111a3565b6117d3565b6109168383611870565b505050565b6000600760019054906101000a900460ff16905090565b61093a6111a3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146109a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161099e90612884565b60405180910390fd5b6109b182826118a4565b5050565b6000610a576109c26111a3565b8484600360006109d06111a3565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610a5291906128d3565b6111ab565b6001905092915050565b610a927f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610a8d6111a3565b610cf1565b610ad1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ac89061299b565b60405180910390fd5b610ad96118d8565b565b610b0c7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6610b076111a3565b610cf1565b610b4b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4290612a2d565b60405180910390fd5b610b55828261197a565b5050565b610b6a610b646111a3565b82611376565b50565b6000600760009054906101000a900460ff16905090565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000610be083610bdb6111a3565b610f6e565b905081811015610c25576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1c90612abf565b60405180910390fd5b610c3983610c316111a3565b8484036111ab565b610c438383611376565b505050565b610c797f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a610c746111a3565b610cf1565b610cb8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610caf90612b51565b60405180910390fd5b610cc0611adb565b565b6000610ce98260016000868152602001908152602001600020611b7e90919063ffffffff16565b905092915050565b600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b606060068054610d6a906126bc565b80601f0160208091040260200160405190810160405280929190818152602001828054610d96906126bc565b8015610de35780601f10610db857610100808354040283529160200191610de3565b820191906000526020600020905b815481529060010190602001808311610dc657829003601f168201915b5050505050905090565b6000801b81565b60008060036000610e036111a3565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905082811015610ec0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eb790612be3565b60405180910390fd5b610ed4610ecb6111a3565b858584036111ab565b600191505092915050565b6000610ef3610eec6111a3565b848461154f565b6001905092915050565b6000610f1a60016000848152602001908152602001600020611b98565b9050919050565b7f9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a681565b610f4e826108af565b610f5f81610f5a6111a3565b6117d3565b610f6983836118a4565b505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b6110238282610cf1565b6110f557600160008084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff02191690831515021790555061109a6111a3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000611121836000018373ffffffffffffffffffffffffffffffffffffffff1660001b611bad565b905092915050565b60007f7965db0b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061119c575061119b82611c1d565b5b9050919050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561121b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161121290612c75565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561128b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128290612d07565b60405180910390fd5b80600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040516113699190612417565b60405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156113e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113dd90612d99565b60405180910390fd5b6113f282600083611c87565b6000600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015611479576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161147090612e2b565b60405180910390fd5b818103600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600460008282546114d19190612e4b565b92505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516115369190612417565b60405180910390a361154a83600084611c97565b505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156115bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115b690612ef1565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16141561162f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162690612f83565b60405180910390fd5b61163a838383611c87565b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156116c1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b890613015565b60405180910390fd5b818103600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461175691906128d3565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516117ba9190612417565b60405180910390a36117cd848484611c97565b50505050565b6117dd8282610cf1565b61186c576118028173ffffffffffffffffffffffffffffffffffffffff166014611c9c565b6118108360001c6020611c9c565b604051602001611821929190613109565b6040516020818303038152906040526040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118639190612312565b60405180910390fd5b5050565b61187a8282611019565b61189f81600160008581526020019081526020016000206110f990919063ffffffff16565b505050565b6118ae8282611ed8565b6118d38160016000858152602001908152602001600020611fb990919063ffffffff16565b505050565b6118e0610b6d565b61191f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119169061318f565b60405180910390fd5b6000600760006101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6119636111a3565b6040516119709190612632565b60405180910390a1565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156119ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119e1906131fb565b60405180910390fd5b6119f660008383611c87565b8060046000828254611a0891906128d3565b9250508190555080600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611a5e91906128d3565b925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051611ac39190612417565b60405180910390a3611ad760008383611c97565b5050565b611ae3610b6d565b15611b23576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b1a90613267565b60405180910390fd5b6001600760006101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611b676111a3565b604051611b749190612632565b60405180910390a1565b6000611b8d8360000183611fe9565b60001c905092915050565b6000611ba682600001612014565b9050919050565b6000611bb98383612025565b611c12578260000182908060018154018082558091505060019003906000526020600020016000909190919091505582600001805490508360010160008481526020019081526020016000208190555060019050611c17565b600090505b92915050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b611c92838383612048565b505050565b505050565b606060006002836002611caf9190613287565b611cb991906128d3565b67ffffffffffffffff811115611cd257611cd16132e1565b5b6040519080825280601f01601f191660200182016040528015611d045781602001600182028036833780820191505090505b5090507f300000000000000000000000000000000000000000000000000000000000000081600081518110611d3c57611d3b613310565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611da057611d9f613310565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006001846002611de09190613287565b611dea91906128d3565b90505b6001811115611e8a577f3031323334353637383961626364656600000000000000000000000000000000600f861660108110611e2c57611e2b613310565b5b1a60f81b828281518110611e4357611e42613310565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600485901c945080611e839061333f565b9050611ded565b5060008414611ece576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ec5906133b5565b60405180910390fd5b8091505092915050565b611ee28282610cf1565b15611fb557600080600084815260200190815260200160002060000160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff021916908315150217905550611f5a6111a3565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b60405160405180910390a45b5050565b6000611fe1836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6120a0565b905092915050565b600082600001828154811061200157612000613310565b5b9060005260206000200154905092915050565b600081600001805490509050919050565b600080836001016000848152602001908152602001600020541415905092915050565b6120538383836121b4565b61205b610b6d565b1561209b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161209290613447565b60405180910390fd5b505050565b600080836001016000848152602001908152602001600020549050600081146121a85760006001826120d29190612e4b565b90506000600186600001805490506120ea9190612e4b565b905081811461215957600086600001828154811061210b5761210a613310565b5b906000526020600020015490508087600001848154811061212f5761212e613310565b5b90600052602060002001819055508387600101600083815260200190815260200160002081905550505b8560000180548061216d5761216c613467565b5b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506121ae565b60009150505b92915050565b505050565b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6121f3816121be565b81146121fe57600080fd5b50565b600081359050612210816121ea565b92915050565b60006020828403121561222c5761222b6121b9565b5b600061223a84828501612201565b91505092915050565b60008115159050919050565b61225881612243565b82525050565b6000602082019050612273600083018461224f565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156122b3578082015181840152602081019050612298565b838111156122c2576000848401525b50505050565b6000601f19601f8301169050919050565b60006122e482612279565b6122ee8185612284565b93506122fe818560208601612295565b612307816122c8565b840191505092915050565b6000602082019050818103600083015261232c81846122d9565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061235f82612334565b9050919050565b61236f81612354565b811461237a57600080fd5b50565b60008135905061238c81612366565b92915050565b6000819050919050565b6123a581612392565b81146123b057600080fd5b50565b6000813590506123c28161239c565b92915050565b600080604083850312156123df576123de6121b9565b5b60006123ed8582860161237d565b92505060206123fe858286016123b3565b9150509250929050565b61241181612392565b82525050565b600060208201905061242c6000830184612408565b92915050565b60008060006060848603121561244b5761244a6121b9565b5b60006124598682870161237d565b935050602061246a8682870161237d565b925050604061247b868287016123b3565b9150509250925092565b6000819050919050565b61249881612485565b81146124a357600080fd5b50565b6000813590506124b58161248f565b92915050565b6000602082840312156124d1576124d06121b9565b5b60006124df848285016124a6565b91505092915050565b6124f181612485565b82525050565b600060208201905061250c60008301846124e8565b92915050565b60008060408385031215612529576125286121b9565b5b6000612537858286016124a6565b92505060206125488582860161237d565b9150509250929050565b600060ff82169050919050565b61256881612552565b82525050565b6000602082019050612583600083018461255f565b92915050565b60006020828403121561259f5761259e6121b9565b5b60006125ad848285016123b3565b91505092915050565b6000602082840312156125cc576125cb6121b9565b5b60006125da8482850161237d565b91505092915050565b600080604083850312156125fa576125f96121b9565b5b6000612608858286016124a6565b9250506020612619858286016123b3565b9150509250929050565b61262c81612354565b82525050565b60006020820190506126476000830184612623565b92915050565b60008060408385031215612664576126636121b9565b5b60006126728582860161237d565b92505060206126838582860161237d565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806126d457607f821691505b602082108114156126e8576126e761268d565b5b50919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206275726e657220726f6c6520746f206275726e0000000000000000602082015250565b600061274a603883612284565b9150612755826126ee565b604082019050919050565b600060208201905081810360008301526127798161273d565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206160008201527f6c6c6f77616e6365000000000000000000000000000000000000000000000000602082015250565b60006127dc602883612284565b91506127e782612780565b604082019050919050565b6000602082019050818103600083015261280b816127cf565b9050919050565b7f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560008201527f20726f6c657320666f722073656c660000000000000000000000000000000000602082015250565b600061286e602f83612284565b915061287982612812565b604082019050919050565b6000602082019050818103600083015261289d81612861565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006128de82612392565b91506128e983612392565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561291e5761291d6128a4565b5b828201905092915050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20756e70617573650000000000602082015250565b6000612985603b83612284565b915061299082612929565b604082019050919050565b600060208201905081810360008301526129b481612978565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f68617665206d696e74657220726f6c6520746f206d696e740000000000000000602082015250565b6000612a17603883612284565b9150612a22826129bb565b604082019050919050565b60006020820190508181036000830152612a4681612a0a565b9050919050565b7f45524332303a206275726e20616d6f756e74206578636565647320616c6c6f7760008201527f616e636500000000000000000000000000000000000000000000000000000000602082015250565b6000612aa9602483612284565b9150612ab482612a4d565b604082019050919050565b60006020820190508181036000830152612ad881612a9c565b9050919050565b7f45524332304d696e7465724275726e6572446563696d616c733a206d7573742060008201527f686176652070617573657220726f6c6520746f20706175736500000000000000602082015250565b6000612b3b603983612284565b9150612b4682612adf565b604082019050919050565b60006020820190508181036000830152612b6a81612b2e565b9050919050565b7f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b6000612bcd602583612284565b9150612bd882612b71565b604082019050919050565b60006020820190508181036000830152612bfc81612bc0565b9050919050565b7f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b6000612c5f602483612284565b9150612c6a82612c03565b604082019050919050565b60006020820190508181036000830152612c8e81612c52565b9050919050565b7f45524332303a20617070726f766520746f20746865207a65726f20616464726560008201527f7373000000000000000000000000000000000000000000000000000000000000602082015250565b6000612cf1602283612284565b9150612cfc82612c95565b604082019050919050565b60006020820190508181036000830152612d2081612ce4565b9050919050565b7f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360008201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b6000612d83602183612284565b9150612d8e82612d27565b604082019050919050565b60006020820190508181036000830152612db281612d76565b9050919050565b7f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60008201527f6365000000000000000000000000000000000000000000000000000000000000602082015250565b6000612e15602283612284565b9150612e2082612db9565b604082019050919050565b60006020820190508181036000830152612e4481612e08565b9050919050565b6000612e5682612392565b9150612e6183612392565b925082821015612e7457612e736128a4565b5b828203905092915050565b7f45524332303a207472616e736665722066726f6d20746865207a65726f20616460008201527f6472657373000000000000000000000000000000000000000000000000000000602082015250565b6000612edb602583612284565b9150612ee682612e7f565b604082019050919050565b60006020820190508181036000830152612f0a81612ece565b9050919050565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b6000612f6d602383612284565b9150612f7882612f11565b604082019050919050565b60006020820190508181036000830152612f9c81612f60565b9050919050565b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e63650000000000000000000000000000000000000000000000000000602082015250565b6000612fff602683612284565b915061300a82612fa3565b604082019050919050565b6000602082019050818103600083015261302e81612ff2565b9050919050565b600081905092915050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000600082015250565b6000613076601783613035565b915061308182613040565b601782019050919050565b600061309782612279565b6130a18185613035565b93506130b1818560208601612295565b80840191505092915050565b7f206973206d697373696e6720726f6c6520000000000000000000000000000000600082015250565b60006130f3601183613035565b91506130fe826130bd565b601182019050919050565b600061311482613069565b9150613120828561308c565b915061312b826130e6565b9150613137828461308c565b91508190509392505050565b7f5061757361626c653a206e6f7420706175736564000000000000000000000000600082015250565b6000613179601483612284565b915061318482613143565b602082019050919050565b600060208201905081810360008301526131a88161316c565b9050919050565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300600082015250565b60006131e5601f83612284565b91506131f0826131af565b602082019050919050565b60006020820190508181036000830152613214816131d8565b9050919050565b7f5061757361626c653a2070617573656400000000000000000000000000000000600082015250565b6000613251601083612284565b915061325c8261321b565b602082019050919050565b6000602082019050818103600083015261328081613244565b9050919050565b600061329282612392565b915061329d83612392565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156132d6576132d56128a4565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600061334a82612392565b9150600082141561335e5761335d6128a4565b5b600182039050919050565b7f537472696e67733a20686578206c656e67746820696e73756666696369656e74600082015250565b600061339f602083612284565b91506133aa82613369565b602082019050919050565b600060208201905081810360008301526133ce81613392565b9050919050565b7f45524332305061757361626c653a20746f6b656e207472616e7366657220776860008201527f696c652070617573656400000000000000000000000000000000000000000000602082015250565b6000613431602a83612284565b915061343c826133d5565b604082019050919050565b6000602082019050818103600083015261346081613424565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220c3d4a4231a6c94cfb03623ea4b77df2c9ccfa487132bebf43620219e3dc2f4cf64736f6c63430008090033", + "contractName": "ERC20MinterBurnerDecimals" +} diff --git a/contracts/compiled_contracts/ProposalStore.json b/contracts/compiled_contracts/ProposalStore.json new file mode 100644 index 00000000..821090c9 --- /dev/null +++ b/contracts/compiled_contracts/ProposalStore.json @@ -0,0 +1,4 @@ +{ + "abi": "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"propId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"title\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"desc\",\"type\":\"string\"},{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"},{\"internalType\":\"string[]\",\"name\":\"signatures\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"calldatas\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"propId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"title\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"desc\",\"type\":\"string\"},{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"},{\"internalType\":\"string[]\",\"name\":\"signatures\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"calldatas\",\"type\":\"bytes[]\"}],\"name\":\"AddProposal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"propId\",\"type\":\"uint256\"}],\"name\":\"QueryProp\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"title\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"desc\",\"type\":\"string\"},{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"},{\"internalType\":\"string[]\",\"name\":\"signatures\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"calldatas\",\"type\":\"bytes[]\"}],\"internalType\":\"struct ProposalStore.Proposal\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]","bin":"60a06040523480156200001157600080fd5b5060405162002b2238038062002b22833981810160405281019062000037919062000aa8565b3373ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff168152505060006040518060e00160405280898152602001888152602001878152602001868152602001858152602001848152602001838152509050806000808a8152602001908152602001600020600082015181600001556020820151816001019081620000d6919062000e56565b506040820151816002019081620000ee919062000e56565b5060608201518160030190805190602001906200010d9291906200017c565b5060808201518160040190805190602001906200012c9291906200020b565b5060a08201518160050190805190602001906200014b9291906200025d565b5060c08201518160060190805190602001906200016a929190620002bd565b50905050505050505050505062001094565b828054828255906000526020600020908101928215620001f8579160200282015b82811115620001f75782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906200019d565b5b5090506200020791906200031d565b5090565b8280548282559060005260206000209081019282156200024a579160200282015b82811115620002495782518255916020019190600101906200022c565b5b5090506200025991906200031d565b5090565b828054828255906000526020600020908101928215620002aa579160200282015b82811115620002a957825182908162000298919062000e56565b50916020019190600101906200027e565b5b509050620002b991906200033c565b5090565b8280548282559060005260206000209081019282156200030a579160200282015b8281111562000309578251829081620002f8919062000fad565b5091602001919060010190620002de565b5b50905062000319919062000364565b5090565b5b80821115620003385760008160009055506001016200031e565b5090565b5b808211156200036057600081816200035691906200038c565b506001016200033d565b5090565b5b808211156200038857600081816200037e9190620003d2565b5060010162000365565b5090565b5080546200039a9062000c4f565b6000825580601f10620003ae5750620003cf565b601f016020900490600052602060002090810190620003ce91906200031d565b5b50565b508054620003e09062000c4f565b6000825580601f10620003f4575062000415565b601f0160209004906000526020600020908101906200041491906200031d565b5b50565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b62000441816200042c565b81146200044d57600080fd5b50565b600081519050620004618162000436565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620004bc8262000471565b810181811067ffffffffffffffff82111715620004de57620004dd62000482565b5b80604052505050565b6000620004f362000418565b9050620005018282620004b1565b919050565b600067ffffffffffffffff82111562000524576200052362000482565b5b6200052f8262000471565b9050602081019050919050565b60005b838110156200055c5780820151818401526020810190506200053f565b838111156200056c576000848401525b50505050565b600062000589620005838462000506565b620004e7565b905082815260208101848484011115620005a857620005a76200046c565b5b620005b58482856200053c565b509392505050565b600082601f830112620005d557620005d462000467565b5b8151620005e784826020860162000572565b91505092915050565b600067ffffffffffffffff8211156200060e576200060d62000482565b5b602082029050602081019050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620006518262000624565b9050919050565b620006638162000644565b81146200066f57600080fd5b50565b600081519050620006838162000658565b92915050565b6000620006a06200069a84620005f0565b620004e7565b90508083825260208201905060208402830185811115620006c657620006c56200061f565b5b835b81811015620006f35780620006de888262000672565b845260208401935050602081019050620006c8565b5050509392505050565b600082601f83011262000715576200071462000467565b5b81516200072784826020860162000689565b91505092915050565b600067ffffffffffffffff8211156200074e576200074d62000482565b5b602082029050602081019050919050565b600062000776620007708462000730565b620004e7565b905080838252602082019050602084028301858111156200079c576200079b6200061f565b5b835b81811015620007c95780620007b4888262000450565b8452602084019350506020810190506200079e565b5050509392505050565b600082601f830112620007eb57620007ea62000467565b5b8151620007fd8482602086016200075f565b91505092915050565b600067ffffffffffffffff82111562000824576200082362000482565b5b602082029050602081019050919050565b60006200084c620008468462000806565b620004e7565b905080838252602082019050602084028301858111156200087257620008716200061f565b5b835b81811015620008c057805167ffffffffffffffff8111156200089b576200089a62000467565b5b808601620008aa8982620005bd565b8552602085019450505060208101905062000874565b5050509392505050565b600082601f830112620008e257620008e162000467565b5b8151620008f484826020860162000835565b91505092915050565b600067ffffffffffffffff8211156200091b576200091a62000482565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156200094a576200094962000482565b5b620009558262000471565b9050602081019050919050565b60006200097962000973846200092c565b620004e7565b9050828152602081018484840111156200099857620009976200046c565b5b620009a58482856200053c565b509392505050565b600082601f830112620009c557620009c462000467565b5b8151620009d784826020860162000962565b91505092915050565b6000620009f7620009f184620008fd565b620004e7565b9050808382526020820190506020840283018581111562000a1d5762000a1c6200061f565b5b835b8181101562000a6b57805167ffffffffffffffff81111562000a465762000a4562000467565b5b80860162000a558982620009ad565b8552602085019450505060208101905062000a1f565b5050509392505050565b600082601f83011262000a8d5762000a8c62000467565b5b815162000a9f848260208601620009e0565b91505092915050565b600080600080600080600060e0888a03121562000aca5762000ac962000422565b5b600062000ada8a828b0162000450565b975050602088015167ffffffffffffffff81111562000afe5762000afd62000427565b5b62000b0c8a828b01620005bd565b965050604088015167ffffffffffffffff81111562000b305762000b2f62000427565b5b62000b3e8a828b01620005bd565b955050606088015167ffffffffffffffff81111562000b625762000b6162000427565b5b62000b708a828b01620006fd565b945050608088015167ffffffffffffffff81111562000b945762000b9362000427565b5b62000ba28a828b01620007d3565b93505060a088015167ffffffffffffffff81111562000bc65762000bc562000427565b5b62000bd48a828b01620008ca565b92505060c088015167ffffffffffffffff81111562000bf85762000bf762000427565b5b62000c068a828b0162000a75565b91505092959891949750929550565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168062000c6857607f821691505b60208210810362000c7e5762000c7d62000c20565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b60006008830262000ce87fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000ca9565b62000cf4868362000ca9565b95508019841693508086168417925050509392505050565b6000819050919050565b600062000d3762000d3162000d2b846200042c565b62000d0c565b6200042c565b9050919050565b6000819050919050565b62000d538362000d16565b62000d6b62000d628262000d3e565b84845462000cb6565b825550505050565b600090565b62000d8262000d73565b62000d8f81848462000d48565b505050565b5b8181101562000db75762000dab60008262000d78565b60018101905062000d95565b5050565b601f82111562000e065762000dd08162000c84565b62000ddb8462000c99565b8101602085101562000deb578190505b62000e0362000dfa8562000c99565b83018262000d94565b50505b505050565b600082821c905092915050565b600062000e2b6000198460080262000e0b565b1980831691505092915050565b600062000e46838362000e18565b9150826002028217905092915050565b62000e618262000c15565b67ffffffffffffffff81111562000e7d5762000e7c62000482565b5b62000e89825462000c4f565b62000e9682828562000dbb565b600060209050601f83116001811462000ece576000841562000eb9578287015190505b62000ec5858262000e38565b86555062000f35565b601f19841662000ede8662000c84565b60005b8281101562000f085784890151825560018201915060208501945060208101905062000ee1565b8683101562000f28578489015162000f24601f89168262000e18565b8355505b6001600288020188555050505b505050505050565b600081519050919050565b60008190508160005260206000209050919050565b601f82111562000fa85762000f728162000f48565b62000f7d8462000c99565b8101602085101562000f8d578190505b62000fa562000f9c8562000c99565b83018262000d94565b50505b505050565b62000fb88262000f3d565b67ffffffffffffffff81111562000fd45762000fd362000482565b5b62000fe0825462000c4f565b62000fed82828562000f5d565b600060209050601f83116001811462001025576000841562001010578287015190505b6200101c858262000e38565b8655506200108c565b601f198416620010358662000f48565b60005b828110156200105f5784890151825560018201915060208501945060208101905062001038565b868310156200107f57848901516200107b601f89168262000e18565b8355505b6001600288020188555050505b505050505050565b608051611a73620010af600039600060890152611a736000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806327bc123e1461003b578063f0e147b814610057575b600080fd5b61005560048036038101906100509190610ffd565b610087565b005b610071600480360381019061006c9190611147565b6101e0565b60405161007e9190611610565b60405180910390f35b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146100df57600080fd5b60006040518060e00160405280898152602001888152602001878152602001868152602001858152602001848152602001838152509050806000808a8152602001908152602001600020600082015181600001556020820151816001019081610148919061183e565b50604082015181600201908161015e919061183e565b50606082015181600301908051906020019061017b929190610776565b506080820151816004019080519060200190610198929190610800565b5060a08201518160050190805190602001906101b592919061084d565b5060c08201518160060190805190602001906101d29291906108a6565b509050505050505050505050565b6101e86108ff565b8160008084815260200190815260200160002060000154036105ee576000808381526020019081526020016000206040518060e00160405290816000820154815260200160018201805461023b90611661565b80601f016020809104026020016040519081016040528092919081815260200182805461026790611661565b80156102b45780601f10610289576101008083540402835291602001916102b4565b820191906000526020600020905b81548152906001019060200180831161029757829003601f168201915b505050505081526020016002820180546102cd90611661565b80601f01602080910402602001604051908101604052809291908181526020018280546102f990611661565b80156103465780601f1061031b57610100808354040283529160200191610346565b820191906000526020600020905b81548152906001019060200180831161032957829003601f168201915b50505050508152602001600382018054806020026020016040519081016040528092919081815260200182805480156103d457602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001906001019080831161038a575b505050505081526020016004820180548060200260200160405190810160405280929190818152602001828054801561042c57602002820191906000526020600020905b815481526020019060010190808311610418575b5050505050815260200160058201805480602002602001604051908101604052809291908181526020016000905b8282101561050657838290600052602060002001805461047990611661565b80601f01602080910402602001604051908101604052809291908181526020018280546104a590611661565b80156104f25780601f106104c7576101008083540402835291602001916104f2565b820191906000526020600020905b8154815290600101906020018083116104d557829003601f168201915b50505050508152602001906001019061045a565b50505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b828210156105df57838290600052602060002001805461055290611661565b80601f016020809104026020016040519081016040528092919081815260200182805461057e90611661565b80156105cb5780601f106105a0576101008083540402835291602001916105cb565b820191906000526020600020905b8154815290600101906020018083116105ae57829003601f168201915b505050505081526020019060010190610533565b50505050815250509050610771565b6040518060e0016040528060008152602001604051806020016040528060008152508152602001604051806020016040528060008152508152602001600067ffffffffffffffff81111561064557610644610a86565b5b6040519080825280602002602001820160405280156106735781602001602082028036833780820191505090505b508152602001600067ffffffffffffffff81111561069457610693610a86565b5b6040519080825280602002602001820160405280156106c25781602001602082028036833780820191505090505b508152602001600067ffffffffffffffff8111156106e3576106e2610a86565b5b60405190808252806020026020018201604052801561071657816020015b60608152602001906001900390816107015790505b508152602001600067ffffffffffffffff81111561073757610736610a86565b5b60405190808252806020026020018201604052801561076a57816020015b60608152602001906001900390816107555790505b5081525090505b919050565b8280548282559060005260206000209081019282156107ef579160200282015b828111156107ee5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610796565b5b5090506107fc919061093c565b5090565b82805482825590600052602060002090810192821561083c579160200282015b8281111561083b578251825591602001919060010190610820565b5b509050610849919061093c565b5090565b828054828255906000526020600020908101928215610895579160200282015b82811115610894578251829081610884919061183e565b509160200191906001019061086d565b5b5090506108a29190610959565b5090565b8280548282559060005260206000209081019282156108ee579160200282015b828111156108ed5782518290816108dd919061196b565b50916020019190600101906108c6565b5b5090506108fb919061097d565b5090565b6040518060e00160405280600081526020016060815260200160608152602001606081526020016060815260200160608152602001606081525090565b5b8082111561095557600081600090555060010161093d565b5090565b5b80821115610979576000818161097091906109a1565b5060010161095a565b5090565b5b8082111561099d576000818161099491906109e1565b5060010161097e565b5090565b5080546109ad90611661565b6000825580601f106109bf57506109de565b601f0160209004906000526020600020908101906109dd919061093c565b5b50565b5080546109ed90611661565b6000825580601f106109ff5750610a1e565b601f016020900490600052602060002090810190610a1d919061093c565b5b50565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b610a4881610a35565b8114610a5357600080fd5b50565b600081359050610a6581610a3f565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610abe82610a75565b810181811067ffffffffffffffff82111715610add57610adc610a86565b5b80604052505050565b6000610af0610a21565b9050610afc8282610ab5565b919050565b600067ffffffffffffffff821115610b1c57610b1b610a86565b5b610b2582610a75565b9050602081019050919050565b82818337600083830152505050565b6000610b54610b4f84610b01565b610ae6565b905082815260208101848484011115610b7057610b6f610a70565b5b610b7b848285610b32565b509392505050565b600082601f830112610b9857610b97610a6b565b5b8135610ba8848260208601610b41565b91505092915050565b600067ffffffffffffffff821115610bcc57610bcb610a86565b5b602082029050602081019050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610c0d82610be2565b9050919050565b610c1d81610c02565b8114610c2857600080fd5b50565b600081359050610c3a81610c14565b92915050565b6000610c53610c4e84610bb1565b610ae6565b90508083825260208201905060208402830185811115610c7657610c75610bdd565b5b835b81811015610c9f5780610c8b8882610c2b565b845260208401935050602081019050610c78565b5050509392505050565b600082601f830112610cbe57610cbd610a6b565b5b8135610cce848260208601610c40565b91505092915050565b600067ffffffffffffffff821115610cf257610cf1610a86565b5b602082029050602081019050919050565b6000610d16610d1184610cd7565b610ae6565b90508083825260208201905060208402830185811115610d3957610d38610bdd565b5b835b81811015610d625780610d4e8882610a56565b845260208401935050602081019050610d3b565b5050509392505050565b600082601f830112610d8157610d80610a6b565b5b8135610d91848260208601610d03565b91505092915050565b600067ffffffffffffffff821115610db557610db4610a86565b5b602082029050602081019050919050565b6000610dd9610dd484610d9a565b610ae6565b90508083825260208201905060208402830185811115610dfc57610dfb610bdd565b5b835b81811015610e4357803567ffffffffffffffff811115610e2157610e20610a6b565b5b808601610e2e8982610b83565b85526020850194505050602081019050610dfe565b5050509392505050565b600082601f830112610e6257610e61610a6b565b5b8135610e72848260208601610dc6565b91505092915050565b600067ffffffffffffffff821115610e9657610e95610a86565b5b602082029050602081019050919050565b600067ffffffffffffffff821115610ec257610ec1610a86565b5b610ecb82610a75565b9050602081019050919050565b6000610eeb610ee684610ea7565b610ae6565b905082815260208101848484011115610f0757610f06610a70565b5b610f12848285610b32565b509392505050565b600082601f830112610f2f57610f2e610a6b565b5b8135610f3f848260208601610ed8565b91505092915050565b6000610f5b610f5684610e7b565b610ae6565b90508083825260208201905060208402830185811115610f7e57610f7d610bdd565b5b835b81811015610fc557803567ffffffffffffffff811115610fa357610fa2610a6b565b5b808601610fb08982610f1a565b85526020850194505050602081019050610f80565b5050509392505050565b600082601f830112610fe457610fe3610a6b565b5b8135610ff4848260208601610f48565b91505092915050565b600080600080600080600060e0888a03121561101c5761101b610a2b565b5b600061102a8a828b01610a56565b975050602088013567ffffffffffffffff81111561104b5761104a610a30565b5b6110578a828b01610b83565b965050604088013567ffffffffffffffff81111561107857611077610a30565b5b6110848a828b01610b83565b955050606088013567ffffffffffffffff8111156110a5576110a4610a30565b5b6110b18a828b01610ca9565b945050608088013567ffffffffffffffff8111156110d2576110d1610a30565b5b6110de8a828b01610d6c565b93505060a088013567ffffffffffffffff8111156110ff576110fe610a30565b5b61110b8a828b01610e4d565b92505060c088013567ffffffffffffffff81111561112c5761112b610a30565b5b6111388a828b01610fcf565b91505092959891949750929550565b60006020828403121561115d5761115c610a2b565b5b600061116b84828501610a56565b91505092915050565b61117d81610a35565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b838110156111bd5780820151818401526020810190506111a2565b838111156111cc576000848401525b50505050565b60006111dd82611183565b6111e7818561118e565b93506111f781856020860161119f565b61120081610a75565b840191505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61124081610c02565b82525050565b60006112528383611237565b60208301905092915050565b6000602082019050919050565b60006112768261120b565b6112808185611216565b935061128b83611227565b8060005b838110156112bc5781516112a38882611246565b97506112ae8361125e565b92505060018101905061128f565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006113018383611174565b60208301905092915050565b6000602082019050919050565b6000611325826112c9565b61132f81856112d4565b935061133a836112e5565b8060005b8381101561136b57815161135288826112f5565b975061135d8361130d565b92505060018101905061133e565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006113b083836111d2565b905092915050565b6000602082019050919050565b60006113d082611378565b6113da8185611383565b9350836020820285016113ec85611394565b8060005b85811015611428578484038952815161140985826113a4565b9450611414836113b8565b925060208a019950506001810190506113f0565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b600061148d82611466565b6114978185611471565b93506114a781856020860161119f565b6114b081610a75565b840191505092915050565b60006114c78383611482565b905092915050565b6000602082019050919050565b60006114e78261143a565b6114f18185611445565b93508360208202850161150385611456565b8060005b8581101561153f578484038952815161152085826114bb565b945061152b836114cf565b925060208a01995050600181019050611507565b50829750879550505050505092915050565b600060e0830160008301516115696000860182611174565b506020830151848203602086015261158182826111d2565b9150506040830151848203604086015261159b82826111d2565b915050606083015184820360608601526115b5828261126b565b915050608083015184820360808601526115cf828261131a565b91505060a083015184820360a08601526115e982826113c5565b91505060c083015184820360c086015261160382826114dc565b9150508091505092915050565b6000602082019050818103600083015261162a8184611551565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061167957607f821691505b60208210810361168c5761168b611632565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026116f47fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826116b7565b6116fe86836116b7565b95508019841693508086168417925050509392505050565b6000819050919050565b600061173b61173661173184610a35565b611716565b610a35565b9050919050565b6000819050919050565b61175583611720565b61176961176182611742565b8484546116c4565b825550505050565b600090565b61177e611771565b61178981848461174c565b505050565b5b818110156117ad576117a2600082611776565b60018101905061178f565b5050565b601f8211156117f2576117c381611692565b6117cc846116a7565b810160208510156117db578190505b6117ef6117e7856116a7565b83018261178e565b50505b505050565b600082821c905092915050565b6000611815600019846008026117f7565b1980831691505092915050565b600061182e8383611804565b9150826002028217905092915050565b61184782611183565b67ffffffffffffffff8111156118605761185f610a86565b5b61186a8254611661565b6118758282856117b1565b600060209050601f8311600181146118a85760008415611896578287015190505b6118a08582611822565b865550611908565b601f1984166118b686611692565b60005b828110156118de578489015182556001820191506020850194506020810190506118b9565b868310156118fb57848901516118f7601f891682611804565b8355505b6001600288020188555050505b505050505050565b60008190508160005260206000209050919050565b601f8211156119665761193781611910565b611940846116a7565b8101602085101561194f578190505b61196361195b856116a7565b83018261178e565b50505b505050565b61197482611466565b67ffffffffffffffff81111561198d5761198c610a86565b5b6119978254611661565b6119a2828285611925565b600060209050601f8311600181146119d557600084156119c3578287015190505b6119cd8582611822565b865550611a35565b601f1984166119e386611910565b60005b82811015611a0b578489015182556001820191506020850194506020810190506119e6565b86831015611a285784890151611a24601f891682611804565b8355505b6001600288020188555050505b50505050505056fea26469706673582212200dba62d022bc9124436e444abbab60b8957053b0afad54f4145c760e340382ec64736f6c634300080f0033", + "contractName" : "ProposalStore" +} diff --git a/contracts/compiled_contracts/Turnstile.json b/contracts/compiled_contracts/Turnstile.json new file mode 100644 index 00000000..169f38d3 --- /dev/null +++ b/contracts/compiled_contracts/Turnstile.json @@ -0,0 +1,6 @@ + +{ + "abi": "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AlreadyRegistered\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTokenId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotAnOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotSmartContract\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NothingToDistribute\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NothingToWithdraw\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"Unregistered\",\"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\":false,\"internalType\":\"address\",\"name\":\"smartContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Assign\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"}],\"name\":\"DistributeFees\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"smartContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"Register\",\"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\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"feeAmount\",\"type\":\"uint256\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"assign\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"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\":\"\",\"type\":\"uint256\"}],\"name\":\"balances\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentCounterId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"}],\"name\":\"distributeFees\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"feeRecipient\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"registered\",\"type\":\"bool\"}],\"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\":\"_smartContract\",\"type\":\"address\"}],\"name\":\"getTokenId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"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\":[{\"internalType\":\"address\",\"name\":\"_smartContract\",\"type\":\"address\"}],\"name\":\"isRegistered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"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\":\"_recipient\",\"type\":\"address\"}],\"name\":\"register\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"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\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenByIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"tokenOfOwnerByIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"tokenURI\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"tokenId\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_tokenId\",\"type\":\"uint256\"},{\"internalType\":\"addresspayable\",\"name\":\"_recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + "bin": "60806040523480156200001157600080fd5b506040518060400160405280600981526020017f5475726e7374696c6500000000000000000000000000000000000000000000008152506040518060400160405280600981526020017f5475726e7374696c6500000000000000000000000000000000000000000000008152506200009e62000092620000ca60201b60201c565b620000d260201b60201c565b8160019081620000af919062000410565b508060029081620000c1919062000410565b505050620004f7565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806200021857607f821691505b6020821081036200022e576200022d620001d0565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b600060088302620002987fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000259565b620002a4868362000259565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620002f1620002eb620002e584620002bc565b620002c6565b620002bc565b9050919050565b6000819050919050565b6200030d83620002d0565b620003256200031c82620002f8565b84845462000266565b825550505050565b600090565b6200033c6200032d565b6200034981848462000302565b505050565b5b8181101562000371576200036560008262000332565b6001810190506200034f565b5050565b601f821115620003c0576200038a8162000234565b620003958462000249565b81016020851015620003a5578190505b620003bd620003b48562000249565b8301826200034e565b50505b505050565b600082821c905092915050565b6000620003e560001984600802620003c5565b1980831691505092915050565b6000620004008383620003d2565b9150826002028217905092915050565b6200041b8262000196565b67ffffffffffffffff811115620004375762000436620001a1565b5b620004438254620001ff565b6200045082828562000375565b600060209050601f83116001811462000488576000841562000473578287015190505b6200047f8582620003f2565b865550620004ef565b601f198416620004988662000234565b60005b82811015620004c2578489015182556001820191506020850194506020810190506200049b565b86831015620004e25784890151620004de601f891682620003d2565b8355505b6001600288020188555050505b505050505050565b613cf180620005076000396000f3fe6080604052600436106101b75760003560e01c806370a08231116100ec578063c87b56dd1161008a578063e66bb34511610064578063e66bb34514610682578063e985e9c5146106ad578063f1537686146106ea578063f2fde38b14610727576101b7565b8063c87b56dd146105ca578063d78162e914610607578063e63697c814610645576101b7565b806395d89b41116100c657806395d89b4114610510578063a22cb4651461053b578063b88d4fde14610564578063c3c5a5471461058d576101b7565b806370a0823114610491578063715018a6146104ce5780638da5cb5b146104e5576101b7565b806342842e0e116101595780634c081138116101335780634c081138146103be5780634f6ccce7146103fb5780636029bf9f146104385780636352211e14610454576101b7565b806342842e0e1461031b5780634420e486146103445780634903b0d114610381576101b7565b8063095ea7b311610195578063095ea7b31461026157806318160ddd1461028a57806323b872dd146102b55780632f745c59146102de576101b7565b806301ffc9a7146101bc57806306fdde03146101f9578063081812fc14610224575b600080fd5b3480156101c857600080fd5b506101e360048036038101906101de919061290f565b610750565b6040516101f09190612957565b60405180910390f35b34801561020557600080fd5b5061020e6107ca565b60405161021b9190612a02565b60405180910390f35b34801561023057600080fd5b5061024b60048036038101906102469190612a5a565b61085c565b6040516102589190612ac8565b60405180910390f35b34801561026d57600080fd5b5061028860048036038101906102839190612b0f565b6108a2565b005b34801561029657600080fd5b5061029f6109b9565b6040516102ac9190612b5e565b60405180910390f35b3480156102c157600080fd5b506102dc60048036038101906102d79190612b79565b6109c6565b005b3480156102ea57600080fd5b5061030560048036038101906103009190612b0f565b610a26565b6040516103129190612b5e565b60405180910390f35b34801561032757600080fd5b50610342600480360381019061033d9190612b79565b610acb565b005b34801561035057600080fd5b5061036b60048036038101906103669190612bcc565b610aeb565b6040516103789190612b5e565b60405180910390f35b34801561038d57600080fd5b506103a860048036038101906103a39190612a5a565b610c82565b6040516103b59190612b5e565b60405180910390f35b3480156103ca57600080fd5b506103e560048036038101906103e09190612a5a565b610c9a565b6040516103f29190612b5e565b60405180910390f35b34801561040757600080fd5b50610422600480360381019061041d9190612a5a565b610deb565b60405161042f9190612b5e565b60405180910390f35b610452600480360381019061044d9190612a5a565b610e5c565b005b34801561046057600080fd5b5061047b60048036038101906104769190612a5a565b610f04565b6040516104889190612ac8565b60405180910390f35b34801561049d57600080fd5b506104b860048036038101906104b39190612bcc565b610fb5565b6040516104c59190612b5e565b60405180910390f35b3480156104da57600080fd5b506104e361106c565b005b3480156104f157600080fd5b506104fa611080565b6040516105079190612ac8565b60405180910390f35b34801561051c57600080fd5b506105256110a9565b6040516105329190612a02565b60405180910390f35b34801561054757600080fd5b50610562600480360381019061055d9190612c25565b61113b565b005b34801561057057600080fd5b5061058b60048036038101906105869190612d9a565b611151565b005b34801561059957600080fd5b506105b460048036038101906105af9190612bcc565b6111b3565b6040516105c19190612957565b60405180910390f35b3480156105d657600080fd5b506105f160048036038101906105ec9190612a5a565b61120c565b6040516105fe9190612a02565b60405180910390f35b34801561061357600080fd5b5061062e60048036038101906106299190612bcc565b611274565b60405161063c929190612e1d565b60405180910390f35b34801561065157600080fd5b5061066c60048036038101906106679190612e84565b6112a5565b6040516106799190612b5e565b60405180910390f35b34801561068e57600080fd5b506106976113f3565b6040516106a49190612b5e565b60405180910390f35b3480156106b957600080fd5b506106d460048036038101906106cf9190612ed7565b611404565b6040516106e19190612957565b60405180910390f35b3480156106f657600080fd5b50610711600480360381019061070c9190612bcc565b611498565b60405161071e9190612b5e565b60405180910390f35b34801561073357600080fd5b5061074e60048036038101906107499190612bcc565b611523565b005b60007f780e9d63000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107c357506107c2826115a6565b5b9050919050565b6060600180546107d990612f46565b80601f016020809104026020016040519081016040528092919081815260200182805461080590612f46565b80156108525780601f1061082757610100808354040283529160200191610852565b820191906000526020600020905b81548152906001019060200180831161083557829003601f168201915b5050505050905090565b600061086782611688565b6005600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60006108ad82610f04565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361091d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091490612fe9565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1661093c6116d3565b73ffffffffffffffffffffffffffffffffffffffff16148061096b575061096a816109656116d3565b611404565b5b6109aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a19061307b565b60405180910390fd5b6109b483836116db565b505050565b6000600980549050905090565b6109d76109d16116d3565b82611794565b610a16576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a0d9061310d565b60405180910390fd5b610a21838383611829565b505050565b6000610a3183610fb5565b8210610a72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a699061319f565b60405180910390fd5b600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002054905092915050565b610ae683838360405180602001604052806000815250611151565b505050565b600080339050610afa816111b3565b15610b31576040517f3a81d6fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000339050600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610b9c576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ba6600b611a8f565b9250610bb28484611a9d565b610bbc600b611c76565b7fcc0bec1447060c88cdc5a739cf29cfa26c453574dd3f5b9e4dcc317d6401cb1c818585604051610bef939291906131bf565b60405180910390a1604051806040016040528084815260200160011515815250600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548160ff0219169083151502179055509050505050919050565b600d6020528060005260406000206000915090505481565b600080339050610ca9816111b3565b15610ce0576040517f3a81d6fc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000339050610cee84611c8c565b610d24576040517f3f6cc76800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f8a0e37b73a0d9c82e205d4d1a3ff3d0b57ce5f4d7bccf6bac03336dc101cb7ba8185604051610d559291906131f6565b60405180910390a1604051806040016040528085815260200160011515815250600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000820151816000015560208201518160010160006101000a81548160ff0219169083151502179055509050508392505050919050565b6000610df56109b9565b8210610e36576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e2d90613291565b60405180910390fd5b60098281548110610e4a57610e496132b1565b5b90600052602060002001549050919050565b610e64611cf8565b60003403610e9e576040517f01663f2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34600d60008381526020019081526020016000206000828254610ec1919061330f565b925050819055507f916ad8171ef8c567c7790377a142f0200f9565940680c06e30dd105cfd9249688134604051610ef9929190613343565b60405180910390a150565b6000806003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610fac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fa3906133b8565b60405180910390fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611025576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161101c9061344a565b60405180910390fd5b600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b611074611cf8565b61107e6000611d76565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6060600280546110b890612f46565b80601f01602080910402602001604051908101604052809291908181526020018280546110e490612f46565b80156111315780601f1061110657610100808354040283529160200191611131565b820191906000526020600020905b81548152906001019060200180831161111457829003601f168201915b5050505050905090565b61114d6111466116d3565b8383611e3a565b5050565b61116261115c6116d3565b83611794565b6111a1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111989061310d565b60405180910390fd5b6111ad84848484611fa6565b50505050565b6000600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010160009054906101000a900460ff169050919050565b606061121782611688565b6000611221612002565b90506000815111611241576040518060200160405280600081525061126c565b8061124b84612019565b60405160200161125c9291906134a6565b6040516020818303038152906040525b915050919050565b600c6020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16905082565b6000833373ffffffffffffffffffffffffffffffffffffffff166112c882610f04565b73ffffffffffffffffffffffffffffffffffffffff1614611315576040517feea91ff800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600d6000878152602001908152602001600020549050600081148061133c5750600084145b15611373576040517fd0d04f6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8084111561137f578093505b838161138b91906134ca565b600d6000888152602001908152602001600020819055507f9da6493a92039daf47d1f2d7a782299c5994c6323eb1e972f69c432089ec52bf8686866040516113d59392919061355d565b60405180910390a16113e78585612179565b83925050509392505050565b60006113ff600b611a8f565b905090565b6000600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b60006114a3826111b3565b6114d9576040517f7748bce600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c60008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001549050919050565b61152b611cf8565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361159a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161159190613606565b60405180910390fd5b6115a381611d76565b50565b60007f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061167157507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061168157506116808261226d565b5b9050919050565b61169181611c8c565b6116d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116c7906133b8565b60405180910390fd5b50565b600033905090565b816005600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff1661174e83610f04565b73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000806117a083610f04565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806117e257506117e18185611404565b5b8061182057508373ffffffffffffffffffffffffffffffffffffffff166118088461085c565b73ffffffffffffffffffffffffffffffffffffffff16145b91505092915050565b8273ffffffffffffffffffffffffffffffffffffffff1661184982610f04565b73ffffffffffffffffffffffffffffffffffffffff161461189f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161189690613698565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361190e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119059061372a565b60405180910390fd5b6119198383836122d7565b6119246000826116db565b6001600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461197491906134ca565b925050819055506001600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546119cb919061330f565b92505081905550816003600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4611a8a8383836123e9565b505050565b600081600001549050919050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611b0c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b0390613796565b60405180910390fd5b611b1581611c8c565b15611b55576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b4c90613802565b60405180910390fd5b611b61600083836122d7565b6001600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611bb1919061330f565b92505081905550816003600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550808273ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4611c72600083836123e9565b5050565b6001816000016000828254019250508190555050565b60008073ffffffffffffffffffffffffffffffffffffffff166003600084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614159050919050565b611d006116d3565b73ffffffffffffffffffffffffffffffffffffffff16611d1e611080565b73ffffffffffffffffffffffffffffffffffffffff1614611d74576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d6b9061386e565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611ea8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e9f906138da565b60405180910390fd5b80600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611f999190612957565b60405180910390a3505050565b611fb1848484611829565b611fbd848484846123ee565b611ffc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ff39061396c565b60405180910390fd5b50505050565b606060405180602001604052806000815250905090565b606060008203612060576040518060400160405280600181526020017f30000000000000000000000000000000000000000000000000000000000000008152509050612174565b600082905060005b6000821461209257808061207b9061398c565b915050600a8261208b9190613a03565b9150612068565b60008167ffffffffffffffff8111156120ae576120ad612c6f565b5b6040519080825280601f01601f1916602001820160405280156120e05781602001600182028036833780820191505090505b5090505b6000851461216d576001826120f991906134ca565b9150600a856121089190613a34565b6030612114919061330f565b60f81b81838151811061212a576121296132b1565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a856121669190613a03565b94506120e4565b8093505050505b919050565b804710156121bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121b390613ab1565b60405180910390fd5b60008273ffffffffffffffffffffffffffffffffffffffff16826040516121e290613b02565b60006040518083038185875af1925050503d806000811461221f576040519150601f19603f3d011682016040523d82523d6000602084013e612224565b606091505b5050905080612268576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225f90613b89565b60405180910390fd5b505050565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6122e2838383612575565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036123245761231f8161257a565b612363565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146123625761236183826125c3565b5b5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036123a5576123a081612730565b6123e4565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16146123e3576123e28282612801565b5b5b505050565b505050565b600061240f8473ffffffffffffffffffffffffffffffffffffffff16612880565b15612568578373ffffffffffffffffffffffffffffffffffffffff1663150b7a026124386116d3565b8786866040518563ffffffff1660e01b815260040161245a9493929190613bfe565b6020604051808303816000875af192505050801561249657506040513d601f19601f820116820180604052508101906124939190613c5f565b60015b612518573d80600081146124c6576040519150601f19603f3d011682016040523d82523d6000602084013e6124cb565b606091505b506000815103612510576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125079061396c565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161491505061256d565b600190505b949350505050565b505050565b600980549050600a600083815260200190815260200160002081905550600981908060018154018082558091505060019003906000526020600020016000909190919091505550565b600060016125d084610fb5565b6125da91906134ca565b90506000600860008481526020019081526020016000205490508181146126bf576000600760008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002054905080600760008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002081905550816008600083815260200190815260200160002081905550505b6008600084815260200190815260200160002060009055600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008381526020019081526020016000206000905550505050565b6000600160098054905061274491906134ca565b90506000600a6000848152602001908152602001600020549050600060098381548110612774576127736132b1565b5b906000526020600020015490508060098381548110612796576127956132b1565b5b906000526020600020018190555081600a600083815260200190815260200160002081905550600a60008581526020019081526020016000206000905560098054806127e5576127e4613c8c565b5b6001900381819060005260206000200160009055905550505050565b600061280c83610fb5565b905081600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002081905550806008600084815260200190815260200160002081905550505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6000604051905090565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6128ec816128b7565b81146128f757600080fd5b50565b600081359050612909816128e3565b92915050565b600060208284031215612925576129246128ad565b5b6000612933848285016128fa565b91505092915050565b60008115159050919050565b6129518161293c565b82525050565b600060208201905061296c6000830184612948565b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156129ac578082015181840152602081019050612991565b60008484015250505050565b6000601f19601f8301169050919050565b60006129d482612972565b6129de818561297d565b93506129ee81856020860161298e565b6129f7816129b8565b840191505092915050565b60006020820190508181036000830152612a1c81846129c9565b905092915050565b6000819050919050565b612a3781612a24565b8114612a4257600080fd5b50565b600081359050612a5481612a2e565b92915050565b600060208284031215612a7057612a6f6128ad565b5b6000612a7e84828501612a45565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612ab282612a87565b9050919050565b612ac281612aa7565b82525050565b6000602082019050612add6000830184612ab9565b92915050565b612aec81612aa7565b8114612af757600080fd5b50565b600081359050612b0981612ae3565b92915050565b60008060408385031215612b2657612b256128ad565b5b6000612b3485828601612afa565b9250506020612b4585828601612a45565b9150509250929050565b612b5881612a24565b82525050565b6000602082019050612b736000830184612b4f565b92915050565b600080600060608486031215612b9257612b916128ad565b5b6000612ba086828701612afa565b9350506020612bb186828701612afa565b9250506040612bc286828701612a45565b9150509250925092565b600060208284031215612be257612be16128ad565b5b6000612bf084828501612afa565b91505092915050565b612c028161293c565b8114612c0d57600080fd5b50565b600081359050612c1f81612bf9565b92915050565b60008060408385031215612c3c57612c3b6128ad565b5b6000612c4a85828601612afa565b9250506020612c5b85828601612c10565b9150509250929050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b612ca7826129b8565b810181811067ffffffffffffffff82111715612cc657612cc5612c6f565b5b80604052505050565b6000612cd96128a3565b9050612ce58282612c9e565b919050565b600067ffffffffffffffff821115612d0557612d04612c6f565b5b612d0e826129b8565b9050602081019050919050565b82818337600083830152505050565b6000612d3d612d3884612cea565b612ccf565b905082815260208101848484011115612d5957612d58612c6a565b5b612d64848285612d1b565b509392505050565b600082601f830112612d8157612d80612c65565b5b8135612d91848260208601612d2a565b91505092915050565b60008060008060808587031215612db457612db36128ad565b5b6000612dc287828801612afa565b9450506020612dd387828801612afa565b9350506040612de487828801612a45565b925050606085013567ffffffffffffffff811115612e0557612e046128b2565b5b612e1187828801612d6c565b91505092959194509250565b6000604082019050612e326000830185612b4f565b612e3f6020830184612948565b9392505050565b6000612e5182612a87565b9050919050565b612e6181612e46565b8114612e6c57600080fd5b50565b600081359050612e7e81612e58565b92915050565b600080600060608486031215612e9d57612e9c6128ad565b5b6000612eab86828701612a45565b9350506020612ebc86828701612e6f565b9250506040612ecd86828701612a45565b9150509250925092565b60008060408385031215612eee57612eed6128ad565b5b6000612efc85828601612afa565b9250506020612f0d85828601612afa565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680612f5e57607f821691505b602082108103612f7157612f70612f17565b5b50919050565b7f4552433732313a20617070726f76616c20746f2063757272656e74206f776e6560008201527f7200000000000000000000000000000000000000000000000000000000000000602082015250565b6000612fd360218361297d565b9150612fde82612f77565b604082019050919050565b6000602082019050818103600083015261300281612fc6565b9050919050565b7f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60008201527f6b656e206f776e6572206e6f7220617070726f76656420666f7220616c6c0000602082015250565b6000613065603e8361297d565b915061307082613009565b604082019050919050565b6000602082019050818103600083015261309481613058565b9050919050565b7f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560008201527f72206e6f7220617070726f766564000000000000000000000000000000000000602082015250565b60006130f7602e8361297d565b91506131028261309b565b604082019050919050565b60006020820190508181036000830152613126816130ea565b9050919050565b7f455243373231456e756d657261626c653a206f776e657220696e646578206f7560008201527f74206f6620626f756e6473000000000000000000000000000000000000000000602082015250565b6000613189602b8361297d565b91506131948261312d565b604082019050919050565b600060208201905081810360008301526131b88161317c565b9050919050565b60006060820190506131d46000830186612ab9565b6131e16020830185612ab9565b6131ee6040830184612b4f565b949350505050565b600060408201905061320b6000830185612ab9565b6132186020830184612b4f565b9392505050565b7f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60008201527f7574206f6620626f756e64730000000000000000000000000000000000000000602082015250565b600061327b602c8361297d565b91506132868261321f565b604082019050919050565b600060208201905081810360008301526132aa8161326e565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061331a82612a24565b915061332583612a24565b925082820190508082111561333d5761333c6132e0565b5b92915050565b60006040820190506133586000830185612b4f565b6133656020830184612b4f565b9392505050565b7f4552433732313a20696e76616c696420746f6b656e2049440000000000000000600082015250565b60006133a260188361297d565b91506133ad8261336c565b602082019050919050565b600060208201905081810360008301526133d181613395565b9050919050565b7f4552433732313a2061646472657373207a65726f206973206e6f74206120766160008201527f6c6964206f776e65720000000000000000000000000000000000000000000000602082015250565b600061343460298361297d565b915061343f826133d8565b604082019050919050565b6000602082019050818103600083015261346381613427565b9050919050565b600081905092915050565b600061348082612972565b61348a818561346a565b935061349a81856020860161298e565b80840191505092915050565b60006134b28285613475565b91506134be8284613475565b91508190509392505050565b60006134d582612a24565b91506134e083612a24565b92508282039050818111156134f8576134f76132e0565b5b92915050565b6000819050919050565b600061352361351e61351984612a87565b6134fe565b612a87565b9050919050565b600061353582613508565b9050919050565b60006135478261352a565b9050919050565b6135578161353c565b82525050565b60006060820190506135726000830186612b4f565b61357f602083018561354e565b61358c6040830184612b4f565b949350505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b60006135f060268361297d565b91506135fb82613594565b604082019050919050565b6000602082019050818103600083015261361f816135e3565b9050919050565b7f4552433732313a207472616e736665722066726f6d20696e636f72726563742060008201527f6f776e6572000000000000000000000000000000000000000000000000000000602082015250565b600061368260258361297d565b915061368d82613626565b604082019050919050565b600060208201905081810360008301526136b181613675565b9050919050565b7f4552433732313a207472616e7366657220746f20746865207a65726f2061646460008201527f7265737300000000000000000000000000000000000000000000000000000000602082015250565b600061371460248361297d565b915061371f826136b8565b604082019050919050565b6000602082019050818103600083015261374381613707565b9050919050565b7f4552433732313a206d696e7420746f20746865207a65726f2061646472657373600082015250565b600061378060208361297d565b915061378b8261374a565b602082019050919050565b600060208201905081810360008301526137af81613773565b9050919050565b7f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000600082015250565b60006137ec601c8361297d565b91506137f7826137b6565b602082019050919050565b6000602082019050818103600083015261381b816137df565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b600061385860208361297d565b915061386382613822565b602082019050919050565b600060208201905081810360008301526138878161384b565b9050919050565b7f4552433732313a20617070726f766520746f2063616c6c657200000000000000600082015250565b60006138c460198361297d565b91506138cf8261388e565b602082019050919050565b600060208201905081810360008301526138f3816138b7565b9050919050565b7f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560008201527f63656976657220696d706c656d656e7465720000000000000000000000000000602082015250565b600061395660328361297d565b9150613961826138fa565b604082019050919050565b6000602082019050818103600083015261398581613949565b9050919050565b600061399782612a24565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036139c9576139c86132e0565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000613a0e82612a24565b9150613a1983612a24565b925082613a2957613a286139d4565b5b828204905092915050565b6000613a3f82612a24565b9150613a4a83612a24565b925082613a5a57613a596139d4565b5b828206905092915050565b7f416464726573733a20696e73756666696369656e742062616c616e6365000000600082015250565b6000613a9b601d8361297d565b9150613aa682613a65565b602082019050919050565b60006020820190508181036000830152613aca81613a8e565b9050919050565b600081905092915050565b50565b6000613aec600083613ad1565b9150613af782613adc565b600082019050919050565b6000613b0d82613adf565b9150819050919050565b7f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260008201527f6563697069656e74206d61792068617665207265766572746564000000000000602082015250565b6000613b73603a8361297d565b9150613b7e82613b17565b604082019050919050565b60006020820190508181036000830152613ba281613b66565b9050919050565b600081519050919050565b600082825260208201905092915050565b6000613bd082613ba9565b613bda8185613bb4565b9350613bea81856020860161298e565b613bf3816129b8565b840191505092915050565b6000608082019050613c136000830187612ab9565b613c206020830186612ab9565b613c2d6040830185612b4f565b8181036060830152613c3f8184613bc5565b905095945050505050565b600081519050613c59816128e3565b92915050565b600060208284031215613c7557613c746128ad565b5b6000613c8384828501613c4a565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220af8e0e24f2d12a183489099cadea3fda44860b88b97c863a8ef139d5fee2459164736f6c63430008110033", + "contractName" : "Turnstile" +} diff --git a/contracts/compiled_contracts/callee.json b/contracts/compiled_contracts/callee.json new file mode 100644 index 00000000..93922ed2 --- /dev/null +++ b/contracts/compiled_contracts/callee.json @@ -0,0 +1,6 @@ + +{ + "abi":"[{\"inputs\":[],\"name\":\"Int\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"val\",\"type\":\"uint256\"}],\"name\":\"setInt\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + "bin":"608060405234801561001057600080fd5b50610133806100206000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806344420311146037578063b6c27e5314604f575b600080fd5b604d60048036038101906049919060af565b6069565b005b60556073565b6040516060919060e4565b60405180910390f35b8060008190555050565b60005481565b600080fd5b6000819050919050565b608f81607e565b8114609957600080fd5b50565b60008135905060a9816088565b92915050565b60006020828403121560c25760c16079565b5b600060ce84828501609c565b91505092915050565b60de81607e565b82525050565b600060208201905060f7600083018460d7565b9291505056fea2646970667358221220419f2ec3c731b473ed042fc9894a33156ca82941a01a95cf30ddd465f0fa469164736f6c634300080f0033", + "contractName" : "callee" +} diff --git a/contracts/compiled_contracts/caller.json b/contracts/compiled_contracts/caller.json new file mode 100644 index 00000000..1cdcb984 --- /dev/null +++ b/contracts/compiled_contracts/caller.json @@ -0,0 +1,5 @@ +{ +"abi":"[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"propId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"title\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"desc\",\"type\":\"string\"},{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"},{\"internalType\":\"string[]\",\"name\":\"signatures\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"calldatas\",\"type\":\"bytes[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"propId\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"title\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"desc\",\"type\":\"string\"},{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"},{\"internalType\":\"string[]\",\"name\":\"signatures\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"calldatas\",\"type\":\"bytes[]\"}],\"name\":\"AddProposal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"propId\",\"type\":\"uint256\"}],\"name\":\"QueryProp\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"title\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"desc\",\"type\":\"string\"},{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"values\",\"type\":\"uint256[]\"},{\"internalType\":\"string[]\",\"name\":\"signatures\",\"type\":\"string[]\"},{\"internalType\":\"bytes[]\",\"name\":\"calldatas\",\"type\":\"bytes[]\"}],\"internalType\":\"struct ProposalStore.Proposal\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", +"bin":"60806040523480156200001157600080fd5b5060405162002acf38038062002acf833981810160405281019062000037919062000ab5565b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060006040518060e0016040528089815260200188815260200187815260200186815260200185815260200184815260200183815250905080600160008a8152602001908152602001600020600082015181600001556020820151816001019081620000e3919062000e63565b506040820151816002019081620000fb919062000e63565b5060608201518160030190805190602001906200011a92919062000189565b5060808201518160040190805190602001906200013992919062000218565b5060a0820151816005019080519060200190620001589291906200026a565b5060c082015181600601908051906020019062000177929190620002ca565b509050505050505050505050620010a1565b82805482825590600052602060002090810192821562000205579160200282015b82811115620002045782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190620001aa565b5b5090506200021491906200032a565b5090565b82805482825590600052602060002090810192821562000257579160200282015b828111156200025657825182559160200191906001019062000239565b5b5090506200026691906200032a565b5090565b828054828255906000526020600020908101928215620002b7579160200282015b82811115620002b6578251829081620002a5919062000e63565b50916020019190600101906200028b565b5b509050620002c6919062000349565b5090565b82805482825590600052602060002090810192821562000317579160200282015b828111156200031657825182908162000305919062000fba565b5091602001919060010190620002eb565b5b50905062000326919062000371565b5090565b5b80821115620003455760008160009055506001016200032b565b5090565b5b808211156200036d576000818162000363919062000399565b506001016200034a565b5090565b5b808211156200039557600081816200038b9190620003df565b5060010162000372565b5090565b508054620003a79062000c5c565b6000825580601f10620003bb5750620003dc565b601f016020900490600052602060002090810190620003db91906200032a565b5b50565b508054620003ed9062000c5c565b6000825580601f1062000401575062000422565b601f0160209004906000526020600020908101906200042191906200032a565b5b50565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6200044e8162000439565b81146200045a57600080fd5b50565b6000815190506200046e8162000443565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b620004c9826200047e565b810181811067ffffffffffffffff82111715620004eb57620004ea6200048f565b5b80604052505050565b60006200050062000425565b90506200050e8282620004be565b919050565b600067ffffffffffffffff8211156200053157620005306200048f565b5b6200053c826200047e565b9050602081019050919050565b60005b83811015620005695780820151818401526020810190506200054c565b8381111562000579576000848401525b50505050565b600062000596620005908462000513565b620004f4565b905082815260208101848484011115620005b557620005b462000479565b5b620005c284828562000549565b509392505050565b600082601f830112620005e257620005e162000474565b5b8151620005f48482602086016200057f565b91505092915050565b600067ffffffffffffffff8211156200061b576200061a6200048f565b5b602082029050602081019050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200065e8262000631565b9050919050565b620006708162000651565b81146200067c57600080fd5b50565b600081519050620006908162000665565b92915050565b6000620006ad620006a784620005fd565b620004f4565b90508083825260208201905060208402830185811115620006d357620006d26200062c565b5b835b81811015620007005780620006eb88826200067f565b845260208401935050602081019050620006d5565b5050509392505050565b600082601f83011262000722576200072162000474565b5b81516200073484826020860162000696565b91505092915050565b600067ffffffffffffffff8211156200075b576200075a6200048f565b5b602082029050602081019050919050565b6000620007836200077d846200073d565b620004f4565b90508083825260208201905060208402830185811115620007a957620007a86200062c565b5b835b81811015620007d65780620007c188826200045d565b845260208401935050602081019050620007ab565b5050509392505050565b600082601f830112620007f857620007f762000474565b5b81516200080a8482602086016200076c565b91505092915050565b600067ffffffffffffffff8211156200083157620008306200048f565b5b602082029050602081019050919050565b600062000859620008538462000813565b620004f4565b905080838252602082019050602084028301858111156200087f576200087e6200062c565b5b835b81811015620008cd57805167ffffffffffffffff811115620008a857620008a762000474565b5b808601620008b78982620005ca565b8552602085019450505060208101905062000881565b5050509392505050565b600082601f830112620008ef57620008ee62000474565b5b81516200090184826020860162000842565b91505092915050565b600067ffffffffffffffff8211156200092857620009276200048f565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156200095757620009566200048f565b5b62000962826200047e565b9050602081019050919050565b600062000986620009808462000939565b620004f4565b905082815260208101848484011115620009a557620009a462000479565b5b620009b284828562000549565b509392505050565b600082601f830112620009d257620009d162000474565b5b8151620009e48482602086016200096f565b91505092915050565b600062000a04620009fe846200090a565b620004f4565b9050808382526020820190506020840283018581111562000a2a5762000a296200062c565b5b835b8181101562000a7857805167ffffffffffffffff81111562000a535762000a5262000474565b5b80860162000a628982620009ba565b8552602085019450505060208101905062000a2c565b5050509392505050565b600082601f83011262000a9a5762000a9962000474565b5b815162000aac848260208601620009ed565b91505092915050565b600080600080600080600060e0888a03121562000ad75762000ad66200042f565b5b600062000ae78a828b016200045d565b975050602088015167ffffffffffffffff81111562000b0b5762000b0a62000434565b5b62000b198a828b01620005ca565b965050604088015167ffffffffffffffff81111562000b3d5762000b3c62000434565b5b62000b4b8a828b01620005ca565b955050606088015167ffffffffffffffff81111562000b6f5762000b6e62000434565b5b62000b7d8a828b016200070a565b945050608088015167ffffffffffffffff81111562000ba15762000ba062000434565b5b62000baf8a828b01620007e0565b93505060a088015167ffffffffffffffff81111562000bd35762000bd262000434565b5b62000be18a828b01620008d7565b92505060c088015167ffffffffffffffff81111562000c055762000c0462000434565b5b62000c138a828b0162000a82565b91505092959891949750929550565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168062000c7557607f821691505b60208210810362000c8b5762000c8a62000c2d565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b60006008830262000cf57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000cb6565b62000d01868362000cb6565b95508019841693508086168417925050509392505050565b6000819050919050565b600062000d4462000d3e62000d388462000439565b62000d19565b62000439565b9050919050565b6000819050919050565b62000d608362000d23565b62000d7862000d6f8262000d4b565b84845462000cc3565b825550505050565b600090565b62000d8f62000d80565b62000d9c81848462000d55565b505050565b5b8181101562000dc45762000db860008262000d85565b60018101905062000da2565b5050565b601f82111562000e135762000ddd8162000c91565b62000de88462000ca6565b8101602085101562000df8578190505b62000e1062000e078562000ca6565b83018262000da1565b50505b505050565b600082821c905092915050565b600062000e386000198460080262000e18565b1980831691505092915050565b600062000e53838362000e25565b9150826002028217905092915050565b62000e6e8262000c22565b67ffffffffffffffff81111562000e8a5762000e896200048f565b5b62000e96825462000c5c565b62000ea382828562000dc8565b600060209050601f83116001811462000edb576000841562000ec6578287015190505b62000ed2858262000e45565b86555062000f42565b601f19841662000eeb8662000c91565b60005b8281101562000f155784890151825560018201915060208501945060208101905062000eee565b8683101562000f35578489015162000f31601f89168262000e25565b8355505b6001600288020188555050505b505050505050565b600081519050919050565b60008190508160005260206000209050919050565b601f82111562000fb55762000f7f8162000f55565b62000f8a8462000ca6565b8101602085101562000f9a578190505b62000fb262000fa98562000ca6565b83018262000da1565b50505b505050565b62000fc58262000f4a565b67ffffffffffffffff81111562000fe15762000fe06200048f565b5b62000fed825462000c5c565b62000ffa82828562000f6a565b600060209050601f8311600181146200103257600084156200101d578287015190505b62001029858262000e45565b86555062001099565b601f198416620010428662000f55565b60005b828110156200106c5784890151825560018201915060208501945060208101905062001045565b868310156200108c578489015162001088601f89168262000e25565b8355505b6001600288020188555050505b505050505050565b611a1e80620010b16000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806327bc123e1461003b578063f0e147b814610057575b600080fd5b61005560048036038101906100509190610fa8565b610087565b005b610071600480360381019061006c91906110f2565b610189565b60405161007e91906115bb565b60405180910390f35b60006040518060e0016040528089815260200188815260200187815260200186815260200185815260200184815260200183815250905080600160008a81526020019081526020016000206000820151816000015560208201518160010190816100f191906117e9565b50604082015181600201908161010791906117e9565b506060820151816003019080519060200190610124929190610721565b5060808201518160040190805190602001906101419291906107ab565b5060a082015181600501908051906020019061015e9291906107f8565b5060c082015181600601908051906020019061017b929190610851565b509050505050505050505050565b6101916108aa565b8160016000848152602001908152602001600020600001540361059957600160008381526020019081526020016000206040518060e0016040529081600082015481526020016001820180546101e69061160c565b80601f01602080910402602001604051908101604052809291908181526020018280546102129061160c565b801561025f5780601f106102345761010080835404028352916020019161025f565b820191906000526020600020905b81548152906001019060200180831161024257829003601f168201915b505050505081526020016002820180546102789061160c565b80601f01602080910402602001604051908101604052809291908181526020018280546102a49061160c565b80156102f15780601f106102c6576101008083540402835291602001916102f1565b820191906000526020600020905b8154815290600101906020018083116102d457829003601f168201915b505050505081526020016003820180548060200260200160405190810160405280929190818152602001828054801561037f57602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610335575b50505050508152602001600482018054806020026020016040519081016040528092919081815260200182805480156103d757602002820191906000526020600020905b8154815260200190600101908083116103c3575b5050505050815260200160058201805480602002602001604051908101604052809291908181526020016000905b828210156104b15783829060005260206000200180546104249061160c565b80601f01602080910402602001604051908101604052809291908181526020018280546104509061160c565b801561049d5780601f106104725761010080835404028352916020019161049d565b820191906000526020600020905b81548152906001019060200180831161048057829003601f168201915b505050505081526020019060010190610405565b50505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b8282101561058a5783829060005260206000200180546104fd9061160c565b80601f01602080910402602001604051908101604052809291908181526020018280546105299061160c565b80156105765780601f1061054b57610100808354040283529160200191610576565b820191906000526020600020905b81548152906001019060200180831161055957829003601f168201915b5050505050815260200190600101906104de565b5050505081525050905061071c565b6040518060e0016040528060008152602001604051806020016040528060008152508152602001604051806020016040528060008152508152602001600067ffffffffffffffff8111156105f0576105ef610a31565b5b60405190808252806020026020018201604052801561061e5781602001602082028036833780820191505090505b508152602001600067ffffffffffffffff81111561063f5761063e610a31565b5b60405190808252806020026020018201604052801561066d5781602001602082028036833780820191505090505b508152602001600067ffffffffffffffff81111561068e5761068d610a31565b5b6040519080825280602002602001820160405280156106c157816020015b60608152602001906001900390816106ac5790505b508152602001600067ffffffffffffffff8111156106e2576106e1610a31565b5b60405190808252806020026020018201604052801561071557816020015b60608152602001906001900390816107005790505b5081525090505b919050565b82805482825590600052602060002090810192821561079a579160200282015b828111156107995782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610741565b5b5090506107a791906108e7565b5090565b8280548282559060005260206000209081019282156107e7579160200282015b828111156107e65782518255916020019190600101906107cb565b5b5090506107f491906108e7565b5090565b828054828255906000526020600020908101928215610840579160200282015b8281111561083f57825182908161082f91906117e9565b5091602001919060010190610818565b5b50905061084d9190610904565b5090565b828054828255906000526020600020908101928215610899579160200282015b828111156108985782518290816108889190611916565b5091602001919060010190610871565b5b5090506108a69190610928565b5090565b6040518060e00160405280600081526020016060815260200160608152602001606081526020016060815260200160608152602001606081525090565b5b808211156109005760008160009055506001016108e8565b5090565b5b80821115610924576000818161091b919061094c565b50600101610905565b5090565b5b80821115610948576000818161093f919061098c565b50600101610929565b5090565b5080546109589061160c565b6000825580601f1061096a5750610989565b601f01602090049060005260206000209081019061098891906108e7565b5b50565b5080546109989061160c565b6000825580601f106109aa57506109c9565b601f0160209004906000526020600020908101906109c891906108e7565b5b50565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6109f3816109e0565b81146109fe57600080fd5b50565b600081359050610a10816109ea565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610a6982610a20565b810181811067ffffffffffffffff82111715610a8857610a87610a31565b5b80604052505050565b6000610a9b6109cc565b9050610aa78282610a60565b919050565b600067ffffffffffffffff821115610ac757610ac6610a31565b5b610ad082610a20565b9050602081019050919050565b82818337600083830152505050565b6000610aff610afa84610aac565b610a91565b905082815260208101848484011115610b1b57610b1a610a1b565b5b610b26848285610add565b509392505050565b600082601f830112610b4357610b42610a16565b5b8135610b53848260208601610aec565b91505092915050565b600067ffffffffffffffff821115610b7757610b76610a31565b5b602082029050602081019050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610bb882610b8d565b9050919050565b610bc881610bad565b8114610bd357600080fd5b50565b600081359050610be581610bbf565b92915050565b6000610bfe610bf984610b5c565b610a91565b90508083825260208201905060208402830185811115610c2157610c20610b88565b5b835b81811015610c4a5780610c368882610bd6565b845260208401935050602081019050610c23565b5050509392505050565b600082601f830112610c6957610c68610a16565b5b8135610c79848260208601610beb565b91505092915050565b600067ffffffffffffffff821115610c9d57610c9c610a31565b5b602082029050602081019050919050565b6000610cc1610cbc84610c82565b610a91565b90508083825260208201905060208402830185811115610ce457610ce3610b88565b5b835b81811015610d0d5780610cf98882610a01565b845260208401935050602081019050610ce6565b5050509392505050565b600082601f830112610d2c57610d2b610a16565b5b8135610d3c848260208601610cae565b91505092915050565b600067ffffffffffffffff821115610d6057610d5f610a31565b5b602082029050602081019050919050565b6000610d84610d7f84610d45565b610a91565b90508083825260208201905060208402830185811115610da757610da6610b88565b5b835b81811015610dee57803567ffffffffffffffff811115610dcc57610dcb610a16565b5b808601610dd98982610b2e565b85526020850194505050602081019050610da9565b5050509392505050565b600082601f830112610e0d57610e0c610a16565b5b8135610e1d848260208601610d71565b91505092915050565b600067ffffffffffffffff821115610e4157610e40610a31565b5b602082029050602081019050919050565b600067ffffffffffffffff821115610e6d57610e6c610a31565b5b610e7682610a20565b9050602081019050919050565b6000610e96610e9184610e52565b610a91565b905082815260208101848484011115610eb257610eb1610a1b565b5b610ebd848285610add565b509392505050565b600082601f830112610eda57610ed9610a16565b5b8135610eea848260208601610e83565b91505092915050565b6000610f06610f0184610e26565b610a91565b90508083825260208201905060208402830185811115610f2957610f28610b88565b5b835b81811015610f7057803567ffffffffffffffff811115610f4e57610f4d610a16565b5b808601610f5b8982610ec5565b85526020850194505050602081019050610f2b565b5050509392505050565b600082601f830112610f8f57610f8e610a16565b5b8135610f9f848260208601610ef3565b91505092915050565b600080600080600080600060e0888a031215610fc757610fc66109d6565b5b6000610fd58a828b01610a01565b975050602088013567ffffffffffffffff811115610ff657610ff56109db565b5b6110028a828b01610b2e565b965050604088013567ffffffffffffffff811115611023576110226109db565b5b61102f8a828b01610b2e565b955050606088013567ffffffffffffffff8111156110505761104f6109db565b5b61105c8a828b01610c54565b945050608088013567ffffffffffffffff81111561107d5761107c6109db565b5b6110898a828b01610d17565b93505060a088013567ffffffffffffffff8111156110aa576110a96109db565b5b6110b68a828b01610df8565b92505060c088013567ffffffffffffffff8111156110d7576110d66109db565b5b6110e38a828b01610f7a565b91505092959891949750929550565b600060208284031215611108576111076109d6565b5b600061111684828501610a01565b91505092915050565b611128816109e0565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561116857808201518184015260208101905061114d565b83811115611177576000848401525b50505050565b60006111888261112e565b6111928185611139565b93506111a281856020860161114a565b6111ab81610a20565b840191505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6111eb81610bad565b82525050565b60006111fd83836111e2565b60208301905092915050565b6000602082019050919050565b6000611221826111b6565b61122b81856111c1565b9350611236836111d2565b8060005b8381101561126757815161124e88826111f1565b975061125983611209565b92505060018101905061123a565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b60006112ac838361111f565b60208301905092915050565b6000602082019050919050565b60006112d082611274565b6112da818561127f565b93506112e583611290565b8060005b838110156113165781516112fd88826112a0565b9750611308836112b8565b9250506001810190506112e9565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600061135b838361117d565b905092915050565b6000602082019050919050565b600061137b82611323565b611385818561132e565b9350836020820285016113978561133f565b8060005b858110156113d357848403895281516113b4858261134f565b94506113bf83611363565b925060208a0199505060018101905061139b565b50829750879550505050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b600061143882611411565b611442818561141c565b935061145281856020860161114a565b61145b81610a20565b840191505092915050565b6000611472838361142d565b905092915050565b6000602082019050919050565b6000611492826113e5565b61149c81856113f0565b9350836020820285016114ae85611401565b8060005b858110156114ea57848403895281516114cb8582611466565b94506114d68361147a565b925060208a019950506001810190506114b2565b50829750879550505050505092915050565b600060e083016000830151611514600086018261111f565b506020830151848203602086015261152c828261117d565b91505060408301518482036040860152611546828261117d565b915050606083015184820360608601526115608282611216565b9150506080830151848203608086015261157a82826112c5565b91505060a083015184820360a08601526115948282611370565b91505060c083015184820360c08601526115ae8282611487565b9150508091505092915050565b600060208201905081810360008301526115d581846114fc565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061162457607f821691505b602082108103611637576116366115dd565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b60006008830261169f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82611662565b6116a98683611662565b95508019841693508086168417925050509392505050565b6000819050919050565b60006116e66116e16116dc846109e0565b6116c1565b6109e0565b9050919050565b6000819050919050565b611700836116cb565b61171461170c826116ed565b84845461166f565b825550505050565b600090565b61172961171c565b6117348184846116f7565b505050565b5b818110156117585761174d600082611721565b60018101905061173a565b5050565b601f82111561179d5761176e8161163d565b61177784611652565b81016020851015611786578190505b61179a61179285611652565b830182611739565b50505b505050565b600082821c905092915050565b60006117c0600019846008026117a2565b1980831691505092915050565b60006117d983836117af565b9150826002028217905092915050565b6117f28261112e565b67ffffffffffffffff81111561180b5761180a610a31565b5b611815825461160c565b61182082828561175c565b600060209050601f8311600181146118535760008415611841578287015190505b61184b85826117cd565b8655506118b3565b601f1984166118618661163d565b60005b8281101561188957848901518255600182019150602085019450602081019050611864565b868310156118a657848901516118a2601f8916826117af565b8355505b6001600288020188555050505b505050505050565b60008190508160005260206000209050919050565b601f821115611911576118e2816118bb565b6118eb84611652565b810160208510156118fa578190505b61190e61190685611652565b830182611739565b50505b505050565b61191f82611411565b67ffffffffffffffff81111561193857611937610a31565b5b611942825461160c565b61194d8282856118d0565b600060209050601f831160018114611980576000841561196e578287015190505b61197885826117cd565b8655506119e0565b601f19841661198e866118bb565b60005b828110156119b657848901518255600182019150602085019450602081019050611991565b868310156119d357848901516119cf601f8916826117af565b8355505b6001600288020188555050505b50505050505056fea26469706673582212201d571f701f84db94a39e107bb15ae56c5d73c1c37a07b755e0d36211a2eed7f864736f6c634300080f0033\"},\"caller.sol:caller\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"queryProp\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"propContract\",\"type\":\"address\"}],\"name\":\"setPropContract\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"govshuttleContract\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"bin\":\"608060405234801561001057600080fd5b50610cde806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80633fa7b4e81461004657806363abc2c314610064578063e26e848214610080575b600080fd5b61004e61009c565b60405161005b9190610360565b60405180910390f35b61007e600480360381019061007991906103c5565b6100c0565b005b61009a6004803603810190610095919061041e565b610283565b005b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff1663f0e147b8846040518263ffffffff1660e01b8152600401610121919061045a565b600060405180830381865afa15801561013e573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906101679190610b5d565b905060008160a0015160008151811061018357610182610ba6565b5b6020026020010151805190602001208260c001516000815181106101aa576101a9610ba6565b5b60200260200101516040516020016101c3929190610c69565b604051602081830303815290604052905081606001516000815181106101ec576101eb610ba6565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16826080015160008151811061022257610221610ba6565b5b6020026020010151826040516102389190610c91565b60006040518083038185875af1925050503d8060008114610275576040519150601f19603f3d011682016040523d82523d6000602084013e61027a565b606091505b50505050505050565b600073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146102dc57600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061034a8261031f565b9050919050565b61035a8161033f565b82525050565b60006020820190506103756000830184610351565b92915050565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6103a28161038f565b81146103ad57600080fd5b50565b6000813590506103bf81610399565b92915050565b6000602082840312156103db576103da610385565b5b60006103e9848285016103b0565b91505092915050565b6103fb8161033f565b811461040657600080fd5b50565b600081359050610418816103f2565b92915050565b60006020828403121561043457610433610385565b5b600061044284828501610409565b91505092915050565b6104548161038f565b82525050565b600060208201905061046f600083018461044b565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6104c38261047a565b810181811067ffffffffffffffff821117156104e2576104e161048b565b5b80604052505050565b60006104f561037b565b905061050182826104ba565b919050565b600080fd5b60008151905061051a81610399565b92915050565b600080fd5b600080fd5b600067ffffffffffffffff8211156105455761054461048b565b5b61054e8261047a565b9050602081019050919050565b60005b8381101561057957808201518184015260208101905061055e565b83811115610588576000848401525b50505050565b60006105a161059c8461052a565b6104eb565b9050828152602081018484840111156105bd576105bc610525565b5b6105c884828561055b565b509392505050565b600082601f8301126105e5576105e4610520565b5b81516105f584826020860161058e565b91505092915050565b600067ffffffffffffffff8211156106195761061861048b565b5b602082029050602081019050919050565b600080fd5b60008151905061063e816103f2565b92915050565b6000610657610652846105fe565b6104eb565b9050808382526020820190506020840283018581111561067a5761067961062a565b5b835b818110156106a3578061068f888261062f565b84526020840193505060208101905061067c565b5050509392505050565b600082601f8301126106c2576106c1610520565b5b81516106d2848260208601610644565b91505092915050565b600067ffffffffffffffff8211156106f6576106f561048b565b5b602082029050602081019050919050565b600061071a610715846106db565b6104eb565b9050808382526020820190506020840283018581111561073d5761073c61062a565b5b835b818110156107665780610752888261050b565b84526020840193505060208101905061073f565b5050509392505050565b600082601f83011261078557610784610520565b5b8151610795848260208601610707565b91505092915050565b600067ffffffffffffffff8211156107b9576107b861048b565b5b602082029050602081019050919050565b60006107dd6107d88461079e565b6104eb565b90508083825260208201905060208402830185811115610800576107ff61062a565b5b835b8181101561084757805167ffffffffffffffff81111561082557610824610520565b5b80860161083289826105d0565b85526020850194505050602081019050610802565b5050509392505050565b600082601f83011261086657610865610520565b5b81516108768482602086016107ca565b91505092915050565b600067ffffffffffffffff82111561089a5761089961048b565b5b602082029050602081019050919050565b600067ffffffffffffffff8211156108c6576108c561048b565b5b6108cf8261047a565b9050602081019050919050565b60006108ef6108ea846108ab565b6104eb565b90508281526020810184848401111561090b5761090a610525565b5b61091684828561055b565b509392505050565b600082601f83011261093357610932610520565b5b81516109438482602086016108dc565b91505092915050565b600061095f61095a8461087f565b6104eb565b905080838252602082019050602084028301858111156109825761098161062a565b5b835b818110156109c957805167ffffffffffffffff8111156109a7576109a6610520565b5b8086016109b4898261091e565b85526020850194505050602081019050610984565b5050509392505050565b600082601f8301126109e8576109e7610520565b5b81516109f884826020860161094c565b91505092915050565b600060e08284031215610a1757610a16610475565b5b610a2160e06104eb565b90506000610a318482850161050b565b600083015250602082015167ffffffffffffffff811115610a5557610a54610506565b5b610a61848285016105d0565b602083015250604082015167ffffffffffffffff811115610a8557610a84610506565b5b610a91848285016105d0565b604083015250606082015167ffffffffffffffff811115610ab557610ab4610506565b5b610ac1848285016106ad565b606083015250608082015167ffffffffffffffff811115610ae557610ae4610506565b5b610af184828501610770565b60808301525060a082015167ffffffffffffffff811115610b1557610b14610506565b5b610b2184828501610851565b60a08301525060c082015167ffffffffffffffff811115610b4557610b44610506565b5b610b51848285016109d3565b60c08301525092915050565b600060208284031215610b7357610b72610385565b5b600082015167ffffffffffffffff811115610b9157610b9061038a565b5b610b9d84828501610a01565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6000819050919050565b610c1c610c1782610bd5565b610c01565b82525050565b600081519050919050565b600081905092915050565b6000610c4382610c22565b610c4d8185610c2d565b9350610c5d81856020860161055b565b80840191505092915050565b6000610c758285610c0b565b600482019150610c858284610c38565b91508190509392505050565b6000610c9d8284610c38565b91508190509291505056fea26469706673582212207e23adca640af3ebc42115e2da4ac7e5b9658141443bc45f2d21eb2eef06f7c264736f6c634300080f0033", +"contractName": "caller" +} diff --git a/contracts/csr.go b/contracts/csr.go new file mode 100644 index 00000000..a299a547 --- /dev/null +++ b/contracts/csr.go @@ -0,0 +1,25 @@ +package contracts + +import ( + _ "embed" // embed compiled smart contract + "encoding/json" + + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +var ( + //go:embed compiled_contracts/Turnstile.json + TurnstileJSON []byte + TurnstileContract evmtypes.CompiledContract +) + +func init() { + err := json.Unmarshal(TurnstileJSON, &TurnstileContract) + if err != nil { + panic(err) + } + + if len(TurnstileContract.Bin) == 0 { + panic("The turnstile contract was not loaded") + } +} diff --git a/contracts/erc20.go b/contracts/erc20.go new file mode 100644 index 00000000..e5f488f3 --- /dev/null +++ b/contracts/erc20.go @@ -0,0 +1,35 @@ +package contracts + +import ( + _ "embed" // embed compiled smart contract + "encoding/json" + + "github.com/ethereum/go-ethereum/common" + evmtypes "github.com/evmos/ethermint/x/evm/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +var ( + //go:embed compiled_contracts/ERC20MinterBurnerDecimals.json + ERC20MinterBurnerDecimalsJSON []byte // nolint: golint + + // ERC20MinterBurnerDecimalsContract is the compiled erc20 contract + ERC20MinterBurnerDecimalsContract evmtypes.CompiledContract + + // ERC20MinterBurnerDecimalsAddress is the erc20 module address + ERC20MinterBurnerDecimalsAddress common.Address +) + +func init() { + ERC20MinterBurnerDecimalsAddress = types.ModuleAddress + + err := json.Unmarshal(ERC20MinterBurnerDecimalsJSON, &ERC20MinterBurnerDecimalsContract) + if err != nil { + panic(err) + } + + if len(ERC20MinterBurnerDecimalsContract.Bin) == 0 { + panic("load contract failed") + } +} diff --git a/contracts/erc20DirectBalanceManipulation.go b/contracts/erc20DirectBalanceManipulation.go new file mode 100644 index 00000000..0238a89f --- /dev/null +++ b/contracts/erc20DirectBalanceManipulation.go @@ -0,0 +1,37 @@ +package contracts + +import ( + _ "embed" // embed compiled smart contract + "encoding/json" + + "github.com/ethereum/go-ethereum/common" + evmtypes "github.com/evmos/ethermint/x/evm/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// This is an evil token. Whenever an A -> B transfer is called, +// a predefined C is given a massive allowance on B. +var ( + //go:embed compiled_contracts/ERC20DirectBalanceManipulation.json + ERC20DirectBalanceManipulationJSON []byte // nolint: golint + + // ERC20DirectBalanceManipulationContract is the compiled erc20 contract + ERC20DirectBalanceManipulationContract evmtypes.CompiledContract + + // ERC20DirectBalanceManipulationAddress is the erc20 module address + ERC20DirectBalanceManipulationAddress common.Address +) + +func init() { + ERC20DirectBalanceManipulationAddress = types.ModuleAddress + + err := json.Unmarshal(ERC20DirectBalanceManipulationJSON, &ERC20DirectBalanceManipulationContract) + if err != nil { + panic(err) + } + + if len(ERC20DirectBalanceManipulationContract.Bin) == 0 { + panic("load contract failed") + } +} diff --git a/contracts/erc20burnable.go b/contracts/erc20burnable.go new file mode 100644 index 00000000..d5e79449 --- /dev/null +++ b/contracts/erc20burnable.go @@ -0,0 +1,23 @@ +package contracts + +import ( + _ "embed" // embed compiled smart contract + "encoding/json" + + evmtypes "github.com/evmos/ethermint/x/evm/types" +) + +var ( + //go:embed compiled_contracts/ERC20Burnable.json + erc20BurnableJSON []byte + + // ERC20BurnableContract is the compiled ERC20Burnable contract + ERC20BurnableContract evmtypes.CompiledContract +) + +func init() { + err := json.Unmarshal(erc20BurnableJSON, &ERC20BurnableContract) + if err != nil { + panic(err) + } +} diff --git a/contracts/erc20maliciousdelayed.go b/contracts/erc20maliciousdelayed.go new file mode 100644 index 00000000..3f38eb38 --- /dev/null +++ b/contracts/erc20maliciousdelayed.go @@ -0,0 +1,37 @@ +package contracts + +import ( + _ "embed" // embed compiled smart contract + "encoding/json" + + "github.com/ethereum/go-ethereum/common" + evmtypes "github.com/evmos/ethermint/x/evm/types" + + "github.com/AltheaFoundation/althea-L1/x/erc20/types" +) + +// This is an evil token. Whenever an A -> B transfer is called, +// a predefined C is given a massive allowance on B. +var ( + //go:embed compiled_contracts/ERC20MaliciousDelayed.json + ERC20MaliciousDelayedJSON []byte // nolint: golint + + // ERC20MaliciousDelayedContract is the compiled erc20 contract + ERC20MaliciousDelayedContract evmtypes.CompiledContract + + // ERC20MaliciousDelayedAddress is the erc20 module address + ERC20MaliciousDelayedAddress common.Address +) + +func init() { + ERC20MaliciousDelayedAddress = types.ModuleAddress + + err := json.Unmarshal(ERC20MaliciousDelayedJSON, &ERC20MaliciousDelayedContract) + if err != nil { + panic(err) + } + + if len(ERC20MaliciousDelayedContract.Bin) == 0 { + panic("load contract failed") + } +} diff --git a/contracts/package-lock.json b/contracts/package-lock.json new file mode 100644 index 00000000..f00733d6 --- /dev/null +++ b/contracts/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "canto", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@openzeppelin/contracts": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.4.2.tgz", + "integrity": "sha512-NyJV7sJgoGYqbtNUWgzzOGW4T6rR19FmX1IJgXGdapGPWsuMelGJn9h03nos0iqfforCbCB0iYIR0MtIuIFLLw==" + } + } +} diff --git a/contracts/package.json b/contracts/package.json new file mode 100644 index 00000000..b40e940d --- /dev/null +++ b/contracts/package.json @@ -0,0 +1,26 @@ +{ + "name": "canto", + "version": "1.0.0", + "description": "", + "main": "index.js", + "directories": { + "doc": "docs" + }, + "dependencies": { + "@openzeppelin/contracts": "^4.4.2" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/canto/canto.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/canto/canto/issues" + }, + "homepage": "https://github.com/canto/canto#readme" +} diff --git a/contracts/turnstile.sol b/contracts/turnstile.sol new file mode 100644 index 00000000..2b7b23e3 --- /dev/null +++ b/contracts/turnstile.sol @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPLv3 +pragma solidity 0.8.17; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; + +/// @notice Implementation of CIP-001 https://github.com/Canto-Improvement-Proposals/CIPs/blob/main/CIP-001.md +/// @dev Every contract is responsible to register itself in the constructor by calling `register(address)`. +/// If contract is using proxy pattern, it's possible to register retroactively, however past fees will be lost. +/// Recipient withdraws fees by calling `withdraw(uint256,address,uint256)`. +contract Turnstile is Ownable, ERC721Enumerable { + using Counters for Counters.Counter; + + struct NftData { + uint256 tokenId; + bool registered; + } + + Counters.Counter private _tokenIdTracker; + + /// @notice maps smart contract address to tokenId + mapping(address => NftData) public feeRecipient; + + /// @notice maps tokenId to fees earned + mapping(uint256 => uint256) public balances; + + event Register(address smartContract, address recipient, uint256 tokenId); + event Assign(address smartContract, uint256 tokenId); + event Withdraw(uint256 tokenId, address recipient, uint256 feeAmount); + event DistributeFees(uint256 tokenId, uint256 feeAmount); + + error NotAnOwner(); + error NotSmartContract(); + error AlreadyRegistered(); + error Unregistered(); + error InvalidRecipient(); + error InvalidTokenId(); + error NothingToWithdraw(); + error NothingToDistribute(); + + /// @dev only owner of _tokenId can call this function + modifier onlyNftOwner(uint256 _tokenId) { + if (ownerOf(_tokenId) != msg.sender) revert NotAnOwner(); + + _; + } + + /// @dev only smart contract that is unregistered can call this function + modifier onlyUnregistered() { + address smartContract = msg.sender; + + if (isRegistered(smartContract)) revert AlreadyRegistered(); + + _; + } + + constructor() ERC721("Turnstile", "Turnstile") {} + + /// @notice Returns current value of counter used to tokenId of new minted NFTs + /// @return current counter value + function currentCounterId() external view returns (uint256) { + return _tokenIdTracker.current(); + } + + /// @notice Returns tokenId that collects fees generated by the smart contract + /// @param _smartContract address of the smart contract + /// @return tokenId that collects fees generated by the smart contract + function getTokenId(address _smartContract) external view returns (uint256) { + if (!isRegistered(_smartContract)) revert Unregistered(); + + return feeRecipient[_smartContract].tokenId; + } + + /// @notice Returns true if smart contract is registered to collect fees + /// @param _smartContract address of the smart contract + /// @return true if smart contract is registered to collect fees, false otherwise + function isRegistered(address _smartContract) public view returns (bool) { + return feeRecipient[_smartContract].registered; + } + + /// @notice Mints ownership NFT that allows the owner to collect fees earned by the smart contract. + /// `msg.sender` is assumed to be a smart contract that earns fees. Only smart contract itself + /// can register a fee receipient. + /// @param _recipient recipient of the ownership NFT + /// @return tokenId of the ownership NFT that collects fees + function register(address _recipient) public onlyUnregistered returns (uint256 tokenId) { + address smartContract = msg.sender; + + if (_recipient == address(0)) revert InvalidRecipient(); + + tokenId = _tokenIdTracker.current(); + _mint(_recipient, tokenId); + _tokenIdTracker.increment(); + + emit Register(smartContract, _recipient, tokenId); + + feeRecipient[smartContract] = NftData({ + tokenId: tokenId, + registered: true + }); + } + + /// @notice Assigns smart contract to existing NFT. That NFT will collect fees generated by the smart contract. + /// Callable only by smart contract itself. + /// @param _tokenId tokenId which will collect fees + /// @return tokenId of the ownership NFT that collects fees + function assign(uint256 _tokenId) public onlyUnregistered returns (uint256) { + address smartContract = msg.sender; + + if (!_exists(_tokenId)) revert InvalidTokenId(); + + emit Assign(smartContract, _tokenId); + + feeRecipient[smartContract] = NftData({ + tokenId: _tokenId, + registered: true + }); + + return _tokenId; + } + + /// @notice Withdraws earned fees to `_recipient` address. Only callable by NFT owner. + /// @param _tokenId token Id + /// @param _recipient recipient of fees + /// @param _amount amount of fees to withdraw + /// @return amount of fees withdrawn + function withdraw(uint256 _tokenId, address payable _recipient, uint256 _amount) + public + onlyNftOwner(_tokenId) + returns (uint256) + { + uint256 earnedFees = balances[_tokenId]; + + if (earnedFees == 0 || _amount == 0) revert NothingToWithdraw(); + if (_amount > earnedFees) _amount = earnedFees; + + balances[_tokenId] = earnedFees - _amount; + + emit Withdraw(_tokenId, _recipient, _amount); + + Address.sendValue(_recipient, _amount); + + return _amount; + } + + /// @notice Distributes collected fees to the smart contract. Only callable by owner. + /// @param _tokenId NFT that earned fees + function distributeFees(uint256 _tokenId) public onlyOwner payable { + if (msg.value == 0) revert NothingToDistribute(); + + balances[_tokenId] += msg.value; + emit DistributeFees(_tokenId, msg.value); + } +} \ No newline at end of file From b190479f8b99832918d87ee2b17a1a692deec79b Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 7 Oct 2024 15:20:54 -0400 Subject: [PATCH 07/25] Add Multicall3 to test env --- integration_tests/test_runner/src/bin/main.rs | 3 ++ .../test_runner/src/bootstrapping.rs | 43 +++++++++++++++++++ solidity-dex | 2 +- 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/integration_tests/test_runner/src/bin/main.rs b/integration_tests/test_runner/src/bin/main.rs index 965fd6b7..b391fb67 100644 --- a/integration_tests/test_runner/src/bin/main.rs +++ b/integration_tests/test_runner/src/bin/main.rs @@ -10,6 +10,7 @@ use deep_space::Contact; use deep_space::PrivateKey; use std::env; use test_runner::bootstrapping::deploy_dex; +use test_runner::bootstrapping::deploy_multicall; use test_runner::bootstrapping::parse_contract_addresses; use test_runner::bootstrapping::parse_dex_contract_addresses; use test_runner::bootstrapping::parse_ibc_validator_keys; @@ -68,6 +69,8 @@ pub async fn main() { deploy_contracts(&contact).await; info!("Deploying DEX"); deploy_dex().await; + info!("Deploying Multicall3"); + deploy_multicall().await; return; } diff --git a/integration_tests/test_runner/src/bootstrapping.rs b/integration_tests/test_runner/src/bootstrapping.rs index 635a27b1..f163aa08 100644 --- a/integration_tests/test_runner/src/bootstrapping.rs +++ b/integration_tests/test_runner/src/bootstrapping.rs @@ -186,6 +186,49 @@ pub async fn deploy_dex() { file.write_all(&output.stdout).unwrap(); } +/// This function deploys Multicall3, which is used by various frontends +pub async fn deploy_multicall() { + const A: [&str; 1] = ["multicall-deployer"]; + // files are placed in a root /solidity-dex/ folder + const B: [&str; 1] = ["/solidity-dex/multicall-deployer"]; + // the default unmoved locations for the Gravity repo + const C: [&str; 2] = [ + "/althea/solidity-dex/misc/scripts/multicall-deployer.ts", + "/althea/solidity-dex/", + ]; + let output = if all_paths_exist(&A) || all_paths_exist(&B) { + let paths = return_existing(A, B); + Command::new(paths[0]) + .args([ + &format!("--eth-node={}", ETH_NODE.as_str()), + &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), + ]) + .output() + .expect("Failed to deploy contracts!") + } else if all_paths_exist(&C) { + Command::new("npx") + .args([ + "ts-node", + C[0], + &format!("--eth-node={}", ETH_NODE.as_str()), + &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), + ]) + .current_dir(C[1]) + .output() + .expect("Failed to deploy contracts!") + } else { + panic!("Could not find json contract artifacts in any known location!") + }; + + info!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + info!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + if !ExitStatus::success(&output.status) { + panic!("Contract deploy failed!") + } + let mut file = File::create("/multicall-contract").unwrap(); + file.write_all(&output.stdout).unwrap(); +} + // TODO: Fix send_erc20_bulk to make this method not so slow pub async fn send_erc20s_to_evm_users( web3: &Web3, diff --git a/solidity-dex b/solidity-dex index 48df2d75..144348db 160000 --- a/solidity-dex +++ b/solidity-dex @@ -1 +1 @@ -Subproject commit 48df2d75f968ed608a7aa94ea73f56c451dda3b7 +Subproject commit 144348db7f7179c5fda65a4f0bf66247fe917bb6 From b66792d07061a11107e4df58ef716eaa88360284 Mon Sep 17 00:00:00 2001 From: Justin Kilpatrick Date: Tue, 8 Oct 2024 15:36:03 -0400 Subject: [PATCH 08/25] Run Integration tests natively in CI This patch modifies the integration tests to run natively, as in without a container wrapping them, in github actions CI. --- .github/workflows/integration-tests.yml | 192 ++++++++---------- integration_tests/Cargo.lock | 10 +- integration_tests/test_runner/src/bin/main.rs | 5 +- .../test_runner/src/bootstrapping.rs | 186 ++++++++--------- .../test_runner/src/tests/mod.rs | 2 +- integration_tests/test_runner/src/utils.rs | 12 +- solidity-dex | 2 +- solidity/contract-deployer.ts | 138 +++++-------- tests/all-up-test-ci.sh | 61 ++++++ tests/container-scripts/run-testnet.sh | 2 +- 10 files changed, 306 insertions(+), 304 deletions(-) create mode 100755 tests/all-up-test-ci.sh diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 2ade30ea..7fb20a8b 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -14,9 +14,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: Swatinem/rust-cache@v1 + - uses: Swatinem/rust-cache@v2 with: - working-directory: integration-tests/ + workspaces: integration_tests/ + cache-on-failure: true - name: Build Integration Tests run: cd integration_tests && cargo check --all --verbose native_token: @@ -24,211 +25,178 @@ jobs: needs: build steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 - continue-on-error: true + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- - - name: Prune cache to keep the size down - run: docker builder prune -af && docker system prune -af + workspaces: integration_tests/ + cache-on-failure: true - name: Test the native token features of the EVM - run: tests/all-up-test.sh NATIVE_TOKEN + run: tests/all-up-test-ci.sh NATIVE_TOKEN lockup: runs-on: ubuntu-latest needs: native_token steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Lock up the chain and ensure funds are not transferrable - run: tests/all-up-test.sh LOCKUP - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh LOCKUP microtx_fees: runs-on: ubuntu-latest needs: native_token steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Assert that fees are collected by the microtx module - run: tests/all-up-test.sh MICROTX_FEES - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh MICROTX_FEES erc20_conversion: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Test the erc20 module's token conversion functionality - run: tests/all-up-test.sh ERC20_CONVERSION - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh ERC20_CONVERSION liquid_accounts: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Test the microtx module's liquid infrastructure accounts functions - run: tests/all-up-test.sh LIQUID_ACCOUNTS - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh LIQUID_ACCOUNTS ica_host: - needs: native_token + #needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Test the interchain accounts host module on Althea-L1 - run: tests/all-up-test.sh ICA_HOST - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh ICA_HOST ONBOARDING_DEFAULT_PARAMS: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Starts the onboarding module with the default params - run: tests/all-up-test.sh ONBOARDING_DEFAULT_PARAMS - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh ONBOARDING_DEFAULT_PARAMS ONBOARDING_DISABLED_WHITELISTED: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Starts the onboarding module disabled with a whitelisted channel - run: tests/all-up-test.sh ONBOARDING_DISABLED_WHITELISTED - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh ONBOARDING_DISABLED_WHITELISTED ONBOARDING_DISABLE_AFTER: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Starts the onboarding module permissively, but disables it after a transfer - run: tests/all-up-test.sh ONBOARDING_DISABLE_AFTER - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh ONBOARDING_DISABLE_AFTER ONBOARDING_DELIST_AFTER: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Starts the onboarding module permissively, but removes the channel from the whilelist after a transfer - run: tests/all-up-test.sh ONBOARDING_DELIST_AFTER - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh ONBOARDING_DELIST_AFTER DEX: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Performs basic DEX tests - run: tests/all-up-test.sh DEX - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh DEX DEX_UPGRADE: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Tests the DEX callpath upgrade functionality - run: tests/all-up-test.sh DEX_UPGRADE - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh DEX_UPGRADE DEX_SAFE_MODE: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Tests the DEX safe mode lockdown functionality - run: tests/all-up-test.sh DEX_SAFE_MODE - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh DEX_SAFE_MODE DEX_OPS_PROPOSAL: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- + workspaces: integration_tests/ + cache-on-failure: true - name: Tests the nativedex OpsProposal function - run: tests/all-up-test.sh DEX_OPS_PROPOSAL - env: - NO_IMAGE_BUILD: True + run: tests/all-up-test-ci.sh DEX_OPS_PROPOSAL UPGRADE: needs: native_token runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: jpribyl/action-docker-layer-caching@v0.1.1 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 with: - key: integration-test-cache-{hash} - restore-keys: | - integration-test-cache- - - name: Tests the nativedex OpsProposal function - run: tests/all-up-test.sh DEX_OPS_PROPOSAL - - name: Tests the Neutrino - run: tests/run-upgrade-test.sh v1.4.0 - env: - NO_IMAGE_BUILD: True + workspaces: integration_tests/ + cache-on-failure: true + - name: Tests the Neutrino upgrade + run: tests/run-upgrade-test.sh v1.4.0 \ No newline at end of file diff --git a/integration_tests/Cargo.lock b/integration_tests/Cargo.lock index 843feb29..132f5e17 100644 --- a/integration_tests/Cargo.lock +++ b/integration_tests/Cargo.lock @@ -1364,11 +1364,11 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", @@ -1396,9 +1396,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", diff --git a/integration_tests/test_runner/src/bin/main.rs b/integration_tests/test_runner/src/bin/main.rs index b391fb67..ace25b52 100644 --- a/integration_tests/test_runner/src/bin/main.rs +++ b/integration_tests/test_runner/src/bin/main.rs @@ -4,7 +4,6 @@ #[macro_use] extern crate log; -use althea_proto::cosmos_sdk_proto::ibc; use deep_space::Coin; use deep_space::Contact; use deep_space::PrivateKey; @@ -16,7 +15,7 @@ use test_runner::bootstrapping::parse_dex_contract_addresses; use test_runner::bootstrapping::parse_ibc_validator_keys; use test_runner::bootstrapping::send_erc20s_to_evm_users; use test_runner::bootstrapping::start_ibc_relayer; -use test_runner::bootstrapping::{deploy_contracts, get_keys}; +use test_runner::bootstrapping::{deploy_erc20_contracts, get_keys}; use test_runner::tests::dex::dex_ops_proposal_test; use test_runner::tests::dex::dex_safe_mode_test; use test_runner::tests::dex::dex_test; @@ -66,7 +65,7 @@ pub async fn main() { if should_deploy_contracts() { info!("test-runner in contract deploying mode, deploying contracts, then exiting"); - deploy_contracts(&contact).await; + deploy_erc20_contracts(&contact).await; info!("Deploying DEX"); deploy_dex().await; info!("Deploying Multicall3"); diff --git a/integration_tests/test_runner/src/bootstrapping.rs b/integration_tests/test_runner/src/bootstrapping.rs index f163aa08..99d53377 100644 --- a/integration_tests/test_runner/src/bootstrapping.rs +++ b/integration_tests/test_runner/src/bootstrapping.rs @@ -91,7 +91,7 @@ pub fn parse_ibc_validator_keys() -> (Vec, Vec) { /// this runs only when the DEPLOY_CONTRACTS env var is set right after /// the Ethereum test chain starts in the testing environment. We write /// the stdout of this to a file for later test runs to parse -pub async fn deploy_contracts(contact: &Contact) { +pub async fn deploy_erc20_contracts(contact: &Contact) { // prevents the node deployer from failing (rarely) when the chain has not // yet produced the next block after submitting each eth address contact.wait_for_next_block(TOTAL_TIMEOUT).await.unwrap(); @@ -100,132 +100,113 @@ pub async fn deploy_contracts(contact: &Contact) { // and the gravity contract itself, feel free to expand this if it makes your // deployments more straightforward. - // both files are just in the PWD - const A: [&str; 1] = ["contract-deployer"]; - // files are placed in a root /solidity/ folder - const B: [&str; 1] = ["/solidity/contract-deployer"]; // the default unmoved locations for the Gravity repo - const C: [&str; 2] = ["/althea/solidity/contract-deployer.ts", "/althea/solidity/"]; - let output = if all_paths_exist(&A) || all_paths_exist(&B) { - let paths = return_existing(A, B); - Command::new(paths[0]) - .args([ - &format!("--eth-node={}", ETH_NODE.as_str()), - &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), - "--test-mode=true", - ]) - .output() - .expect("Failed to deploy contracts!") - } else if all_paths_exist(&C) { - Command::new("npx") + const A: [&str; 2] = ["/althea/solidity/contract-deployer.ts", "/althea/solidity/"]; + // the default unmoved locations for Github Actions + const B: [&str; 2] = [ + "/home/runner/work/althea-L1/althea-L1/solidity/contract-deployer.ts", + "/home/runner/work/althea-L1/althea-L1/solidity/", + ]; + let output = match return_existing(vec![A, B]) { + Some(path) => Command::new("npx") .args([ "ts-node", - C[0], + path[0], &format!("--eth-node={}", ETH_NODE.as_str()), &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), - "--test-mode=true", + &format!("--artifacts-root={}", path[1]), ]) - .current_dir(C[1]) + .current_dir(path[1]) .output() - .expect("Failed to deploy contracts!") - } else { - panic!("Could not find json contract artifacts in any known location!") + .expect("Failed to deploy contracts!"), + None => { + panic!("Could not find json contract artifacts in any known location!") + } }; - info!("stdout: {}", String::from_utf8_lossy(&output.stdout)); info!("stderr: {}", String::from_utf8_lossy(&output.stderr)); if !ExitStatus::success(&output.status) { panic!("Contract deploy failed!") } - let mut file = File::create("/contracts").unwrap(); + let mut file = File::create(ERC20_CONTRACTS_FILE).unwrap(); file.write_all(&output.stdout).unwrap(); } +/// The file where the contract addresses are stored +const DEX_CONTRACTS_FILE: &str = "/tmp/dex-contracts"; + /// This function deploys the Ambient (aka CrocSwap) dex contracts and configures them pub async fn deploy_dex() { - const A: [&str; 1] = ["dex-deployer"]; - // files are placed in a root /solidity-dex/ folder - const B: [&str; 1] = ["/solidity-dex/dex-deployer"]; - // the default unmoved locations for the Gravity repo - const C: [&str; 2] = [ + // the default unmoved locations for the Gravity repo in the docker container + const A: [&str; 2] = [ "/althea/solidity-dex/misc/scripts/dex-deployer.ts", - "/althea/solidity-dex/", + "/althea/solidity-dex/artifacts/contracts/", ]; - let output = if all_paths_exist(&A) || all_paths_exist(&B) { - let paths = return_existing(A, B); - Command::new(paths[0]) - .args([ - &format!("--eth-node={}", ETH_NODE.as_str()), - &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), - "--test-mode=true", - ]) - .output() - .expect("Failed to deploy contracts!") - } else if all_paths_exist(&C) { - Command::new("npx") + // the default unmoved locations for Github Actions + const B: [&str; 2] = [ + "/home/runner/work/althea-L1/althea-L1/solidity-dex/misc/scripts/dex-deployer.ts", + "/home/runner/work/althea-L1/althea-L1/solidity-dex/artifacts/contracts/", + ]; + let output = match return_existing(vec![A, B]) { + Some(path) => Command::new("npx") .args([ "ts-node", - C[0], + path[0], &format!("--eth-node={}", ETH_NODE.as_str()), &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), - "--test-mode=true", + &format!("--artifacts-root={}", path[1]), ]) - .current_dir(C[1]) + .current_dir(path[1]) .output() - .expect("Failed to deploy contracts!") - } else { - panic!("Could not find json contract artifacts in any known location!") + .expect("Failed to deploy contracts!"), + None => { + panic!("Could not find dex artifacts in any known location!") + } }; - info!("stdout: {}", String::from_utf8_lossy(&output.stdout)); info!("stderr: {}", String::from_utf8_lossy(&output.stderr)); if !ExitStatus::success(&output.status) { panic!("Contract deploy failed!") } - let mut file = File::create("/dex-contracts").unwrap(); + let mut file = File::create(DEX_CONTRACTS_FILE).unwrap(); file.write_all(&output.stdout).unwrap(); } /// This function deploys Multicall3, which is used by various frontends pub async fn deploy_multicall() { - const A: [&str; 1] = ["multicall-deployer"]; - // files are placed in a root /solidity-dex/ folder - const B: [&str; 1] = ["/solidity-dex/multicall-deployer"]; - // the default unmoved locations for the Gravity repo - const C: [&str; 2] = [ + // the default unmoved locations for the Gravity repo in the docker container + const A: [&str; 2] = [ "/althea/solidity-dex/misc/scripts/multicall-deployer.ts", - "/althea/solidity-dex/", + "/althea/solidity-dex/artifacts/contracts/periphery/", ]; - let output = if all_paths_exist(&A) || all_paths_exist(&B) { - let paths = return_existing(A, B); - Command::new(paths[0]) - .args([ - &format!("--eth-node={}", ETH_NODE.as_str()), - &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), - ]) - .output() - .expect("Failed to deploy contracts!") - } else if all_paths_exist(&C) { - Command::new("npx") + // locations for Github Actions + const B: [&str; 2] = [ + "/home/runner/work/althea-L1/althea-L1/solidity-dex/misc/scripts/multicall-deployer.ts", + "/home/runner/work/althea-L1/althea-L1/solidity-dex/artifacts/contracts/periphery/", + ]; + let paths = vec![A, B]; + let output = match return_existing(paths) { + Some(path) => Command::new("npx") .args([ "ts-node", - C[0], + path[0], &format!("--eth-node={}", ETH_NODE.as_str()), &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), + &format!("--artifacts-root={}", path[1]), ]) - .current_dir(C[1]) + .current_dir(path[1]) .output() - .expect("Failed to deploy contracts!") - } else { - panic!("Could not find json contract artifacts in any known location!") + .expect("Failed to deploy contracts!"), + None => { + panic!("Could not find json contract artifacts in any known location!") + } }; - info!("stdout: {}", String::from_utf8_lossy(&output.stdout)); info!("stderr: {}", String::from_utf8_lossy(&output.stderr)); if !ExitStatus::success(&output.status) { panic!("Contract deploy failed!") } - let mut file = File::create("/multicall-contract").unwrap(); + let mut file = File::create("/tmp/multicall-contract").unwrap(); file.write_all(&output.stdout).unwrap(); } @@ -268,14 +249,8 @@ fn all_paths_exist(input: &[&str]) -> bool { true } -fn return_existing<'a>(a: [&'a str; 1], b: [&'a str; 1]) -> [&'a str; 1] { - if all_paths_exist(&a) { - a - } else if all_paths_exist(&b) { - b - } else { - panic!("No paths exist!") - } +fn return_existing(paths: Vec<[&str; 2]>) -> Option<[&str; 2]> { + paths.into_iter().find(|&path| all_paths_exist(&path)) } pub struct BootstrapContractAddresses { @@ -284,11 +259,13 @@ pub struct BootstrapContractAddresses { pub uniswap_liquidity_address: Option, } +pub const ERC20_CONTRACTS_FILE: &str = "/tmp/contracts"; + /// Parses the ERC20 and Gravity contract addresses from the file created /// in deploy_contracts() pub fn parse_contract_addresses() -> BootstrapContractAddresses { let mut file = - File::open("/contracts").expect("Failed to find contracts! did they not deploy?"); + File::open(ERC20_CONTRACTS_FILE).expect("Failed to find contracts! did they not deploy?"); let mut output = String::new(); file.read_to_string(&mut output).unwrap(); let mut erc20_addresses = Vec::new(); @@ -328,7 +305,7 @@ pub struct DexAddresses { /// in deploy_dex() pub fn parse_dex_contract_addresses() -> DexAddresses { let mut file = - File::open("/dex-contracts").expect("Failed to find dex contracts! did they not deploy?"); + File::open(DEX_CONTRACTS_FILE).expect("Failed to find dex contracts! did they not deploy?"); let mut output = String::new(); file.read_to_string(&mut output).unwrap(); let mut dex: EthAddress = EthAddress::default(); @@ -372,6 +349,14 @@ pub fn parse_dex_contract_addresses() -> DexAddresses { // Hermes stores its keys in hermes_home/ pub fn setup_relayer_keys() -> Result<(), Box> { let mut command = hermes_base(); + let mut mnemonic_path: Option<&str> = None; + for path in RELAYER_MNEMONIC_FILE { + if Path::new(path).exists() { + mnemonic_path = Some(path); + break; + } + } + let mnemonic_path = mnemonic_path.expect("Could not find relayer mnemonic file"); let _althea_key = command .args([ "keys", @@ -383,7 +368,7 @@ pub fn setup_relayer_keys() -> Result<(), Box> { "--hd-path", "m/44'/60'/0'/0/0", "--mnemonic-file", - RELAYER_MNEMONIC_FILE, + mnemonic_path, ]) .spawn() .expect("Failed to add althea key"); @@ -399,7 +384,7 @@ pub fn setup_relayer_keys() -> Result<(), Box> { "--chain", &get_ibc_chain_id(), "--mnemonic-file", - RELAYER_MNEMONIC_FILE, + mnemonic_path, ]) .spawn() .expect("Failed to add ibc key"); @@ -408,6 +393,8 @@ pub fn setup_relayer_keys() -> Result<(), Box> { Ok(()) } +const IBC_RELAYER_LOGS_ROOT: &str = "/tmp/ibc-relayer-logs/"; + // Create a channel between gravity chain and the ibc test chain over the "transfer" port // Writes the output to /ibc-relayer-logs/channel-creation pub fn create_ibc_channel(hermes_base: Command) { @@ -429,9 +416,11 @@ pub fn create_ibc_channel(hermes_base: Command) { "--yes", ]); + std::fs::create_dir_all(IBC_RELAYER_LOGS_ROOT).unwrap(); let out_file = File::options() .write(true) - .open("/ibc-relayer-logs/channel-creation") + .create(true) + .open(format!("{}channel-creation", IBC_RELAYER_LOGS_ROOT)) .unwrap() .into_raw_fd(); unsafe { @@ -453,9 +442,11 @@ pub fn run_ibc_relayer(hermes_base: Command, full_scan: bool) { if full_scan { start = start.arg("--full-scan"); } + std::fs::create_dir_all(IBC_RELAYER_LOGS_ROOT).unwrap(); let out_file = File::options() .write(true) - .open("/ibc-relayer-logs/hermes-logs") + .create(true) + .open(format!("{}hermes-logs", IBC_RELAYER_LOGS_ROOT)) .unwrap() .into_raw_fd(); unsafe { @@ -526,11 +517,22 @@ pub async fn start_ibc_relayer( thread::spawn(|| { run_ibc_relayer(hermes_base(), true); // likely will not return from here, just keep running }); - info!("Running ibc relayer in the background, directing output to /ibc-relayer-logs"); + info!( + "Running ibc relayer in the background, directing output to {}", + IBC_RELAYER_LOGS_ROOT + ); } fn hermes_base() -> Command { let mut hermes_base = Command::new("hermes"); - hermes_base.arg("--config").arg(HERMES_CONFIG); + let mut config: Option<&str> = None; + for path in HERMES_CONFIG { + if Path::new(path).exists() { + config = Some(path); + break; + } + } + let config = config.expect("Could not find hermes config file"); + hermes_base.arg("--config").arg(config); hermes_base } diff --git a/integration_tests/test_runner/src/tests/mod.rs b/integration_tests/test_runner/src/tests/mod.rs index 1ebfcd3b..191584e3 100644 --- a/integration_tests/test_runner/src/tests/mod.rs +++ b/integration_tests/test_runner/src/tests/mod.rs @@ -6,4 +6,4 @@ pub mod lockup; pub mod microtx_fees; pub mod native_token; pub mod onboarding; -pub mod upgrade; \ No newline at end of file +pub mod upgrade; diff --git a/integration_tests/test_runner/src/utils.rs b/integration_tests/test_runner/src/utils.rs index b6fa15c7..8c4a51ff 100644 --- a/integration_tests/test_runner/src/utils.rs +++ b/integration_tests/test_runner/src/utils.rs @@ -36,9 +36,15 @@ use web30::{client::Web3, jsonrpc::error::Web3Error, types::SendTxOption}; pub const OPERATION_TIMEOUT: Duration = Duration::from_secs(30); /// the timeout for the total system pub const TOTAL_TIMEOUT: Duration = Duration::from_secs(300); -// The config file location for hermes -pub const HERMES_CONFIG: &str = "/althea/tests/assets/ibc-relayer-config.toml"; -pub const RELAYER_MNEMONIC_FILE: &str = "/althea/tests/assets/relayer-mnemonic.txt"; +// The config file location for hermes, two possibe locations are provided +pub const HERMES_CONFIG: [&str; 2] = [ + "/althea/tests/assets/ibc-relayer-config.toml", + "/home/runner/work/althea-L1/althea-L1/tests/assets/ibc-relayer-config.toml", +]; +pub const RELAYER_MNEMONIC_FILE: [&str; 2] = [ + "/althea/tests/assets/relayer-mnemonic.txt", + "/home/runner/work/althea-L1/althea-L1/tests/assets/relayer-mnemonic.txt", +]; pub const ALTHEA_RELAYER_ADDRESS: &str = "althea1zcr3730w7cwl5q7n28yuu3l9hmuq4w9j8rg8at"; pub const IBC_RELAYER_ADDRESS: &str = "cosmos1vdv5jau58qxv2xgzw6fj3ql70txnpl08z9pngs"; diff --git a/solidity-dex b/solidity-dex index 144348db..433af992 160000 --- a/solidity-dex +++ b/solidity-dex @@ -1 +1 @@ -Subproject commit 144348db7f7179c5fda65a4f0bf66247fe917bb6 +Subproject commit 433af992fda3f055026d9c10e7cc47f6515a6eb5 diff --git a/solidity/contract-deployer.ts b/solidity/contract-deployer.ts index cd14cb02..ccb4621a 100644 --- a/solidity/contract-deployer.ts +++ b/solidity/contract-deployer.ts @@ -12,8 +12,8 @@ const args = commandLineArgs([ { name: "eth-node", type: String }, // the Ethereum private key that will contain the gas required to pay for the contact deployment { name: "eth-privkey", type: String }, - // test mode, if enabled this script deploys three ERC20 contracts for testing - { name: "test-mode", type: String }, + // path to the artifacts folder + { name: "artifacts-root", type: String }, ]); // 4. Now, the deployer script hits a full node api, gets the Eth signatures of the valset from the latest block, and deploys the Ethereum contract. @@ -51,96 +51,62 @@ async function deploy() { var startTime = new Date(); const provider = await new ethers.providers.JsonRpcProvider(args["eth-node"]); let wallet = new ethers.Wallet(args["eth-privkey"], provider); - const testMode = args["test-mode"] == "True" || args["test-mode"] == "true"; - - if (testMode) { - var success = false; - while (!success) { - var present = new Date(); - var timeDiff: number = present.getTime() - startTime.getTime(); - timeDiff = timeDiff / 1000 - provider.getBlockNumber().then(_ => success = true).catch(_ => console.log("Ethereum RPC error, trying again")) - - if (timeDiff > 600) { - console.log("Could not contact Ethereum RPC after 10 minutes, check the URL!") - exit(1) - } - await sleep(1000); - } - } + let artifacts = args["artifacts-root"]; + + var success = false; + while (!success) { + var present = new Date(); + var timeDiff: number = present.getTime() - startTime.getTime(); + timeDiff = timeDiff / 1000 + provider.getBlockNumber().then(_ => success = true).catch(_ => console.log("Ethereum RPC error, trying again")) - if (testMode) { - console.log("Test mode, deploying ERC20 contracts"); - - // this handles several possible locations for the ERC20 artifacts - var erc20_a_path: string - var erc20_b_path: string - var erc20_c_path: string - var erc721_a_path: string - const main_location_a = "/althea/solidity/artifacts/contracts/TestERC20A.sol/TestERC20A.json" - const main_location_b = "/althea/solidity/artifacts/contracts/TestERC20B.sol/TestERC20B.json" - const main_location_c = "/althea/solidity/artifacts/contracts/TestERC20C.sol/TestERC20C.json" - const main_location_721_a = "/althea/solidity/artifacts/contracts/TestERC721A.sol/TestERC721A.json" - - const alt_location_1_a = "/solidity/TestERC20A.json" - const alt_location_1_b = "/solidity/TestERC20B.json" - const alt_location_1_c = "/solidity/TestERC20C.json" - const alt_location_1_721a = "/solidity/TestERC721A.json" - - const alt_location_2_a = "TestERC20A.json" - const alt_location_2_b = "TestERC20B.json" - const alt_location_2_c = "TestERC20C.json" - const alt_location_2_721a = "TestERC721A.json" - - if (fs.existsSync(main_location_a)) { - erc20_a_path = main_location_a - erc20_b_path = main_location_b - erc20_c_path = main_location_c - erc721_a_path = main_location_721_a - } else if (fs.existsSync(alt_location_1_a)) { - erc20_a_path = alt_location_1_a - erc20_b_path = alt_location_1_b - erc20_c_path = alt_location_1_c - erc721_a_path = alt_location_1_721a - } else if (fs.existsSync(alt_location_2_a)) { - erc20_a_path = alt_location_2_a - erc20_b_path = alt_location_2_b - erc20_c_path = alt_location_2_c - erc721_a_path = alt_location_2_721a - } else { - console.log("Test mode was enabled but the ERC20 contracts can't be found!") + if (timeDiff > 600) { + console.log("Could not contact Ethereum RPC after 10 minutes, check the URL!") exit(1) } + await sleep(1000); + } + + console.log("Deploying ERC20 contracts"); + // this handles several possible locations for the ERC20 artifacts + var erc20_a_path: string = artifacts + "/artifacts/contracts/TestERC20A.sol/TestERC20A.json" + var erc20_b_path: string = artifacts + "/artifacts/contracts/TestERC20B.sol/TestERC20B.json" + var erc20_c_path: string = artifacts + "/artifacts/contracts/TestERC20C.sol/TestERC20C.json" + var erc721_a_path: string = artifacts + "/artifacts/contracts/TestERC721A.sol/TestERC721A.json" - const { abi, bytecode } = getContractArtifacts(erc20_a_path); - const erc20Factory = new ethers.ContractFactory(abi, bytecode, wallet); - const testERC20 = (await erc20Factory.deploy(overrides)) as TestERC20A; - await testERC20.deployed(); - const erc20TestAddress = testERC20.address; - console.log("ERC20 deployed at Address - ", erc20TestAddress); - - const { abi: abi1, bytecode: bytecode1 } = getContractArtifacts(erc20_b_path); - const erc20Factory1 = new ethers.ContractFactory(abi1, bytecode1, wallet); - const testERC201 = (await erc20Factory1.deploy(overrides)) as TestERC20B; - await testERC201.deployed(); - const erc20TestAddress1 = testERC201.address; - console.log("ERC20 deployed at Address - ", erc20TestAddress1); - - const { abi: abi2, bytecode: bytecode2 } = getContractArtifacts(erc20_c_path); - const erc20Factory2 = new ethers.ContractFactory(abi2, bytecode2, wallet); - const testERC202 = (await erc20Factory2.deploy(overrides)) as TestERC20C; - await testERC202.deployed(); - const erc20TestAddress2 = testERC202.address; - console.log("ERC20 deployed at Address - ", erc20TestAddress2); - - const { abi: abi3, bytecode: bytecode3 } = getContractArtifacts(erc721_a_path); - const erc721Factory1 = new ethers.ContractFactory(abi3, bytecode3, wallet); - const testERC721 = (await erc721Factory1.deploy(overrides)) as TestERC721A; - await testERC721.deployed(); - const erc721TestAddress = testERC721.address; - console.log("ERC721 deployed at Address - ", erc721TestAddress); + if (!fs.existsSync(artifacts)) { + console.log("Artifacts folder not found, please specify the correct path using the --artifacts-root flag") + exit(1) } + + const { abi, bytecode } = getContractArtifacts(erc20_a_path); + const erc20Factory = new ethers.ContractFactory(abi, bytecode, wallet); + const testERC20 = (await erc20Factory.deploy(overrides)) as TestERC20A; + await testERC20.deployed(); + const erc20TestAddress = testERC20.address; + console.log("ERC20 deployed at Address - ", erc20TestAddress); + + const { abi: abi1, bytecode: bytecode1 } = getContractArtifacts(erc20_b_path); + const erc20Factory1 = new ethers.ContractFactory(abi1, bytecode1, wallet); + const testERC201 = (await erc20Factory1.deploy(overrides)) as TestERC20B; + await testERC201.deployed(); + const erc20TestAddress1 = testERC201.address; + console.log("ERC20 deployed at Address - ", erc20TestAddress1); + + const { abi: abi2, bytecode: bytecode2 } = getContractArtifacts(erc20_c_path); + const erc20Factory2 = new ethers.ContractFactory(abi2, bytecode2, wallet); + const testERC202 = (await erc20Factory2.deploy(overrides)) as TestERC20C; + await testERC202.deployed(); + const erc20TestAddress2 = testERC202.address; + console.log("ERC20 deployed at Address - ", erc20TestAddress2); + + const { abi: abi3, bytecode: bytecode3 } = getContractArtifacts(erc721_a_path); + const erc721Factory1 = new ethers.ContractFactory(abi3, bytecode3, wallet); + const testERC721 = (await erc721Factory1.deploy(overrides)) as TestERC721A; + await testERC721.deployed(); + const erc721TestAddress = testERC721.address; + console.log("ERC721 deployed at Address - ", erc721TestAddress); } function getContractArtifacts(path: string): { bytecode: string; abi: string } { diff --git a/tests/all-up-test-ci.sh b/tests/all-up-test-ci.sh new file mode 100755 index 00000000..91a0b5ac --- /dev/null +++ b/tests/all-up-test-ci.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# This script is used in Github actions CI to prep and run a testnet environment +TEST_TYPE=$1 +set -eux +NODES=4 + +sudo apt-get update +sudo apt-get install -y git make gcc g++ iproute2 iputils-ping procps vim tmux net-tools htop tar jq npm libssl-dev perl rustc cargo wget + +# Setup Althea L1 binary +GOPROXY=https://proxy.golang.org make +make install +sudo cp ~/go/bin/althea /usr/bin/althea + +# Download the althea gaia fork as a IBC test chain +sudo wget https://github.com/althea-net/ibc-test-chain/releases/download/v9.1.2/gaiad-v9.1.2-linux-amd64 -O /usr/bin/gaiad + +# Setup Hermes for IBC connections between chains +pushd /tmp/ +wget https://github.com/informalsystems/ibc-rs/releases/download/v1.7.0/hermes-v1.7.0-x86_64-unknown-linux-gnu.tar.gz +tar -xvf hermes-v1.7.0-x86_64-unknown-linux-gnu.tar.gz +sudo mv hermes /usr/bin/ +popd + +# make log dirs +sudo mkdir /ibc-relayer-logs +sudo touch /ibc-relayer-logs/hermes-logs +sudo touch /ibc-relayer-logs/channel-creation + +# Compile the solidity contracts +pushd solidity/ +HUSKY_SKIP_INSTALL=1 npm install +npm run typechain +ls -lah +ls -lah artifacts/ +ls -lah artifacts/contracts/ +pwd +popd + +git clone https://github.com/AltheaFoundation/althea-dex.git solidity-dex/ +pushd solidity-dex/ +HUSKY_SKIP_INSTALL=1 npm install +npx hardhat compile +ls -lah +ls -lah misc/scripts/ +pwd +popd + +sudo bash tests/container-scripts/setup-validators.sh $NODES +sudo bash tests/container-scripts/setup-ibc-validators.sh $NODES +sudo bash tests/container-scripts/run-testnet.sh $NODES $TEST_TYPE + +# deploy the ethereum contracts +pushd integration_tests/test_runner +DEPLOY_CONTRACTS=1 RUST_BACKTRACE=full TEST_TYPE=$TEST_TYPE NO_GAS_OPT=1 RUST_LOG="INFO" PATH=$PATH:$HOME/.cargo/bin cargo run --release --bin test-runner +popd + +echo "Running ibc relayer in the background, directing output to /ibc-relayer-logs" + +pushd integration_tests +RUST_BACKTRACE=full TEST_TYPE=$TEST_TYPE RUST_LOG=INFO PATH=$PATH:$HOME/.cargo/bin cargo run --release --bin test-runner diff --git a/tests/container-scripts/run-testnet.sh b/tests/container-scripts/run-testnet.sh index 149346c5..7f48bcc6 100755 --- a/tests/container-scripts/run-testnet.sh +++ b/tests/container-scripts/run-testnet.sh @@ -7,7 +7,7 @@ NODES=$1 set +u TEST_TYPE=$2 -GITHUB_ACTIONS_PATH="/home/runner/work/AltheaFoundation/althea-L1/" +GITHUB_ACTIONS_PATH="/home/runner/work/althea-L1/althea-L1/" DOCKER_PATH="/althea/" if [[ -d "$GITHUB_ACTIONS_PATH" ]]; then From 46ec8164c88de6079d56a23b98f4e348a718ef7a Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Fri, 15 Nov 2024 15:26:56 -0500 Subject: [PATCH 09/25] Advanced dex usage --- integration_tests/Cargo.lock | 1 + integration_tests/Cargo.toml | 3 +- integration_tests/test_runner/Cargo.toml | 1 + integration_tests/test_runner/src/bin/main.rs | 4 +- .../test_runner/src/dex_utils.rs | 587 +++++++++++++++++- .../test_runner/src/tests/dex.rs | 264 ++++++-- 6 files changed, 801 insertions(+), 59 deletions(-) diff --git a/integration_tests/Cargo.lock b/integration_tests/Cargo.lock index 132f5e17..72a4e750 100644 --- a/integration_tests/Cargo.lock +++ b/integration_tests/Cargo.lock @@ -2110,6 +2110,7 @@ dependencies = [ "lazy_static", "log", "num", + "num-traits", "num256", "prost", "prost-types", diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index e493b648..4251149e 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -12,4 +12,5 @@ actix = "0.13" actix-rt = "2.2" log = "0.4" env_logger = "0.9" -num = "0.4.0" \ No newline at end of file +num = "0.4.0" +num-traits = "0.2" \ No newline at end of file diff --git a/integration_tests/test_runner/Cargo.toml b/integration_tests/test_runner/Cargo.toml index dc789c48..6b243df3 100644 --- a/integration_tests/test_runner/Cargo.toml +++ b/integration_tests/test_runner/Cargo.toml @@ -32,6 +32,7 @@ actix-rt = {workspace = true} lazy_static = "1" url = "2" num = {workspace = true} +num-traits = {workspace = true} log = {workspace = true} env_logger = {workspace = true} tokio = "1.4.0" diff --git a/integration_tests/test_runner/src/bin/main.rs b/integration_tests/test_runner/src/bin/main.rs index ace25b52..e4ba8ccd 100644 --- a/integration_tests/test_runner/src/bin/main.rs +++ b/integration_tests/test_runner/src/bin/main.rs @@ -16,9 +16,9 @@ use test_runner::bootstrapping::parse_ibc_validator_keys; use test_runner::bootstrapping::send_erc20s_to_evm_users; use test_runner::bootstrapping::start_ibc_relayer; use test_runner::bootstrapping::{deploy_erc20_contracts, get_keys}; +use test_runner::tests::dex::basic_dex_test; use test_runner::tests::dex::dex_ops_proposal_test; use test_runner::tests::dex::dex_safe_mode_test; -use test_runner::tests::dex::dex_test; use test_runner::tests::dex::dex_upgrade_test; use test_runner::tests::erc20_conversion::erc20_conversion_test; use test_runner::tests::ica_host::ica_host_happy_path; @@ -227,7 +227,7 @@ pub async fn main() { return; } else if test_type == "DEX" { info!("Start dex test"); - dex_test( + basic_dex_test( &contact, &web30, keys, diff --git a/integration_tests/test_runner/src/dex_utils.rs b/integration_tests/test_runner/src/dex_utils.rs index 899a6f88..d56b60a8 100644 --- a/integration_tests/test_runner/src/dex_utils.rs +++ b/integration_tests/test_runner/src/dex_utils.rs @@ -1,16 +1,19 @@ -use std::time::Duration; +use std::{convert::TryInto, time::Duration}; -use clarity::{abi::AbiToken, Address as EthAddress, PrivateKey, Uint256}; +use clarity::{ + abi::{encode_tokens, AbiToken}, + Address as EthAddress, PrivateKey, Uint256, +}; use num256::Int256; -use num::ToPrimitive; +use num::{ToPrimitive, Zero}; use web30::{ client::Web3, jsonrpc::error::Web3Error, types::{TransactionRequest, TransactionResponse}, }; -use crate::utils::OPERATION_TIMEOUT; +use crate::utils::{EthermintUserKey, OPERATION_TIMEOUT}; // Callpath Indices pub const BOOT_PATH: u16 = 0; @@ -312,6 +315,9 @@ pub struct CrocQueryRangePosition { pub atomic: bool, } +/// This query returns the stored ranged position information, which is not an accurate reflection of +/// the tokens that the position represents. Calling croc_query_ranged_tokens may be more useful since +/// it will return the token amounts which would be paid out on burning BUT NOT THE ACCUMULATED FEE REWARDS #[allow(clippy::too_many_arguments)] pub async fn croc_query_range_position( web30: &Web3, @@ -373,11 +379,145 @@ pub async fn croc_query_range_position( }) } +#[derive(Debug, Clone)] +pub struct CrocQueryTokens { + pub liq: Uint256, + pub base_qty: Uint256, + pub quote_qty: Uint256, +} + +/// This query returns the liquidity and tokens that the ranged position represents. +/// If you instead need the stored position information, use croc_query_range_position +#[allow(clippy::too_many_arguments)] +pub async fn croc_query_range_tokens( + web30: &Web3, + croc_query_contract: EthAddress, + caller: Option, + owner: EthAddress, + base: EthAddress, // The base token, must be lexically smaller than quote + quote: EthAddress, // The quote token, must be lexically larger than base + pool_idx: Uint256, // The index of the pool's template + lower_tick: Int256, // The lower tick boundary of the position + upper_tick: Int256, // The lower tick boundary of the position +) -> Result { + if base.gt("e) { + return Err(Web3Error::ContractCallError( + "croc_query_range_tokens: base must be lexically smaller than quote".to_string(), + )); + } + + // ABI: queryRangeTokens(address owner, address base, address quote, uint256 poolIdx, int24 lowerTick, int24 upperTick) + // returns (uint128 liq, uint128 baseQty, uint128 quoteQty) + let caller = caller.unwrap_or(owner); + let payload = clarity::abi::encode_call( + "queryRangeTokens(address,address,address,uint256,int24,int24)", + &[ + owner.into(), + base.into(), + quote.into(), + pool_idx.into(), + lower_tick.into(), + upper_tick.into(), + ], + )?; + + let query_res = web30 + .simulate_transaction( + TransactionRequest::quick_tx(caller, croc_query_contract, payload), + None, + ) + .await?; + + let mut i: usize = 0; + let liq = Uint256::from_be_bytes(&query_res[i..i + 32]); + i += 32; + let base_qty = Uint256::from_be_bytes(&query_res[i..i + 32]); + i += 32; + let quote_qty = Uint256::from_be_bytes(&query_res[i..i + 32]); + + Ok(CrocQueryTokens { + liq, + base_qty, + quote_qty, + }) +} + +pub struct CrocQueryKnockoutTokens { + pub liq: Uint256, + pub base_qty: Uint256, + pub quote_qty: Uint256, + pub knocked_out: bool, +} + +pub async fn croc_query_knockout_tokens( + web30: &Web3, + croc_query_contract: EthAddress, + caller: Option, + owner: EthAddress, + base: EthAddress, // The base token, must be lexically smaller than quote + quote: EthAddress, // The quote token, must be lexically larger than base + pool_idx: Uint256, // The index of the pool's template + pivot: u32, // The block timestamp associated with the minting of the knockout position (cast to a u32, which will allegedly work until the year 2106) + lower_tick: Int256, // The lower tick boundary of the position + upper_tick: Int256, // The lower tick boundary of the position + is_bid: bool, +) -> Result { + if base.gt("e) { + return Err(Web3Error::ContractCallError( + "croc_query_knockout_tokens: base must be lexically smaller than quote".to_string(), + )); + } + + // ABI: queryKnockoutTokens (address owner, address base, address quote, uint256 poolIdx, uint32 pivot, bool isBid, int24 lowerTick, int24 upperTick) + // returns (uint128 liq, uint128 baseQty, uint128 quoteQty, bool knockedOut) + let caller = caller.unwrap_or(owner); + let payload = clarity::abi::encode_call( + "queryKnockoutTokens(address,address,address,uint256,uint32,bool,int24,int24)", + &[ + owner.into(), + base.into(), + quote.into(), + pool_idx.into(), + pivot.into(), + is_bid.into(), + lower_tick.into(), + upper_tick.into(), + ], + )?; + + let query_res = web30 + .simulate_transaction( + TransactionRequest::quick_tx(caller, croc_query_contract, payload), + None, + ) + .await?; + + let mut i: usize = 0; + let liq = Uint256::from_be_bytes(&query_res[i..i + 32]); + i += 32; + let base_qty = Uint256::from_be_bytes(&query_res[i..i + 32]); + i += 32; + let quote_qty = Uint256::from_be_bytes(&query_res[i..i + 32]); + i += 32; + let knocked_out = query_res[i + 32] > 0u8; + + Ok(CrocQueryKnockoutTokens { + liq, + base_qty, + quote_qty, + knocked_out, + }) +} + #[derive(Debug, Clone)] pub struct CrocQueryAmbientPosition { pub seeds: Uint256, pub timestamp: u32, } + +/// This query returns the stored ambient position information, which is not an accurate reflection of +/// the tokens that the position represents. Calling croc_query_ambient_tokens may be more useful since +/// it will return the "inflated" liquidity as the base and quote tokens which would be paid out on burning. #[allow(clippy::too_many_arguments)] pub async fn croc_query_ambient_position( web30: &Web3, @@ -419,6 +559,53 @@ pub async fn croc_query_ambient_position( Ok(CrocQueryAmbientPosition { seeds, timestamp }) } +/// This query returns the liquidity and tokens that the ambient position represents. +/// If you instead need the stored position information, use croc_query_ambient_position +#[allow(clippy::too_many_arguments)] +pub async fn croc_query_ambient_tokens( + web30: &Web3, + croc_query_contract: EthAddress, + caller: Option, + owner: EthAddress, + base: EthAddress, // The base token, must be lexically smaller than quote + quote: EthAddress, // The quote token, must be lexically larger than base + pool_idx: Uint256, // The index of the pool's template +) -> Result { + if base.gt("e) { + return Err(Web3Error::ContractCallError( + "croc_query_ambient_tokens: base must be lexically smaller than quote".to_string(), + )); + } + + // ABI: queryAmbientTokens(address owner, address base, address quote, uint256 poolIdx) + // returns (uint128 liq, uint128 baseQty, uint128 quoteQty) + let caller = caller.unwrap_or(owner); + let payload = clarity::abi::encode_call( + "queryAmbientTokens(address,address,address,uint256)", + &[owner.into(), base.into(), quote.into(), pool_idx.into()], + )?; + + let query_res = web30 + .simulate_transaction( + TransactionRequest::quick_tx(caller, croc_query_contract, payload), + None, + ) + .await?; + + let mut i: usize = 0; + let liq = Uint256::from_be_bytes(&query_res[i..i + 32]); + i += 32; + let base_qty = Uint256::from_be_bytes(&query_res[i..i + 32]); + i += 32; + let quote_qty = Uint256::from_be_bytes(&query_res[i..i + 32]); + + Ok(CrocQueryTokens { + liq, + base_qty, + quote_qty, + }) +} + #[derive(Debug, Clone)] pub struct CrocQueryConcRewards { pub liq_rewards: Uint256, @@ -750,3 +937,395 @@ pub async fn croc_policy_treasury_resolution( .await?; web30.wait_for_transaction(txhash, timeout, None).await } + +#[allow(clippy::too_many_arguments)] +pub async fn mint_ranged_pos( + web3: &Web3, + dex: EthAddress, + query: EthAddress, + evm_privkey: PrivateKey, + evm_user: &EthermintUserKey, + base: EthAddress, + quote: EthAddress, + pool_idx: Uint256, + bid_tick: Int256, + ask_tick: Int256, + liq: Uint256, // The liquidity to mint (must be a multiple of 1024) +) { + let start_pos = croc_query_range_position( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + bid_tick, + ask_tick, + ) + .await + .expect("Could not query position"); + + let mint_ranged_pos_args = UserCmdArgs { + callpath: WARM_PATH, // Warm Path index + cmd: vec![ + Uint256::from(1u8).into(), // Mint Ranged Liq code + base.into(), // base + quote.into(), // quote + pool_idx.into(), // poolIdx + bid_tick.into(), // bid (lower) tick + ask_tick.into(), // ask (upper) tick + liq.into(), // liq (in liquidity units, which must be a multiple of 1024) + (*MIN_PRICE).into(), // limitLower + (*MAX_PRICE).into(), // limitHigher + Uint256::from(0u8).into(), // reserveFlags + EthAddress::default().into(), // lpConduit + ], + }; + info!("Minting position in both tokens: {mint_ranged_pos_args:?}"); + dex_user_cmd(web3, dex, evm_privkey, mint_ranged_pos_args, None, None) + .await + .expect("Failed to mint position in pool"); + let range_pos = croc_query_range_position( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + bid_tick, + ask_tick, + ) + .await + .expect("Could not query position"); + assert_eq!(range_pos.liq - start_pos.liq, liq); +} + +#[allow(clippy::too_many_arguments)] +pub async fn burn_ranged_pos( + web3: &Web3, + dex: EthAddress, + query: EthAddress, + evm_privkey: PrivateKey, + evm_user: &EthermintUserKey, + base: EthAddress, + quote: EthAddress, + pool_idx: Uint256, + bid_tick: Int256, + ask_tick: Int256, + liq: Uint256, // The liquidity to burn (must be a multiple of 1024) +) { + let pos_start = croc_query_range_position( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + bid_tick, + ask_tick, + ) + .await + .expect("Could not query position"); + + let burn_ranged_pos_args = UserCmdArgs { + callpath: WARM_PATH, // Warm Path index + cmd: vec![ + Uint256::from(2u8).into(), // Burn Ranged Liq code + base.into(), // base + quote.into(), // quote + (pool_idx).into(), // poolIdx + bid_tick.into(), // bid (lower) tick + ask_tick.into(), // ask (upper) tick + liq.into(), // liq (in liquidity units, which must be a multiple of 1024) + (*MIN_PRICE).into(), // limitLower + (*MAX_PRICE).into(), // limitHigher + Uint256::from(0u8).into(), // reserveFlags + EthAddress::default().into(), // lpConduit + ], + }; + info!("Burning position: {burn_ranged_pos_args:?}"); + dex_user_cmd(web3, dex, evm_privkey, burn_ranged_pos_args, None, None) + .await + .expect("Failed to burn position in pool"); + let range_pos = croc_query_range_position( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + bid_tick, + ask_tick, + ) + .await + .expect("Could not query position"); + + assert_eq!(pos_start.liq - range_pos.liq, liq); +} + +#[allow(clippy::too_many_arguments)] +pub async fn mint_knockout_pos( + web3: &Web3, + dex: EthAddress, + query: EthAddress, + evm_privkey: PrivateKey, + evm_user: &EthermintUserKey, + base: EthAddress, + quote: EthAddress, + pool_idx: Uint256, + bid_tick: Int256, + ask_tick: Int256, + is_bid: bool, + reserve_flags: u8, // Controls what happens with "surplus" values held by the dex + qty: Uint256, + inside_mid: bool, +) { + let arg_bytes = encode_tokens(&[qty.into(), inside_mid.into()]); + let mint_ko_pos_args = UserCmdArgs { + callpath: KNOCKOUT_LIQ_PATH, // KnockoutLiqPath index + cmd: vec![ + Uint256::from(91u8).into(), // Mint Knockout code + base.into(), // base + quote.into(), // quote + (pool_idx).into(), // poolIdx + bid_tick.into(), // bid (lower) tick + ask_tick.into(), // ask (upper) tick + is_bid.into(), + reserve_flags.into(), + arg_bytes.into(), + ], + }; + info!("Minting knockout position: {mint_ko_pos_args:?}"); + let res = dex_user_cmd(web3, dex, evm_privkey, mint_ko_pos_args, None, None) + .await + .expect("Failed to mint knockout position in pool"); + + // Querying the knockout position requires the "pivotTime", which is the timestamp of the block that the position was minted in + let pivot = web3 + .eth_get_block_by_number(res.get_block_number().unwrap()) + .await + .unwrap() + .timestamp; + let pivot: u32 = u32::from_be_bytes(pivot.to_be_bytes()[28..32].try_into().unwrap()); + + let ko_pos = croc_query_knockout_tokens( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + pivot, + bid_tick, + ask_tick, + is_bid, + ) + .await + .expect("Could not query position"); + assert!(ko_pos.base_qty > 0u8.into() || ko_pos.quote_qty > 0u8.into()); +} + +#[allow(clippy::too_many_arguments)] +pub async fn burn_knockout_pos( + web3: &Web3, + dex: EthAddress, + query: EthAddress, + evm_privkey: PrivateKey, + evm_user: &EthermintUserKey, + base: EthAddress, + quote: EthAddress, + pool_idx: Uint256, + bid_tick: Int256, + ask_tick: Int256, + is_bid: bool, + reserve_flags: u8, // Controls what happens with "surplus" values held by the dex + qty: Uint256, + in_liq_qty: bool, + inside_mid: bool, + pivot: Option, +) { + let start_pos = if let Some(pivot) = pivot { + Some( + croc_query_knockout_tokens( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + pivot, + bid_tick, + ask_tick, + is_bid, + ) + .await + .expect("Could not query position"), + ) + } else { + None + }; + + let arg_bytes = encode_tokens(&[qty.into(), in_liq_qty.into(), inside_mid.into()]); + let burn_ko_pos_args = UserCmdArgs { + callpath: KNOCKOUT_LIQ_PATH, // KnockoutLiqPath index + cmd: vec![ + Uint256::from(92u8).into(), // Burn Knockout code + base.into(), // base + quote.into(), // quote + (pool_idx).into(), // poolIdx + bid_tick.into(), // bid (lower) tick + ask_tick.into(), // ask (upper) tick + is_bid.into(), + reserve_flags.into(), + arg_bytes.into(), + ], + }; + info!("Burning position: {burn_ko_pos_args:?}"); + dex_user_cmd(web3, dex, evm_privkey, burn_ko_pos_args, None, None) + .await + .expect("Failed to burn position in pool"); + + // Unfortunately there is no way to compare the `qty` we put into the position with the `liq` result we can query + // but we can determine if the position's liquidity has changed + if let Some(start_pos) = start_pos { + let pivot = pivot.unwrap(); + let ko_pos = croc_query_knockout_tokens( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + pivot, + bid_tick, + ask_tick, + is_bid, + ) + .await + .expect("Could not query position"); + assert!(ko_pos.liq < start_pos.liq); + } +} + +#[allow(clippy::too_many_arguments)] +pub async fn mint_ambient_pos( + web3: &Web3, + dex: EthAddress, + query: EthAddress, + evm_privkey: PrivateKey, + evm_user: &EthermintUserKey, + base: EthAddress, + quote: EthAddress, + pool_idx: Uint256, + liq: Uint256, // The liquidity to mint (must be a multiple of 1024) +) { + let start_pos = croc_query_ambient_tokens( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + ) + .await + .expect("Could not query position"); + + let mint_ambient_pos_args = UserCmdArgs { + callpath: WARM_PATH, // Warm Path index + cmd: vec![ + Uint256::from(3u8).into(), // Mint Ambient Liq code + base.into(), // base + quote.into(), // quote + (pool_idx).into(), // poolIdx + Uint256::zero().into(), // bid (lower) tick + Uint256::zero().into(), // ask (upper) tick + liq.into(), // liq (in liquidity units, which must be a multiple of 1024) + (*MIN_PRICE).into(), // limitLower + (*MAX_PRICE).into(), // limitHigher + Uint256::zero().into(), // reserveFlags + EthAddress::default().into(), // lpConduit + ], + }; + info!("Minting ambient position: {mint_ambient_pos_args:?}"); + dex_user_cmd(web3, dex, evm_privkey, mint_ambient_pos_args, None, None) + .await + .expect("Failed to mint position in pool"); + let amb_pos = croc_query_ambient_tokens( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + ) + .await + .expect("Could not query position"); + assert_eq!(amb_pos.liq - start_pos.liq, liq); +} + +#[allow(clippy::too_many_arguments)] +pub async fn burn_ambient_pos( + web3: &Web3, + dex: EthAddress, + query: EthAddress, + evm_privkey: PrivateKey, + evm_user: &EthermintUserKey, + base: EthAddress, + quote: EthAddress, + pool_idx: Uint256, + liq: Uint256, // The liquidity to mint (must be a multiple of 1024) +) { + let start_pos = croc_query_ambient_tokens( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + ) + .await + .expect("Could not query position"); + + let burn_ambient_pos_args = UserCmdArgs { + callpath: WARM_PATH, // Warm Path index + cmd: vec![ + Uint256::from(4u8).into(), // Burn Ambient Liq code + base.into(), // base + quote.into(), // quote + (pool_idx).into(), // poolIdx + Uint256::zero().into(), // bid (lower) tick + Uint256::zero().into(), // ask (upper) tick + liq.into(), // liq (in liquidity units, which must be a multiple of 1024) + (*MIN_PRICE).into(), // limitLower + (*MAX_PRICE).into(), // limitHigher + Uint256::zero().into(), // reserveFlags + EthAddress::default().into(), // lpConduit + ], + }; + info!("Burning ambient position: {burn_ambient_pos_args:?}"); + dex_user_cmd(web3, dex, evm_privkey, burn_ambient_pos_args, None, None) + .await + .expect("Failed to burn position in pool"); + let amb_pos = croc_query_ambient_tokens( + web3, + query, + None, + evm_user.eth_address, + base, + quote, + pool_idx, + ) + .await + .expect("Could not query position"); + assert_eq!(start_pos.liq - amb_pos.liq, liq); +} diff --git a/integration_tests/test_runner/src/tests/dex.rs b/integration_tests/test_runner/src/tests/dex.rs index 12bf84bf..b55ce520 100644 --- a/integration_tests/test_runner/src/tests/dex.rs +++ b/integration_tests/test_runner/src/tests/dex.rs @@ -4,11 +4,12 @@ use std::time::Duration; use crate::bootstrapping::DexAddresses; use crate::dex_utils::{ - croc_policy_ops_resolution, croc_policy_treasury_resolution, croc_query_curve_tick, - croc_query_dex, croc_query_pool_params, croc_query_pool_template, croc_query_range_position, - dex_authority_transfer, dex_direct_protocol_cmd, dex_query_authority, dex_query_safe_mode, - dex_swap, dex_user_cmd, OpsResolutionArgs, ProtocolCmdArgs, SwapArgs, UserCmdArgs, BOOT_PATH, - COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, + burn_ambient_pos, burn_knockout_pos, burn_ranged_pos, croc_policy_ops_resolution, + croc_policy_treasury_resolution, croc_query_curve_tick, croc_query_dex, croc_query_pool_params, + croc_query_pool_template, croc_query_range_position, dex_authority_transfer, + dex_direct_protocol_cmd, dex_query_authority, dex_query_safe_mode, dex_swap, dex_user_cmd, + mint_ambient_pos, mint_knockout_pos, mint_ranged_pos, OpsResolutionArgs, ProtocolCmdArgs, + SwapArgs, UserCmdArgs, BOOT_PATH, COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, }; use crate::type_urls::{ COLLECT_TREASURY_PROPOSAL_TYPE_URL, HOT_PATH_OPEN_PROPOSAL_TYPE_URL, OPS_PROPOSAL_TYPE_URL, @@ -31,8 +32,7 @@ use althea_proto::cosmos_sdk_proto::cosmos::params::v1beta1::{ }; use clarity::{Address as EthAddress, PrivateKey, Uint256}; use deep_space::{Coin, Contact}; -use num::ToPrimitive; - +use num_traits::ToPrimitive; use rand::Rng; use web30::client::Web3; use web30::jsonrpc::error::Web3Error; @@ -42,7 +42,7 @@ lazy_static! { pub static ref POOL_IDX: Uint256 = 36000u32.into(); } -pub async fn dex_test( +pub async fn basic_dex_test( contact: &Contact, web3: &Web3, validator_keys: Vec, @@ -50,16 +50,21 @@ pub async fn dex_test( erc20_contracts: Vec, dex_contracts: DexAddresses, ) { - let evm_user = evm_user_keys.first().unwrap(); - let evm_privkey = evm_user.eth_privkey; - let optional_caller = Some(evm_user.eth_address); - let croc_query_contract = dex_contracts.query; - let dex_result = croc_query_dex(web3, croc_query_contract, optional_caller).await; - assert!(dex_result.is_ok(), "Bad result"); - let dex = dex_result.unwrap(); - assert_eq!(dex, dex_contracts.dex, "Dex contract address mismatch"); - - let (pool_base, pool_quote) = pool_tokens(erc20_contracts.clone()); + let DexTestParams { + evm_user, + evm_privkey, + caller, + query, + dex, + pool_base, + pool_quote, + } = setup_params( + web3, + evm_user_keys, + dex_contracts.clone(), + erc20_contracts.clone(), + ) + .await; basic_dex_setup( contact, @@ -67,7 +72,7 @@ pub async fn dex_test( dex_contracts.dex, dex_contracts.query, dex_contracts.policy, - evm_user, + &evm_user, &validator_keys, pool_base, pool_quote, @@ -106,55 +111,210 @@ pub async fn dex_test( if range_pos.liq > 0u8.into() { info!("Range position already exists: {:?}", range_pos); } else { - let mint_ranged_pos_args = UserCmdArgs { - callpath: WARM_PATH, // Warm Path index - cmd: vec![ - Uint256::from(1u8).into(), // Mint Ranged Liq in base token code - pool_base.into(), // base - pool_quote.into(), // quote - (*POOL_IDX).into(), // poolIdx - bid_tick.into(), // bid (lower) tick - ask_tick.into(), // ask (upper) tick - (one_eth() * 10240u32.into()).into(), // liq (in liquidity units, which must be a multiple of 1024) - (*MIN_PRICE).into(), // limitLower - (*MAX_PRICE).into(), // limitHigher - Uint256::from(0u8).into(), // reserveFlags - EthAddress::default().into(), // lpConduit - ], - }; - info!("Minting position in both tokens: {mint_ranged_pos_args:?}"); - dex_user_cmd( + let liq = one_eth() * 10240u32.into(); + mint_ranged_pos( web3, dex_contracts.dex, - evm_privkey, - mint_ranged_pos_args, - None, - None, - ) - .await - .expect("Failed to mint position in pool"); - let range_pos = croc_query_range_position( - web3, dex_contracts.query, - None, - evm_user.eth_address, + evm_privkey, + &evm_user, pool_base, pool_quote, *POOL_IDX, bid_tick, ask_tick, + liq, ) - .await - .expect("Could not query position"); - assert!(range_pos.liq > 0u8.into()); + .await; } // Finally, perform many smaller swaps to ensure the pool is working as expected - swap_many(web3, dex_contracts, pool_base, pool_quote, evm_user, 30).await; + swap_many(web3, dex_contracts, pool_base, pool_quote, &evm_user, 30).await; + + info!("Successfully tested DEX"); +} + +// Generates some additional positions, minting and burning ambient and ranged and knockout positions +pub async fn advanced_dex_test( + contact: &Contact, + web3: &Web3, + validator_keys: Vec, + evm_user_keys: Vec, + erc20_contracts: Vec, + dex_contracts: DexAddresses, +) { + let DexTestParams { + evm_user, + evm_privkey, + caller: _, + query: _, + dex: _, + pool_base, + pool_quote, + } = setup_params( + web3, + evm_user_keys, + dex_contracts.clone(), + erc20_contracts.clone(), + ) + .await; + + basic_dex_setup( + contact, + web3, + dex_contracts.dex, + dex_contracts.query, + dex_contracts.policy, + &evm_user, + &validator_keys, + pool_base, + pool_quote, + ) + .await; + let tick = croc_query_curve_tick( + web3, + dex_contracts.query, + Some(evm_user.eth_address), + pool_base, + pool_quote, + *POOL_IDX, + ) + .await + .expect("Could not get curve tick for pool"); + + let bid_tick = tick - 75u8.into(); + let ask_tick = tick + 75u8.into(); + let liq = one_eth() * 10240u32.into(); + mint_ranged_pos( + web3, + dex_contracts.dex, + dex_contracts.query, + evm_privkey, + &evm_user, + pool_base, + pool_quote, + *POOL_IDX, + bid_tick, + ask_tick, + liq, + ) + .await; + mint_knockout_pos( + web3, + dex_contracts.dex, + dex_contracts.query, + evm_privkey, + &evm_user, + pool_base, + pool_quote, + *POOL_IDX, + bid_tick, + ask_tick, + true, + 0u8, + liq, + true, + ) + .await; + mint_ambient_pos( + web3, + dex_contracts.dex, + dex_contracts.query, + evm_privkey, + &evm_user, + pool_base, + pool_quote, + *POOL_IDX, + liq, + ) + .await; + burn_ranged_pos( + web3, + dex_contracts.dex, + dex_contracts.query, + evm_privkey, + &evm_user, + pool_base, + pool_quote, + *POOL_IDX, + bid_tick, + ask_tick, + liq, + ) + .await; + burn_knockout_pos( + web3, + dex_contracts.dex, + dex_contracts.query, + evm_privkey, + &evm_user, + pool_base, + pool_quote, + *POOL_IDX, + bid_tick, + ask_tick, + true, + 0u8, + liq, + true, + true, + None, + ) + .await; + burn_ambient_pos( + web3, + dex_contracts.dex, + dex_contracts.query, + evm_privkey, + &evm_user, + pool_base, + pool_quote, + *POOL_IDX, + liq, + ) + .await; info!("Successfully tested DEX"); } +pub struct DexTestParams { + pub evm_user: EthermintUserKey, + pub evm_privkey: PrivateKey, + pub caller: Option, + pub query: EthAddress, + pub dex: EthAddress, + pub pool_base: EthAddress, + pub pool_quote: EthAddress, +} + +pub async fn setup_params( + web3: &Web3, + evm_user_keys: Vec, + dex_contracts: DexAddresses, + erc20_contracts: Vec, +) -> DexTestParams { + let evm_user = *evm_user_keys.first().unwrap(); + let evm_privkey = evm_user.eth_privkey; + let optional_caller = Some(evm_user.eth_address); + let croc_query_contract = dex_contracts.query; + let dex_result = croc_query_dex(web3, croc_query_contract, optional_caller).await; + assert!(dex_result.is_ok(), "Bad result"); + let dex = dex_result.unwrap(); + assert_eq!(dex, dex_contracts.dex, "Dex contract address mismatch"); + + let (pool_base, pool_quote) = pool_tokens(erc20_contracts); + + DexTestParams { + evm_user, + evm_privkey, + caller: optional_caller, + query: croc_query_contract, + dex, + pool_base, + pool_quote, + } +} + pub async fn dex_upgrade_test( contact: &Contact, web3: &Web3, From 65a728bdf8da1b61c2cf3300f486a69dd204c168 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Wed, 20 Nov 2024 14:27:19 -0500 Subject: [PATCH 10/25] Change testnet chain id to 6633438 --- x/gasfree/module_test.go | 62 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/x/gasfree/module_test.go b/x/gasfree/module_test.go index 517fdb5f..ade306e2 100644 --- a/x/gasfree/module_test.go +++ b/x/gasfree/module_test.go @@ -1,6 +1,7 @@ package gasfree_test import ( + "encoding/json" "testing" "time" @@ -86,6 +87,37 @@ func (suite *GasfreeTestSuite) DoSetupTest(t require.TestingT) { return genesis }) + coins := sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(100000000000000))) + genesisState := althea.ModuleBasics.DefaultGenesis(suite.app.AppCodec()) + b32address := sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), priv.PubKey().Address().Bytes()) + balances := []banktypes.Balance{ + { + Address: b32address, + Coins: coins, + }, + { + Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(), + Coins: coins, + }, + } + // Update total supply + bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(200000000000000))), []banktypes.Metadata{}) + genesisState[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(bankGenesis) + + stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ") + require.NoError(t, err) + + // Initialize the chain + suite.app.InitChain( + // nolint: exhaustruct + abci.RequestInitChain{ + ChainId: "althea_6633438-1", + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: DefaultConsensusParams, + AppStateBytes: stateBytes, + }, + ) + // nolint: exhaustruct suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{ Height: 1, @@ -139,8 +171,34 @@ func (suite *GasfreeTestSuite) DoSetupTest(t require.TestingT) { } // Setup initializes a new Althea app. A Nop logger is set in AltheaApp. -func Setup(isCheckTx bool, patchGenesis func(*althea.AltheaApp, simapp.GenesisState) simapp.GenesisState) *althea.AltheaApp { - return althea.NewSetup(isCheckTx, patchGenesis) +func Setup(isCheckTx bool, patchGenesis func(*althea.AltheaApp, althea.GenesisState) althea.GenesisState) *althea.AltheaApp { + db := dbm.NewMemDB() + app := althea.NewAltheaApp(tmlog.NewNopLogger(), db, nil, true, map[int64]bool{}, althea.DefaultNodeHome, 5, althea.MakeEncodingConfig(), simapp.EmptyAppOptions{}) + if !isCheckTx { + // init chain must be called to stop deliverState from being nil + genesisState := althea.NewDefaultGenesisState() + if patchGenesis != nil { + genesisState = patchGenesis(app, genesisState) + } + + stateBytes, err := json.MarshalIndent(genesisState, "", " ") + if err != nil { + panic(err) + } + + // Initialize the chain + app.InitChain( + // nolint: exhaustruct + abci.RequestInitChain{ + ChainId: "althea_6633438-1", + Validators: []abci.ValidatorUpdate{}, + ConsensusParams: DefaultConsensusParams, + AppStateBytes: stateBytes, + }, + ) + } + + return app } // DefaultConsensusParams defines the default Tendermint consensus params used in From 3fa9bdf90acc0efd3acd816422750290c2a763b0 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Wed, 20 Nov 2024 14:35:15 -0500 Subject: [PATCH 11/25] Fix contract deployment --- integration_tests/test_runner/src/bootstrapping.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/integration_tests/test_runner/src/bootstrapping.rs b/integration_tests/test_runner/src/bootstrapping.rs index 99d53377..c11ea579 100644 --- a/integration_tests/test_runner/src/bootstrapping.rs +++ b/integration_tests/test_runner/src/bootstrapping.rs @@ -192,7 +192,6 @@ pub async fn deploy_multicall() { path[0], &format!("--eth-node={}", ETH_NODE.as_str()), &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), - &format!("--artifacts-root={}", path[1]), ]) .current_dir(path[1]) .output() From 057d6886087ec9186b4e83fecd5cedd7dce195f7 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Wed, 20 Nov 2024 14:47:53 -0500 Subject: [PATCH 12/25] Update solidity-dex --- solidity-dex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solidity-dex b/solidity-dex index 433af992..7b10334c 160000 --- a/solidity-dex +++ b/solidity-dex @@ -1 +1 @@ -Subproject commit 433af992fda3f055026d9c10e7cc47f6515a6eb5 +Subproject commit 7b10334c2de6855613b8f3cce23372e65e6ca5ee From d24593c680fd6726332728518c2cd0139c237647 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Wed, 20 Nov 2024 14:58:26 -0500 Subject: [PATCH 13/25] Fix multicall deployment --- integration_tests/test_runner/src/bootstrapping.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/integration_tests/test_runner/src/bootstrapping.rs b/integration_tests/test_runner/src/bootstrapping.rs index c11ea579..99d53377 100644 --- a/integration_tests/test_runner/src/bootstrapping.rs +++ b/integration_tests/test_runner/src/bootstrapping.rs @@ -192,6 +192,7 @@ pub async fn deploy_multicall() { path[0], &format!("--eth-node={}", ETH_NODE.as_str()), &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), + &format!("--artifacts-root={}", path[1]), ]) .current_dir(path[1]) .output() From bae9262ca4663d0a858a9e89047802168250e25a Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Wed, 20 Nov 2024 15:44:43 -0500 Subject: [PATCH 14/25] Update solidity-dex --- solidity-dex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solidity-dex b/solidity-dex index 7b10334c..dd37563b 160000 --- a/solidity-dex +++ b/solidity-dex @@ -1 +1 @@ -Subproject commit 7b10334c2de6855613b8f3cce23372e65e6ca5ee +Subproject commit dd37563b69ef401d04e9f116cb3d1930e001350a From 5868a623bee42c48c38fe7f229e6691ed6d37afa Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Thu, 21 Nov 2024 09:38:45 -0500 Subject: [PATCH 15/25] Add CONTRACTS_ROOT, DEX_CONTRACTS_ROOT env var support --- .../test_runner/src/bootstrapping.rs | 128 ++++++++++++------ integration_tests/test_runner/src/utils.rs | 8 ++ 2 files changed, 91 insertions(+), 45 deletions(-) diff --git a/integration_tests/test_runner/src/bootstrapping.rs b/integration_tests/test_runner/src/bootstrapping.rs index 99d53377..eb91b469 100644 --- a/integration_tests/test_runner/src/bootstrapping.rs +++ b/integration_tests/test_runner/src/bootstrapping.rs @@ -1,8 +1,8 @@ use crate::ibc_utils::get_channel; use crate::utils::{ - get_chain_id, get_deposit, get_ibc_chain_id, ALTHEA_RELAYER_ADDRESS, COSMOS_NODE_GRPC, - HERMES_CONFIG, IBC_RELAYER_ADDRESS, IBC_STAKING_TOKEN, OPERATION_TIMEOUT, - RELAYER_MNEMONIC_FILE, + get_chain_id, get_deposit, get_ibc_chain_id, parse_contracts_root, parse_dex_contracts_root, + ALTHEA_RELAYER_ADDRESS, COSMOS_NODE_GRPC, HERMES_CONFIG, IBC_RELAYER_ADDRESS, + IBC_STAKING_TOKEN, OPERATION_TIMEOUT, RELAYER_MNEMONIC_FILE, }; use crate::utils::{ send_erc20_bulk, EthermintUserKey, ValidatorKeys, ETH_NODE, MINER_PRIVATE_KEY, TOTAL_TIMEOUT, @@ -96,10 +96,6 @@ pub async fn deploy_erc20_contracts(contact: &Contact) { // yet produced the next block after submitting each eth address contact.wait_for_next_block(TOTAL_TIMEOUT).await.unwrap(); - // these are the possible paths where we could find the contract deployer - // and the gravity contract itself, feel free to expand this if it makes your - // deployments more straightforward. - // the default unmoved locations for the Gravity repo const A: [&str; 2] = ["/althea/solidity/contract-deployer.ts", "/althea/solidity/"]; // the default unmoved locations for Github Actions @@ -107,18 +103,33 @@ pub async fn deploy_erc20_contracts(contact: &Contact) { "/home/runner/work/althea-L1/althea-L1/solidity/contract-deployer.ts", "/home/runner/work/althea-L1/althea-L1/solidity/", ]; - let output = match return_existing(vec![A, B]) { - Some(path) => Command::new("npx") - .args([ - "ts-node", - path[0], - &format!("--eth-node={}", ETH_NODE.as_str()), - &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), - &format!("--artifacts-root={}", path[1]), - ]) - .current_dir(path[1]) - .output() - .expect("Failed to deploy contracts!"), + + // the user specified contracts root + let contracts_root = parse_contracts_root(); + let paths = if let Ok(root) = contracts_root { + Some(vec![ + format!("{}/contract-deployer.ts", root), + format!("{}/", root), + ]) + } else { + return_existing(vec![A, B]).map(|path| vec![path[0].to_string(), path[1].to_string()]) + }; + + let output = match paths { + Some(path) => { + info!("Deploying contracts from {:?}", path); + Command::new("npx") + .args([ + "ts-node", + &path[0], + &format!("--eth-node={}", ETH_NODE.as_str()), + &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), + &format!("--artifacts-root={}", path[1]), + ]) + .current_dir(&path[1]) + .output() + .expect("Failed to deploy contracts!") + } None => { panic!("Could not find json contract artifacts in any known location!") } @@ -147,20 +158,34 @@ pub async fn deploy_dex() { "/home/runner/work/althea-L1/althea-L1/solidity-dex/misc/scripts/dex-deployer.ts", "/home/runner/work/althea-L1/althea-L1/solidity-dex/artifacts/contracts/", ]; - let output = match return_existing(vec![A, B]) { - Some(path) => Command::new("npx") - .args([ - "ts-node", - path[0], - &format!("--eth-node={}", ETH_NODE.as_str()), - &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), - &format!("--artifacts-root={}", path[1]), - ]) - .current_dir(path[1]) - .output() - .expect("Failed to deploy contracts!"), + // the user specified contracts root + let contracts_root = parse_dex_contracts_root(); + let paths = if let Ok(root) = contracts_root { + Some(vec![ + format!("{}/misc/scripts/dex-deployer.ts", root), + format!("{}/artifacts/contracts/", root), + ]) + } else { + return_existing(vec![A, B]).map(|path| vec![path[0].to_string(), path[1].to_string()]) + }; + + let output = match paths { + Some(path) => { + info!("Deploying contracts from {:?}", path); + Command::new("npx") + .args([ + "ts-node", + &path[0], + &format!("--eth-node={}", ETH_NODE.as_str()), + &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), + &format!("--artifacts-root={}", path[1]), + ]) + .current_dir(&path[1]) + .output() + .expect("Failed to deploy contracts!") + } None => { - panic!("Could not find dex artifacts in any known location!") + panic!("Could not find json contract artifacts in any known location!") } }; info!("stdout: {}", String::from_utf8_lossy(&output.stdout)); @@ -184,19 +209,32 @@ pub async fn deploy_multicall() { "/home/runner/work/althea-L1/althea-L1/solidity-dex/misc/scripts/multicall-deployer.ts", "/home/runner/work/althea-L1/althea-L1/solidity-dex/artifacts/contracts/periphery/", ]; - let paths = vec![A, B]; - let output = match return_existing(paths) { - Some(path) => Command::new("npx") - .args([ - "ts-node", - path[0], - &format!("--eth-node={}", ETH_NODE.as_str()), - &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), - &format!("--artifacts-root={}", path[1]), - ]) - .current_dir(path[1]) - .output() - .expect("Failed to deploy contracts!"), + // the user specified contracts root + let contracts_root = parse_dex_contracts_root(); + let paths = if let Ok(root) = contracts_root { + Some(vec![ + format!("{}/misc/scripts/multicall-deployer.ts", root), + format!("{}/artifacts/contracts/periphery/", root), + ]) + } else { + return_existing(vec![A, B]).map(|path| vec![path[0].to_string(), path[1].to_string()]) + }; + + let output = match paths { + Some(path) => { + info!("Deploying contracts from {:?}", path); + Command::new("npx") + .args([ + "ts-node", + &path[0], + &format!("--eth-node={}", ETH_NODE.as_str()), + &format!("--eth-privkey={:#x}", *MINER_PRIVATE_KEY), + &format!("--artifacts-root={}", path[1]), + ]) + .current_dir(&path[1]) + .output() + .expect("Failed to deploy contracts!") + } None => { panic!("Could not find json contract artifacts in any known location!") } diff --git a/integration_tests/test_runner/src/utils.rs b/integration_tests/test_runner/src/utils.rs index 8c4a51ff..69dabc14 100644 --- a/integration_tests/test_runner/src/utils.rs +++ b/integration_tests/test_runner/src/utils.rs @@ -104,6 +104,14 @@ pub fn should_deploy_contracts() -> bool { } } +pub fn parse_contracts_root() -> Result { + env::var("CONTRACTS_ROOT") +} + +pub fn parse_dex_contracts_root() -> Result { + env::var("DEX_CONTRACTS_ROOT") +} + /// Gets the standard non-token fee for the testnet. We deploy the test chain with STAKE /// and FOOTOKEN balances by default, one footoken is sufficient for any Cosmos tx fee except /// fees for send_to_eth messages which have to be of the same bridged denom so that the relayers From f0e389e04c659b52da5c11ef5f754b548f4f9a4a Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Thu, 21 Nov 2024 14:05:04 -0500 Subject: [PATCH 16/25] Add WETH contract to solidity folder, fix lots of DEX test issues --- integration_tests/test_runner/src/bin/main.rs | 38 +- .../test_runner/src/bootstrapping.rs | 6 + .../test_runner/src/dex_utils.rs | 149 +++- .../test_runner/src/tests/dex.rs | 294 +++++-- solidity/contract-deployer.ts | 11 + solidity/contracts/WETH9.sol | 762 ++++++++++++++++++ 6 files changed, 1122 insertions(+), 138 deletions(-) create mode 100644 solidity/contracts/WETH9.sol diff --git a/integration_tests/test_runner/src/bin/main.rs b/integration_tests/test_runner/src/bin/main.rs index e4ba8ccd..1caa81b8 100644 --- a/integration_tests/test_runner/src/bin/main.rs +++ b/integration_tests/test_runner/src/bin/main.rs @@ -16,6 +16,7 @@ use test_runner::bootstrapping::parse_ibc_validator_keys; use test_runner::bootstrapping::send_erc20s_to_evm_users; use test_runner::bootstrapping::start_ibc_relayer; use test_runner::bootstrapping::{deploy_erc20_contracts, get_keys}; +use test_runner::tests::dex::advanced_dex_test; use test_runner::tests::dex::basic_dex_test; use test_runner::tests::dex::dex_ops_proposal_test; use test_runner::tests::dex::dex_safe_mode_test; @@ -33,6 +34,7 @@ use test_runner::tests::onboarding::onboarding_disabled_whitelisted; use test_runner::tests::upgrade::upgrade_part_1; use test_runner::tests::upgrade::upgrade_part_2; use test_runner::utils::one_atom; +use test_runner::utils::one_eth; use test_runner::utils::one_hundred_eth; use test_runner::utils::send_funds_bulk; use test_runner::utils::ETH_NODE; @@ -83,7 +85,7 @@ pub async fn main() { &web30, erc20_addresses.clone(), EVM_USER_KEYS.clone(), - one_hundred_eth(), + one_eth() * 60_000u32.into(), ) .await .unwrap(); @@ -97,23 +99,6 @@ pub async fn main() { let (ibc_keys, _ibc_phrases) = parse_ibc_validator_keys(); info!("Funding EVM users with the native coin"); - // Send the EVM users some althea token - send_funds_bulk( - &contact, - keys.first().expect("No validator keys?").validator_key, - &EVM_USER_KEYS - .clone() - .into_iter() - .map(|euk| euk.ethermint_address) - .collect::>(), - Coin { - amount: one_atom(), - denom: STAKING_TOKEN.to_string(), - }, - Some(OPERATION_TIMEOUT), - ) - .await - .unwrap(); info!("Checking footoken balances"); // assert that the validators have a balance of the footoken we use @@ -234,6 +219,20 @@ pub async fn main() { EVM_USER_KEYS.clone(), erc20_addresses, dex_contracts, + contracts.weth_address, + ) + .await; + return; + } else if test_type == "DEX_ADVANCED" { + info!("Start advanced dex test"); + advanced_dex_test( + &contact, + &web30, + keys, + EVM_USER_KEYS.clone(), + erc20_addresses, + dex_contracts, + contracts.weth_address, ) .await; return; @@ -246,6 +245,7 @@ pub async fn main() { EVM_USER_KEYS.clone(), erc20_addresses, dex_contracts, + contracts.weth_address, ) .await; return; @@ -258,6 +258,7 @@ pub async fn main() { EVM_USER_KEYS.clone(), erc20_addresses, dex_contracts, + contracts.weth_address, ) .await; return; @@ -270,6 +271,7 @@ pub async fn main() { EVM_USER_KEYS.clone(), erc20_addresses, dex_contracts, + contracts.weth_address, ) .await; return; diff --git a/integration_tests/test_runner/src/bootstrapping.rs b/integration_tests/test_runner/src/bootstrapping.rs index eb91b469..aab762ad 100644 --- a/integration_tests/test_runner/src/bootstrapping.rs +++ b/integration_tests/test_runner/src/bootstrapping.rs @@ -294,6 +294,7 @@ fn return_existing(paths: Vec<[&str; 2]>) -> Option<[&str; 2]> { pub struct BootstrapContractAddresses { pub erc20_addresses: Vec, pub erc721_addresses: Vec, + pub weth_address: EthAddress, pub uniswap_liquidity_address: Option, } @@ -308,6 +309,7 @@ pub fn parse_contract_addresses() -> BootstrapContractAddresses { file.read_to_string(&mut output).unwrap(); let mut erc20_addresses = Vec::new(); let mut erc721_addresses = Vec::new(); + let mut weth_address = EthAddress::default(); let mut uniswap_liquidity = None; for line in output.lines() { if line.contains("ERC20 deployed at Address -") { @@ -318,6 +320,9 @@ pub fn parse_contract_addresses() -> BootstrapContractAddresses { let address_string = line.split('-').last().unwrap(); erc721_addresses.push(address_string.trim().parse().unwrap()); info!("found erc721 address it is {}", address_string); + } else if line.contains("WETH deployed at Address -") { + let address_string = line.split('-').last().unwrap(); + weth_address = address_string.trim().parse().unwrap(); } else if line.contains("Uniswap Liquidity test deployed at Address - ") { let address_string = line.split('-').last().unwrap(); uniswap_liquidity = Some(address_string.trim().parse().unwrap()); @@ -326,6 +331,7 @@ pub fn parse_contract_addresses() -> BootstrapContractAddresses { BootstrapContractAddresses { erc20_addresses, erc721_addresses, + weth_address, uniswap_liquidity_address: uniswap_liquidity, } } diff --git a/integration_tests/test_runner/src/dex_utils.rs b/integration_tests/test_runner/src/dex_utils.rs index d56b60a8..a75d34af 100644 --- a/integration_tests/test_runner/src/dex_utils.rs +++ b/integration_tests/test_runner/src/dex_utils.rs @@ -442,6 +442,61 @@ pub async fn croc_query_range_tokens( }) } +#[derive(Debug, Clone)] +pub struct CrocQueryKnockoutPivot { + pub lots: Uint256, // Multiply by 1024 to get the amount of sqrt(X*Y) liquidity at the pivot + pub pivot: u32, // The pivot time used in later referring to the knockout pivot + pub range: u16, // The width of the knockout range liquidity in ticks at the pivot +} + +#[allow(clippy::too_many_arguments)] +pub async fn croc_query_knockout_pivot( + web30: &Web3, + croc_query_contract: EthAddress, + caller: EthAddress, + base: EthAddress, // The base token, must be lexically smaller than quote + quote: EthAddress, // The quote token, must be lexically larger than base + pool_idx: Uint256, // The index of the pool's template + is_bid: bool, // If true then the liquidity knocks out when the price moves below tick, otherwise above + tick: Int256, // The tick of the knockout pivot +) -> Result { + if base.gt("e) { + return Err(Web3Error::ContractCallError( + "croc_query_knockout_pivot: base must be lexically smaller than quote".to_string(), + )); + } + + // ABI: queryKnockoutPivot(address base, address quote, uint256 poolIdx, bool isBid, int24 tick) + // returns (uint96 lots, uint32 pivot, uint16 range) + let payload = clarity::abi::encode_call( + "queryKnockoutPivot(address,address,uint256,bool,int24)", + &[ + base.into(), + quote.into(), + pool_idx.into(), + is_bid.into(), + tick.into(), + ], + )?; + + let query_res = web30 + .simulate_transaction( + TransactionRequest::quick_tx(caller, croc_query_contract, payload), + None, + ) + .await?; + + let mut i: usize = 0; + let lots = Uint256::from_be_bytes(&query_res[i..i + 32]); + i += 32; + let pivot = u32::from_be_bytes(query_res[i + 28..i + 32].try_into().unwrap()); + i += 32; + let range = u16::from_be_bytes(query_res[i + 30..i + 32].try_into().unwrap()); + + Ok(CrocQueryKnockoutPivot { lots, pivot, range }) +} + +#[derive(Debug, Clone)] pub struct CrocQueryKnockoutTokens { pub liq: Uint256, pub base_qty: Uint256, @@ -449,6 +504,7 @@ pub struct CrocQueryKnockoutTokens { pub knocked_out: bool, } +#[allow(clippy::too_many_arguments)] pub async fn croc_query_knockout_tokens( web30: &Web3, croc_query_contract: EthAddress, @@ -498,8 +554,7 @@ pub async fn croc_query_knockout_tokens( let base_qty = Uint256::from_be_bytes(&query_res[i..i + 32]); i += 32; let quote_qty = Uint256::from_be_bytes(&query_res[i..i + 32]); - i += 32; - let knocked_out = query_res[i + 32] > 0u8; + let knocked_out = query_res.last().unwrap() > &0u8; Ok(CrocQueryKnockoutTokens { liq, @@ -939,7 +994,7 @@ pub async fn croc_policy_treasury_resolution( } #[allow(clippy::too_many_arguments)] -pub async fn mint_ranged_pos( +pub async fn dex_mint_ranged_pos( web3: &Web3, dex: EthAddress, query: EthAddress, @@ -952,6 +1007,7 @@ pub async fn mint_ranged_pos( ask_tick: Int256, liq: Uint256, // The liquidity to mint (must be a multiple of 1024) ) { + assert!(base.lt("e), "base must be lexically smaller than quote"); let start_pos = croc_query_range_position( web3, query, @@ -1003,7 +1059,7 @@ pub async fn mint_ranged_pos( } #[allow(clippy::too_many_arguments)] -pub async fn burn_ranged_pos( +pub async fn dex_burn_ranged_pos( web3: &Web3, dex: EthAddress, query: EthAddress, @@ -1016,6 +1072,7 @@ pub async fn burn_ranged_pos( ask_tick: Int256, liq: Uint256, // The liquidity to burn (must be a multiple of 1024) ) { + assert!(base.lt("e), "base must be lexically smaller than quote"); let pos_start = croc_query_range_position( web3, query, @@ -1068,12 +1125,12 @@ pub async fn burn_ranged_pos( } #[allow(clippy::too_many_arguments)] -pub async fn mint_knockout_pos( +pub async fn dex_mint_knockout_pos( web3: &Web3, dex: EthAddress, - query: EthAddress, + _query: EthAddress, evm_privkey: PrivateKey, - evm_user: &EthermintUserKey, + _evm_user: &EthermintUserKey, base: EthAddress, quote: EthAddress, pool_idx: Uint256, @@ -1084,6 +1141,7 @@ pub async fn mint_knockout_pos( qty: Uint256, inside_mid: bool, ) { + assert!(base.lt("e), "base must be lexically smaller than quote"); let arg_bytes = encode_tokens(&[qty.into(), inside_mid.into()]); let mint_ko_pos_args = UserCmdArgs { callpath: KNOCKOUT_LIQ_PATH, // KnockoutLiqPath index @@ -1091,7 +1149,7 @@ pub async fn mint_knockout_pos( Uint256::from(91u8).into(), // Mint Knockout code base.into(), // base quote.into(), // quote - (pool_idx).into(), // poolIdx + pool_idx.into(), // poolIdx bid_tick.into(), // bid (lower) tick ask_tick.into(), // ask (upper) tick is_bid.into(), @@ -1100,38 +1158,52 @@ pub async fn mint_knockout_pos( ], }; info!("Minting knockout position: {mint_ko_pos_args:?}"); - let res = dex_user_cmd(web3, dex, evm_privkey, mint_ko_pos_args, None, None) + dex_user_cmd(web3, dex, evm_privkey, mint_ko_pos_args, None, None) .await .expect("Failed to mint knockout position in pool"); - // Querying the knockout position requires the "pivotTime", which is the timestamp of the block that the position was minted in - let pivot = web3 - .eth_get_block_by_number(res.get_block_number().unwrap()) - .await - .unwrap() - .timestamp; - let pivot: u32 = u32::from_be_bytes(pivot.to_be_bytes()[28..32].try_into().unwrap()); - - let ko_pos = croc_query_knockout_tokens( - web3, - query, - None, - evm_user.eth_address, - base, - quote, - pool_idx, - pivot, - bid_tick, - ask_tick, - is_bid, - ) - .await - .expect("Could not query position"); - assert!(ko_pos.base_qty > 0u8.into() || ko_pos.quote_qty > 0u8.into()); + // let pivot_tick = if is_bid { bid_tick } else { ask_tick }; + // info!( + // "Querying knockout position: {} {} {} {} {}", + // base, quote, pool_idx, is_bid, pivot_tick + // ); + // // Querying the knockout position requires the "pivotTime", which is the timestamp of the block that the position was minted in + // let pivot = croc_query_knockout_pivot( + // web3, + // dex, + // evm_user.eth_address, + // base, + // quote, + // pool_idx, + // is_bid, + // pivot_tick, + // ) + // .await + // .expect("Could not query pivot"); + // info!("Queried pivot: {pivot:?}"); + // let pivot = pivot.pivot; + + // let ko_pos = croc_query_knockout_tokens( + // web3, + // query, + // None, + // evm_user.eth_address, + // base, + // quote, + // pool_idx, + // pivot, + // bid_tick, + // ask_tick, + // is_bid, + // ) + // .await + // .expect("Could not query position"); + // info!("Minted knockout position: {ko_pos:?}"); + // assert!(ko_pos.base_qty > 0u8.into() || ko_pos.quote_qty > 0u8.into()); } #[allow(clippy::too_many_arguments)] -pub async fn burn_knockout_pos( +pub async fn dex_burn_knockout_pos( web3: &Web3, dex: EthAddress, query: EthAddress, @@ -1149,6 +1221,7 @@ pub async fn burn_knockout_pos( inside_mid: bool, pivot: Option, ) { + assert!(base.lt("e), "base must be lexically smaller than quote"); let start_pos = if let Some(pivot) = pivot { Some( croc_query_knockout_tokens( @@ -1215,7 +1288,7 @@ pub async fn burn_knockout_pos( } #[allow(clippy::too_many_arguments)] -pub async fn mint_ambient_pos( +pub async fn dex_mint_ambient_pos( web3: &Web3, dex: EthAddress, query: EthAddress, @@ -1226,6 +1299,7 @@ pub async fn mint_ambient_pos( pool_idx: Uint256, liq: Uint256, // The liquidity to mint (must be a multiple of 1024) ) { + assert!(base.lt("e), "base must be lexically smaller than quote"); let start_pos = croc_query_ambient_tokens( web3, query, @@ -1269,11 +1343,11 @@ pub async fn mint_ambient_pos( ) .await .expect("Could not query position"); - assert_eq!(amb_pos.liq - start_pos.liq, liq); + assert!(liq - (amb_pos.liq - start_pos.liq) < 1000u32.into()); } #[allow(clippy::too_many_arguments)] -pub async fn burn_ambient_pos( +pub async fn dex_burn_ambient_pos( web3: &Web3, dex: EthAddress, query: EthAddress, @@ -1284,6 +1358,7 @@ pub async fn burn_ambient_pos( pool_idx: Uint256, liq: Uint256, // The liquidity to mint (must be a multiple of 1024) ) { + assert!(base.lt("e), "base must be lexically smaller than quote"); let start_pos = croc_query_ambient_tokens( web3, query, diff --git a/integration_tests/test_runner/src/tests/dex.rs b/integration_tests/test_runner/src/tests/dex.rs index b55ce520..123db2e6 100644 --- a/integration_tests/test_runner/src/tests/dex.rs +++ b/integration_tests/test_runner/src/tests/dex.rs @@ -4,12 +4,12 @@ use std::time::Duration; use crate::bootstrapping::DexAddresses; use crate::dex_utils::{ - burn_ambient_pos, burn_knockout_pos, burn_ranged_pos, croc_policy_ops_resolution, - croc_policy_treasury_resolution, croc_query_curve_tick, croc_query_dex, croc_query_pool_params, - croc_query_pool_template, croc_query_range_position, dex_authority_transfer, - dex_direct_protocol_cmd, dex_query_authority, dex_query_safe_mode, dex_swap, dex_user_cmd, - mint_ambient_pos, mint_knockout_pos, mint_ranged_pos, OpsResolutionArgs, ProtocolCmdArgs, - SwapArgs, UserCmdArgs, BOOT_PATH, COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, + croc_policy_ops_resolution, croc_policy_treasury_resolution, croc_query_curve_tick, + croc_query_dex, croc_query_pool_params, croc_query_pool_template, croc_query_range_position, + dex_authority_transfer, dex_burn_ambient_pos, dex_burn_knockout_pos, dex_burn_ranged_pos, + dex_direct_protocol_cmd, dex_mint_ambient_pos, dex_mint_knockout_pos, dex_mint_ranged_pos, + dex_query_authority, dex_query_safe_mode, dex_swap, dex_user_cmd, OpsResolutionArgs, + ProtocolCmdArgs, SwapArgs, UserCmdArgs, BOOT_PATH, COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, }; use crate::type_urls::{ COLLECT_TREASURY_PROPOSAL_TYPE_URL, HOT_PATH_OPEN_PROPOSAL_TYPE_URL, OPS_PROPOSAL_TYPE_URL, @@ -34,6 +34,7 @@ use clarity::{Address as EthAddress, PrivateKey, Uint256}; use deep_space::{Coin, Contact}; use num_traits::ToPrimitive; use rand::Rng; +use tokio::time::sleep; use web30::client::Web3; use web30::jsonrpc::error::Web3Error; use web30::types::TransactionResponse; @@ -49,11 +50,11 @@ pub async fn basic_dex_test( evm_user_keys: Vec, erc20_contracts: Vec, dex_contracts: DexAddresses, + walthea: EthAddress, ) { let DexTestParams { evm_user, - evm_privkey, - caller, + caller: _, query, dex, pool_base, @@ -69,22 +70,72 @@ pub async fn basic_dex_test( basic_dex_setup( contact, web3, - dex_contracts.dex, - dex_contracts.query, + dex, + query, dex_contracts.policy, &evm_user, &validator_keys, pool_base, pool_quote, + walthea, ) .await; + let (a, b) = if walthea < pool_base { + (walthea, pool_base) + } else { + (pool_base, walthea) + }; + populate_pool_basic(web3, &dex_contracts, &evm_user, a, b).await; + + populate_pool_basic(web3, &dex_contracts, &evm_user, pool_base, pool_quote).await; + info!("Successfully tested DEX"); +} + +pub async fn populate_pool_basic( + web3: &Web3, + dex_contracts: &DexAddresses, + evm_user: &EthermintUserKey, + base: EthAddress, + quote: EthAddress, +) { + if base != EthAddress::default() + && !web3 + .check_erc20_approved(base, evm_user.eth_address, dex_contracts.dex) + .await + .expect("Unable to check erc20 approval") + { + web3.approve_erc20_transfers( + base, + evm_user.eth_privkey, + dex_contracts.dex, + Some(OPERATION_TIMEOUT), + vec![], + ) + .await + .expect("Unable to approve erc20"); + } + if !web3 + .check_erc20_approved(quote, evm_user.eth_address, dex_contracts.dex) + .await + .expect("Unable to check erc20 approval") + { + web3.approve_erc20_transfers( + quote, + evm_user.eth_privkey, + dex_contracts.dex, + Some(OPERATION_TIMEOUT), + vec![], + ) + .await + .expect("Unable to approve erc20"); + } let tick = croc_query_curve_tick( web3, dex_contracts.query, Some(evm_user.eth_address), - pool_base, - pool_quote, + base, + quote, *POOL_IDX, ) .await @@ -100,8 +151,8 @@ pub async fn basic_dex_test( dex_contracts.query, None, evm_user.eth_address, - pool_base, - pool_quote, + base, + quote, *POOL_IDX, bid_tick, ask_tick, @@ -111,15 +162,32 @@ pub async fn basic_dex_test( if range_pos.liq > 0u8.into() { info!("Range position already exists: {:?}", range_pos); } else { - let liq = one_eth() * 10240u32.into(); - mint_ranged_pos( + let liq: Uint256 = one_atom() * 1024000000u32.into(); + let bb = web3 + .get_erc20_balance(base, evm_user.eth_address) + .await + .unwrap(); + let qb = web3 + .get_erc20_balance(quote, evm_user.eth_address) + .await + .unwrap(); + let ba = web3 + .check_erc20_approved(base, evm_user.eth_address, dex_contracts.dex) + .await + .unwrap(); + let qa = web3 + .check_erc20_approved(quote, evm_user.eth_address, dex_contracts.dex) + .await + .unwrap(); + info!("Before minting ranged position: base balance: {}, quote balance: {}, base approved: {}, quote approved: {}", bb, qb, ba, qa); + dex_mint_ranged_pos( web3, dex_contracts.dex, dex_contracts.query, - evm_privkey, - &evm_user, - pool_base, - pool_quote, + evm_user.eth_privkey, + evm_user, + base, + quote, *POOL_IDX, bid_tick, ask_tick, @@ -129,9 +197,7 @@ pub async fn basic_dex_test( } // Finally, perform many smaller swaps to ensure the pool is working as expected - swap_many(web3, dex_contracts, pool_base, pool_quote, &evm_user, 30).await; - - info!("Successfully tested DEX"); + swap_many(web3, dex_contracts, base, quote, evm_user, 30).await; } // Generates some additional positions, minting and burning ambient and ranged and knockout positions @@ -142,10 +208,10 @@ pub async fn advanced_dex_test( evm_user_keys: Vec, erc20_contracts: Vec, dex_contracts: DexAddresses, + walthea: EthAddress, ) { let DexTestParams { evm_user, - evm_privkey, caller: _, query: _, dex: _, @@ -169,6 +235,7 @@ pub async fn advanced_dex_test( &validator_keys, pool_base, pool_quote, + walthea, ) .await; @@ -183,95 +250,113 @@ pub async fn advanced_dex_test( .await .expect("Could not get curve tick for pool"); - let bid_tick = tick - 75u8.into(); - let ask_tick = tick + 75u8.into(); + let ranged_bid_tick = tick - 32u8.into(); + let ranged_ask_tick = tick + 32u8.into(); let liq = one_eth() * 10240u32.into(); - mint_ranged_pos( + + dex_mint_ambient_pos( web3, dex_contracts.dex, dex_contracts.query, - evm_privkey, + evm_user.eth_privkey, &evm_user, pool_base, pool_quote, *POOL_IDX, - bid_tick, - ask_tick, - liq, + (1024u32 * 10000u32).into(), ) .await; - mint_knockout_pos( + dex_mint_ranged_pos( web3, dex_contracts.dex, dex_contracts.query, - evm_privkey, + evm_user.eth_privkey, &evm_user, pool_base, pool_quote, *POOL_IDX, - bid_tick, - ask_tick, - true, - 0u8, - liq, - true, + ranged_bid_tick, + ranged_ask_tick, + liq / 4u8.into(), ) .await; - mint_ambient_pos( + + let tick = croc_query_curve_tick( + web3, + dex_contracts.query, + Some(evm_user.eth_address), + pool_base, + pool_quote, + *POOL_IDX, + ) + .await + .expect("Could not get curve tick for pool"); + let ko_bid_tick = tick - 32u32.into(); + let ko_ask_tick = tick + 32u32.into(); + + dex_mint_knockout_pos( web3, dex_contracts.dex, dex_contracts.query, - evm_privkey, + evm_user.eth_privkey, &evm_user, pool_base, pool_quote, *POOL_IDX, - liq, + ko_bid_tick, + ko_ask_tick, + true, + 0u8, + (1024u32 * 10000u32).into(), + true, ) .await; - burn_ranged_pos( + + sleep(Duration::from_secs(15)).await; + + dex_burn_ranged_pos( web3, dex_contracts.dex, dex_contracts.query, - evm_privkey, + evm_user.eth_privkey, &evm_user, pool_base, pool_quote, *POOL_IDX, - bid_tick, - ask_tick, - liq, + ranged_bid_tick, + ranged_ask_tick, + liq / 4u8.into(), ) .await; - burn_knockout_pos( + dex_burn_knockout_pos( web3, dex_contracts.dex, dex_contracts.query, - evm_privkey, + evm_user.eth_privkey, &evm_user, pool_base, pool_quote, *POOL_IDX, - bid_tick, - ask_tick, + ko_bid_tick, + ko_ask_tick, true, 0u8, - liq, + (1024u32 * 10000u32).into(), true, true, None, ) .await; - burn_ambient_pos( + dex_burn_ambient_pos( web3, dex_contracts.dex, dex_contracts.query, - evm_privkey, + evm_user.eth_privkey, &evm_user, pool_base, pool_quote, *POOL_IDX, - liq, + (1024u32 * 10000u32).into(), ) .await; info!("Successfully tested DEX"); @@ -279,7 +364,6 @@ pub async fn advanced_dex_test( pub struct DexTestParams { pub evm_user: EthermintUserKey, - pub evm_privkey: PrivateKey, pub caller: Option, pub query: EthAddress, pub dex: EthAddress, @@ -294,7 +378,6 @@ pub async fn setup_params( erc20_contracts: Vec, ) -> DexTestParams { let evm_user = *evm_user_keys.first().unwrap(); - let evm_privkey = evm_user.eth_privkey; let optional_caller = Some(evm_user.eth_address); let croc_query_contract = dex_contracts.query; let dex_result = croc_query_dex(web3, croc_query_contract, optional_caller).await; @@ -306,7 +389,6 @@ pub async fn setup_params( DexTestParams { evm_user, - evm_privkey, caller: optional_caller, query: croc_query_contract, dex, @@ -322,6 +404,7 @@ pub async fn dex_upgrade_test( evm_user_keys: Vec, erc20_contracts: Vec, dex_contracts: DexAddresses, + walthea: EthAddress, ) { let evm_user = evm_user_keys.first().unwrap(); let emergency_user = evm_user_keys.last().unwrap(); @@ -339,6 +422,7 @@ pub async fn dex_upgrade_test( &validator_keys, pool_base, pool_quote, + walthea, ) .await; @@ -477,6 +561,7 @@ pub async fn dex_safe_mode_test( evm_user_keys: Vec, erc20_contracts: Vec, dex_contracts: DexAddresses, + walthea: EthAddress, ) { let emergency_user = evm_user_keys.last().unwrap(); let evm_user = evm_user_keys.first().unwrap(); @@ -492,6 +577,7 @@ pub async fn dex_safe_mode_test( &validator_keys, pool_base, pool_quote, + walthea, ) .await; let tick = croc_query_curve_tick( @@ -592,6 +678,7 @@ pub async fn dex_ops_proposal_test( evm_user_keys: Vec, erc20_contracts: Vec, dex_contracts: DexAddresses, + walthea: EthAddress, ) { let evm_user = evm_user_keys.first().unwrap(); let (pool_base, pool_quote) = pool_tokens(erc20_contracts.clone()); @@ -606,6 +693,7 @@ pub async fn dex_ops_proposal_test( &validator_keys, pool_base, pool_quote, + walthea, ) .await; let callpath = COLD_PATH; @@ -674,7 +762,7 @@ pub fn pool_tokens(erc20_contracts: Vec) -> (EthAddress, EthAddress) async fn swap_many( web3: &Web3, - dex_contracts: DexAddresses, + dex_contracts: &DexAddresses, pool_base: EthAddress, pool_quote: EthAddress, evm_user: &EthermintUserKey, @@ -684,8 +772,8 @@ async fn swap_many( let mut rng = rand::thread_rng(); for _ in 0..swaps { - let qty_multi: u32 = rng.gen(); - let qty = one_atom() * qty_multi.into(); + let qty_multi: u16 = rng.gen(); + let qty = (1024u32 * u32::from(qty_multi)).into(); let pre_swap_base = web3 .get_erc20_balance(pool_base, evm_user.eth_address) .await @@ -826,6 +914,7 @@ pub async fn basic_dex_setup( validator_keys: &[ValidatorKeys], pool_base: EthAddress, pool_quote: EthAddress, + walthea: EthAddress, ) { let current_auth = dex_query_authority(web3, dex, Some(evm_user.eth_address)) .await @@ -853,28 +942,46 @@ pub async fn basic_dex_setup( info!("Dex is in safe mode, disabling safe mode"); submit_and_pass_safe_mode_proposal(contact, validator_keys, false, true).await; } - let pool = croc_query_pool_params( - web3, - query, - Some(evm_user.eth_address), - pool_base, - pool_quote, - *POOL_IDX, - ) - .await; - if pool.is_ok() && pool.unwrap().tick_size != 0 { - info!("Pool already created, approving use of base and quote tokens"); - web3.approve_erc20_transfers( - pool_base, + + if web3 + .get_erc20_balance(walthea, evm_user.eth_address) + .await + .unwrap() + < one_eth() * 60_000u32.into() + { + web3.wrap_eth( + one_eth() * 60_000u32.into(), evm_user.eth_privkey, - dex, - Some(OPERATION_TIMEOUT), - vec![], + Some(walthea), + Some(Duration::from_secs(15)), ) .await - .expect("Could not approve base token"); + .expect("Unable to wrap native token!"); + } + + // Create or prepare the pool with Base and wAlthea tokens + let (a, b) = if walthea < pool_base { + (walthea, pool_base) + } else { + (pool_base, walthea) + }; + create_or_prepare_pool(web3, dex, query, evm_user, a, b, *POOL_IDX).await; + // Create or prepare the pool with Base and Quote tokens + create_or_prepare_pool(web3, dex, query, evm_user, pool_base, pool_quote, *POOL_IDX).await; +} + +pub async fn create_or_prepare_pool( + web3: &Web3, + dex: EthAddress, + query: EthAddress, + evm_user: &EthermintUserKey, + base: EthAddress, + quote: EthAddress, + pool_idx: Uint256, +) { + if base != EthAddress::default() { web3.approve_erc20_transfers( - pool_quote, + base, evm_user.eth_privkey, dex, Some(OPERATION_TIMEOUT), @@ -882,15 +989,36 @@ pub async fn basic_dex_setup( ) .await .expect("Could not approve base token"); + } + web3.approve_erc20_transfers( + quote, + evm_user.eth_privkey, + dex, + Some(OPERATION_TIMEOUT), + vec![], + ) + .await + .expect("Could not approve quote token"); + let pool = croc_query_pool_params( + web3, + query, + Some(evm_user.eth_address), + base, + quote, + pool_idx, + ) + .await; + if pool.is_ok() && pool.unwrap().tick_size != 0 { + info!("Pool already created"); } else { - info!("Creating pool"); + info!("Creating {base}/{quote} pool"); init_pool( web3, evm_user.eth_privkey, dex, - pool_base, - pool_quote, - None, + base, + quote, + Some(pool_idx), None, ) .await diff --git a/solidity/contract-deployer.ts b/solidity/contract-deployer.ts index ccb4621a..efbd446a 100644 --- a/solidity/contract-deployer.ts +++ b/solidity/contract-deployer.ts @@ -1,3 +1,4 @@ +import { WETH9 } from "./typechain/WETH9"; import { TestERC20A } from "./typechain/TestERC20A"; import { TestERC20B } from "./typechain/TestERC20B"; import { TestERC20C } from "./typechain/TestERC20C"; @@ -74,6 +75,7 @@ async function deploy() { var erc20_b_path: string = artifacts + "/artifacts/contracts/TestERC20B.sol/TestERC20B.json" var erc20_c_path: string = artifacts + "/artifacts/contracts/TestERC20C.sol/TestERC20C.json" var erc721_a_path: string = artifacts + "/artifacts/contracts/TestERC721A.sol/TestERC721A.json" + var weth9_path: string = artifacts + "/artifacts/contracts/WETH9.sol/WETH9.json" if (!fs.existsSync(artifacts)) { console.log("Artifacts folder not found, please specify the correct path using the --artifacts-root flag") @@ -107,6 +109,15 @@ async function deploy() { await testERC721.deployed(); const erc721TestAddress = testERC721.address; console.log("ERC721 deployed at Address - ", erc721TestAddress); + + const { abi: abi4, bytecode: bytecode4 } = getContractArtifacts(weth9_path); + const weth9Factory = new ethers.ContractFactory(abi4, bytecode4, wallet); + const weth9 = (await weth9Factory.deploy(overrides)) as WETH9; + await weth9.deployed(); + const weth9Address = weth9.address; + console.log("WETH deployed at Address - ", weth9Address); + + } function getContractArtifacts(path: string): { bytecode: string; abi: string } { diff --git a/solidity/contracts/WETH9.sol b/solidity/contracts/WETH9.sol new file mode 100644 index 00000000..6cf6e169 --- /dev/null +++ b/solidity/contracts/WETH9.sol @@ -0,0 +1,762 @@ +// Copyright (C) 2015, 2016, 2017 Dapphub + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program 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 General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity >=0.4.22; + +/// This contract is a copy of the WETH9 contract found at https://github.com/gnosis/canonical-weth/blob/master/contracts/WETH9.sol +/// with the only notable changes being a solidity compiler version relaxation and minimal syntactic changes to ensure +/// the contract compiles and produces no warnings. +contract WETH9 { + string public name = "Wrapped Ether"; + string public symbol = "WETH"; + 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; + } +} + + +/* + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + +*/ \ No newline at end of file From 6ca9dc530668d031d4724d37385a5c5bc51fee31 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 9 Dec 2024 11:15:31 -0500 Subject: [PATCH 17/25] Update solidity-dex --- solidity-dex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solidity-dex b/solidity-dex index dd37563b..4cd0b972 160000 --- a/solidity-dex +++ b/solidity-dex @@ -1 +1 @@ -Subproject commit dd37563b69ef401d04e9f116cb3d1930e001350a +Subproject commit 4cd0b972df204e93c87b9dd52e0ee1c5a9466aef From a2220e7d295c081712da5c10e4aec59e78d0c8c0 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 9 Dec 2024 11:36:43 -0500 Subject: [PATCH 18/25] Fix gasfree module tests --- x/gasfree/module_test.go | 169 +++++++++------------------------------ 1 file changed, 40 insertions(+), 129 deletions(-) diff --git a/x/gasfree/module_test.go b/x/gasfree/module_test.go index ade306e2..e72fbf46 100644 --- a/x/gasfree/module_test.go +++ b/x/gasfree/module_test.go @@ -1,7 +1,6 @@ package gasfree_test import ( - "encoding/json" "testing" "time" @@ -14,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -25,24 +25,24 @@ import ( "github.com/evmos/ethermint/crypto/ethsecp256k1" "github.com/evmos/ethermint/tests" - "github.com/evmos/ethermint/x/evm" "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" + feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" althea "github.com/AltheaFoundation/althea-L1/app" - altheaconfig "github.com/AltheaFoundation/althea-L1/config" + altheacfg "github.com/AltheaFoundation/althea-L1/config" ) type GasfreeTestSuite struct { suite.Suite - ctx sdk.Context - handler sdk.Handler - app *althea.AltheaApp + ctx sdk.Context + app *althea.AltheaApp - signer keyring.Signer - ethSigner ethtypes.Signer - from common.Address + signer keyring.Signer + ethSigner ethtypes.Signer + from common.Address + mintFeeCollector bool } // / DoSetupTest setup test environment, it uses `require.TestingT` to support both `testing.T` and `testing.B`. @@ -52,83 +52,48 @@ func (suite *GasfreeTestSuite) DoSetupTest(t require.TestingT) { // account key priv, err := ethsecp256k1.GenerateKey() require.NoError(t, err) - address := common.BytesToAddress(priv.PubKey().Address().Bytes()) suite.signer = tests.NewSigner(priv) - suite.from = address - // consensus key - priv, err = ethsecp256k1.GenerateKey() - require.NoError(t, err) - consAddress := sdk.ConsAddress(priv.PubKey().Address()) - - suite.app = Setup(checkTx, func(app *althea.AltheaApp, genesis simapp.GenesisState) simapp.GenesisState { - evmGenesis := evmtypes.DefaultGenesisState() - evmGenesis.Params.EvmDenom = altheaconfig.BaseDenom - evmGenesis.Params.AllowUnprotectedTxs = false - - genesis[evmtypes.ModuleName] = app.AppCodec().MustMarshalJSON(evmGenesis) - - coins := sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(100000000000000))) - genesisState := althea.ModuleBasics.DefaultGenesis(app.AppCodec()) - b32address := sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), priv.PubKey().Address().Bytes()) - balances := []banktypes.Balance{ - { - Address: b32address, - Coins: coins, - }, - { - Address: app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(), - Coins: coins, - }, - } - // Update total supply - bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(200000000000000))), []banktypes.Metadata{}) - genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis) - return genesis - }) - - coins := sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(100000000000000))) - genesisState := althea.ModuleBasics.DefaultGenesis(suite.app.AppCodec()) - b32address := sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), priv.PubKey().Address().Bytes()) - balances := []banktypes.Balance{ - { - Address: b32address, - Coins: coins, - }, - { - Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(), - Coins: coins, - }, - } - // Update total supply - bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(sdk.NewCoin(altheaconfig.BaseDenom, sdk.NewInt(200000000000000))), []banktypes.Metadata{}) - genesisState[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(bankGenesis) + // init app + suite.app = althea.NewSetup(checkTx, func(aa *althea.AltheaApp, gs simapp.GenesisState) simapp.GenesisState { + // setup feemarketGenesis params + feemarketGenesis := feemarkettypes.DefaultGenesisState() + feemarketGenesis.Params.EnableHeight = 1 + feemarketGenesis.Params.NoBaseFee = false + feemarketGenesis.Params.BaseFee = sdk.NewInt(1) + + gs[feemarkettypes.ModuleName] = aa.AppCodec().MustMarshalJSON(feemarketGenesis) + + if suite.mintFeeCollector { + // mint some coin to fee collector + coins := sdk.NewCoins(sdk.NewCoin(altheacfg.BaseDenom, sdk.NewInt(int64(params.TxGas)-1))) + balances := []banktypes.Balance{ + { + Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(), + Coins: coins, + }, + } + // update total supply + var bankGenesis banktypes.GenesisState + aa.AppCodec().MustUnmarshalJSON(gs[banktypes.ModuleName], &bankGenesis) + bankGenesis.Balances = append(bankGenesis.Balances, balances...) + bankGenesis.Supply = bankGenesis.Supply.Add(coins...) + gs[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(&bankGenesis) - stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ") - require.NoError(t, err) + } - // Initialize the chain - suite.app.InitChain( - // nolint: exhaustruct - abci.RequestInitChain{ - ChainId: "althea_6633438-1", - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: DefaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) + return gs + }) - // nolint: exhaustruct suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{ Height: 1, - ChainID: "althea_6633438-1", + ChainID: "althea_7357-1", Time: time.Now().UTC(), - ProposerAddress: consAddress.Bytes(), - // nolint: exhaustruct + ProposerAddress: althea.ValidatorPubKey.Address().Bytes(), + Version: tmversion.Consensus{ Block: version.BlockProtocol, }, - // nolint: exhaustruct LastBlockId: tmproto.BlockID{ Hash: tmhash.Sum([]byte("block_id")), PartSetHeader: tmproto.PartSetHeader{ @@ -145,60 +110,6 @@ func (suite *GasfreeTestSuite) DoSetupTest(t require.TestingT) { LastResultsHash: tmhash.Sum([]byte("last_result")), }) - // queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry()) - // evmtypes.RegisterQueryServer(queryHelper, suite.app.EvmKeeper) - - // acc := ðermint.EthAccount{ - // BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0), - // CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(), - // } - - // suite.app.AccountKeeper.SetAccount(suite.ctx, acc) - - // valAddr := sdk.ValAddress(address.Bytes()) - // // nolint: exhaustruct - // validator, err := stakingtypes.NewValidator(valAddr, priv.PubKey(), stakingtypes.Description{}) - // require.NoError(t, err) - - // err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) - // require.NoError(t, err) - // err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator) - // require.NoError(t, err) - // suite.app.StakingKeeper.SetValidator(suite.ctx, validator) - - suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID()) - suite.handler = evm.NewHandler(suite.app.EvmKeeper) -} - -// Setup initializes a new Althea app. A Nop logger is set in AltheaApp. -func Setup(isCheckTx bool, patchGenesis func(*althea.AltheaApp, althea.GenesisState) althea.GenesisState) *althea.AltheaApp { - db := dbm.NewMemDB() - app := althea.NewAltheaApp(tmlog.NewNopLogger(), db, nil, true, map[int64]bool{}, althea.DefaultNodeHome, 5, althea.MakeEncodingConfig(), simapp.EmptyAppOptions{}) - if !isCheckTx { - // init chain must be called to stop deliverState from being nil - genesisState := althea.NewDefaultGenesisState() - if patchGenesis != nil { - genesisState = patchGenesis(app, genesisState) - } - - stateBytes, err := json.MarshalIndent(genesisState, "", " ") - if err != nil { - panic(err) - } - - // Initialize the chain - app.InitChain( - // nolint: exhaustruct - abci.RequestInitChain{ - ChainId: "althea_6633438-1", - Validators: []abci.ValidatorUpdate{}, - ConsensusParams: DefaultConsensusParams, - AppStateBytes: stateBytes, - }, - ) - } - - return app } // DefaultConsensusParams defines the default Tendermint consensus params used in From c2877af3d0487e5d8c15e6c7450ff9600ddc8f16 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Tue, 10 Dec 2024 15:43:05 -0500 Subject: [PATCH 19/25] Mint DEX positions in base and quote quantities --- .../test_runner/src/dex_utils.rs | 42 +++++++++++++++++++ .../test_runner/src/tests/dex.rs | 31 ++++++++++---- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/integration_tests/test_runner/src/dex_utils.rs b/integration_tests/test_runner/src/dex_utils.rs index a75d34af..d6d25b39 100644 --- a/integration_tests/test_runner/src/dex_utils.rs +++ b/integration_tests/test_runner/src/dex_utils.rs @@ -1058,6 +1058,48 @@ pub async fn dex_mint_ranged_pos( assert_eq!(range_pos.liq - start_pos.liq, liq); } +#[allow(clippy::too_many_arguments)] +pub async fn dex_mint_ranged_in_amount( + web3: &Web3, + dex: EthAddress, + evm_privkey: PrivateKey, + base: EthAddress, + quote: EthAddress, + pool_idx: Uint256, + bid_tick: Int256, + ask_tick: Int256, + qty: Uint256, // The amount of a token to mint a position with + in_base: bool, // Whether to mint in the base token or the quote token +) { + assert!(base.lt("e), "base must be lexically smaller than quote"); + + let code = if in_base { + Uint256::from(11u8) // Mint in base amount code + } else { + Uint256::from(12u8) // Mint in quote amount code + }; + let mint_ranged_pos_args = UserCmdArgs { + callpath: WARM_PATH, // Warm Path index + cmd: vec![ + code.into(), + base.into(), // base + quote.into(), // quote + pool_idx.into(), // poolIdx + bid_tick.into(), // bid (lower) tick + ask_tick.into(), // ask (upper) tick + qty.into(), // liq (in liquidity units, which must be a multiple of 1024) + (*MIN_PRICE).into(), // limitLower + (*MAX_PRICE).into(), // limitHigher + Uint256::from(0u8).into(), // reserveFlags + EthAddress::default().into(), // lpConduit + ], + }; + info!("Minting position in single token: {mint_ranged_pos_args:?}"); + dex_user_cmd(web3, dex, evm_privkey, mint_ranged_pos_args, None, None) + .await + .expect("Failed to mint position in pool"); +} + #[allow(clippy::too_many_arguments)] pub async fn dex_burn_ranged_pos( web3: &Web3, diff --git a/integration_tests/test_runner/src/tests/dex.rs b/integration_tests/test_runner/src/tests/dex.rs index 123db2e6..361c1389 100644 --- a/integration_tests/test_runner/src/tests/dex.rs +++ b/integration_tests/test_runner/src/tests/dex.rs @@ -7,9 +7,10 @@ use crate::dex_utils::{ croc_policy_ops_resolution, croc_policy_treasury_resolution, croc_query_curve_tick, croc_query_dex, croc_query_pool_params, croc_query_pool_template, croc_query_range_position, dex_authority_transfer, dex_burn_ambient_pos, dex_burn_knockout_pos, dex_burn_ranged_pos, - dex_direct_protocol_cmd, dex_mint_ambient_pos, dex_mint_knockout_pos, dex_mint_ranged_pos, - dex_query_authority, dex_query_safe_mode, dex_swap, dex_user_cmd, OpsResolutionArgs, - ProtocolCmdArgs, SwapArgs, UserCmdArgs, BOOT_PATH, COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, + dex_direct_protocol_cmd, dex_mint_ambient_pos, dex_mint_knockout_pos, + dex_mint_ranged_in_amount, dex_mint_ranged_pos, dex_query_authority, dex_query_safe_mode, + dex_swap, dex_user_cmd, OpsResolutionArgs, ProtocolCmdArgs, SwapArgs, UserCmdArgs, BOOT_PATH, + COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, }; use crate::type_urls::{ COLLECT_TREASURY_PROPOSAL_TYPE_URL, HOT_PATH_OPEN_PROPOSAL_TYPE_URL, OPS_PROPOSAL_TYPE_URL, @@ -162,7 +163,7 @@ pub async fn populate_pool_basic( if range_pos.liq > 0u8.into() { info!("Range position already exists: {:?}", range_pos); } else { - let liq: Uint256 = one_atom() * 1024000000u32.into(); + let qty: Uint256 = one_eth() * 1024u32.into(); let bb = web3 .get_erc20_balance(base, evm_user.eth_address) .await @@ -180,18 +181,32 @@ pub async fn populate_pool_basic( .await .unwrap(); info!("Before minting ranged position: base balance: {}, quote balance: {}, base approved: {}, quote approved: {}", bb, qb, ba, qa); - dex_mint_ranged_pos( + // Mint using the base token + dex_mint_ranged_in_amount( web3, dex_contracts.dex, - dex_contracts.query, evm_user.eth_privkey, - evm_user, base, quote, *POOL_IDX, bid_tick, ask_tick, - liq, + qty, + true, + ) + .await; + // Mint using the quote token + dex_mint_ranged_in_amount( + web3, + dex_contracts.dex, + evm_user.eth_privkey, + base, + quote, + *POOL_IDX, + bid_tick, + ask_tick, + qty, + false, ) .await; } From 6c326a5590de8c79ea4093e4c775c4c405913692 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Fri, 13 Dec 2024 17:50:49 -0500 Subject: [PATCH 20/25] Improve DEX_ADVANCED test, calculate liq -> flows, add DEX_SWAP_MANY test --- integration_tests/test_runner/src/bin/main.rs | 15 +- .../test_runner/src/bootstrapping.rs | 1 + .../test_runner/src/dex_utils.rs | 267 ++++++++++++++---- .../test_runner/src/tests/dex.rs | 219 +++++++------- 4 files changed, 316 insertions(+), 186 deletions(-) diff --git a/integration_tests/test_runner/src/bin/main.rs b/integration_tests/test_runner/src/bin/main.rs index 1caa81b8..1be37c7f 100644 --- a/integration_tests/test_runner/src/bin/main.rs +++ b/integration_tests/test_runner/src/bin/main.rs @@ -4,7 +4,6 @@ #[macro_use] extern crate log; -use deep_space::Coin; use deep_space::Contact; use deep_space::PrivateKey; use std::env; @@ -20,6 +19,7 @@ use test_runner::tests::dex::advanced_dex_test; use test_runner::tests::dex::basic_dex_test; use test_runner::tests::dex::dex_ops_proposal_test; use test_runner::tests::dex::dex_safe_mode_test; +use test_runner::tests::dex::dex_swap_many; use test_runner::tests::dex::dex_upgrade_test; use test_runner::tests::erc20_conversion::erc20_conversion_test; use test_runner::tests::ica_host::ica_host_happy_path; @@ -33,15 +33,11 @@ use test_runner::tests::onboarding::onboarding_disable_after; use test_runner::tests::onboarding::onboarding_disabled_whitelisted; use test_runner::tests::upgrade::upgrade_part_1; use test_runner::tests::upgrade::upgrade_part_2; -use test_runner::utils::one_atom; use test_runner::utils::one_eth; -use test_runner::utils::one_hundred_eth; -use test_runner::utils::send_funds_bulk; use test_runner::utils::ETH_NODE; use test_runner::utils::EVM_USER_KEYS; use test_runner::utils::IBC_ADDRESS_PREFIX; use test_runner::utils::IBC_NODE_GRPC; -use test_runner::utils::STAKING_TOKEN; use test_runner::utils::{ get_test_token_name, should_deploy_contracts, wait_for_cosmos_online, ADDRESS_PREFIX, COSMOS_NODE_GRPC, OPERATION_TIMEOUT, TOTAL_TIMEOUT, @@ -236,6 +232,15 @@ pub async fn main() { ) .await; return; + } else if test_type == "DEX_SWAP_MANY" { + dex_swap_many( + &web30, + EVM_USER_KEYS.clone(), + erc20_addresses, + dex_contracts, + ) + .await; + return; } else if test_type == "DEX_UPGRADE" { info!("Start dex upgrade test"); dex_upgrade_test( diff --git a/integration_tests/test_runner/src/bootstrapping.rs b/integration_tests/test_runner/src/bootstrapping.rs index aab762ad..2f75350f 100644 --- a/integration_tests/test_runner/src/bootstrapping.rs +++ b/integration_tests/test_runner/src/bootstrapping.rs @@ -323,6 +323,7 @@ pub fn parse_contract_addresses() -> BootstrapContractAddresses { } else if line.contains("WETH deployed at Address -") { let address_string = line.split('-').last().unwrap(); weth_address = address_string.trim().parse().unwrap(); + info!("found weth address it is {}", address_string); } else if line.contains("Uniswap Liquidity test deployed at Address - ") { let address_string = line.split('-').last().unwrap(); uniswap_liquidity = Some(address_string.trim().parse().unwrap()); diff --git a/integration_tests/test_runner/src/dex_utils.rs b/integration_tests/test_runner/src/dex_utils.rs index d6d25b39..5848bb6e 100644 --- a/integration_tests/test_runner/src/dex_utils.rs +++ b/integration_tests/test_runner/src/dex_utils.rs @@ -1,4 +1,4 @@ -use std::{convert::TryInto, time::Duration}; +use std::{convert::TryInto, str::FromStr, time::Duration}; use clarity::{ abi::{encode_tokens, AbiToken}, @@ -13,7 +13,7 @@ use web30::{ types::{TransactionRequest, TransactionResponse}, }; -use crate::utils::{EthermintUserKey, OPERATION_TIMEOUT}; +use crate::utils::OPERATION_TIMEOUT; // Callpath Indices pub const BOOT_PATH: u16 = 0; @@ -999,7 +999,7 @@ pub async fn dex_mint_ranged_pos( dex: EthAddress, query: EthAddress, evm_privkey: PrivateKey, - evm_user: &EthermintUserKey, + evm_address: EthAddress, base: EthAddress, quote: EthAddress, pool_idx: Uint256, @@ -1012,7 +1012,7 @@ pub async fn dex_mint_ranged_pos( web3, query, None, - evm_user.eth_address, + evm_address, base, quote, pool_idx, @@ -1046,7 +1046,7 @@ pub async fn dex_mint_ranged_pos( web3, query, None, - evm_user.eth_address, + evm_address, base, quote, pool_idx, @@ -1106,7 +1106,7 @@ pub async fn dex_burn_ranged_pos( dex: EthAddress, query: EthAddress, evm_privkey: PrivateKey, - evm_user: &EthermintUserKey, + evm_address: EthAddress, base: EthAddress, quote: EthAddress, pool_idx: Uint256, @@ -1119,7 +1119,7 @@ pub async fn dex_burn_ranged_pos( web3, query, None, - evm_user.eth_address, + evm_address, base, quote, pool_idx, @@ -1153,7 +1153,7 @@ pub async fn dex_burn_ranged_pos( web3, query, None, - evm_user.eth_address, + evm_address, base, quote, pool_idx, @@ -1172,7 +1172,7 @@ pub async fn dex_mint_knockout_pos( dex: EthAddress, _query: EthAddress, evm_privkey: PrivateKey, - _evm_user: &EthermintUserKey, + _evm_address: EthAddress, base: EthAddress, quote: EthAddress, pool_idx: Uint256, @@ -1213,7 +1213,7 @@ pub async fn dex_mint_knockout_pos( // let pivot = croc_query_knockout_pivot( // web3, // dex, - // evm_user.eth_address, + // evm_address, // base, // quote, // pool_idx, @@ -1229,7 +1229,7 @@ pub async fn dex_mint_knockout_pos( // web3, // query, // None, - // evm_user.eth_address, + // evm_address, // base, // quote, // pool_idx, @@ -1250,7 +1250,7 @@ pub async fn dex_burn_knockout_pos( dex: EthAddress, query: EthAddress, evm_privkey: PrivateKey, - evm_user: &EthermintUserKey, + evm_address: EthAddress, base: EthAddress, quote: EthAddress, pool_idx: Uint256, @@ -1270,7 +1270,7 @@ pub async fn dex_burn_knockout_pos( web3, query, None, - evm_user.eth_address, + evm_address, base, quote, pool_idx, @@ -1314,7 +1314,7 @@ pub async fn dex_burn_knockout_pos( web3, query, None, - evm_user.eth_address, + evm_address, base, quote, pool_idx, @@ -1335,24 +1335,17 @@ pub async fn dex_mint_ambient_pos( dex: EthAddress, query: EthAddress, evm_privkey: PrivateKey, - evm_user: &EthermintUserKey, + evm_address: EthAddress, base: EthAddress, quote: EthAddress, pool_idx: Uint256, liq: Uint256, // The liquidity to mint (must be a multiple of 1024) ) { assert!(base.lt("e), "base must be lexically smaller than quote"); - let start_pos = croc_query_ambient_tokens( - web3, - query, - None, - evm_user.eth_address, - base, - quote, - pool_idx, - ) - .await - .expect("Could not query position"); + let start_pos = + croc_query_ambient_tokens(web3, query, None, evm_address, base, quote, pool_idx) + .await + .expect("Could not query position"); let mint_ambient_pos_args = UserCmdArgs { callpath: WARM_PATH, // Warm Path index @@ -1374,44 +1367,81 @@ pub async fn dex_mint_ambient_pos( dex_user_cmd(web3, dex, evm_privkey, mint_ambient_pos_args, None, None) .await .expect("Failed to mint position in pool"); - let amb_pos = croc_query_ambient_tokens( - web3, - query, - None, - evm_user.eth_address, - base, - quote, - pool_idx, - ) - .await - .expect("Could not query position"); + let amb_pos = croc_query_ambient_tokens(web3, query, None, evm_address, base, quote, pool_idx) + .await + .expect("Could not query position"); assert!(liq - (amb_pos.liq - start_pos.liq) < 1000u32.into()); } +#[allow(clippy::too_many_arguments)] +pub async fn dex_mint_ambient_in_amount( + web3: &Web3, + dex: EthAddress, + query: EthAddress, + evm_privkey: PrivateKey, + evm_address: EthAddress, + base: EthAddress, + quote: EthAddress, + pool_idx: Uint256, + qty: Uint256, // The amount of a token to mint a position with + in_base: bool, // Whether to mint in the base token or the quote token +) { + assert!(base.lt("e), "base must be lexically smaller than quote"); + + let code = if in_base { + Uint256::from(31u8) // Mint in base amount code + } else { + Uint256::from(32u8) // Mint in quote amount code + }; + + let start_pos = + croc_query_ambient_tokens(web3, query, None, evm_address, base, quote, pool_idx) + .await + .expect("Could not query position"); + + let mint_ambient_pos_args = UserCmdArgs { + callpath: WARM_PATH, // Warm Path index + cmd: vec![ + code.into(), + base.into(), // base + quote.into(), // quote + (pool_idx).into(), // poolIdx + Uint256::zero().into(), // bid (lower) tick + Uint256::zero().into(), // ask (upper) tick + qty.into(), // qty of tokens to supply + (*MIN_PRICE).into(), // limitLower + (*MAX_PRICE).into(), // limitHigher + Uint256::zero().into(), // reserveFlags + EthAddress::default().into(), // lpConduit + ], + }; + info!("Minting ambient position: {mint_ambient_pos_args:?}"); + dex_user_cmd(web3, dex, evm_privkey, mint_ambient_pos_args, None, None) + .await + .expect("Failed to mint position in pool"); + let amb_pos = croc_query_ambient_tokens(web3, query, None, evm_address, base, quote, pool_idx) + .await + .expect("Could not query position"); + assert!(amb_pos.liq > start_pos.liq); +} + #[allow(clippy::too_many_arguments)] pub async fn dex_burn_ambient_pos( web3: &Web3, dex: EthAddress, query: EthAddress, evm_privkey: PrivateKey, - evm_user: &EthermintUserKey, + evm_address: EthAddress, base: EthAddress, quote: EthAddress, pool_idx: Uint256, liq: Uint256, // The liquidity to mint (must be a multiple of 1024) ) { assert!(base.lt("e), "base must be lexically smaller than quote"); - let start_pos = croc_query_ambient_tokens( - web3, - query, - None, - evm_user.eth_address, - base, - quote, - pool_idx, - ) - .await - .expect("Could not query position"); + let start_pos = + croc_query_ambient_tokens(web3, query, None, evm_address, base, quote, pool_idx) + .await + .expect("Could not query position"); let burn_ambient_pos_args = UserCmdArgs { callpath: WARM_PATH, // Warm Path index @@ -1433,16 +1463,133 @@ pub async fn dex_burn_ambient_pos( dex_user_cmd(web3, dex, evm_privkey, burn_ambient_pos_args, None, None) .await .expect("Failed to burn position in pool"); - let amb_pos = croc_query_ambient_tokens( - web3, - query, - None, - evm_user.eth_address, - base, - quote, - pool_idx, - ) - .await - .expect("Could not query position"); + let amb_pos = croc_query_ambient_tokens(web3, query, None, evm_address, base, quote, pool_idx) + .await + .expect("Could not query position"); assert_eq!(start_pos.liq - amb_pos.liq, liq); } + +// Mimics the logic in the Ambient sizeAmbientLiq() function +pub fn size_ambient_liq(collateral: u128, is_add: bool, price_root: u128, in_base: bool) -> u128 { + let buffered = buffer_collateral(collateral, is_add); + let liq = liquidity_supported(buffered, price_root, in_base); + + if is_add { + liq + } else { + liq + 1 + } +} + +// Mimics the logic in the Ambient sizeConcentratedLiq() function +pub fn size_concentrated_liq( + collateral: u128, + is_add: bool, + price_root: u128, + lower_tick: i32, + upper_tick: i32, + in_base: bool, +) -> u128 { + let (mut bid_price, mut ask_price) = + determine_price_range(price_root, lower_tick, upper_tick, in_base).unwrap(); + let buffered = buffer_collateral(collateral, is_add); + if !in_base { + bid_price = recip_q64(bid_price); + ask_price = recip_q64(ask_price); + } + let price_delta = if bid_price > ask_price { + bid_price - ask_price + } else { + ask_price - bid_price + }; + let liq = liquidity_supported(buffered, price_delta, in_base); + + if is_add { + shave_round_lots(liq) + } else { + shave_round_lots_up(liq) + } +} + +pub fn buffer_collateral(collateral: u128, is_add: bool) -> u128 { + const BUFFER: u128 = 4; + + if is_add { + if collateral < BUFFER { + 0 + } else { + collateral - BUFFER + } + } else { + #[allow(clippy::collapsible_if)] + if collateral > u128::MAX - BUFFER { + u128::MAX + } else { + collateral + BUFFER + } + } +} + +pub fn liquidity_supported(buffered_collateral: u128, price_root: u128, in_base: bool) -> u128 { + let bc_f = buffered_collateral.to_f64().unwrap(); + let pr_f = price_root.to_f64().unwrap(); + + if in_base { + (bc_f * 2f64.powf(64f64) / pr_f).to_u128() + } else { + (bc_f * pr_f / 2f64.powf(64f64)).to_u128() + } + .unwrap() +} + +pub fn determine_price_range( + curve_price: u128, + lower_tick: i32, + upper_tick: i32, + in_base: bool, +) -> Result<(u128, u128), String> { + let mut bid_price = tick_to_sqrt_ratio(lower_tick); + let mut ask_price = tick_to_sqrt_ratio(upper_tick); + + if curve_price <= bid_price { + if in_base { + return Err("Price is below the bid price".to_string()); + } + } else if curve_price >= ask_price { + if !in_base { + return Err("Price is above the ask price".to_string()); + } + } else if in_base { + ask_price = curve_price; + } else { + bid_price = curve_price; + } + + Ok((bid_price, ask_price)) +} + +pub fn tick_to_sqrt_ratio(tick: i32) -> u128 { + (1.0001f64.powf(tick as f64).sqrt() * 2f64.powf(64f64)) + .to_u128() + .unwrap() +} + +fn recip_q64(x: u128) -> u128 { + let q128 = Uint256::from_str("340282366920938463463374607431768211456").unwrap(); + (q128 / x.into()).to_u128().unwrap() +} + +fn shave_round_lots(liq: u128) -> u128 { + (liq >> 11) << 11 +} + +fn shave_round_lots_up(liq: u128) -> u128 { + ((liq >> 11) + 1) << 11 +} + +pub fn ambient_liq_to_flows(liq: u128, price_root: u128) -> (i128, i128) { + let base = (price_root * liq) >> 64; + let quote = (price_root << 64) / liq; + + (base as i128, quote as i128) +} diff --git a/integration_tests/test_runner/src/tests/dex.rs b/integration_tests/test_runner/src/tests/dex.rs index 361c1389..8c52ed12 100644 --- a/integration_tests/test_runner/src/tests/dex.rs +++ b/integration_tests/test_runner/src/tests/dex.rs @@ -4,13 +4,13 @@ use std::time::Duration; use crate::bootstrapping::DexAddresses; use crate::dex_utils::{ - croc_policy_ops_resolution, croc_policy_treasury_resolution, croc_query_curve_tick, - croc_query_dex, croc_query_pool_params, croc_query_pool_template, croc_query_range_position, - dex_authority_transfer, dex_burn_ambient_pos, dex_burn_knockout_pos, dex_burn_ranged_pos, - dex_direct_protocol_cmd, dex_mint_ambient_pos, dex_mint_knockout_pos, + ambient_liq_to_flows, croc_policy_ops_resolution, croc_policy_treasury_resolution, + croc_query_curve_tick, croc_query_dex, croc_query_pool_params, croc_query_pool_template, + croc_query_price, croc_query_range_position, dex_authority_transfer, dex_direct_protocol_cmd, + dex_mint_ambient_in_amount, dex_mint_ambient_pos, dex_mint_knockout_pos, dex_mint_ranged_in_amount, dex_mint_ranged_pos, dex_query_authority, dex_query_safe_mode, - dex_swap, dex_user_cmd, OpsResolutionArgs, ProtocolCmdArgs, SwapArgs, UserCmdArgs, BOOT_PATH, - COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, + dex_swap, dex_user_cmd, size_ambient_liq, OpsResolutionArgs, ProtocolCmdArgs, SwapArgs, + UserCmdArgs, BOOT_PATH, COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, }; use crate::type_urls::{ COLLECT_TREASURY_PROPOSAL_TYPE_URL, HOT_PATH_OPEN_PROPOSAL_TYPE_URL, OPS_PROPOSAL_TYPE_URL, @@ -33,9 +33,9 @@ use althea_proto::cosmos_sdk_proto::cosmos::params::v1beta1::{ }; use clarity::{Address as EthAddress, PrivateKey, Uint256}; use deep_space::{Coin, Contact}; +use num256::Int256; use num_traits::ToPrimitive; use rand::Rng; -use tokio::time::sleep; use web30::client::Web3; use web30::jsonrpc::error::Web3Error; use web30::types::TransactionResponse; @@ -163,7 +163,7 @@ pub async fn populate_pool_basic( if range_pos.liq > 0u8.into() { info!("Range position already exists: {:?}", range_pos); } else { - let qty: Uint256 = one_eth() * 1024u32.into(); + let qty: Uint256 = 1024000000000000000u128.into(); // 1.024 eth let bb = web3 .get_erc20_balance(base, evm_user.eth_address) .await @@ -180,39 +180,29 @@ pub async fn populate_pool_basic( .check_erc20_approved(quote, evm_user.eth_address, dex_contracts.dex) .await .unwrap(); - info!("Before minting ranged position: base balance: {}, quote balance: {}, base approved: {}, quote approved: {}", bb, qb, ba, qa); + let one_eth_f = one_eth().to_f64().unwrap(); + let bb_f = bb.to_i128().unwrap().to_f64().unwrap(); + let qb_f = qb.to_i128().unwrap().to_f64().unwrap(); + info!("Before minting ranged position: base balance: {}, quote balance: {}, base approved: {}, quote approved: {}", (bb_f) / one_eth_f, (qb_f) / one_eth_f, ba, qa); // Mint using the base token - dex_mint_ranged_in_amount( - web3, - dex_contracts.dex, - evm_user.eth_privkey, - base, - quote, - *POOL_IDX, - bid_tick, - ask_tick, - qty, - true, - ) - .await; - // Mint using the quote token - dex_mint_ranged_in_amount( + dex_mint_ranged_pos( web3, dex_contracts.dex, + dex_contracts.query, evm_user.eth_privkey, + evm_user.eth_address, base, quote, *POOL_IDX, bid_tick, ask_tick, qty, - false, ) .await; } // Finally, perform many smaller swaps to ensure the pool is working as expected - swap_many(web3, dex_contracts, base, quote, evm_user, 30).await; + swap_many(web3, dex_contracts, base, quote, evm_user, 30, None).await; } // Generates some additional positions, minting and burning ambient and ranged and knockout positions @@ -230,8 +220,8 @@ pub async fn advanced_dex_test( caller: _, query: _, dex: _, - pool_base, - pool_quote, + pool_base: base, + pool_quote: quote, } = setup_params( web3, evm_user_keys, @@ -248,51 +238,42 @@ pub async fn advanced_dex_test( dex_contracts.policy, &evm_user, &validator_keys, - pool_base, - pool_quote, + base, + quote, walthea, ) .await; - - let tick = croc_query_curve_tick( + let bb = web3 + .get_erc20_balance(base, evm_user.eth_address) + .await + .unwrap(); + let qb = web3 + .get_erc20_balance(quote, evm_user.eth_address) + .await + .unwrap(); + let ambient_qty = one_eth(); + let price_root = croc_query_price( web3, dex_contracts.query, - Some(evm_user.eth_address), - pool_base, - pool_quote, + Some(*MINER_ETH_ADDRESS), + base, + quote, *POOL_IDX, ) .await - .expect("Could not get curve tick for pool"); - - let ranged_bid_tick = tick - 32u8.into(); - let ranged_ask_tick = tick + 32u8.into(); - let liq = one_eth() * 10240u32.into(); - + .unwrap(); + let pr_u128 = price_root.to_u128().unwrap(); + let liq = size_ambient_liq(ambient_qty.to_u128().unwrap(), true, pr_u128, false); dex_mint_ambient_pos( web3, dex_contracts.dex, dex_contracts.query, evm_user.eth_privkey, - &evm_user, - pool_base, - pool_quote, - *POOL_IDX, - (1024u32 * 10000u32).into(), - ) - .await; - dex_mint_ranged_pos( - web3, - dex_contracts.dex, - dex_contracts.query, - evm_user.eth_privkey, - &evm_user, - pool_base, - pool_quote, + evm_user.eth_address, + base, + quote, *POOL_IDX, - ranged_bid_tick, - ranged_ask_tick, - liq / 4u8.into(), + liq.into(), ) .await; @@ -300,81 +281,71 @@ pub async fn advanced_dex_test( web3, dex_contracts.query, Some(evm_user.eth_address), - pool_base, - pool_quote, + base, + quote, *POOL_IDX, ) .await .expect("Could not get curve tick for pool"); - let ko_bid_tick = tick - 32u32.into(); - let ko_ask_tick = tick + 32u32.into(); - dex_mint_knockout_pos( - web3, - dex_contracts.dex, - dex_contracts.query, - evm_user.eth_privkey, - &evm_user, - pool_base, - pool_quote, - *POOL_IDX, - ko_bid_tick, - ko_ask_tick, - true, - 0u8, - (1024u32 * 10000u32).into(), - true, - ) - .await; + let liq = one_eth() * 1024u32.into() / 100u32.into(); + let tick_range = 10240; + for i in 0..10 { + let position_width = tick_range / 10; // Make the positions 1/10th of the total range + let tick_offset = tick_range / 10 * i - (tick_range / 2); // Divide into 10 portions, center around the current tick + let bid_tick = tick + tick_offset.into() - (Int256::from(position_width) / 2i8.into()); + let ask_tick = tick + tick_offset.into() + (Int256::from(position_width) / 2i8.into()); - sleep(Duration::from_secs(15)).await; + info!("Minting position between ticks {bid_tick} and {ask_tick}"); - dex_burn_ranged_pos( - web3, - dex_contracts.dex, - dex_contracts.query, - evm_user.eth_privkey, - &evm_user, + // Mint two ranged positions (in each token) + dex_mint_ranged_in_amount( + web3, + dex_contracts.dex, + evm_user.eth_privkey, + base, + quote, + *POOL_IDX, + bid_tick, + ask_tick, + liq, + true, + ) + .await; + } + info!("Successfully tested DEX"); +} +pub async fn dex_swap_many( + web3: &Web3, + evm_user_keys: Vec, + erc20_contracts: Vec, + dex_contracts: DexAddresses, +) { + let DexTestParams { + evm_user, + caller: _, + query: _, + dex: _, pool_base, pool_quote, - *POOL_IDX, - ranged_bid_tick, - ranged_ask_tick, - liq / 4u8.into(), - ) - .await; - dex_burn_knockout_pos( + } = setup_params( web3, - dex_contracts.dex, - dex_contracts.query, - evm_user.eth_privkey, - &evm_user, - pool_base, - pool_quote, - *POOL_IDX, - ko_bid_tick, - ko_ask_tick, - true, - 0u8, - (1024u32 * 10000u32).into(), - true, - true, - None, + evm_user_keys, + dex_contracts.clone(), + erc20_contracts.clone(), ) .await; - dex_burn_ambient_pos( + swap_many( web3, - dex_contracts.dex, - dex_contracts.query, - evm_user.eth_privkey, - &evm_user, + &dex_contracts, pool_base, pool_quote, - *POOL_IDX, - (1024u32 * 10000u32).into(), + &evm_user, + 40, + Some(true), ) .await; - info!("Successfully tested DEX"); + info!("Successfully swapped many times"); } pub struct DexTestParams { @@ -782,13 +753,17 @@ async fn swap_many( pool_quote: EthAddress, evm_user: &EthermintUserKey, swaps: usize, + direction: Option, ) { - let mut is_buy = true; // Switch direction frequently, starting with base for quote + let mut is_buy = if let Some(d) = direction { d } else { true }; let mut rng = rand::thread_rng(); for _ in 0..swaps { - let qty_multi: u16 = rng.gen(); - let qty = (1024u32 * u32::from(qty_multi)).into(); + let mut qty_multi: u8 = rng.gen(); // 0 to 255 + if qty_multi == 0 { + qty_multi = 1; + } + let qty = Uint256::from(1000000000000000u128) * qty_multi.into(); // .001 eth * qty_multi let pre_swap_base = web3 .get_erc20_balance(pool_base, evm_user.eth_address) .await @@ -855,7 +830,9 @@ async fn swap_many( ); } - is_buy = !is_buy; + if direction.is_none() { + is_buy = !is_buy; + } } } From 7c69ee2042e9aeae15a6b99ab2ab2e877b5733e4 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 16 Dec 2024 18:20:41 -0500 Subject: [PATCH 21/25] Implement evm fee burning test --- .github/workflows/integration-tests.yml | 12 ++ integration_tests/test_runner/src/bin/main.rs | 16 +++ .../test_runner/src/tests/evm_fee_burning.rs | 135 ++++++++++++++++++ .../test_runner/src/tests/mod.rs | 1 + 4 files changed, 164 insertions(+) create mode 100644 integration_tests/test_runner/src/tests/evm_fee_burning.rs diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 7fb20a8b..ccd68f4a 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -188,6 +188,18 @@ jobs: cache-on-failure: true - name: Tests the nativedex OpsProposal function run: tests/all-up-test-ci.sh DEX_OPS_PROPOSAL + EVM_FEE_BURNING: + needs: native_token + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v5 + - uses: Swatinem/rust-cache@v2 + with: + workspaces: integration_tests/ + cache-on-failure: true + - name: Checks that evm fees are truly burned + run: tests/all-up-test-ci.sh EVM_FEE_BURNING UPGRADE: needs: native_token runs-on: ubuntu-latest diff --git a/integration_tests/test_runner/src/bin/main.rs b/integration_tests/test_runner/src/bin/main.rs index 1be37c7f..9993b773 100644 --- a/integration_tests/test_runner/src/bin/main.rs +++ b/integration_tests/test_runner/src/bin/main.rs @@ -4,6 +4,7 @@ #[macro_use] extern crate log; +use althea_proto::canto::erc20; use deep_space::Contact; use deep_space::PrivateKey; use std::env; @@ -22,6 +23,7 @@ use test_runner::tests::dex::dex_safe_mode_test; use test_runner::tests::dex::dex_swap_many; use test_runner::tests::dex::dex_upgrade_test; use test_runner::tests::erc20_conversion::erc20_conversion_test; +use test_runner::tests::evm_fee_burning::evm_fee_burning_test; use test_runner::tests::ica_host::ica_host_happy_path; use test_runner::tests::liquid_accounts::liquid_accounts_test; use test_runner::tests::lockup::lockup_test; @@ -280,6 +282,20 @@ pub async fn main() { ) .await; return; + } else if test_type == "EVM_FEES" + || test_type == "EVM_FEE_BURNING" + || test_type == "EVM_FEE_BURN" + { + info!("Start evm fee burning test"); + evm_fee_burning_test( + &contact, + &web30, + keys, + EVM_USER_KEYS.clone(), + erc20_addresses, + ) + .await; + return; } else if test_type == "UPGRADE_PART_1" { upgrade_part_1( &web30, diff --git a/integration_tests/test_runner/src/tests/evm_fee_burning.rs b/integration_tests/test_runner/src/tests/evm_fee_burning.rs new file mode 100644 index 00000000..55357d14 --- /dev/null +++ b/integration_tests/test_runner/src/tests/evm_fee_burning.rs @@ -0,0 +1,135 @@ +use std::time::Duration; + +use crate::utils::{ + create_parameter_change_proposal, one_atom, vote_yes_on_proposals, + wait_for_proposals_to_execute, EthermintUserKey, ValidatorKeys, OPERATION_TIMEOUT, + STAKING_TOKEN, +}; +use althea_proto::cosmos_sdk_proto::cosmos::base::v1beta1::DecCoin; +use althea_proto::cosmos_sdk_proto::cosmos::distribution::v1beta1::{ + query_client::QueryClient as DistributionQueryClient, QueryValidatorOutstandingRewardsRequest, +}; +use althea_proto::cosmos_sdk_proto::cosmos::params::v1beta1::ParamChange; +use clarity::Address as EthAddress; +use deep_space::{Coin, Contact, PrivateKey}; +use futures::future::join_all; +use num256::Uint256; +use tokio::time::sleep; +use web30::client::Web3; + +pub async fn evm_fee_burning_test( + contact: &Contact, + web3: &Web3, + validator_keys: Vec, + evm_user_keys: Vec, + erc20_contracts: Vec, +) { + info!("Set inflation to 0"); + set_inflation_to_zero(contact, &validator_keys).await; + + let pre_balances = snapshot_validator_rewards(contact, &validator_keys).await; + + info!("Generating some fees"); + let gas_multiplier = web30::types::SendTxOption::GasPriceMultiplier(10.0); + for _ in 0..35 { + let mut fs = vec![]; + for user in &evm_user_keys { + fs.push(web3.approve_erc20_transfers( + erc20_contracts[0], + user.eth_privkey, + erc20_contracts[1], + Some(Duration::from_secs(15)), + vec![gas_multiplier.clone()], + )); + } + + join_all(fs).await; + } + + sleep(Duration::from_secs(10)).await; + let post_balances = snapshot_validator_rewards(contact, &validator_keys).await; + assert_eq!(pre_balances, post_balances); + + // Check that other fees are not burned, and wind up in validator accounts + let pre_balances = snapshot_validator_rewards(contact, &validator_keys).await; + let mut fs = vec![]; + for user in &evm_user_keys { + fs.push(contact.send_coins( + Coin { + amount: one_atom(), + denom: STAKING_TOKEN.clone(), + }, + Some(Coin { + amount: one_atom() * 100u8.into(), + denom: STAKING_TOKEN.clone(), + }), + evm_user_keys[0].ethermint_address, + Some(Duration::from_secs(20)), + user.ethermint_key, + )); + } + join_all(fs).await; + // info!("Results: {:?}", results); + sleep(Duration::from_secs(10)).await; + let post_balances = snapshot_validator_rewards(contact, &validator_keys).await; + info!("Pre: {:?}, Post: {:?}", pre_balances, post_balances); + for (pre, post) in pre_balances.iter().zip(post_balances.iter()) { + for (pr, po) in pre.iter().zip(post.iter()) { + assert_eq!(pr.denom, po.denom); + let pree: Uint256 = pr.amount.parse().expect("Invalid integer?"); + let postt: Uint256 = po.amount.parse().expect("Invalid integer?"); + assert!(pree < postt); + } + } + + info!("Successfully tested EVM fee burning"); +} + +pub async fn set_inflation_to_zero(contact: &Contact, validator_keys: &[ValidatorKeys]) { + let to_change = vec![ + ParamChange { + subspace: "mint".to_string(), + key: "InflationMax".to_string(), + value: "\"0.0\"".to_string(), + }, + ParamChange { + subspace: "mint".to_string(), + key: "InflationMin".to_string(), + value: "\"0.0\"".to_string(), + }, + ]; + + let proposer = validator_keys.first().unwrap(); + let zero_fee = Coin { + denom: STAKING_TOKEN.clone(), + amount: 0u8.into(), + }; + create_parameter_change_proposal(contact, proposer.validator_key, to_change, zero_fee).await; + + vote_yes_on_proposals(contact, validator_keys, Some(OPERATION_TIMEOUT)).await; + wait_for_proposals_to_execute(contact).await; +} + +pub async fn snapshot_validator_rewards( + contact: &Contact, + validator_keys: &[ValidatorKeys], +) -> Vec> { + let mut grpc = DistributionQueryClient::connect(contact.get_url()) + .await + .unwrap(); + let mut rewards = Vec::new(); + for key in validator_keys { + let reward = grpc + .validator_outstanding_rewards(QueryValidatorOutstandingRewardsRequest { + validator_address: key + .validator_key + .to_address("altheavaloper") + .unwrap() + .to_string(), + }) + .await + .expect("Unable to get rewards"); + rewards.push(reward.into_inner().rewards.expect("No rewards").rewards); + } + rewards +} diff --git a/integration_tests/test_runner/src/tests/mod.rs b/integration_tests/test_runner/src/tests/mod.rs index 191584e3..b043aa35 100644 --- a/integration_tests/test_runner/src/tests/mod.rs +++ b/integration_tests/test_runner/src/tests/mod.rs @@ -1,5 +1,6 @@ pub mod dex; pub mod erc20_conversion; +pub mod evm_fee_burning; pub mod ica_host; pub mod liquid_accounts; pub mod lockup; From 9bce867d4416cff55ed659cb2577628da526f159 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 16 Dec 2024 20:53:10 -0500 Subject: [PATCH 22/25] Fix MsgEthereumTx support in lockup module --- integration_tests/test_runner/src/bin/main.rs | 9 ++- .../test_runner/src/tests/lockup.rs | 64 +++++++++++++++++-- x/lockup/ante.go | 24 ++++++- x/lockup/types/genesis.go | 13 +++- 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/integration_tests/test_runner/src/bin/main.rs b/integration_tests/test_runner/src/bin/main.rs index 9993b773..cff343bc 100644 --- a/integration_tests/test_runner/src/bin/main.rs +++ b/integration_tests/test_runner/src/bin/main.rs @@ -119,7 +119,14 @@ pub async fn main() { if let Ok(test_type) = test_type { if test_type == "LOCKUP" { info!("Starting Lockup test"); - lockup_test(&contact, keys).await; + lockup_test( + &contact, + keys, + &web30, + EVM_USER_KEYS.clone(), + erc20_addresses, + ) + .await; return; } else if test_type == "MICROTX_FEES" { info!("Starting microtx fees test"); diff --git a/integration_tests/test_runner/src/tests/lockup.rs b/integration_tests/test_runner/src/tests/lockup.rs index 5cab3093..b0122a5c 100644 --- a/integration_tests/test_runner/src/tests/lockup.rs +++ b/integration_tests/test_runner/src/tests/lockup.rs @@ -1,4 +1,4 @@ -use std::time::SystemTime; +use std::time::{Duration, SystemTime}; use crate::type_urls::{ GENERIC_AUTHORIZATION_TYPE_URL, MSG_EXEC_TYPE_URL, MSG_GRANT_TYPE_URL, MSG_MICROTX_TYPE_URL, @@ -18,9 +18,11 @@ use althea_proto::cosmos_sdk_proto::cosmos::bank::v1beta1::{Input, MsgMultiSend, use althea_proto::cosmos_sdk_proto::cosmos::base::v1beta1::Coin as ProtoCoin; use althea_proto::cosmos_sdk_proto::cosmos::distribution::v1beta1::MsgSetWithdrawAddress; use althea_proto::cosmos_sdk_proto::cosmos::params::v1beta1::ParamChange; +use clarity::Address as EthAddress; use clarity::Uint256; use deep_space::error::CosmosGrpcError; use deep_space::{Address, Coin, Contact, Msg, PrivateKey}; +use web30::client::Web3; /// These *_PARAM_KEY constants are defined in x/lockup/types/types.go and must match those values exactly pub const LOCKED_PARAM_KEY: &str = "locked"; @@ -31,7 +33,13 @@ pub const LOCKED_TOKEN_DENOMS_PARAM_KEY: &str = "lockedTokenDenoms"; /// Simulates the launch lockup process by setting the lockup module params via governance, /// attempting to transfer tokens a variety of ways, and finally clearing the lockup module params /// and asserting that balances can successfully be transferred -pub async fn lockup_test(contact: &Contact, validator_keys: Vec) { +pub async fn lockup_test( + contact: &Contact, + validator_keys: Vec, + web3: &Web3, + evm_user_keys: Vec, + erc20_addresses: Vec, +) { let lock_exempt = get_user_key(None); let msg_send_authorized = get_user_key(None); let msg_multi_send_authorized = get_user_key(None); @@ -44,7 +52,14 @@ pub async fn lockup_test(contact: &Contact, validator_keys: Vec) msg_multi_send_authorized, ) .await; - lockup_the_chain(contact, &validator_keys, &lock_exempt).await; + lockup_the_chain( + contact, + &validator_keys, + vec![&lock_exempt, &evm_user_keys[0]], + ) + .await; + send_evm_tx(evm_user_keys[1], web3, &erc20_addresses, false).await; + send_evm_tx(evm_user_keys[0], web3, &erc20_addresses, true).await; // TODO: Add ibc transfer and check that transfers are blocked outbound for aalthea fail_to_send( @@ -62,6 +77,8 @@ pub async fn lockup_test(contact: &Contact, validator_keys: Vec) unlock_the_chain(contact, &validator_keys).await; successfully_send(contact, &validator_keys, lock_exempt).await; + send_evm_tx(evm_user_keys[1], web3, &erc20_addresses, true).await; + send_evm_tx(evm_user_keys[0], web3, &erc20_addresses, true).await; } async fn fund_lock_exempt_user( @@ -126,9 +143,9 @@ async fn fund_authorized_users( pub async fn lockup_the_chain( contact: &Contact, validator_keys: &[ValidatorKeys], - lock_exempt: &EthermintUserKey, + lock_exempt: Vec<&EthermintUserKey>, ) { - let to_change = create_lockup_param_changes(lock_exempt.ethermint_address); + let to_change = create_lockup_param_changes(lock_exempt); let proposer = validator_keys.first().unwrap(); let zero_fee = Coin { denom: STAKING_TOKEN.clone(), @@ -140,7 +157,7 @@ pub async fn lockup_the_chain( wait_for_proposals_to_execute(contact).await; } -pub fn create_lockup_param_changes(exempt_user: Address) -> Vec { +pub fn create_lockup_param_changes(exempt_users: Vec<&EthermintUserKey>) -> Vec { // Params{lock_exempt:, locked: false, locked_message_types: Vec::new() }; let lockup_param = ParamChange { subspace: "lockup".to_string(), @@ -153,7 +170,13 @@ pub fn create_lockup_param_changes(exempt_user: Address) -> Vec { let mut lock_exempt = lockup_param.clone(); lock_exempt.key = LOCK_EXEMPT_PARAM_KEY.to_string(); - lock_exempt.value = serde_json::to_string(&vec![exempt_user.to_string()]).unwrap(); + lock_exempt.value = serde_json::to_string( + &exempt_users + .into_iter() + .map(|v| v.ethermint_address) + .collect::>(), + ) + .unwrap(); let locked_msgs = vec![ MSG_SEND_TYPE_URL.to_string(), @@ -680,3 +703,30 @@ async fn send_unlocked_token(contact: &Contact, validator_keys: &[ValidatorKeys] }; send_from_and_assert_balance_changes(contact, val0, amount.clone()).await; } + +async fn send_evm_tx( + user: EthermintUserKey, + web3: &Web3, + erc20_addresses: &[EthAddress], + expect_success: bool, +) { + let tx = web3 + .approve_erc20_transfers( + erc20_addresses[0], + user.eth_privkey, + erc20_addresses[1], + Some(Duration::from_secs(15)), + vec![], + ) + .await; + info!( + "Submitted evm tx ({} expecting an error): {:?}", + if expect_success { "not" } else { "" }, + tx + ); + if expect_success { + tx.expect("Failed to submit evm tx!"); + } else { + tx.expect_err("Successfully submitted evm tx? Should not be possible!"); + } +} diff --git a/x/lockup/ante.go b/x/lockup/ante.go index 5f869855..e1dcaeb7 100644 --- a/x/lockup/ante.go +++ b/x/lockup/ante.go @@ -12,9 +12,12 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authz "github.com/cosmos/cosmos-sdk/x/authz" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/common" ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + microtxtypes "github.com/AltheaFoundation/althea-L1/x/microtx/types" "github.com/AltheaFoundation/althea-L1/x/lockup/keeper" @@ -125,6 +128,9 @@ func (lad LockAnteDecorator) isAcceptable(ctx sdk.Context, msg sdk.Msg) error { // Check that any locked msg is permissible on a type-case basis if allow, err := allowMessage(msg, exemptSet, lockedTokenDenomsSet); !allow { return sdkerrors.Wrap(err, fmt.Sprintf("Transaction blocked because of message %v", msg)) + } else { + // The user is exempt, allow it to pass + return nil } } if msgType == "/cosmos.distribution.v1beta1.MsgSetWithdrawAddress" { @@ -134,7 +140,11 @@ func (lad LockAnteDecorator) isAcceptable(ctx sdk.Context, msg sdk.Msg) error { return sdkerrors.Wrap(types.ErrLocked, "The chain is locked, recursively MsgExec-wrapped Msgs are not allowed") } if msgType == "/ethermint.evm.v1.MsgEthereumTx" { - return sdkerrors.Wrap(types.ErrLocked, "The chain is locked, only exempt addresses may submit this Msg type") + if allow, err := allowMessage(msg, exemptSet, lockedTokenDenomsSet); !allow { + return sdkerrors.Wrap(err, "The chain is locked, only exempt addresses may submit this Msg type") + } else { + return nil + } } return nil @@ -213,6 +223,18 @@ func allowMessage(msg sdk.Msg, exemptSet map[string]struct{}, lockedTokenDenomsS } return true, nil + // ^v^v^v^v^v^v^v^v^v^v^v^v EVM MODULE MESSAGES ^v^v^v^v^v^v^v^v^v^v^v^v + // nolint: exhaustruct + case sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}): + msgEvmTx := msg.(*evmtypes.MsgEthereumTx) + addressBytes := common.HexToAddress(msgEvmTx.From).Bytes() + ethermintAddr := sdk.AccAddress(addressBytes) + if _, present := exemptSet[ethermintAddr.String()]; !present { + return false, sdkerrors.Wrap(types.ErrLocked, + "The chain is locked, only exempt addresses may send a MsgEthereumTx") + } + return true, nil + default: return false, sdkerrors.Wrap(types.ErrUnhandled, fmt.Sprintf("Message type %v does not have a case in allowMessage, unable to handle messages like this", diff --git a/x/lockup/types/genesis.go b/x/lockup/types/genesis.go index 8b7c5d16..61010084 100644 --- a/x/lockup/types/genesis.go +++ b/x/lockup/types/genesis.go @@ -9,6 +9,8 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types" + evmtypes "github.com/evmos/ethermint/x/evm/types" + "github.com/AltheaFoundation/althea-L1/config" microtxtypes "github.com/AltheaFoundation/althea-L1/x/microtx/types" ) @@ -23,7 +25,7 @@ func DefaultGenesisState() *GenesisState { func DefaultParams() *Params { return &Params{ Locked: false, - LockExempt: []string{"0x0000000000000000000000000000000000000000"}, + LockExempt: []string{}, LockedMessageTypes: []string{ // nolint: exhaustruct sdk.MsgTypeURL(&banktypes.MsgSend{}), @@ -33,6 +35,8 @@ func DefaultParams() *Params { sdk.MsgTypeURL(&ibctransfertypes.MsgTransfer{}), // nolint: exhaustruct sdk.MsgTypeURL(µtxtypes.MsgMicrotx{}), + // nolint: exhaustruct + sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}), }, /* Note: The authoritative way to get the native token of the chain is by calling mintKeeper.GetParams(ctx).MintDenom, but the context is not available yet @@ -71,9 +75,12 @@ func ValidateLockExempt(i interface{}) error { if !ok { return fmt.Errorf("invalid lock exempt type: %T", i) } - if len(v) == 0 { - return fmt.Errorf("no lock exempt addresses %v", v) + for i, address := range v { + if _, err := sdk.AccAddressFromBech32(address); err != nil { + return fmt.Errorf("invalid lock exempt address %d: %s", i, address) + } } + return nil } From 4acdb8c45f8d8dec2a7d105406b1d643bf0df14b Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Thu, 19 Dec 2024 16:54:57 -0500 Subject: [PATCH 23/25] Update dex contracts for events --- solidity-dex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solidity-dex b/solidity-dex index 4cd0b972..1f970635 160000 --- a/solidity-dex +++ b/solidity-dex @@ -1 +1 @@ -Subproject commit 4cd0b972df204e93c87b9dd52e0ee1c5a9466aef +Subproject commit 1f970635f0de00ba133b201fafb1f28ee03bcd89 From 1e6bcf2a110945b44b3b6131657c71194c51d892 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 23 Dec 2024 20:36:22 -0500 Subject: [PATCH 24/25] Make two-script tests easier to run --- tests/container-scripts/all-up-test-internal.sh | 5 +++++ tests/container-scripts/integration-tests.sh | 8 +++++--- tests/container-scripts/manual-upgrade-test-internal.sh | 5 +++++ tests/container-scripts/reload-code.sh | 8 ++++++++ tests/container-scripts/upgrade-test-internal.sh | 4 ++++ 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/tests/container-scripts/all-up-test-internal.sh b/tests/container-scripts/all-up-test-internal.sh index e0ab7242..29417c70 100755 --- a/tests/container-scripts/all-up-test-internal.sh +++ b/tests/container-scripts/all-up-test-internal.sh @@ -2,6 +2,9 @@ # the script run inside the container for all-up-test.sh NODES=$1 TEST_TYPE=$2 + +rm /althea/test-ready-to-run + set -eux bash /althea/tests/container-scripts/setup-validators.sh $NODES @@ -14,4 +17,6 @@ sleep 30 pushd /althea/integration_tests/test_runner DEPLOY_CONTRACTS=1 RUST_BACKTRACE=full TEST_TYPE=$TEST_TYPE NO_GAS_OPT=1 RUST_LOG="INFO" PATH=$PATH:$HOME/.cargo/bin cargo run --release --bin test-runner +touch /althea/test-ready-to-run + bash /althea/tests/container-scripts/integration-tests.sh $NODES $TEST_TYPE \ No newline at end of file diff --git a/tests/container-scripts/integration-tests.sh b/tests/container-scripts/integration-tests.sh index fa68e55a..d0340a1d 100755 --- a/tests/container-scripts/integration-tests.sh +++ b/tests/container-scripts/integration-tests.sh @@ -3,9 +3,11 @@ NODES=$1 TEST_TYPE=$2 set -eu -set +e -killall -9 test-runner -set -e +echo "Waiting for /althea/test-ready-to-run to exist before starting the test" +while [ ! -f /althea/test-ready-to-run ]; +do + sleep 1 +done pushd /althea/integration_tests/test_runner RUST_BACKTRACE=full TEST_TYPE=$TEST_TYPE RUST_LOG=INFO PATH=$PATH:$HOME/.cargo/bin cargo run --release --bin test-runner diff --git a/tests/container-scripts/manual-upgrade-test-internal.sh b/tests/container-scripts/manual-upgrade-test-internal.sh index 7b80df4e..6d012bee 100755 --- a/tests/container-scripts/manual-upgrade-test-internal.sh +++ b/tests/container-scripts/manual-upgrade-test-internal.sh @@ -1,4 +1,7 @@ #!/bin/bash + +rm /althea/test-ready-to-run + set -eux # Number of validators to start NODES=$1 @@ -41,6 +44,8 @@ pushd integration_tests/test_runner DEPLOY_CONTRACTS=1 RUST_BACKTRACE=full NO_GAS_OPT=1 RUST_LOG="INFO" PATH=$PATH:$HOME/.cargo/bin cargo run --release --bin test-runner popd +touch /althea/test-ready-to-run + # This allows the tester to run the first part of the test # immediately if the nodes are killed by a different process diff --git a/tests/container-scripts/reload-code.sh b/tests/container-scripts/reload-code.sh index 24faa753..ea129d9a 100755 --- a/tests/container-scripts/reload-code.sh +++ b/tests/container-scripts/reload-code.sh @@ -15,6 +15,11 @@ do done +# Remove the setup complete flag file +set +e +rm -fr /althea/test-ready-to-run +set -e + cd /althea/ export PATH=$PATH:/usr/local/go/bin make install-core @@ -35,6 +40,9 @@ sleep 10 pushd /althea/integration_tests/test_runner DEPLOY_CONTRACTS=1 RUST_BACKTRACE=full TEST_TYPE=$TEST_TYPE NO_GAS_OPT=1 RUST_LOG="INFO" PATH=$PATH:$HOME/.cargo/bin cargo run --release --bin test-runner +# Create a setup complete flag file used by the integration tests +touch /althea/test-ready-to-run + # This keeps the script open to prevent Docker from stopping the container # immediately if the nodes are killed by a different process read -p "Press Return to Close..." \ No newline at end of file diff --git a/tests/container-scripts/upgrade-test-internal.sh b/tests/container-scripts/upgrade-test-internal.sh index da3fc95b..103fab27 100755 --- a/tests/container-scripts/upgrade-test-internal.sh +++ b/tests/container-scripts/upgrade-test-internal.sh @@ -1,4 +1,6 @@ #!/bin/bash + +rm /althea/test-ready-to-run set -eux # Number of validators to start NODES=$1 @@ -39,6 +41,8 @@ pushd /althea/integration_tests/test_runner DEPLOY_CONTRACTS=1 RUST_BACKTRACE=full NO_GAS_OPT=1 RUST_LOG="INFO" PATH=$PATH:$HOME/.cargo/bin cargo run --release --bin test-runner popd +touch /althea/test-ready-to-run + # Run the pre-upgrade tests pushd /althea/ tests/container-scripts/integration-tests.sh $NODES UPGRADE_PART_1 From 5a9267dbd10011df24f33aca835bee3d0c140266 Mon Sep 17 00:00:00 2001 From: Christian Borst Date: Mon, 23 Dec 2024 21:07:06 -0500 Subject: [PATCH 25/25] Add supply check to evm fee burning test --- .gitignore | 1 + integration_tests/test_runner/src/bin/main.rs | 1 - .../test_runner/src/tests/dex.rs | 23 ++++++------------- .../test_runner/src/tests/evm_fee_burning.rs | 15 ++++++++++++ 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 43babe7d..dea6936c 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ mytestnet coverage.txt profile.out tests/dockerfile/althea.tar.gz +test-ready-to-run # Vagrant .vagrant/ diff --git a/integration_tests/test_runner/src/bin/main.rs b/integration_tests/test_runner/src/bin/main.rs index cff343bc..8b189a4b 100644 --- a/integration_tests/test_runner/src/bin/main.rs +++ b/integration_tests/test_runner/src/bin/main.rs @@ -4,7 +4,6 @@ #[macro_use] extern crate log; -use althea_proto::canto::erc20; use deep_space::Contact; use deep_space::PrivateKey; use std::env; diff --git a/integration_tests/test_runner/src/tests/dex.rs b/integration_tests/test_runner/src/tests/dex.rs index 8c52ed12..113a43dc 100644 --- a/integration_tests/test_runner/src/tests/dex.rs +++ b/integration_tests/test_runner/src/tests/dex.rs @@ -4,13 +4,12 @@ use std::time::Duration; use crate::bootstrapping::DexAddresses; use crate::dex_utils::{ - ambient_liq_to_flows, croc_policy_ops_resolution, croc_policy_treasury_resolution, - croc_query_curve_tick, croc_query_dex, croc_query_pool_params, croc_query_pool_template, - croc_query_price, croc_query_range_position, dex_authority_transfer, dex_direct_protocol_cmd, - dex_mint_ambient_in_amount, dex_mint_ambient_pos, dex_mint_knockout_pos, - dex_mint_ranged_in_amount, dex_mint_ranged_pos, dex_query_authority, dex_query_safe_mode, - dex_swap, dex_user_cmd, size_ambient_liq, OpsResolutionArgs, ProtocolCmdArgs, SwapArgs, - UserCmdArgs, BOOT_PATH, COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, + croc_policy_ops_resolution, croc_policy_treasury_resolution, croc_query_curve_tick, + croc_query_dex, croc_query_pool_params, croc_query_pool_template, croc_query_price, + croc_query_range_position, dex_authority_transfer, dex_direct_protocol_cmd, + dex_mint_ambient_pos, dex_mint_ranged_in_amount, dex_mint_ranged_pos, dex_query_authority, + dex_query_safe_mode, dex_swap, dex_user_cmd, size_ambient_liq, OpsResolutionArgs, + ProtocolCmdArgs, SwapArgs, UserCmdArgs, BOOT_PATH, COLD_PATH, MAX_PRICE, MIN_PRICE, WARM_PATH, }; use crate::type_urls::{ COLLECT_TREASURY_PROPOSAL_TYPE_URL, HOT_PATH_OPEN_PROPOSAL_TYPE_URL, OPS_PROPOSAL_TYPE_URL, @@ -243,14 +242,6 @@ pub async fn advanced_dex_test( walthea, ) .await; - let bb = web3 - .get_erc20_balance(base, evm_user.eth_address) - .await - .unwrap(); - let qb = web3 - .get_erc20_balance(quote, evm_user.eth_address) - .await - .unwrap(); let ambient_qty = one_eth(); let price_root = croc_query_price( web3, @@ -755,7 +746,7 @@ async fn swap_many( swaps: usize, direction: Option, ) { - let mut is_buy = if let Some(d) = direction { d } else { true }; + let mut is_buy = direction.unwrap_or(true); let mut rng = rand::thread_rng(); for _ in 0..swaps { diff --git a/integration_tests/test_runner/src/tests/evm_fee_burning.rs b/integration_tests/test_runner/src/tests/evm_fee_burning.rs index 55357d14..91eabf06 100644 --- a/integration_tests/test_runner/src/tests/evm_fee_burning.rs +++ b/integration_tests/test_runner/src/tests/evm_fee_burning.rs @@ -27,6 +27,11 @@ pub async fn evm_fee_burning_test( info!("Set inflation to 0"); set_inflation_to_zero(contact, &validator_keys).await; + let pre_supply = contact + .query_supply_of(STAKING_TOKEN.clone()) + .await + .expect("Unable to get aalthea supply") + .expect("No supply of aalthea?"); let pre_balances = snapshot_validator_rewards(contact, &validator_keys).await; info!("Generating some fees"); @@ -47,6 +52,16 @@ pub async fn evm_fee_burning_test( } sleep(Duration::from_secs(10)).await; + let post_supply = contact + .query_supply_of(STAKING_TOKEN.clone()) + .await + .expect("Unable to get aalthea supply") + .expect("No supply of aalthea?"); + assert!(pre_supply.amount > post_supply.amount); + info!( + "Supply decreased by: {}", + pre_supply.amount - post_supply.amount + ); let post_balances = snapshot_validator_rewards(contact, &validator_keys).await; assert_eq!(pre_balances, post_balances);