From 03435b4abc973a36eafa9114f6d73ae39c0e41a3 Mon Sep 17 00:00:00 2001 From: jkan2 Date: Mon, 30 Sep 2024 01:57:04 -0700 Subject: [PATCH 01/36] ci: Add SARIF upload to GitHub Security Dashboard (#2929) * add semgrep sarif upload to GHAS * added comment to clairfy the usage of the utility script * use ghcr.io instead * add tag to image * bad org name --------- Co-authored-by: jkan2 <5862123+jkan2@users.noreply.github.com> --- .github/workflows/semgrep.yml | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index f76ee3d14b..fcffcf7855 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -15,8 +15,26 @@ jobs: env: SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} container: - image: semgrep/semgrep + image: ghcr.io/zeta-chain/semgrep-semgrep:1.90.0 + if: (github.actor != 'dependabot[bot]') steps: - - uses: actions/checkout@v4 - - run: semgrep ci + - uses: actions/checkout@v4 + - name: Checkout semgrep-utilities repo + uses: actions/checkout@v4 + with: + repository: zeta-chain/semgrep-utilities + path: semgrep-utilities + + # uses json for semgrep script for transformation in the next step + - run: semgrep ci --json --output semgrep-findings.json + + # transforms the the output from the above into a GHAS compatible SARIF + # SARIF output by "semgrep --sarif" doesn't integrate well with GHAS dashboard + # Example: the event name uses segmrep rules name/ID, severities are [error, warning, info], tags are a bit confusing) + - run: python semgrep-utilities/utilities/github-sarif-helper/src/semgrep-json-to-sarif.py --json semgrep-findings.json --sarif semgrep-github.sarif + + - name: Upload SARIF file for GitHub Advanced Security Dashboard + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: semgrep-github.sarif From ec64772091bdfb800891dfc08be32ea26d41ffaf Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 30 Sep 2024 15:27:30 +0530 Subject: [PATCH 02/36] fix: add recover to InitChainer to diplay informative message when starting a node from block 1 (#2925) * add recover to InitChainer * generate files * add docs link to error message * move InitChainErrorMessage to app.go * Update app/app.go Co-authored-by: Francisco de Borja Aranda Castillejo * use const for message --------- Co-authored-by: Francisco de Borja Aranda Castillejo --- app/app.go | 21 +++++++++++++++++++++ changelog.md | 1 + 2 files changed, 22 insertions(+) diff --git a/app/app.go b/app/app.go index cc271fc35f..4fe5595199 100644 --- a/app/app.go +++ b/app/app.go @@ -4,6 +4,7 @@ import ( "io" "net/http" "os" + "runtime/debug" "time" cosmoserrors "cosmossdk.io/errors" @@ -876,6 +877,26 @@ func (app *App) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.Respo // InitChainer application update at chain initialization func (app *App) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + // InitChainErrorMessage is the error message displayed when trying to sync testnet or mainnet from block 1 using the latest binary. + const InitChainErrorMessage = ` +Unable to sync testnet or mainnet from block 1 using the latest version. +Please use a snapshot to sync your node. +Refer to the documentation for more information: +https://www.zetachain.com/docs/nodes/start-here/syncing/` + + // The defer is used to catch panics during InitChain + // and display a more meaningful message for people trying to sync a node from block 1 using the latest binary. + // We exit the process after displaying the message as we do not need to start a node with empty state. + + defer func() { + if r := recover(); r != nil { + ctx.Logger().Error("panic occurred during InitGenesis", "error", r) + ctx.Logger().Debug("stack trace", "stack", string(debug.Stack())) + ctx.Logger(). + Info(InitChainErrorMessage) + os.Exit(1) + } + }() var genesisState GenesisState if err := tmjson.Unmarshal(req.AppStateBytes, &genesisState); err != nil { panic(err) diff --git a/changelog.md b/changelog.md index d78c1861ae..437b97382d 100644 --- a/changelog.md +++ b/changelog.md @@ -45,6 +45,7 @@ * [2944](https://github.com/zeta-chain/node/pull/2844) - add tsspubkey to index for tss keygen voting * [2842](https://github.com/zeta-chain/node/pull/2842) - fix: move interval assignment out of cctx loop in EVM outbound tx scheduler * [2853](https://github.com/zeta-chain/node/pull/2853) - calling precompile through sc with sc state update +* [2925](https://github.com/zeta-chain/node/pull/2925) - add recover to init chainer to diplay informative message when starting a node from block 1 ## v20.0.0 From ebd42f94577131f21c254bdc4b4aab3a5ec7f70a Mon Sep 17 00:00:00 2001 From: Tanmay Date: Mon, 30 Sep 2024 19:11:09 +0530 Subject: [PATCH 03/36] test: add wait for block to tss migration test (#2931) * add wait for block to tss migration test * add comments * refactor identifiers * rename checkNumberOfTssGenerated to checkNumberOfTSSGenerated --- e2e/e2etests/test_migrate_tss.go | 2 ++ e2e/runner/zeta.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/e2e/e2etests/test_migrate_tss.go b/e2e/e2etests/test_migrate_tss.go index cb5e3c35c4..3825228c14 100644 --- a/e2e/e2etests/test_migrate_tss.go +++ b/e2e/e2etests/test_migrate_tss.go @@ -48,6 +48,8 @@ func TestMigrateTSS(r *runner.E2ERunner, _ []string) { btcBalance = btcBalance - 0.01 btcChain := chains.BitcoinRegtest.ChainId + r.WaitForTSSGeneration(2) + //migrate btc funds // #nosec G701 e2eTest - always in range migrationAmountBTC := sdkmath.NewUint(uint64(btcBalance * 1e8)) diff --git a/e2e/runner/zeta.go b/e2e/runner/zeta.go index cec59219cd..bdada4763c 100644 --- a/e2e/runner/zeta.go +++ b/e2e/runner/zeta.go @@ -15,8 +15,11 @@ import ( "github.com/zeta-chain/node/e2e/utils" "github.com/zeta-chain/node/pkg/retry" "github.com/zeta-chain/node/x/crosschain/types" + observertypes "github.com/zeta-chain/node/x/observer/types" ) +// WaitForBlocks waits for a specific number of blocks to be generated +// The parameter n is the number of blocks to wait for func (r *E2ERunner) WaitForBlocks(n int64) { height, err := r.CctxClient.LastZetaHeight(r.Ctx, &types.QueryLastZetaHeightRequest{}) if err != nil { @@ -31,6 +34,32 @@ func (r *E2ERunner) WaitForBlocks(n int64) { err = retry.DoWithBackoff(call, boWithMaxRetries) require.NoError(r, err, "failed to wait for %d blocks", n) } + +// WaitForTSSGeneration waits for a specific number of TSS to be generated +// The parameter n is the number of TSS to wait for +func (r *E2ERunner) WaitForTSSGeneration(tssNumber int64) { + call := func() error { + return retry.Retry(r.checkNumberOfTSSGenerated(tssNumber)) + } + bo := backoff.NewConstantBackOff(time.Second * 5) + boWithMaxRetries := backoff.WithMaxRetries(bo, 10) + err := retry.DoWithBackoff(call, boWithMaxRetries) + require.NoError(r, err, "failed to wait for %d tss generation", tssNumber) +} + +// checkNumberOfTSSGenerated checks the number of TSS generated +// if the number of tss is less that the `tssNumber` provided we return an error +func (r *E2ERunner) checkNumberOfTSSGenerated(tssNumber int64) error { + tssList, err := r.ObserverClient.TssHistory(r.Ctx, &observertypes.QueryTssHistoryRequest{}) + if err != nil { + return err + } + if int64(len(tssList.TssList)) < tssNumber { + return fmt.Errorf("waiting for %d tss generation, number of TSS :%d", tssNumber, len(tssList.TssList)) + } + return nil +} + func (r *E2ERunner) waitForBlock(n int64) error { height, err := r.CctxClient.LastZetaHeight(r.Ctx, &types.QueryLastZetaHeightRequest{}) if err != nil { From 77486d71d184c1db8475d9a9e01eb34391efc4d4 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Tue, 1 Oct 2024 00:16:13 -0700 Subject: [PATCH 04/36] chore: allow full zetaclient config overlay (#2945) --- .gitignore | 2 +- contrib/localnet/scripts/start-zetaclientd.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index e0f51f8d4a..3f8e6a6ff4 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,4 @@ contrib/localnet/addresses.txt # Config for e2e tests e2e_conf* -contrib/localnet/scripts/extra-evm-chains.json \ No newline at end of file +contrib/localnet/scripts/zetaclient-config-overlay.json \ No newline at end of file diff --git a/contrib/localnet/scripts/start-zetaclientd.sh b/contrib/localnet/scripts/start-zetaclientd.sh index 7d2768b177..e403e2d599 100755 --- a/contrib/localnet/scripts/start-zetaclientd.sh +++ b/contrib/localnet/scripts/start-zetaclientd.sh @@ -109,9 +109,9 @@ then fi fi -# merge extra-evm-chains.json into zetaclient_config.json if specified -if [[ -f /root/extra-evm-chains.json ]]; then - jq '.EVMChainConfigs *= input' /root/.zetacored/config/zetaclient_config.json /root/extra-evm-chains.json > /tmp/merged_config.json +# merge zetaclient-config-overlay.json into zetaclient_config.json if specified +if [[ -f /root/zetaclient-config-overlay.json ]]; then + jq -s '.[0] * .[1]' /root/.zetacored/config/zetaclient_config.json /root/zetaclient-config-overlay.json > /tmp/merged_config.json mv /tmp/merged_config.json /root/.zetacored/config/zetaclient_config.json fi From 2e13c049adf015a762cf5d14fe96599f406d318a Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 1 Oct 2024 10:10:26 +0200 Subject: [PATCH 05/36] test(e2e): add gateway upgrade in upgrade test (#2932) * add gateway upgrade * change reference * add v2 setup for all tests * test v2 in light upgrade * refactor setup to use custody v2 directly --- Makefile | 4 +- changelog.md | 1 + cmd/zetae2e/local/local.go | 29 ++++++---- .../localnet/orchestrator/start-zetae2e.sh | 4 +- e2e/runner/v2_gateway.go | 55 +++++++++++++++++++ 5 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 e2e/runner/v2_gateway.go diff --git a/Makefile b/Makefile index b3fbf4009a..40053db864 100644 --- a/Makefile +++ b/Makefile @@ -299,12 +299,12 @@ start-v2-test: zetanode ifdef UPGRADE_TEST_FROM_SOURCE zetanode-upgrade: zetanode @echo "Building zetanode-upgrade from source" - $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime-source --build-arg OLD_VERSION='release/v19' . + $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime-source --build-arg OLD_VERSION='release/v20' . .PHONY: zetanode-upgrade else zetanode-upgrade: zetanode @echo "Building zetanode-upgrade from binaries" - $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime --build-arg OLD_VERSION='https://github.com/zeta-chain/node/releases/download/v19.1.1' . + $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime --build-arg OLD_VERSION='https://github.com/zeta-chain/node/releases/download/v20.0.2' . .PHONY: zetanode-upgrade endif diff --git a/changelog.md b/changelog.md index 437b97382d..dc83cb839b 100644 --- a/changelog.md +++ b/changelog.md @@ -36,6 +36,7 @@ * [2874](https://github.com/zeta-chain/node/pull/2874) - add support for multiple runs for precompile tests * [2895](https://github.com/zeta-chain/node/pull/2895) - add e2e test for bitcoin deposit and call * [2894](https://github.com/zeta-chain/node/pull/2894) - increase gas limit for TSS vote tx +* [2932](https://github.com/zeta-chain/node/pull/2932) - add gateway upgrade as part of the upgrade test ### Fixes diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index ced848aadc..4a7fbef39c 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -46,6 +46,7 @@ const ( flagTestV2Migration = "test-v2-migration" flagSkipTrackerCheck = "skip-tracker-check" flagSkipPrecompiles = "skip-precompiles" + flagUpgradeGateways = "upgrade-gateways" ) var ( @@ -83,6 +84,7 @@ func NewLocalCmd() *cobra.Command { cmd.Flags().Bool(flagTestV2Migration, false, "set to true to run tests for v2 contracts migration test") cmd.Flags().Bool(flagSkipTrackerCheck, false, "set to true to skip tracker check at the end of the tests") cmd.Flags().Bool(flagSkipPrecompiles, false, "set to true to skip stateful precompiled contracts test") + cmd.Flags().Bool(flagUpgradeGateways, false, "set to true to upgrade gateways during setup for ZEVM and EVM") return cmd } @@ -112,6 +114,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { testV2 = must(cmd.Flags().GetBool(flagTestV2)) testV2Migration = must(cmd.Flags().GetBool(flagTestV2Migration)) skipPrecompiles = must(cmd.Flags().GetBool(flagSkipPrecompiles)) + upgradeGateways = must(cmd.Flags().GetBool(flagUpgradeGateways)) ) logger := runner.NewLogger(verbose, color.FgWhite, "setup") @@ -202,21 +205,26 @@ func localE2ETest(cmd *cobra.Command, _ []string) { logger.Print("⚙️ setting up networks") startTime := time.Now() + // TODO: merge v1 and v2 together + // https://github.com/zeta-chain/node/issues/2627 + deployerRunner.SetupEVM(contractsDeployed, true) - if testV2 { - deployerRunner.SetupEVMV2() - } + deployerRunner.SetupEVMV2() deployerRunner.SetZEVMSystemContracts() - if testV2 { - // NOTE: v2 (gateway) setup called here because system contract needs to be set first, then gateway, then zrc20 - deployerRunner.SetZEVMContractsV2() - } + // NOTE: v2 (gateway) setup called here because system contract needs to be set first, then gateway, then zrc20 + deployerRunner.SetZEVMContractsV2() deployerRunner.SetZEVMZRC20s() + // Update the chain params to use v2 contract for ERC20Custody + // TODO: this function should be removed and the chain params should be directly set to use v2 contract + // https://github.com/zeta-chain/node/issues/2627 + deployerRunner.UpdateChainParamsV2Contracts() + deployerRunner.ERC20CustodyAddr = deployerRunner.ERC20CustodyV2Addr + if testSolana { deployerRunner.SetSolanaContracts(conf.AdditionalAccounts.UserSolana.SolanaPrivateKey.String()) } @@ -404,10 +412,9 @@ func localE2ETest(cmd *cobra.Command, _ []string) { eg.Go(tonTestRoutine(conf, deployerRunner, verbose, tonTests...)) } - if testV2 { - // update the ERC20 custody contract for v2 tests - // note: not run in testV2Migration because it is already run in the migration process - deployerRunner.UpdateChainParamsV2Contracts() + // upgrade gateways + if upgradeGateways { + deployerRunner.UpgradeGateways() } if testV2 || testV2Migration { diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index 9977b7dbd9..e7374216f3 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -258,9 +258,9 @@ if [ "$LOCALNET_MODE" == "upgrade" ]; then # When the upgrade height is greater than 100 for upgrade test, the Bitcoin tests have been run once, therefore the Bitcoin wallet is already set up # Use light flag to skip advanced tests if [ "$UPGRADE_HEIGHT" -lt 100 ]; then - zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --light ${COMMON_ARGS} + zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --light --test-v2 --upgrade-gateways ${COMMON_ARGS} else - zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --skip-bitcoin-setup --light ${COMMON_ARGS} + zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --skip-bitcoin-setup --light --test-v2 --upgrade-gateways ${COMMON_ARGS} fi ZETAE2E_EXIT_CODE=$? diff --git a/e2e/runner/v2_gateway.go b/e2e/runner/v2_gateway.go new file mode 100644 index 0000000000..2bede9e3fe --- /dev/null +++ b/e2e/runner/v2_gateway.go @@ -0,0 +1,55 @@ +package runner + +import ( + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol" + + "github.com/zeta-chain/node/e2e/utils" +) + +// UpgradeGateways upgrades the GatewayEVM and GatewayZEVM contracts +// It deploy new gateway contract implementation with the current imported artifacts and upgrade the gateway contract +func (r *E2ERunner) UpgradeGateways() { + r.UpgradeGatewayZEVM() + r.UpgradeGatewayEVM() +} + +// UpgradeGatewayZEVM upgrades the GatewayZEVM contract +func (r *E2ERunner) UpgradeGatewayZEVM() { + ensureTxReceipt := func(tx *ethtypes.Transaction, failMessage string) { + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt, failMessage+" tx hash: "+tx.Hash().Hex()) + } + + r.Logger.Info("Upgrading Gateway ZEVM contract") + // Deploy the new gateway contract implementation + newImplementationAddress, txDeploy, _, err := gatewayzevm.DeployGatewayZEVM(r.ZEVMAuth, r.ZEVMClient) + require.NoError(r, err) + ensureTxReceipt(txDeploy, "New GatewayZEVM implementation deployment failed") + + // Upgrade + txUpgrade, err := r.GatewayZEVM.UpgradeToAndCall(r.ZEVMAuth, newImplementationAddress, []byte{}) + require.NoError(r, err) + ensureTxReceipt(txUpgrade, "GatewayZEVM upgrade failed") +} + +// UpgradeGatewayEVM upgrades the GatewayEVM contract +func (r *E2ERunner) UpgradeGatewayEVM() { + ensureTxReceipt := func(tx *ethtypes.Transaction, failMessage string) { + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt, failMessage+" tx hash: "+tx.Hash().Hex()) + } + + r.Logger.Info("Upgrading Gateway EVM contract") + // Deploy the new gateway contract implementation + newImplementationAddress, txDeploy, _, err := gatewayevm.DeployGatewayEVM(r.EVMAuth, r.EVMClient) + require.NoError(r, err) + ensureTxReceipt(txDeploy, "New GatewayEVM implementation deployment failed") + + // Upgrade + txUpgrade, err := r.GatewayEVM.UpgradeToAndCall(r.EVMAuth, newImplementationAddress, []byte{}) + require.NoError(r, err) + ensureTxReceipt(txUpgrade, "GatewayEVM upgrade failed") +} From f9cbcfce56873678d63f21556b60dc40c49392a8 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Tue, 1 Oct 2024 03:27:44 -0700 Subject: [PATCH 06/36] chore: improve localnet build performance (#2928) * chore: improve localnet build performance * propagate NODE_VERSION and NODE_COMMIT --- .dockerignore | 1 + Dockerfile-localnet | 8 ++++++-- Makefile | 14 +++++++------- version.sh | 21 ++++++++++++++------- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.dockerignore b/.dockerignore index d53ebfff61..1e084d8263 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,6 +4,7 @@ yarn.lock .github/ .gitignore dist/** +.git # dockerfiles are not needed inside the docker build Dockerfile diff --git a/Dockerfile-localnet b/Dockerfile-localnet index cfe5e19a48..0ec2408120 100644 --- a/Dockerfile-localnet +++ b/Dockerfile-localnet @@ -19,9 +19,13 @@ COPY go.sum . RUN go mod download COPY version.sh . COPY --exclude=*.sh --exclude=*.md --exclude=*.yml . . +ARG NODE_VERSION +ARG NODE_COMMIT -RUN --mount=type=cache,target="/root/.cache/go-build" make install -RUN --mount=type=cache,target="/root/.cache/go-build" make install-zetae2e +RUN --mount=type=cache,target="/root/.cache/go-build" \ + NODE_VERSION=${NODE_VERSION} \ + NODE_COMMIT=${NODE_COMMIT} \ + make install install-zetae2e FROM ghcr.io/zeta-chain/golang:1.22.5-bookworm AS cosmovisor-build RUN go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@v1.6.0 diff --git a/Makefile b/Makefile index 40053db864..36e414f012 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ .PHONY: build PACKAGE_NAME := github.com/zeta-chain/node -VERSION := $(shell ./version.sh) -COMMIT := $(shell [ -z "${COMMIT_ID}" ] && git log -1 --format='%H' || echo ${COMMIT_ID} ) +NODE_VERSION := $(shell ./version.sh) +NODE_COMMIT := $(shell [ -z "${NODE_COMMIT}" ] && git log -1 --format='%H' || echo ${NODE_COMMIT} ) BUILDTIME := $(shell date -u +"%Y%m%d.%H%M%S" ) DOCKER ?= docker # allow setting of NODE_COMPOSE_ARGS to pass additional args to docker compose @@ -17,11 +17,11 @@ GOPATH ?= '$(HOME)/go' ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=zetacore \ -X github.com/cosmos/cosmos-sdk/version.ServerName=zetacored \ -X github.com/cosmos/cosmos-sdk/version.ClientName=zetaclientd \ - -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \ - -X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \ + -X github.com/cosmos/cosmos-sdk/version.Version=$(NODE_VERSION) \ + -X github.com/cosmos/cosmos-sdk/version.Commit=$(NODE_COMMIT) \ -X github.com/zeta-chain/node/pkg/constant.Name=zetacored \ - -X github.com/zeta-chain/node/pkg/constant.Version=$(VERSION) \ - -X github.com/zeta-chain/node/pkg/constant.CommitHash=$(COMMIT) \ + -X github.com/zeta-chain/node/pkg/constant.Version=$(NODE_VERSION) \ + -X github.com/zeta-chain/node/pkg/constant.CommitHash=$(NODE_COMMIT) \ -X github.com/zeta-chain/node/pkg/constant.BuildTime=$(BUILDTIME) \ -X github.com/cosmos/cosmos-sdk/types.DBBackend=pebbledb @@ -233,7 +233,7 @@ stop-localnet: zetanode: @echo "Building zetanode" - $(DOCKER) build -t zetanode --target latest-runtime -f ./Dockerfile-localnet . + $(DOCKER) build -t zetanode --build-arg NODE_VERSION=$(NODE_VERSION) --build-arg NODE_COMMIT=$(NODE_COMMIT) --target latest-runtime -f ./Dockerfile-localnet . $(DOCKER) build -t orchestrator -f contrib/localnet/orchestrator/Dockerfile.fastbuild . .PHONY: zetanode diff --git a/version.sh b/version.sh index ac8987e430..aedbfa5eeb 100755 --- a/version.sh +++ b/version.sh @@ -1,5 +1,12 @@ #!/bin/bash +# if NODE_VERSION is set, just return it immediately +# this allows you to do docker builds without the git directory +if [[ -n $NODE_VERSION ]]; then + echo $NODE_VERSION + exit +fi + # --exact-match will ensure the tag is only returned if our commit is a tag version=$(git describe --exact-match --tags 2>/dev/null) if [[ $? -eq 0 ]]; then @@ -9,14 +16,14 @@ if [[ $? -eq 0 ]]; then exit fi -# use current timestamp for dirty builds +# develop build and use commit timestamp for version +commit_timestamp=$(git show --no-patch --format=%at) +short_commit=$(git rev-parse --short HEAD) + +# append -dirty for dirty builds if ! git diff --no-ext-diff --quiet --exit-code ; then - current_timestamp=$(date +"%s") - echo "0.0.${current_timestamp}-dirty" + echo "0.0.${commit_timestamp}-${short_commit}-dirty" exit fi -# otherwise assume we are on a develop build and use commit timestamp for version -commit_timestamp=$(git show --no-patch --format=%at) - -echo "0.0.${commit_timestamp}-develop" \ No newline at end of file +echo "0.0.${commit_timestamp}-${short_commit}" \ No newline at end of file From fce09b2ac320ed41f0b04ca13512bf9acb7a268d Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Wed, 2 Oct 2024 00:58:37 -0700 Subject: [PATCH 07/36] ci: ensure variables are set for cache build (#2948) --- .github/workflows/reusable-e2e.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/reusable-e2e.yml b/.github/workflows/reusable-e2e.yml index 1ef194667e..aaac140960 100644 --- a/.github/workflows/reusable-e2e.yml +++ b/.github/workflows/reusable-e2e.yml @@ -69,6 +69,14 @@ jobs: } skip-extraction: ${{ steps.restore-go-cache.outputs.cache-hit || github.event_name != 'push' }} + # this ensures that the version is consistent between cache build and make build + - name: Set version for cache + run: | + NODE_VERSION=$(./version.sh) + echo "NODE_VERSION=$NODE_VERSION" >> $GITHUB_ENV + NODE_COMMIT=$(git log -1 --format='%H') + echo "NODE_COMMIT=$NODE_COMMIT" >> $GITHUB_ENV + # build zetanode with cache options - name: Build zetanode for cache uses: docker/build-push-action@v6 @@ -83,6 +91,9 @@ jobs: cache-from: ${{ env.CACHE_FROM_CONFIG }} cache-to: ${{ github.event_name == 'push' && env.CACHE_TO_CONFIG || '' }} target: latest-runtime + build-args: | + NODE_VERSION=${{ env.NODE_VERSION }} + NODE_COMMIT=${{ env.NODE_COMMIT }} - name: Enable monitoring if: inputs.enable-monitoring From 5d981aa1e1626a0311ef28638a4d5b67b8ab6ef9 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Wed, 2 Oct 2024 01:22:18 -0700 Subject: [PATCH 08/36] chore: upgrade cometbft and cosmos-sdk (#2934) * chore: upgrade cometbft and cosmos-sdk * use build flags for docs generation * use libsecp256k1_sdk in golangci build tags * add required build flags to rpcimportable test * comments and unify ldflags --- .github/workflows/ci.yml | 2 +- .golangci.yml | 2 + Makefile | 16 +++- contrib/rpcimportable/test.sh | 14 +++ go.mod | 95 ++++++++++--------- go.sum | 172 +++++++++++++++++++++------------- scripts/gen-docs-zetacored.sh | 2 - zetaclient/context/chain.go | 3 +- 8 files changed, 189 insertions(+), 117 deletions(-) create mode 100755 contrib/rpcimportable/test.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 518823b42f..9131d389e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,7 +115,7 @@ jobs: run: cat go.mod - name: go test working-directory: contrib/rpcimportable - run: go test ./... + run: ./test.sh ci-ok: runs-on: ubuntu-22.04 needs: diff --git a/.golangci.yml b/.golangci.yml index 8fb8a0084a..b7472a5fd0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,6 +2,8 @@ run: go: '1.20' # as in go.mod timeout: 5m tests: false # exclude test from linting + build-tags: + - libsecp256k1_sdk linters: disable-all: true diff --git a/Makefile b/Makefile index 36e414f012..f1ce7b6fe6 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ GOFLAGS := "" GOLANG_CROSS_VERSION ?= v1.22.4 GOPATH ?= '$(HOME)/go' -ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=zetacore \ +build_ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=zetacore \ -X github.com/cosmos/cosmos-sdk/version.ServerName=zetacored \ -X github.com/cosmos/cosmos-sdk/version.ClientName=zetaclientd \ -X github.com/cosmos/cosmos-sdk/version.Version=$(NODE_VERSION) \ @@ -25,11 +25,17 @@ ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=zetacore \ -X github.com/zeta-chain/node/pkg/constant.BuildTime=$(BUILDTIME) \ -X github.com/cosmos/cosmos-sdk/types.DBBackend=pebbledb -BUILD_FLAGS := -ldflags '$(ldflags)' -tags pebbledb,ledger +# --allow-multiple-definitions need to be set when you are importing both cosmos-sdk +# and go-ethereum: https://github.com/cosmos/cosmos-sdk/tree/release/v0.47.x/crypto/keys/secp256k1/internal/secp256k1 +all_ldflags = -extldflags=-Wl,--allow-multiple-definition + +# enable libsecp256k1_sdk to bypass the btcec breaking change: +# https://github.com/btcsuite/btcd/issues/2243 +BUILD_FLAGS := -ldflags '$(build_ldflags) $(all_ldflags)' -tags pebbledb,ledger,libsecp256k1_sdk TEST_DIR ?= "./..." -TEST_BUILD_FLAGS := -tags pebbledb,ledger -HSM_BUILD_FLAGS := -tags pebbledb,ledger,hsm_test +TEST_BUILD_FLAGS := -ldflags='$(all_ldflags)' -tags pebbledb,ledger,libsecp256k1_sdk +HSM_BUILD_FLAGS := -ldflags='$(all_ldflags)' -tags pebbledb,ledger,libsecp256k1_sdk,hsm_test export DOCKER_BUILDKIT := 1 @@ -193,7 +199,7 @@ specs: @go run ./scripts/gen-spec.go .PHONY: specs -docs-zetacored: +docs-zetacored: install-zetacore @echo "--> Generating zetacored documentation" @bash ./scripts/gen-docs-zetacored.sh .PHONY: docs-zetacored diff --git a/contrib/rpcimportable/test.sh b/contrib/rpcimportable/test.sh new file mode 100755 index 0000000000..3ba925bc6f --- /dev/null +++ b/contrib/rpcimportable/test.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# run rpcimportable test with the required build flags + +set -eo pipefail + +cd "$(dirname "$0")" + +# --allow-multiple-definitions need to be set when you are importing both cosmos-sdk +# and go-ethereum: https://github.com/cosmos/cosmos-sdk/tree/release/v0.47.x/crypto/keys/secp256k1/internal/secp256k1 +# +# enable libsecp256k1_sdk to bypass the btcec breaking change: +# https://github.com/btcsuite/btcd/issues/2243 +go test -tags libsecp256k1_sdk -ldflags="-extldflags=-Wl,--allow-multiple-definition" ./... diff --git a/go.mod b/go.mod index 7625fc2047..c3078fb3dc 100644 --- a/go.mod +++ b/go.mod @@ -10,26 +10,26 @@ require ( cosmossdk.io/tools/rosetta v0.2.1 github.com/99designs/keyring v1.2.1 github.com/btcsuite/btcd v0.24.2 - github.com/btcsuite/btcd/btcec/v2 v2.3.2 + github.com/btcsuite/btcd/btcec/v2 v2.3.4 github.com/btcsuite/btcd/btcutil v1.1.6 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 github.com/cenkalti/backoff/v4 v4.3.0 github.com/cockroachdb/errors v1.11.1 github.com/coinbase/rosetta-sdk-go v0.7.9 - github.com/cometbft/cometbft v0.37.4 + github.com/cometbft/cometbft v0.37.11 github.com/cometbft/cometbft-db v0.12.0 github.com/cosmos/btcutil v1.0.5 - github.com/cosmos/cosmos-sdk v0.47.10 - github.com/cosmos/gogoproto v1.4.10 + github.com/cosmos/cosmos-sdk v0.47.14 + github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/ibc-go/v7 v7.4.0 - github.com/davecgh/go-spew v1.1.1 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/emicklei/proto v1.11.1 github.com/ethereum/go-ethereum v1.10.26 - github.com/fatih/color v1.13.0 + github.com/fatih/color v1.14.1 github.com/frumioj/crypto11 v1.2.5-0.20210823151709-946ce662cc0e github.com/gagliardetto/solana-go v1.10.0 github.com/golang/mock v1.6.0 - github.com/golang/protobuf v1.5.3 + github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 @@ -49,26 +49,26 @@ require ( github.com/prometheus/client_golang v1.14.0 github.com/rakyll/statik v0.1.7 github.com/rs/cors v1.8.3 - github.com/rs/zerolog v1.32.0 + github.com/rs/zerolog v1.33.0 github.com/samber/lo v1.46.0 github.com/spf13/afero v1.11.0 - github.com/spf13/cast v1.5.1 + github.com/spf13/cast v1.6.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.16.0 + github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 github.com/zeta-chain/ethermint v0.0.0-20240927155358-f34e2a4a86f1 github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20240924201108-3a274ce7bad0 gitlab.com/thorchain/tss/go-tss v1.6.5 go.nhat.io/grpcmock v0.25.0 - golang.org/x/crypto v0.23.0 - golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb + golang.org/x/crypto v0.26.0 + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/net v0.25.0 - golang.org/x/sync v0.7.0 - google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 - google.golang.org/grpc v1.60.1 - google.golang.org/protobuf v1.32.0 + golang.org/x/sync v0.8.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 + google.golang.org/grpc v1.62.1 + google.golang.org/protobuf v1.33.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -77,18 +77,18 @@ require ( ) require ( - cloud.google.com/go v0.111.0 // indirect - cloud.google.com/go/compute v1.23.3 // indirect + cloud.google.com/go v0.112.1 // indirect + cloud.google.com/go/compute v1.24.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.5 // indirect - cloud.google.com/go/storage v1.35.1 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + cloud.google.com/go/storage v1.38.0 // indirect cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect - cosmossdk.io/log v1.3.1 // indirect + cosmossdk.io/log v1.4.1 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect - github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect + github.com/ChainSafe/go-schnorrkel v1.1.0 // indirect github.com/DataDog/zstd v1.5.0 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect @@ -116,7 +116,7 @@ require ( github.com/confio/ics23/go v0.9.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.4 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.1 // indirect @@ -140,9 +140,9 @@ require ( github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/felixge/httpsnoop v1.0.2 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/flynn/noise v1.0.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gagliardetto/binary v0.8.0 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect @@ -150,7 +150,7 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect @@ -159,7 +159,7 @@ require ( github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang/glog v1.1.2 // indirect + github.com/golang/glog v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect @@ -170,7 +170,7 @@ require ( github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/googleapis/gax-go/v2 v2.12.3 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect @@ -202,7 +202,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -233,7 +233,7 @@ require ( github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/highwayhash v1.0.2 // indirect + github.com/minio/highwayhash v1.0.3 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -258,9 +258,9 @@ require ( github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/otiai10/primes v0.0.0-20180210170552-f6d2a1ba97c4 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect @@ -272,14 +272,13 @@ require ( github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/sergi/go-diff v1.3.1 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/subosito/gotenv v1.4.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/swaggest/assertjson v1.9.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/btcd v0.1.1 // indirect @@ -304,9 +303,9 @@ require ( go.nhat.io/matcher/v2 v2.0.0 // indirect go.nhat.io/wait v0.1.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.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/atomic v1.11.0 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.19.2 // indirect @@ -314,17 +313,17 @@ require ( go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/term v0.20.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gonum.org/v1/gonum v0.13.0 // indirect - google.golang.org/api v0.152.0 // indirect + google.golang.org/api v0.171.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect lukechampine.com/blake3 v1.2.1 // indirect @@ -341,8 +340,14 @@ require ( require ( github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/snksoft/crc v1.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // 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 ) replace ( diff --git a/go.sum b/go.sum index dd2ce7f425..bcaab711d6 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,9 @@ cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5x cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= -cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= +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/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -325,8 +326,9 @@ cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdi cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= @@ -629,8 +631,9 @@ cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+K cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= -cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= +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/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= @@ -1057,8 +1060,8 @@ cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= -cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +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/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= @@ -1213,8 +1216,9 @@ cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vM cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= -cosmossdk.io/log v1.3.1 h1:UZx8nWIkfbbNEWusZqzAx3ZGvu54TZacWib3EzUYmGI= cosmossdk.io/log v1.3.1/go.mod h1:2/dIomt8mKdk6vl3OWJcPk2be3pGOS8OQaLUM/3/tCM= +cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= +cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= cosmossdk.io/math v1.0.0-beta.3/go.mod h1:3LYasri3Zna4XpbrTNdKsWmD5fHHkaNAod/mNT9XdE4= cosmossdk.io/math v1.0.0-beta.4/go.mod h1:An0MllWJY6PxibUpnwGk8jOm+a/qIxlKmL5Zyp9NnaM= cosmossdk.io/math v1.0.0-beta.6/go.mod h1:gUVtWwIzfSXqcOT+lBVz2jyjfua8DoBdzRsIyaUAT/8= @@ -1313,8 +1317,9 @@ github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 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/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= -github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= +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/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= @@ -1363,8 +1368,9 @@ github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOp github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -1579,8 +1585,9 @@ github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v5 github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= -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/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= @@ -1733,8 +1740,9 @@ github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZ github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= github.com/cometbft/cometbft v0.34.27-alpha.1/go.mod h1:hct3hasQ2hIF3HoD7foVw4RaqTNSSeJ/lgcrVK6uDvs= -github.com/cometbft/cometbft v0.37.4 h1:xyvvEqlyfK8MgNIIKVJaMsuIp03wxOcFmVkT26+Ikpg= github.com/cometbft/cometbft v0.37.4/go.mod h1:Cmg5Hp4sNpapm7j+x0xRyt2g0juQfmB752ous+pA0G8= +github.com/cometbft/cometbft v0.37.11 h1:gFr13UXt0MVzgfW11FKsDDy3T9nz/VWqEnFbHf08H2U= +github.com/cometbft/cometbft v0.37.11/go.mod h1:PR1WWNZC6BMPD5rnHVxKsaLk5ZSwcduQd73ON3PAVjc= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/cometbft/cometbft-db v0.12.0 h1:v77/z0VyfSU7k682IzZeZPFZrQAKiQwkqGN0QzAjMi0= github.com/cometbft/cometbft-db v0.12.0/go.mod h1:aX2NbCrjNVd2ZajYxt1BsiFf/Z+TQ2MN0VxdicheYuw= @@ -1891,12 +1899,14 @@ github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32/go.mod h1:kwMlEC4 github.com/cosmos/cosmos-proto v1.0.0-alpha7/go.mod h1:dosO4pSAbJF8zWCzCoTWP7nNsjcvSUBQmniFxDg5daw= github.com/cosmos/cosmos-proto v1.0.0-alpha8/go.mod h1:6/p+Bc4O8JKeZqe0VqUGTX31eoYqemTT4C1hLCWsO7I= github.com/cosmos/cosmos-proto v1.0.0-beta.1/go.mod h1:8k2GNZghi5sDRFw/scPL8gMSowT1vDA+5ouxL8GjaUE= -github.com/cosmos/cosmos-proto v1.0.0-beta.4 h1:aEL7tU/rLOmxZQ9z4i7mzxcLbSCY48OdY7lIWTLG7oU= github.com/cosmos/cosmos-proto v1.0.0-beta.4/go.mod h1:oeB+FyVzG3XrQJbJng0EnV8Vljfk9XvTIpGILNU/9Co= +github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= +github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20221207001918-ed5124f932fd/go.mod h1:dmCp0cYz6/S5KWKJ9QzePRwWNEbcSu+jbBTRgnzPnPo= github.com/cosmos/cosmos-sdk v0.47.0-rc2.0.20230220103612-f094a0c33410/go.mod h1:SNeHakoKi9YlfhI53+ijEZZIHp90NrB1By4NgWN0KZ0= -github.com/cosmos/cosmos-sdk v0.47.10 h1:Wxf5yEN3jZbG4fftxAMKB6rpd8ME0mxuCVihpz65dt0= github.com/cosmos/cosmos-sdk v0.47.10/go.mod h1:UWpgWkhcsBIATS68uUC0del7IiBN4hPv/vqg8Zz23uw= +github.com/cosmos/cosmos-sdk v0.47.14 h1:vD9JyIdlbVaXMOE/BLamViQvylfUq0E0FpqdPVv/fWw= +github.com/cosmos/cosmos-sdk v0.47.14/go.mod h1:GrDj/zd9Tiuy8ZpG9PbUbhghCVU7lwyH0GS7CpxHpyM= github.com/cosmos/cosmos-sdk/db v1.0.0-beta.1.0.20220726092710-f848e4300a8a/go.mod h1:c8IO23vgNxueCCJlSI9awQtcxsvc+buzaeThB85qfBU= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 h1:iKclrn3YEOwk4jQHT2ulgzuXyxmzmPczUalMwW4XH9k= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpFP3wWDPgdHPargtyw30= @@ -1909,8 +1919,9 @@ github.com/cosmos/gogoproto v1.4.1/go.mod h1:Ac9lzL4vFpBMcptJROQ6dQ4M3pOEK5Z/l0Q github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU= github.com/cosmos/gogoproto v1.4.4/go.mod h1:/yl6/nLwsZcZ2JY3OrqjRqvqCG9InUMcXRfRjQiF9DU= -github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= +github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= +github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/iavl v0.20.0-alpha4/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= @@ -1963,8 +1974,9 @@ github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= @@ -2125,13 +2137,15 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= 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/firefart/nonamedreturns v1.0.1/go.mod h1:D3dpIBojGGNh5UfElmwPu73SwDCm+VKhHYqwlNOk2uQ= github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= @@ -2155,16 +2169,17 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +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/frumioj/crypto11 v1.2.5-0.20210823151709-946ce662cc0e h1:HRagc2sBsKLDvVVXQMaCEU8ueRFAl3txucwykhQPbGc= github.com/frumioj/crypto11 v1.2.5-0.20210823151709-946ce662cc0e/go.mod h1:/1u7qgWwAI7wja4BdNu5Vd5gqMtmtoiACHlhl46uY1E= 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.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +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/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= @@ -2255,8 +2270,9 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/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.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= @@ -2381,8 +2397,9 @@ github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgR github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/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-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -2421,8 +2438,9 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -2584,8 +2602,9 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +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/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= @@ -2740,6 +2759,8 @@ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -2993,8 +3014,9 @@ github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrD github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= @@ -3232,8 +3254,9 @@ github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcs github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -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/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= @@ -3555,8 +3578,8 @@ github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZO github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +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/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -3593,8 +3616,9 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ 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 v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/pointlander/compress v1.1.1-0.20190518213731-ff44bd196cc3/go.mod h1:q5NXNGzqj5uPnVuhGkZfmgHqNUhf15VLi6L9kW0VEc0= github.com/pointlander/jetset v1.0.1-0.20190518214125-eee7eff80bd4/go.mod h1:RdR1j20Aj5pB6+fw6Y9Ur7lMHpegTEjY1vc19hEZL40= github.com/pointlander/peg v1.0.1/go.mod h1:5hsGDQR2oZI4QoWz0/Kdg3VSVEC31iJw/b7WjqCBGRI= @@ -3735,8 +3759,9 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= @@ -3758,6 +3783,10 @@ github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43 github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sagikazarmark/crypt v0.8.0/go.mod h1:TmKwZAo97S4Fy4sfMH/HX/cQP5D+ijra2NyLpNNmttY= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +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/samber/lo v1.46.0 h1:w8G+oaCPgz1PoCJztqymCFaKwXt+5cCXn51uPxExFfQ= github.com/samber/lo v1.46.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -3789,8 +3818,8 @@ github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfP 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/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= -github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= @@ -3845,6 +3874,8 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak= github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= @@ -3863,8 +3894,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -3880,7 +3911,6 @@ github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUq github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 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 v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -3899,8 +3929,8 @@ github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUs github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= -github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= -github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +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/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= 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.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= @@ -3951,8 +3981,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= @@ -4260,17 +4290,22 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.2 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0/go.mod h1:LsankqVDx4W+RhZNA5uWarULII/MBhF5qwCYxTuyXjs= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0/go.mod h1:y/SlJpJQPd2UzfBCj0E9Flk9FDCtTyqUmaCB41qFrWI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.3/go.mod h1:Dts42MGkzZne2yCru741+bFiTMWkIj/LLRizad7b9tw= +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/httptrace/otelhttptrace v0.29.0/go.mod h1:vHItvsnJtp7ES++nFLLFBzUWny7fJQSvTlxFcqQGUr4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0/go.mod h1:tLYsuf2v8fZreBVwp9gVMhefZlLFZaUiNVSq8QxXRII= +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 v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk= go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4= go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +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/exporters/jaeger v1.4.1/go.mod h1:ZW7vkOu9nC1CxsD8bHNHCia5JUbwP39vxgd1q4Z5rCI= go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= @@ -4285,14 +4320,16 @@ go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/on go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g= go.opentelemetry.io/otel/metric v0.32.3/go.mod h1:pgiGmKohxHyTPHGOff+vrtIH39/R9fiO/WoenUQ3kcc= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +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/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= go.opentelemetry.io/otel/sdk v1.4.1/go.mod h1:NBwHDgDIBYjwK2WNu1OPgsIc2IJzmBXNnvIJxJc8BpE= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +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/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= @@ -4301,8 +4338,9 @@ go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+ go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc= go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +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.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ= @@ -4426,8 +4464,8 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= 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= @@ -4452,8 +4490,9 @@ golang.org/x/exp v0.0.0-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -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/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= @@ -4672,8 +4711,8 @@ golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= +golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 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= @@ -4696,8 +4735,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +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-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -4905,8 +4944,9 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.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-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -4930,8 +4970,8 @@ golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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= @@ -4954,8 +4994,8 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.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= @@ -5128,8 +5168,9 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T 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 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= 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.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= @@ -5226,8 +5267,8 @@ google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvy google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= -google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY= -google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= +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.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -5428,8 +5469,9 @@ google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJ google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= +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-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= @@ -5448,8 +5490,9 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go. google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= -google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 h1:s1w3X6gQxwrLEpxnLd/qXTVLgQE2yXwaOaoa6IlY/+o= google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= +google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= +google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= @@ -5473,8 +5516,9 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4= google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -5539,8 +5583,9 @@ google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSs google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= 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= @@ -5565,8 +5610,9 @@ google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 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= diff --git a/scripts/gen-docs-zetacored.sh b/scripts/gen-docs-zetacored.sh index 4ae0710dc1..3185f5ae2c 100755 --- a/scripts/gen-docs-zetacored.sh +++ b/scripts/gen-docs-zetacored.sh @@ -4,8 +4,6 @@ DIR=docs/cli/zetacored rm -rf $DIR -go install ./cmd/zetacored - zetacored docs --path $DIR # Recursive function to process files diff --git a/zetaclient/context/chain.go b/zetaclient/context/chain.go index 117b921168..29105c8362 100644 --- a/zetaclient/context/chain.go +++ b/zetaclient/context/chain.go @@ -1,6 +1,7 @@ package context import ( + "cmp" "fmt" "sync" @@ -65,7 +66,7 @@ func (cr *ChainRegistry) Get(chainID int64) (Chain, error) { func (cr *ChainRegistry) All() []Chain { items := maps.Values(cr.chains) - slices.SortFunc(items, func(a, b Chain) bool { return a.ID() < b.ID() }) + slices.SortFunc(items, func(a, b Chain) int { return cmp.Compare(a.ID(), b.ID()) }) return items } From f0ed61d88286a3b0aff9d69b0e26e685541eb458 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Wed, 2 Oct 2024 16:23:54 +0200 Subject: [PATCH 09/36] Revert "chore: upgrade cometbft and cosmos-sdk (#2934)" (#2956) This reverts commit 5d981aa1e1626a0311ef28638a4d5b67b8ab6ef9. --- .github/workflows/ci.yml | 2 +- .golangci.yml | 2 - Makefile | 16 +--- contrib/rpcimportable/test.sh | 14 --- go.mod | 95 +++++++++---------- go.sum | 172 +++++++++++++--------------------- scripts/gen-docs-zetacored.sh | 2 + zetaclient/context/chain.go | 3 +- 8 files changed, 117 insertions(+), 189 deletions(-) delete mode 100755 contrib/rpcimportable/test.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9131d389e1..518823b42f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -115,7 +115,7 @@ jobs: run: cat go.mod - name: go test working-directory: contrib/rpcimportable - run: ./test.sh + run: go test ./... ci-ok: runs-on: ubuntu-22.04 needs: diff --git a/.golangci.yml b/.golangci.yml index b7472a5fd0..8fb8a0084a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,8 +2,6 @@ run: go: '1.20' # as in go.mod timeout: 5m tests: false # exclude test from linting - build-tags: - - libsecp256k1_sdk linters: disable-all: true diff --git a/Makefile b/Makefile index f1ce7b6fe6..36e414f012 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ GOFLAGS := "" GOLANG_CROSS_VERSION ?= v1.22.4 GOPATH ?= '$(HOME)/go' -build_ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=zetacore \ +ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=zetacore \ -X github.com/cosmos/cosmos-sdk/version.ServerName=zetacored \ -X github.com/cosmos/cosmos-sdk/version.ClientName=zetaclientd \ -X github.com/cosmos/cosmos-sdk/version.Version=$(NODE_VERSION) \ @@ -25,17 +25,11 @@ build_ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=zetacore \ -X github.com/zeta-chain/node/pkg/constant.BuildTime=$(BUILDTIME) \ -X github.com/cosmos/cosmos-sdk/types.DBBackend=pebbledb -# --allow-multiple-definitions need to be set when you are importing both cosmos-sdk -# and go-ethereum: https://github.com/cosmos/cosmos-sdk/tree/release/v0.47.x/crypto/keys/secp256k1/internal/secp256k1 -all_ldflags = -extldflags=-Wl,--allow-multiple-definition - -# enable libsecp256k1_sdk to bypass the btcec breaking change: -# https://github.com/btcsuite/btcd/issues/2243 -BUILD_FLAGS := -ldflags '$(build_ldflags) $(all_ldflags)' -tags pebbledb,ledger,libsecp256k1_sdk +BUILD_FLAGS := -ldflags '$(ldflags)' -tags pebbledb,ledger TEST_DIR ?= "./..." -TEST_BUILD_FLAGS := -ldflags='$(all_ldflags)' -tags pebbledb,ledger,libsecp256k1_sdk -HSM_BUILD_FLAGS := -ldflags='$(all_ldflags)' -tags pebbledb,ledger,libsecp256k1_sdk,hsm_test +TEST_BUILD_FLAGS := -tags pebbledb,ledger +HSM_BUILD_FLAGS := -tags pebbledb,ledger,hsm_test export DOCKER_BUILDKIT := 1 @@ -199,7 +193,7 @@ specs: @go run ./scripts/gen-spec.go .PHONY: specs -docs-zetacored: install-zetacore +docs-zetacored: @echo "--> Generating zetacored documentation" @bash ./scripts/gen-docs-zetacored.sh .PHONY: docs-zetacored diff --git a/contrib/rpcimportable/test.sh b/contrib/rpcimportable/test.sh deleted file mode 100755 index 3ba925bc6f..0000000000 --- a/contrib/rpcimportable/test.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -# run rpcimportable test with the required build flags - -set -eo pipefail - -cd "$(dirname "$0")" - -# --allow-multiple-definitions need to be set when you are importing both cosmos-sdk -# and go-ethereum: https://github.com/cosmos/cosmos-sdk/tree/release/v0.47.x/crypto/keys/secp256k1/internal/secp256k1 -# -# enable libsecp256k1_sdk to bypass the btcec breaking change: -# https://github.com/btcsuite/btcd/issues/2243 -go test -tags libsecp256k1_sdk -ldflags="-extldflags=-Wl,--allow-multiple-definition" ./... diff --git a/go.mod b/go.mod index c3078fb3dc..7625fc2047 100644 --- a/go.mod +++ b/go.mod @@ -10,26 +10,26 @@ require ( cosmossdk.io/tools/rosetta v0.2.1 github.com/99designs/keyring v1.2.1 github.com/btcsuite/btcd v0.24.2 - github.com/btcsuite/btcd/btcec/v2 v2.3.4 + github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/btcsuite/btcd/btcutil v1.1.6 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 github.com/cenkalti/backoff/v4 v4.3.0 github.com/cockroachdb/errors v1.11.1 github.com/coinbase/rosetta-sdk-go v0.7.9 - github.com/cometbft/cometbft v0.37.11 + github.com/cometbft/cometbft v0.37.4 github.com/cometbft/cometbft-db v0.12.0 github.com/cosmos/btcutil v1.0.5 - github.com/cosmos/cosmos-sdk v0.47.14 - github.com/cosmos/gogoproto v1.7.0 + github.com/cosmos/cosmos-sdk v0.47.10 + github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-go/v7 v7.4.0 - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc + github.com/davecgh/go-spew v1.1.1 github.com/emicklei/proto v1.11.1 github.com/ethereum/go-ethereum v1.10.26 - github.com/fatih/color v1.14.1 + github.com/fatih/color v1.13.0 github.com/frumioj/crypto11 v1.2.5-0.20210823151709-946ce662cc0e github.com/gagliardetto/solana-go v1.10.0 github.com/golang/mock v1.6.0 - github.com/golang/protobuf v1.5.4 + github.com/golang/protobuf v1.5.3 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 @@ -49,26 +49,26 @@ require ( github.com/prometheus/client_golang v1.14.0 github.com/rakyll/statik v0.1.7 github.com/rs/cors v1.8.3 - github.com/rs/zerolog v1.33.0 + github.com/rs/zerolog v1.32.0 github.com/samber/lo v1.46.0 github.com/spf13/afero v1.11.0 - github.com/spf13/cast v1.6.0 + github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.19.0 + github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.9.0 github.com/zeta-chain/ethermint v0.0.0-20240927155358-f34e2a4a86f1 github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20240924201108-3a274ce7bad0 gitlab.com/thorchain/tss/go-tss v1.6.5 go.nhat.io/grpcmock v0.25.0 - golang.org/x/crypto v0.26.0 - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 + golang.org/x/crypto v0.23.0 + golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb golang.org/x/net v0.25.0 - golang.org/x/sync v0.8.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 - google.golang.org/grpc v1.62.1 - google.golang.org/protobuf v1.33.0 + golang.org/x/sync v0.7.0 + google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 + google.golang.org/grpc v1.60.1 + google.golang.org/protobuf v1.32.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -77,18 +77,18 @@ require ( ) require ( - cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute v1.24.0 // indirect + cloud.google.com/go v0.111.0 // indirect + cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.6 // indirect - cloud.google.com/go/storage v1.38.0 // indirect + cloud.google.com/go/iam v1.1.5 // indirect + cloud.google.com/go/storage v1.35.1 // indirect cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect - cosmossdk.io/log v1.4.1 // indirect + cosmossdk.io/log v1.3.1 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect - github.com/ChainSafe/go-schnorrkel v1.1.0 // indirect + github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect github.com/DataDog/zstd v1.5.0 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.6.0 // indirect @@ -116,7 +116,7 @@ require ( github.com/confio/ics23/go v0.9.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.4 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.1 // indirect @@ -140,9 +140,9 @@ require ( github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/felixge/httpsnoop v1.0.2 // indirect github.com/flynn/noise v1.0.0 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gagliardetto/binary v0.8.0 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect @@ -150,7 +150,7 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect @@ -159,7 +159,7 @@ require ( github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang/glog v1.2.0 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect @@ -170,7 +170,7 @@ require ( github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.3 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect @@ -202,7 +202,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.2 // indirect + github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -233,7 +233,7 @@ require ( github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/highwayhash v1.0.3 // indirect + github.com/minio/highwayhash v1.0.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -258,9 +258,9 @@ require ( github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/otiai10/primes v0.0.0-20180210170552-f6d2a1ba97c4 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect @@ -272,13 +272,14 @@ require ( github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/sergi/go-diff v1.3.1 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/subosito/gotenv v1.6.0 // indirect + github.com/subosito/gotenv v1.4.2 // indirect github.com/swaggest/assertjson v1.9.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/btcd v0.1.1 // indirect @@ -303,9 +304,9 @@ require ( go.nhat.io/matcher/v2 v2.0.0 // indirect go.nhat.io/wait v0.1.0 // indirect go.opencensus.io v0.24.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.opentelemetry.io/otel v1.19.0 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect + go.opentelemetry.io/otel/trace v1.19.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.19.2 // indirect @@ -313,17 +314,17 @@ require ( go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect - golang.org/x/sys v0.23.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/term v0.20.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gonum.org/v1/gonum v0.13.0 // indirect - google.golang.org/api v0.171.0 // indirect + google.golang.org/api v0.152.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect + google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect lukechampine.com/blake3 v1.2.1 // indirect @@ -340,14 +341,8 @@ require ( require ( github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/snksoft/crc v1.1.0 // indirect - github.com/sourcegraph/conc v0.3.0 // 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 ) replace ( diff --git a/go.sum b/go.sum index bcaab711d6..dd2ce7f425 100644 --- a/go.sum +++ b/go.sum @@ -57,9 +57,8 @@ cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5x cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= +cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= -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/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -326,9 +325,8 @@ cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdi cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78= cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns= +cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= @@ -631,9 +629,8 @@ cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+K cloud.google.com/go/iam v1.1.2/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE= cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8= +cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= -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/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= @@ -1060,8 +1057,8 @@ cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -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/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= +cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= @@ -1216,9 +1213,8 @@ cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vM cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= +cosmossdk.io/log v1.3.1 h1:UZx8nWIkfbbNEWusZqzAx3ZGvu54TZacWib3EzUYmGI= cosmossdk.io/log v1.3.1/go.mod h1:2/dIomt8mKdk6vl3OWJcPk2be3pGOS8OQaLUM/3/tCM= -cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= -cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= cosmossdk.io/math v1.0.0-beta.3/go.mod h1:3LYasri3Zna4XpbrTNdKsWmD5fHHkaNAod/mNT9XdE4= cosmossdk.io/math v1.0.0-beta.4/go.mod h1:An0MllWJY6PxibUpnwGk8jOm+a/qIxlKmL5Zyp9NnaM= cosmossdk.io/math v1.0.0-beta.6/go.mod h1:gUVtWwIzfSXqcOT+lBVz2jyjfua8DoBdzRsIyaUAT/8= @@ -1317,9 +1313,8 @@ github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 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/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= -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/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= @@ -1368,9 +1363,8 @@ github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOp github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -1585,9 +1579,8 @@ github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v5 github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= +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/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= @@ -1740,9 +1733,8 @@ github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZ github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= github.com/cometbft/cometbft v0.34.27-alpha.1/go.mod h1:hct3hasQ2hIF3HoD7foVw4RaqTNSSeJ/lgcrVK6uDvs= +github.com/cometbft/cometbft v0.37.4 h1:xyvvEqlyfK8MgNIIKVJaMsuIp03wxOcFmVkT26+Ikpg= github.com/cometbft/cometbft v0.37.4/go.mod h1:Cmg5Hp4sNpapm7j+x0xRyt2g0juQfmB752ous+pA0G8= -github.com/cometbft/cometbft v0.37.11 h1:gFr13UXt0MVzgfW11FKsDDy3T9nz/VWqEnFbHf08H2U= -github.com/cometbft/cometbft v0.37.11/go.mod h1:PR1WWNZC6BMPD5rnHVxKsaLk5ZSwcduQd73ON3PAVjc= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/cometbft/cometbft-db v0.12.0 h1:v77/z0VyfSU7k682IzZeZPFZrQAKiQwkqGN0QzAjMi0= github.com/cometbft/cometbft-db v0.12.0/go.mod h1:aX2NbCrjNVd2ZajYxt1BsiFf/Z+TQ2MN0VxdicheYuw= @@ -1899,14 +1891,12 @@ github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32/go.mod h1:kwMlEC4 github.com/cosmos/cosmos-proto v1.0.0-alpha7/go.mod h1:dosO4pSAbJF8zWCzCoTWP7nNsjcvSUBQmniFxDg5daw= github.com/cosmos/cosmos-proto v1.0.0-alpha8/go.mod h1:6/p+Bc4O8JKeZqe0VqUGTX31eoYqemTT4C1hLCWsO7I= github.com/cosmos/cosmos-proto v1.0.0-beta.1/go.mod h1:8k2GNZghi5sDRFw/scPL8gMSowT1vDA+5ouxL8GjaUE= +github.com/cosmos/cosmos-proto v1.0.0-beta.4 h1:aEL7tU/rLOmxZQ9z4i7mzxcLbSCY48OdY7lIWTLG7oU= github.com/cosmos/cosmos-proto v1.0.0-beta.4/go.mod h1:oeB+FyVzG3XrQJbJng0EnV8Vljfk9XvTIpGILNU/9Co= -github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= -github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20221207001918-ed5124f932fd/go.mod h1:dmCp0cYz6/S5KWKJ9QzePRwWNEbcSu+jbBTRgnzPnPo= github.com/cosmos/cosmos-sdk v0.47.0-rc2.0.20230220103612-f094a0c33410/go.mod h1:SNeHakoKi9YlfhI53+ijEZZIHp90NrB1By4NgWN0KZ0= +github.com/cosmos/cosmos-sdk v0.47.10 h1:Wxf5yEN3jZbG4fftxAMKB6rpd8ME0mxuCVihpz65dt0= github.com/cosmos/cosmos-sdk v0.47.10/go.mod h1:UWpgWkhcsBIATS68uUC0del7IiBN4hPv/vqg8Zz23uw= -github.com/cosmos/cosmos-sdk v0.47.14 h1:vD9JyIdlbVaXMOE/BLamViQvylfUq0E0FpqdPVv/fWw= -github.com/cosmos/cosmos-sdk v0.47.14/go.mod h1:GrDj/zd9Tiuy8ZpG9PbUbhghCVU7lwyH0GS7CpxHpyM= github.com/cosmos/cosmos-sdk/db v1.0.0-beta.1.0.20220726092710-f848e4300a8a/go.mod h1:c8IO23vgNxueCCJlSI9awQtcxsvc+buzaeThB85qfBU= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 h1:iKclrn3YEOwk4jQHT2ulgzuXyxmzmPczUalMwW4XH9k= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpFP3wWDPgdHPargtyw30= @@ -1919,9 +1909,8 @@ github.com/cosmos/gogoproto v1.4.1/go.mod h1:Ac9lzL4vFpBMcptJROQ6dQ4M3pOEK5Z/l0Q github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU= github.com/cosmos/gogoproto v1.4.4/go.mod h1:/yl6/nLwsZcZ2JY3OrqjRqvqCG9InUMcXRfRjQiF9DU= +github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= -github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= -github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/iavl v0.20.0-alpha4/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= @@ -1974,9 +1963,8 @@ github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= @@ -2137,15 +2125,13 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= 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/firefart/nonamedreturns v1.0.1/go.mod h1:D3dpIBojGGNh5UfElmwPu73SwDCm+VKhHYqwlNOk2uQ= github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= @@ -2169,17 +2155,16 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -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/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frumioj/crypto11 v1.2.5-0.20210823151709-946ce662cc0e h1:HRagc2sBsKLDvVVXQMaCEU8ueRFAl3txucwykhQPbGc= github.com/frumioj/crypto11 v1.2.5-0.20210823151709-946ce662cc0e/go.mod h1:/1u7qgWwAI7wja4BdNu5Vd5gqMtmtoiACHlhl46uY1E= 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.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -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/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= @@ -2270,9 +2255,8 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/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.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= @@ -2397,9 +2381,8 @@ github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgR github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= -github.com/golang/glog v1.2.0/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-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -2438,9 +2421,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -2602,9 +2584,8 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -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/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= @@ -2759,8 +2740,6 @@ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -3014,9 +2993,8 @@ github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrD github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= -github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= @@ -3254,9 +3232,8 @@ github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcs github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +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/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= -github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= @@ -3578,8 +3555,8 @@ github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZO github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -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/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -3616,9 +3593,8 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ 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 v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/pointlander/compress v1.1.1-0.20190518213731-ff44bd196cc3/go.mod h1:q5NXNGzqj5uPnVuhGkZfmgHqNUhf15VLi6L9kW0VEc0= github.com/pointlander/jetset v1.0.1-0.20190518214125-eee7eff80bd4/go.mod h1:RdR1j20Aj5pB6+fw6Y9Ur7lMHpegTEjY1vc19hEZL40= github.com/pointlander/peg v1.0.1/go.mod h1:5hsGDQR2oZI4QoWz0/Kdg3VSVEC31iJw/b7WjqCBGRI= @@ -3759,9 +3735,8 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= +github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= -github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= @@ -3783,10 +3758,6 @@ github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43 github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sagikazarmark/crypt v0.8.0/go.mod h1:TmKwZAo97S4Fy4sfMH/HX/cQP5D+ijra2NyLpNNmttY= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= -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/samber/lo v1.46.0 h1:w8G+oaCPgz1PoCJztqymCFaKwXt+5cCXn51uPxExFfQ= github.com/samber/lo v1.46.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -3818,8 +3789,8 @@ github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfP 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/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My1xr/u+HZrFQ1tOQQQQrOawfyMUH13ai5brBc= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= @@ -3874,8 +3845,6 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak= github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= @@ -3894,8 +3863,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -3911,6 +3880,7 @@ github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUq github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 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 v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -3929,8 +3899,8 @@ github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUs github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= 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/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= 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.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= @@ -3981,8 +3951,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= @@ -4290,22 +4260,17 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.2 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0/go.mod h1:LsankqVDx4W+RhZNA5uWarULII/MBhF5qwCYxTuyXjs= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0/go.mod h1:y/SlJpJQPd2UzfBCj0E9Flk9FDCtTyqUmaCB41qFrWI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.3/go.mod h1:Dts42MGkzZne2yCru741+bFiTMWkIj/LLRizad7b9tw= -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/httptrace/otelhttptrace v0.29.0/go.mod h1:vHItvsnJtp7ES++nFLLFBzUWny7fJQSvTlxFcqQGUr4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0/go.mod h1:tLYsuf2v8fZreBVwp9gVMhefZlLFZaUiNVSq8QxXRII= -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 v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk= go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4= go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -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/exporters/jaeger v1.4.1/go.mod h1:ZW7vkOu9nC1CxsD8bHNHCia5JUbwP39vxgd1q4Z5rCI= go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= @@ -4320,16 +4285,14 @@ go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/on go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g= go.opentelemetry.io/otel/metric v0.32.3/go.mod h1:pgiGmKohxHyTPHGOff+vrtIH39/R9fiO/WoenUQ3kcc= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -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/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= go.opentelemetry.io/otel/sdk v1.4.1/go.mod h1:NBwHDgDIBYjwK2WNu1OPgsIc2IJzmBXNnvIJxJc8BpE= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -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/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= @@ -4338,9 +4301,8 @@ go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+ go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc= go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -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.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ= @@ -4464,8 +4426,8 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -4490,9 +4452,8 @@ golang.org/x/exp v0.0.0-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +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/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= @@ -4711,8 +4672,8 @@ golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 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= @@ -4735,8 +4696,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -4944,9 +4905,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -4970,8 +4930,8 @@ golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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= @@ -4994,8 +4954,8 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 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= @@ -5168,9 +5128,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T 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 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= 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.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= @@ -5267,8 +5226,8 @@ google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvy google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= -google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= -google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY= +google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= 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.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -5469,9 +5428,8 @@ google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJ google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= +google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -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-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= @@ -5490,9 +5448,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go. google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= +google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 h1:s1w3X6gQxwrLEpxnLd/qXTVLgQE2yXwaOaoa6IlY/+o= google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= @@ -5516,9 +5473,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4= google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -5583,9 +5539,8 @@ google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSs google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= 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= @@ -5610,9 +5565,8 @@ google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 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= diff --git a/scripts/gen-docs-zetacored.sh b/scripts/gen-docs-zetacored.sh index 3185f5ae2c..4ae0710dc1 100755 --- a/scripts/gen-docs-zetacored.sh +++ b/scripts/gen-docs-zetacored.sh @@ -4,6 +4,8 @@ DIR=docs/cli/zetacored rm -rf $DIR +go install ./cmd/zetacored + zetacored docs --path $DIR # Recursive function to process files diff --git a/zetaclient/context/chain.go b/zetaclient/context/chain.go index 29105c8362..117b921168 100644 --- a/zetaclient/context/chain.go +++ b/zetaclient/context/chain.go @@ -1,7 +1,6 @@ package context import ( - "cmp" "fmt" "sync" @@ -66,7 +65,7 @@ func (cr *ChainRegistry) Get(chainID int64) (Chain, error) { func (cr *ChainRegistry) All() []Chain { items := maps.Values(cr.chains) - slices.SortFunc(items, func(a, b Chain) int { return cmp.Compare(a.ID(), b.ID()) }) + slices.SortFunc(items, func(a, b Chain) bool { return a.ID() < b.ID() }) return items } From 1ed1015549e8b08ec22ff14e493524708cc29998 Mon Sep 17 00:00:00 2001 From: skosito Date: Thu, 3 Oct 2024 08:43:40 +0100 Subject: [PATCH 10/36] remove redundant error in parsing synthetic txs (#2962) --- rpc/backend/blocks.go | 1 + rpc/types/events.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rpc/backend/blocks.go b/rpc/backend/blocks.go index 6607fcbc07..a91118168a 100644 --- a/rpc/backend/blocks.go +++ b/rpc/backend/blocks.go @@ -339,6 +339,7 @@ func (b *Backend) parseSyntheticTxFromBlockResults( return nil, nil } if additional == nil || res == nil { + b.logger.Debug("synthetic ethereum tx not found in msgs: block %d, index %d", block.Height, i) return nil, nil } return b.parseSyntethicTxFromAdditionalFields(additional), additional diff --git a/rpc/types/events.go b/rpc/types/events.go index 886b0e6a87..3026d13158 100644 --- a/rpc/types/events.go +++ b/rpc/types/events.go @@ -271,7 +271,7 @@ func ParseTxBlockResult( } if len(txs.Txs) == 0 { - return nil, nil, fmt.Errorf("ethereum tx not found in msgs: block %d, index %d", height, txIndex) + return nil, nil, nil } parsedTx := txs.Txs[0] if parsedTx.Type == CosmosEVMTxType { From 49d641bbac9c42280a391111d100de29e741219b Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Thu, 3 Oct 2024 11:04:44 +0200 Subject: [PATCH 11/36] fix(zetaclient): tolerate priorityFee > gasFee (#2955) * Fix priority fees edge case * Address PR comments * add some context comment * comment --------- Co-authored-by: Dmitry S <11892559+swift1337@users.noreply.github.com> --- zetaclient/chains/evm/signer/gas.go | 11 ++++++++++- zetaclient/chains/evm/signer/gas_test.go | 13 ++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/zetaclient/chains/evm/signer/gas.go b/zetaclient/chains/evm/signer/gas.go index 540302b91c..6727758edd 100644 --- a/zetaclient/chains/evm/signer/gas.go +++ b/zetaclient/chains/evm/signer/gas.go @@ -92,7 +92,16 @@ func gasFromCCTX(cctx *types.CrossChainTx, logger zerolog.Logger) (Gas, error) { case err != nil: return Gas{}, errors.Wrap(err, "unable to parse priorityFee") case gasPrice.Cmp(priorityFee) == -1: - return Gas{}, fmt.Errorf("gasPrice (%d) is less than priorityFee (%d)", gasPrice.Int64(), priorityFee.Int64()) + logger.Warn(). + Str("cctx.initial_priority_fee", priorityFee.String()). + Str("cctx.forced_priority_fee", gasPrice.String()). + Msg("gasPrice is less than priorityFee, setting priorityFee = gasPrice") + + // this should in theory never happen, but this reported bug might be a cause: https://github.com/zeta-chain/node/issues/2954 + // in this case we lower the priorityFee to the gasPrice to ensure the transaction is valid + // the only potential issue is the transaction might not cover the baseFee + // the gas stability pool mechanism help to mitigate this issue + priorityFee = big.NewInt(0).Set(gasPrice) } return Gas{ diff --git a/zetaclient/chains/evm/signer/gas_test.go b/zetaclient/chains/evm/signer/gas_test.go index 71bbf97b5d..aa9a683b37 100644 --- a/zetaclient/chains/evm/signer/gas_test.go +++ b/zetaclient/chains/evm/signer/gas_test.go @@ -98,9 +98,16 @@ func TestGasFromCCTX(t *testing.T) { errorContains: "unable to parse priorityFee: big.Int is negative", }, { - name: "gasPrice is less than priorityFee", - cctx: makeCCTX(123_000, gwei(4).String(), gwei(5).String()), - errorContains: "gasPrice (4000000000) is less than priorityFee (5000000000)", + name: "gasPrice is less than priorityFee", + cctx: makeCCTX(123_000, gwei(4).String(), gwei(5).String()), + assert: func(t *testing.T, g Gas) { + assert.False(t, g.isLegacy()) + assertGasEquals(t, Gas{ + Limit: 123_000, + Price: gwei(4), + PriorityFee: gwei(4), + }, g) + }, }, { name: "gasPrice is invalid", From 90924e94d0ac420dc0eea740cb4e2d92b6239ff9 Mon Sep 17 00:00:00 2001 From: morde08 Date: Thu, 3 Oct 2024 07:14:42 -0700 Subject: [PATCH 12/36] ci: 2598 artillery based stress testing is inaccurate due to misconfiguration (#2953) * update artillery config * more fixes * feat: integrate authenticated calls smart contract functionality into protocol (#2904) * e2e tests and modifications for authenticated call * extend test with sender check and revert case * separate tests into separate files * cleanup * withdraw and call support and tests * bump protocol contracts * split tests into separate files * small cleanup * fmt * generate * lint * changelog * PR comments * fix case in proto * bump vote inbound gas limit in zetaclient * fix test * generate * fixing tests * call options non empty * generate * test fix * rename gateway caller * pr comments rename tests * PR comment * generate * tests * update tests fixes * tests fixes * fix * test fix * feat!: bank precompile (#2860) * feat: bank precompile * feat: add deposit * feat: extend deposit * PoC: spend amount on behalf of EOA * feat: expand deposit with transferFrom * use CallEVM instead on ZRC20 bindings * divide the contract into different files * initialize e2e testing * remove duplicated funding * add codecov * expand e2e * fix: wait for deposit tx to be mined * apply first round of reviews * cover al error types test * fixes using time.Since * Include CallContract interface * fix eth events in deposit precompile method * emit Deposit event * add withdraw function * finalize withdraw * pack event arguments generically * add high level event function * first round of review fixes * second round of reviews * create bank account when instantiating bank * e2e: add good and bad scenarios * modify fmt * chore: group input into eventData struct * docs: document bank's methods * chore: generate files with suffix .gen.go * chore: assert errors with errorIs * chore: reset e2e test by resetting allowance * test: add first batch of unit test * test: cover all cases * test: complete unit test cases * include review suggestions * include e2e through contract * test: add e2e through contract complete * test: revert balance between tests * Update precompiles/bank/const.go Co-authored-by: Lucas Bertrand * fix: changed coin denom --------- Co-authored-by: skosito Co-authored-by: Lucas Bertrand * feat: add sender to revert context (#2919) * e2e tests and modifications for authenticated call * extend test with sender check and revert case * separate tests into separate files * cleanup * withdraw and call support and tests * bump protocol contracts * split tests into separate files * small cleanup * fmt * generate * lint * changelog * PR comments * fix case in proto * bump vote inbound gas limit in zetaclient * fix test * generate * fixing tests * call options non empty * generate * test fix * rename gateway caller * pr comments rename tests * PR comment * generate * tests * add sender in test contract * extend e2e tests * generate * changelog * PR comment * generate * update tests fixes * tests fixes * fix * test fix * gas limit fixes * PR comment fix * fix bad merge * ci: add option to enable monitoring stack (#2927) * ci: add option to enable monitoring stack * start prometheus faster * update * ci: add rpcimportable test (#2817) * ci: add rpcimportable test * add ci * fmt * use github.com/btcsuite/btcd/btcutil in pkg/chains * remove app imports types tests * use standalone sdkconfig package * fix policies test * move crosschain keeper tests from types to keeper * never seal config in tests * use https://github.com/zeta-chain/ethermint/pull/126 * add some comments * use merged ethermint hash * show resulting go.mod * ci: Add SARIF upload to GitHub Security Dashboard (#2929) * add semgrep sarif upload to GHAS * added comment to clairfy the usage of the utility script * use ghcr.io instead * add tag to image * bad org name --------- Co-authored-by: jkan2 <5862123+jkan2@users.noreply.github.com> * fix: add recover to InitChainer to diplay informative message when starting a node from block 1 (#2925) * add recover to InitChainer * generate files * add docs link to error message * move InitChainErrorMessage to app.go * Update app/app.go Co-authored-by: Francisco de Borja Aranda Castillejo * use const for message --------- Co-authored-by: Francisco de Borja Aranda Castillejo * test: add wait for block to tss migration test (#2931) * add wait for block to tss migration test * add comments * refactor identifiers * rename checkNumberOfTssGenerated to checkNumberOfTSSGenerated * chore: allow full zetaclient config overlay (#2945) * test(e2e): add gateway upgrade in upgrade test (#2932) * add gateway upgrade * change reference * add v2 setup for all tests * test v2 in light upgrade * refactor setup to use custody v2 directly * chore: improve localnet build performance (#2928) * chore: improve localnet build performance * propagate NODE_VERSION and NODE_COMMIT * update hashes --------- Co-authored-by: skosito Co-authored-by: Francisco de Borja Aranda Castillejo Co-authored-by: Lucas Bertrand Co-authored-by: Alex Gartner Co-authored-by: jkan2 Co-authored-by: jkan2 <5862123+jkan2@users.noreply.github.com> Co-authored-by: Tanmay --- .github/actions/performance-tests/art.yaml | 343 +++++++++++---------- 1 file changed, 172 insertions(+), 171 deletions(-) diff --git a/.github/actions/performance-tests/art.yaml b/.github/actions/performance-tests/art.yaml index 806a4d6321..0424eb96a1 100644 --- a/.github/actions/performance-tests/art.yaml +++ b/.github/actions/performance-tests/art.yaml @@ -9,11 +9,10 @@ config: http: timeout: 60 plugins: + expect: {} + ensure: {} metrics-by-endpoint: useOnlyRequestNames: true - ensure: - - type: "failure" - threshold: 1 publish-metrics: - type: prometheus pushgateway: 'https://pushgateway-testnet.rpc.zetachain.com/-=CLOUDFLARE_UUID=-' @@ -26,6 +25,7 @@ config: - type: "html" filename: "artillery_report.html" logLevel: debug + scenarios: - name: web3_clientVersion flow: @@ -38,13 +38,13 @@ scenarios: params: [] capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: web3_sha3 flow: @@ -58,13 +58,13 @@ scenarios: - "0x68656c6c6f20776f726c64" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: net_version flow: @@ -77,13 +77,13 @@ scenarios: params: [] capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: net_listening flow: @@ -96,13 +96,16 @@ scenarios: params: [] capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" + - equals: + - "true" + - "{{ response.result }}" - name: net_peerCount flow: @@ -115,13 +118,13 @@ scenarios: params: [] capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_chainId flow: @@ -134,13 +137,13 @@ scenarios: params: [] capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getStorageAt flow: @@ -154,13 +157,13 @@ scenarios: - "latest" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getTransactionByBlockHashAndIndex flow: @@ -171,16 +174,17 @@ scenarios: jsonrpc: "2.0" method: "eth_getTransactionByBlockHashAndIndex" params: + - "0xbd8bd16e5d4375ed4bab633c4fb8aca58fdf7ed6c340853b20cfa91ed9a3b9e1" - "0x0" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getTransactionByBlockNumberAndIndex flow: @@ -195,13 +199,13 @@ scenarios: - "0x0" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getUncleByBlockHashAndIndex flow: @@ -212,16 +216,17 @@ scenarios: jsonrpc: "2.0" method: "eth_getUncleByBlockHashAndIndex" params: + - "0xbd8bd16e5d4375ed4bab633c4fb8aca58fdf7ed6c340853b20cfa91ed9a3b9e1" - "0x0" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getUncleByBlockNumberAndIndex flow: @@ -236,13 +241,13 @@ scenarios: - "0x0" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_newFilter flow: @@ -253,21 +258,19 @@ scenarios: jsonrpc: "2.0" method: "eth_newFilter" params: - - { - fromBlock: "latest", - toBlock: "latest", - address: "0x0", + - fromBlock: "latest" + toBlock: "latest" + address: "0x81eF14691E9ea2f711cf56a9f0889c49C5Fe995a" topics: [] - } capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getFilterChanges flow: @@ -278,16 +281,16 @@ scenarios: jsonrpc: "2.0" method: "eth_getFilterChanges" params: - - "0x0" + - "0xbd8bd16e5d4375ed4bab633c4fb8aca58fdf7ed6c340853b20cfa91ed9a3b9e1" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getFilterLogs flow: @@ -298,16 +301,16 @@ scenarios: jsonrpc: "2.0" method: "eth_getFilterLogs" params: - - "0x0" + - "0xbd8bd16e5d4375ed4bab633c4fb8aca58fdf7ed6c340853b20cfa91ed9a3b9e1" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_blockNumber flow: @@ -320,13 +323,13 @@ scenarios: params: [] capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getBlockByHash flow: @@ -337,17 +340,17 @@ scenarios: jsonrpc: "2.0" method: "eth_getBlockByHash" params: - - "0x0" + - "0x8716674e0acdbe87bab4595ecd33436f8a1a1b32fcda721362fe98dfc764affe" - true capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getBlockByNumber flow: @@ -362,13 +365,13 @@ scenarios: - true capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getBlockTransactionCountByHash flow: @@ -379,16 +382,16 @@ scenarios: jsonrpc: "2.0" method: "eth_getBlockTransactionCountByHash" params: - - "0x0" + - "0x8716674e0acdbe87bab4595ecd33436f8a1a1b32fcda721362fe98dfc764affe" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getBlockTransactionCountByNumber flow: @@ -402,13 +405,13 @@ scenarios: - "latest" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getCode flow: @@ -419,17 +422,17 @@ scenarios: jsonrpc: "2.0" method: "eth_getCode" params: - - "0x0" + - "0x0cbe0dF132a6c6B4a2974Fa1b7Fb953CF0Cc798a" - "latest" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getTransactionByHash flow: @@ -440,16 +443,16 @@ scenarios: jsonrpc: "2.0" method: "eth_getTransactionByHash" params: - - "0x0" + - "0x1a363840b12fa22aae5920edf11e2c59dde5260ffe5c9bc108250fe8380f5e75" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getTransactionReceipt flow: @@ -460,16 +463,16 @@ scenarios: jsonrpc: "2.0" method: "eth_getTransactionReceipt" params: - - "0x0" + - "0x1a363840b12fa22aae5920edf11e2c59dde5260ffe5c9bc108250fe8380f5e75" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getLogs flow: @@ -480,19 +483,16 @@ scenarios: jsonrpc: "2.0" method: "eth_getLogs" params: - - fromBlock: "0x1" - toBlock: "latest" - address: "0x0" - topics: ["0x0"] + - address: "0x0cbe0dF132a6c6B4a2974Fa1b7Fb953CF0Cc798a" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_getBalance flow: @@ -503,17 +503,17 @@ scenarios: jsonrpc: "2.0" method: "eth_getBalance" params: - - "0x0" + - "0x735b14BB79463307AAcBED86DAf3322B1e6226aB" - "latest" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" - name: eth_estimateGas flow: @@ -524,13 +524,14 @@ scenarios: jsonrpc: "2.0" method: "eth_estimateGas" params: - - from: "0x0" + - from: "0x239e96c8f17C85c30100AC26F635Ea15f23E9c67" + to: "0x0cbe0dF132a6c6B4a2974Fa1b7Fb953CF0Cc798a" capture: - json: "$" - as: "response" + as: response ensure: - - statusCode: 200 - - statusCode: 201 - assert: - - subject: response.error - equals: null + - statusCode: + - 200 + - 201 + expect: + - notHasProperty: "{{ response.error }}" \ No newline at end of file From e124d34e0ce9d907b52cf1773b2b205137e4328a Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Fri, 4 Oct 2024 13:10:21 +0200 Subject: [PATCH 13/36] fix(`observer`): remove error return on staking hooks (#2968) * update hook * update errors * generate --- x/observer/keeper/hooks.go | 8 ++++---- x/observer/keeper/hooks_test.go | 9 +++++++-- x/observer/keeper/voting.go | 5 +++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/x/observer/keeper/hooks.go b/x/observer/keeper/hooks.go index ec002b5a2f..631abd00e3 100644 --- a/x/observer/keeper/hooks.go +++ b/x/observer/keeper/hooks.go @@ -15,7 +15,7 @@ type Hooks struct { func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) error { err := h.k.CleanObservers(ctx, valAddr) if err != nil { - return err + ctx.Logger().Error("Error cleaning observer set", "error", err) } return nil } @@ -23,7 +23,7 @@ func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr func (h Hooks) AfterValidatorBeginUnbonding(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) error { err := h.k.CheckAndCleanObserver(ctx, valAddr) if err != nil { - return err + ctx.Logger().Error("Error cleaning observer set", "error", err) } return nil } @@ -31,7 +31,7 @@ func (h Hooks) AfterValidatorBeginUnbonding(ctx sdk.Context, _ sdk.ConsAddress, func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { err := h.k.CheckAndCleanObserverDelegator(ctx, valAddr, delAddr) if err != nil { - return err + ctx.Logger().Error("Error cleaning observer set", "error", err) } return nil } @@ -39,7 +39,7 @@ func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) error { err := h.k.CleanSlashedValidator(ctx, valAddr, fraction) if err != nil { - return err + ctx.Logger().Error("Error cleaning observer set", "error", err) } return nil } diff --git a/x/observer/keeper/hooks_test.go b/x/observer/keeper/hooks_test.go index 7b5ef7ed64..09088bed44 100644 --- a/x/observer/keeper/hooks_test.go +++ b/x/observer/keeper/hooks_test.go @@ -139,15 +139,20 @@ func TestKeeper_AfterDelegationModified(t *testing.T) { } func TestKeeper_BeforeValidatorSlashed(t *testing.T) { - t.Run("should error if validator not found", func(t *testing.T) { + t.Run("should not error if validator not found", func(t *testing.T) { k, ctx, _, _ := keepertest.ObserverKeeper(t) r := rand.New(rand.NewSource(9)) validator := sample.Validator(t, r) + os := sample.ObserverSet(10) + k.SetObserverSet(ctx, os) hooks := k.Hooks() err := hooks.BeforeValidatorSlashed(ctx, validator.GetOperator(), sdk.NewDec(1)) - require.Error(t, err) + require.NoError(t, err) + storedOs, found := k.GetObserverSet(ctx) + require.True(t, found) + require.Equal(t, os, storedOs) }) t.Run("should not error if observer set not found", func(t *testing.T) { diff --git a/x/observer/keeper/voting.go b/x/observer/keeper/voting.go index 1f624da5aa..9314c1bca2 100644 --- a/x/observer/keeper/voting.go +++ b/x/observer/keeper/voting.go @@ -5,6 +5,7 @@ import ( sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/pkg/errors" "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/x/observer/types" @@ -134,12 +135,12 @@ func (k Keeper) CheckObserverSelfDelegation(ctx sdk.Context, accAddress string) } validator, found := k.stakingKeeper.GetValidator(ctx, valAddress) if !found { - return types.ErrNotValidator + return errors.Wrapf(types.ErrNotValidator, "validator : %s", valAddress) } delegation, found := k.stakingKeeper.GetDelegation(ctx, selfdelAddr, valAddress) if !found { - return types.ErrSelfDelegation + return errors.Wrapf(types.ErrSelfDelegation, "self delegation : %s , valAddres : %s", selfdelAddr, valAddress) } minDelegation, err := types.GetMinObserverDelegationDec() From 1a32f0524fe0c110b9108a397dbab49267213e75 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Fri, 4 Oct 2024 15:31:44 +0200 Subject: [PATCH 14/36] feat: allow parsing Bitcoin deposit memo with inscription (#2957) * inscription support * disable for mainnet * format * fix unit tests * changelog * fix filename * fix the error for BTC donations --- changelog.md | 1 + contrib/localnet/bitcoin-sidecar/Dockerfile | 14 + .../localnet/bitcoin-sidecar/js/package.json | 23 ++ .../localnet/bitcoin-sidecar/js/src/client.ts | 183 +++++++++++++ .../localnet/bitcoin-sidecar/js/src/index.ts | 38 +++ .../localnet/bitcoin-sidecar/js/src/script.ts | 52 ++++ .../bitcoin-sidecar/js/src/tsconfig.json | 11 + .../localnet/bitcoin-sidecar/js/src/util.ts | 1 + contrib/localnet/docker-compose.yml | 13 + e2e/e2etests/e2etests.go | 8 + .../test_extract_bitcoin_inscription_memo.go | 57 +++++ e2e/runner/bitcoin.go | 55 +++- e2e/runner/bitcoin_inscription.go | 119 +++++++++ zetaclient/chains/bitcoin/observer/inbound.go | 21 +- .../chains/bitcoin/observer/inbound_test.go | 242 ++++++++++++++++-- zetaclient/chains/bitcoin/observer/witness.go | 2 +- 16 files changed, 818 insertions(+), 22 deletions(-) create mode 100644 contrib/localnet/bitcoin-sidecar/Dockerfile create mode 100644 contrib/localnet/bitcoin-sidecar/js/package.json create mode 100644 contrib/localnet/bitcoin-sidecar/js/src/client.ts create mode 100644 contrib/localnet/bitcoin-sidecar/js/src/index.ts create mode 100644 contrib/localnet/bitcoin-sidecar/js/src/script.ts create mode 100644 contrib/localnet/bitcoin-sidecar/js/src/tsconfig.json create mode 100644 contrib/localnet/bitcoin-sidecar/js/src/util.ts create mode 100644 e2e/e2etests/test_extract_bitcoin_inscription_memo.go create mode 100644 e2e/runner/bitcoin_inscription.go diff --git a/changelog.md b/changelog.md index dc83cb839b..78b9ab0b59 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,7 @@ * [2911](https://github.com/zeta-chain/node/pull/2911) - add chain static information for btc testnet4 * [2904](https://github.com/zeta-chain/node/pull/2904) - integrate authenticated calls smart contract functionality into protocol * [2919](https://github.com/zeta-chain/node/pull/2919) - add inbound sender to revert context +* [2957](https://github.com/zeta-chain/node/pull/2957) - enable Bitcoin inscription support on testnet ### Refactor diff --git a/contrib/localnet/bitcoin-sidecar/Dockerfile b/contrib/localnet/bitcoin-sidecar/Dockerfile new file mode 100644 index 0000000000..aef54cf56d --- /dev/null +++ b/contrib/localnet/bitcoin-sidecar/Dockerfile @@ -0,0 +1,14 @@ +FROM node:18.20.4 as builder + +WORKDIR /home/zeta/node + +COPY bitcoin-sidecar/js/* . + +RUN npm install && npm install typescript -g && tsc + +FROM node:alpine + +COPY --from=builder /home/zeta/node/dist ./dist +COPY --from=builder /home/zeta/node/node_modules ./node_modules + +CMD ["node", "dist/index.js"] \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/package.json b/contrib/localnet/bitcoin-sidecar/js/package.json new file mode 100644 index 0000000000..1a4dd4b90a --- /dev/null +++ b/contrib/localnet/bitcoin-sidecar/js/package.json @@ -0,0 +1,23 @@ +{ + "name": "zeta-btc-client", + "version": "0.0.1", + "description": "The Zetachain BTC client", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "bip32": "^4.0.0", + "bitcoinjs-lib": "^6.1.6", + "ecpair": "^2.1.0", + "express": "^4.19.2", + "randombytes": "^2.1.0", + "tiny-secp256k1": "^2.2.3" + }, + "devDependencies": { + "@types/node": "^20.14.11", + "typescript": "^5.5.3" + } +} \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/client.ts b/contrib/localnet/bitcoin-sidecar/js/src/client.ts new file mode 100644 index 0000000000..678b90f6da --- /dev/null +++ b/contrib/localnet/bitcoin-sidecar/js/src/client.ts @@ -0,0 +1,183 @@ +import { initEccLib, payments, Psbt } from "bitcoinjs-lib"; +import { bitcoin, Network, regtest } from "bitcoinjs-lib/src/networks"; +import BIP32Factory, { BIP32Interface } from 'bip32'; +import * as ecc from 'tiny-secp256k1'; +import randomBytes from "randombytes"; +import { ScriptBuilder } from "./script"; +import { Taptree } from "bitcoinjs-lib/src/types"; +import { toXOnly } from "./util"; + +const LEAF_VERSION_TAPSCRIPT = 0xc0; + +initEccLib(ecc); +const bip32 = BIP32Factory(ecc); +const rng = randomBytes; + +/// The evm address type, a 20 bytes hex string +export type Address = String; +export type BtcAddress = String; + +/// The BTC transaction hash returned +export type BtcTxnHash = String; +export interface BtcInput { + txn: BtcTxnHash, + idx: number, +} + +/** + * The example client for interacting with ZetaChain in BTC. There are currently two ways + * of calling a smart contract on ZetaChain from BTC: + * + * - Using OP_RETURN + * - Using Witness + * + * The method used is now based on the data size. Within 80 bytes, `OP_RETURN` is used, else + * the data is written to Witness. + * + * This class handles only the case where data is more than 80 bytes. + */ +export class ZetaBtcClient { + /** The BTC network interracting with */ + readonly network: Network; + + private reveal: RevealTxnBuilder | null; + + private constructor(network: Network) { + this.network = network; + } + + public static regtest(): ZetaBtcClient { + return new ZetaBtcClient(regtest); + } + + public static mainnet(): ZetaBtcClient { + return new ZetaBtcClient(bitcoin); + } + + /** + * Call a target address and passing the data call. + * + * @param address The target zetachain evm address + * @param calldata The calldata that will be invoked on Zetachain + */ + public call( + address: Address, + calldata: Buffer, + ): Address { + if (calldata.length <= 80) { + throw Error("Use op return instead"); + } + + if (address.startsWith("0x")) { + address = address.substring(2); + } + + return this.callWithWitness(Buffer.concat([Buffer.from(address, "hex"), calldata])); + } + + private callWithWitness( + data: Buffer, + ): Address { + const internalKey = bip32.fromSeed(rng(64), this.network); + + const leafScript = this.genLeafScript(internalKey.publicKey, data); + + const scriptTree: Taptree = { output: leafScript }; + + const { address: commitAddress } = payments.p2tr({ + internalPubkey: toXOnly(internalKey.publicKey), + scriptTree, + network: this.network, + }); + + this.reveal = new RevealTxnBuilder(internalKey, leafScript, this.network); + + return commitAddress; + } + + public buildRevealTxn(to: string, commitTxn: BtcInput, commitAmount: number, feeRate: number): Buffer { + if (this.reveal === null) { + throw new Error("commit txn not built yet"); + } + + this.reveal.with_commit_tx(to, commitTxn, commitAmount, feeRate); + return this.reveal.dump(); + } + + private genLeafScript(publicKey: Buffer, data: Buffer,): Buffer { + const builder = ScriptBuilder.new(publicKey); + builder.pushData(data); + return builder.build(); + } +} + +class RevealTxnBuilder { + private psbt: Psbt; + private key: BIP32Interface; + private leafScript: Buffer; + private network: Network + + constructor(key: BIP32Interface, leafScript: Buffer, network: Network) { + this.psbt = new Psbt({ network });; + this.key = key; + this.leafScript = leafScript; + this.network = network; + } + + public with_commit_tx(to: string, commitTxn: BtcInput, commitAmount: number, feeRate: number): RevealTxnBuilder { + const scriptTree: Taptree = { output: this.leafScript }; + + const { output, witness } = payments.p2tr({ + internalPubkey: toXOnly(this.key.publicKey), + scriptTree, + redeem: { + output: this.leafScript, + redeemVersion: LEAF_VERSION_TAPSCRIPT, + }, + network: this.network, + }); + + this.psbt.addInput({ + hash: commitTxn.txn.toString(), + index: commitTxn.idx, + witnessUtxo: { value: commitAmount, script: output! }, + tapLeafScript: [ + { + leafVersion: LEAF_VERSION_TAPSCRIPT, + script: this.leafScript, + controlBlock: witness![witness!.length - 1], + }, + ], + }); + + this.psbt.addOutput({ + value: commitAmount - this.estimateFee(to, commitAmount, feeRate), + address: to, + }); + + this.psbt.signAllInputs(this.key); + this.psbt.finalizeAllInputs(); + + return this; + } + + public dump(): Buffer { + return this.psbt.extractTransaction(true).toBuffer(); + } + + private estimateFee(to: string, amount: number, feeRate: number): number { + const cloned = this.psbt.clone(); + + cloned.addOutput({ + value: amount, + address: to, + }); + + // should have a way to avoid signing but just providing mocked signautre + cloned.signAllInputs(this.key); + cloned.finalizeAllInputs(); + + const size = cloned.extractTransaction().virtualSize(); + return size * feeRate; + } +} \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/index.ts b/contrib/localnet/bitcoin-sidecar/js/src/index.ts new file mode 100644 index 0000000000..5164a6f148 --- /dev/null +++ b/contrib/localnet/bitcoin-sidecar/js/src/index.ts @@ -0,0 +1,38 @@ +import { ZetaBtcClient } from "./client"; +import express, { Request, Response } from 'express'; + +const app = express(); +const PORT = process.env.PORT || 3000; +let zetaClient = ZetaBtcClient.regtest(); + +app.use(express.json()); + +// Middleware to parse URL-encoded bodies +app.use(express.urlencoded({ extended: true })); + +// Route to handle JSON POST requests +app.post('/commit', (req: Request, res: Response) => { + const memo: string = req.body.memo; + const address = zetaClient.call("", Buffer.from(memo, "hex")); + res.json({ address }); +}); + +// Route to handle URL-encoded POST requests +app.post('/reveal', (req: Request, res: Response) => { + const { txn, idx, amount, feeRate, to } = req.body; + console.log(txn, idx, amount, feeRate); + + const rawHex = zetaClient.buildRevealTxn(to,{ txn, idx }, Number(amount), feeRate).toString("hex"); + zetaClient = ZetaBtcClient.regtest(); + res.json({ rawHex }); +}); + +// Start the server +app.listen(PORT, () => { + console.log(`Server is running on http://localhost:${PORT}`); +}); + +/** + * curl --request POST --header "Content-Type: application/json" --data '{"memo":"72f080c854647755d0d9e6f6821f6931f855b9acffd53d87433395672756d58822fd143360762109ab898626556b1c3b8d3096d2361f1297df4a41c1b429471a9aa2fc9be5f27c13b3863d6ac269e4b587d8389f8fd9649859935b0d48dea88cdb40f20c"}' http://localhost:3000/commit + * curl --request POST --header "Content-Type: application/json" --data '{"txn": "7a57f987a3cb605896a5909d9ef2bf7afbf0c78f21e4118b85d00d9e4cce0c2c", "idx": 0, "amount": 1000, "feeRate": 10}' http://localhost:3000/reveal + */ \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/script.ts b/contrib/localnet/bitcoin-sidecar/js/src/script.ts new file mode 100644 index 0000000000..f282e39f01 --- /dev/null +++ b/contrib/localnet/bitcoin-sidecar/js/src/script.ts @@ -0,0 +1,52 @@ +import { opcodes, script, Stack } from "bitcoinjs-lib"; +import { toXOnly } from "./util"; + +const MAX_SCRIPT_ELEMENT_SIZE = 520; + +/** The tapscript builder for zetaclient spending script */ +export class ScriptBuilder { + private script: Stack; + + private constructor(initialScript: Stack) { + this.script = initialScript; + } + + public static new(publicKey: Buffer): ScriptBuilder { + const stack = [ + toXOnly(publicKey), + opcodes.OP_CHECKSIG, + ]; + return new ScriptBuilder(stack); + } + + public pushData(data: Buffer) { + if (data.length <= 80) { + throw new Error("data length should be more than 80 bytes"); + } + + this.script.push( + opcodes.OP_FALSE, + opcodes.OP_IF + ); + + const chunks = chunkBuffer(data, MAX_SCRIPT_ELEMENT_SIZE); + for (const chunk of chunks) { + this.script.push(chunk); + } + + this.script.push(opcodes.OP_ENDIF); + } + + public build(): Buffer { + return script.compile(this.script); + } +} + +function chunkBuffer(buffer: Buffer, chunkSize: number): Buffer[] { + const chunks = []; + for (let i = 0; i < buffer.length; i += chunkSize) { + const chunk = buffer.slice(i, i + chunkSize); + chunks.push(chunk); + } + return chunks; +} \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/tsconfig.json b/contrib/localnet/bitcoin-sidecar/js/src/tsconfig.json new file mode 100644 index 0000000000..4033670b3d --- /dev/null +++ b/contrib/localnet/bitcoin-sidecar/js/src/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "commonjs", + "esModuleInterop": true, + "target": "es6", + "moduleResolution": "node", + "sourceMap": true, + "outDir": "dist" + }, + "lib": ["es2015"] +} \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/util.ts b/contrib/localnet/bitcoin-sidecar/js/src/util.ts new file mode 100644 index 0000000000..87c4d36d0f --- /dev/null +++ b/contrib/localnet/bitcoin-sidecar/js/src/util.ts @@ -0,0 +1 @@ +export const toXOnly = pubKey => (pubKey.length === 32 ? pubKey : pubKey.slice(1, 33)); \ No newline at end of file diff --git a/contrib/localnet/docker-compose.yml b/contrib/localnet/docker-compose.yml index 2c2efbd87f..7044390647 100644 --- a/contrib/localnet/docker-compose.yml +++ b/contrib/localnet/docker-compose.yml @@ -227,6 +227,19 @@ services: -rpcauth=smoketest:63acf9b8dccecce914d85ff8c044b78b$$5892f9bbc84f4364e79f0970039f88bdd823f168d4acc76099ab97b14a766a99 -txindex=1 + bitcoin-node-sidecar: + build: + dockerfile: ./bitcoin-sidecar/Dockerfile + container_name: bitcoin-node-sidecar + hostname: bitcoin-node-sidecar + networks: + mynetwork: + ipv4_address: 172.20.0.111 + environment: + - PORT=8000 + ports: + - "8000:8000" + solana: image: solana-local:latest container_name: solana diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index 29f5a3857a..004271c696 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -82,6 +82,7 @@ const ( TestBitcoinWithdrawP2SHName = "bitcoin_withdraw_p2sh" TestBitcoinWithdrawInvalidAddressName = "bitcoin_withdraw_invalid" TestBitcoinWithdrawRestrictedName = "bitcoin_withdraw_restricted" + TestExtractBitcoinInscriptionMemoName = "bitcoin_memo_from_inscription" /* Application tests @@ -451,6 +452,13 @@ var AllE2ETests = []runner.E2ETest{ /* Bitcoin tests */ + runner.NewE2ETest( + TestExtractBitcoinInscriptionMemoName, + "extract memo from BTC inscription", []runner.ArgDefinition{ + {Description: "amount in btc", DefaultValue: "0.1"}, + }, + TestExtractBitcoinInscriptionMemo, + ), runner.NewE2ETest( TestBitcoinDepositName, "deposit Bitcoin into ZEVM", diff --git a/e2e/e2etests/test_extract_bitcoin_inscription_memo.go b/e2e/e2etests/test_extract_bitcoin_inscription_memo.go new file mode 100644 index 0000000000..eedc24b577 --- /dev/null +++ b/e2e/e2etests/test_extract_bitcoin_inscription_memo.go @@ -0,0 +1,57 @@ +package e2etests + +import ( + "encoding/hex" + + "github.com/btcsuite/btcd/btcjson" + "github.com/rs/zerolog/log" + "github.com/stretchr/testify/require" + + "github.com/zeta-chain/node/e2e/runner" + btcobserver "github.com/zeta-chain/node/zetaclient/chains/bitcoin/observer" +) + +func TestExtractBitcoinInscriptionMemo(r *runner.E2ERunner, args []string) { + r.SetBtcAddress(r.Name, false) + + // obtain some initial fund + stop := r.MineBlocksIfLocalBitcoin() + defer stop() + r.Logger.Info("Mined blocks") + + // list deployer utxos + utxos, err := r.ListDeployerUTXOs() + require.NoError(r, err) + + amount := parseFloat(r, args[0]) + // this is just some random test memo for inscription + memo, err := hex.DecodeString( + "72f080c854647755d0d9e6f6821f6931f855b9acffd53d87433395672756d58822fd143360762109ab898626556b1c3b8d3096d2361f1297df4a41c1b429471a9aa2fc9be5f27c13b3863d6ac269e4b587d8389f8fd9649859935b0d48dea88cdb40f20c", + ) + require.NoError(r, err) + + txid := r.InscribeToTSSFromDeployerWithMemo(amount, utxos, memo) + + _, err = r.GenerateToAddressIfLocalBitcoin(6, r.BTCDeployerAddress) + require.NoError(r, err) + + rawtx, err := r.BtcRPCClient.GetRawTransactionVerbose(txid) + require.NoError(r, err) + r.Logger.Info("obtained reveal txn id %s", txid) + + dummyCoinbaseTxn := rawtx + events, err := btcobserver.FilterAndParseIncomingTx( + r.BtcRPCClient, + []btcjson.TxRawResult{*dummyCoinbaseTxn, *rawtx}, + 0, + r.BTCTSSAddress.String(), + log.Logger, + r.BitcoinParams, + ) + require.NoError(r, err) + + require.Equal(r, 1, len(events)) + event := events[0] + + require.Equal(r, event.MemoBytes, memo) +} diff --git a/e2e/runner/bitcoin.go b/e2e/runner/bitcoin.go index 6fbd6b40d7..d2c04fccf0 100644 --- a/e2e/runner/bitcoin.go +++ b/e2e/runner/bitcoin.go @@ -2,7 +2,9 @@ package runner import ( "bytes" + "encoding/hex" "fmt" + "net/http" "sort" "time" @@ -177,9 +179,17 @@ func (r *E2ERunner) SendToTSSFromDeployerWithMemo( amount float64, inputUTXOs []btcjson.ListUnspentResult, memo []byte, +) (*chainhash.Hash, error) { + return r.sendToAddrFromDeployerWithMemo(amount, r.BTCTSSAddress, inputUTXOs, memo) +} + +func (r *E2ERunner) sendToAddrFromDeployerWithMemo( + amount float64, + to btcutil.Address, + inputUTXOs []btcjson.ListUnspentResult, + memo []byte, ) (*chainhash.Hash, error) { btcRPC := r.BtcRPCClient - to := r.BTCTSSAddress btcDeployerAddress := r.BTCDeployerAddress require.NotNil(r, r.BTCDeployerAddress, "btcDeployerAddress is nil") @@ -288,6 +298,49 @@ func (r *E2ERunner) SendToTSSFromDeployerWithMemo( return txid, nil } +// InscribeToTSSFromDeployerWithMemo creates an inscription that is sent to the tss address with the corresponding memo +func (r *E2ERunner) InscribeToTSSFromDeployerWithMemo( + amount float64, + inputUTXOs []btcjson.ListUnspentResult, + memo []byte, +) *chainhash.Hash { + // TODO: replace builder with Go function to enable instructions + // https://github.com/zeta-chain/node/issues/2759 + builder := InscriptionBuilder{sidecarURL: "http://bitcoin-node-sidecar:8000", client: http.Client{}} + + address, err := builder.GenerateCommitAddress(memo) + require.NoError(r, err) + r.Logger.Info("received inscription commit address %s", address) + + receiver, err := chains.DecodeBtcAddress(address, r.GetBitcoinChainID()) + require.NoError(r, err) + + txnHash, err := r.sendToAddrFromDeployerWithMemo(amount, receiver, inputUTXOs, []byte(constant.DonationMessage)) + require.NoError(r, err) + r.Logger.Info("obtained inscription commit txn hash %s", txnHash.String()) + + // sendToAddrFromDeployerWithMemo makes sure index is 0 + outpointIdx := 0 + hexTx, err := builder.GenerateRevealTxn(r.BTCTSSAddress.String(), txnHash.String(), outpointIdx, amount) + require.NoError(r, err) + + // Decode the hex string into raw bytes + rawTxBytes, err := hex.DecodeString(hexTx) + require.NoError(r, err) + + // Deserialize the raw bytes into a wire.MsgTx structure + msgTx := wire.NewMsgTx(wire.TxVersion) + err = msgTx.Deserialize(bytes.NewReader(rawTxBytes)) + require.NoError(r, err) + r.Logger.Info("recovered inscription reveal txn %s", hexTx) + + txid, err := r.BtcRPCClient.SendRawTransaction(msgTx, true) + require.NoError(r, err) + r.Logger.Info("txid: %+v", txid) + + return txid +} + // GetBitcoinChainID gets the bitcoin chain ID from the network params func (r *E2ERunner) GetBitcoinChainID() int64 { chainID, err := chains.BitcoinChainIDFromNetworkName(r.BitcoinParams.Name) diff --git a/e2e/runner/bitcoin_inscription.go b/e2e/runner/bitcoin_inscription.go new file mode 100644 index 0000000000..6f90068905 --- /dev/null +++ b/e2e/runner/bitcoin_inscription.go @@ -0,0 +1,119 @@ +package runner + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/pkg/errors" +) + +type commitResponse struct { + Address string `json:"address"` +} + +type revealResponse struct { + RawHex string `json:"rawHex"` +} + +type revealRequest struct { + Txn string `json:"txn"` + Idx int `json:"idx"` + Amount int `json:"amount"` + FeeRate int `json:"feeRate"` + To string `json:"to"` +} + +// InscriptionBuilder is a util struct that help create inscription commit and reveal transactions +type InscriptionBuilder struct { + sidecarURL string + client http.Client +} + +// GenerateCommitAddress generates a commit p2tr address that one can send funds to this address +func (r *InscriptionBuilder) GenerateCommitAddress(memo []byte) (string, error) { + // Create the payload + postData := map[string]string{ + "memo": hex.EncodeToString(memo), + } + + // Convert the payload to JSON + jsonData, err := json.Marshal(postData) + if err != nil { + return "", err + } + + postURL := r.sidecarURL + "/commit" + req, err := http.NewRequest("POST", postURL, bytes.NewBuffer(jsonData)) + if err != nil { + return "", errors.Wrap(err, "cannot create commit request") + } + req.Header.Set("Content-Type", "application/json") + + // Send the request + resp, err := r.client.Do(req) + if err != nil { + return "", errors.Wrap(err, "cannot send to sidecar") + } + defer resp.Body.Close() + + // Read the response body + var response commitResponse + err = json.NewDecoder(resp.Body).Decode(&response) + if err != nil { + return "", err + } + + fmt.Print("raw commit response ", response.Address) + + return response.Address, nil +} + +// GenerateRevealTxn creates the corresponding reveal txn to the commit txn. +func (r *InscriptionBuilder) GenerateRevealTxn(to string, txnHash string, idx int, amount float64) (string, error) { + postData := revealRequest{ + Txn: txnHash, + Idx: idx, + Amount: int(amount * 100000000), + FeeRate: 10, + To: to, + } + + // Convert the payload to JSON + jsonData, err := json.Marshal(postData) + if err != nil { + return "", err + } + + postURL := r.sidecarURL + "/reveal" + req, err := http.NewRequest("POST", postURL, bytes.NewBuffer(jsonData)) + if err != nil { + return "", errors.Wrap(err, "cannot create reveal request") + } + req.Header.Set("Content-Type", "application/json") + + // Send the request + resp, err := r.client.Do(req) + if err != nil { + return "", errors.Wrap(err, "cannot send reveal to sidecar") + } + defer resp.Body.Close() + + // Read the response body + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", errors.Wrap(err, "cannot read reveal response body") + } + + // Parse the JSON response + var response revealResponse + if err := json.Unmarshal(body, &response); err != nil { + return "", errors.Wrap(err, "cannot parse reveal response body") + } + + // Access the "address" field + return response.RawHex, nil +} diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index e75d9cc1a0..d31715db9a 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -431,10 +431,27 @@ func (ob *Observer) DoesInboundContainsRestrictedAddress(inTx *BTCInboundEvent) return false } -// GetBtcEvent either returns a valid BTCInboundEvent or nil +// GetBtcEvent returns a valid BTCInboundEvent or nil +// it uses witness data to extract the sender address, except for mainnet +func GetBtcEvent( + rpcClient interfaces.BTCRPCClient, + tx btcjson.TxRawResult, + tssAddress string, + blockNumber uint64, + logger zerolog.Logger, + netParams *chaincfg.Params, + depositorFee float64, +) (*BTCInboundEvent, error) { + if netParams.Name == chaincfg.MainNetParams.Name { + return GetBtcEventWithoutWitness(rpcClient, tx, tssAddress, blockNumber, logger, netParams, depositorFee) + } + return GetBtcEventWithWitness(rpcClient, tx, tssAddress, blockNumber, logger, netParams, depositorFee) +} + +// GetBtcEventWithoutWitness either returns a valid BTCInboundEvent or nil // Note: the caller should retry the tx on error (e.g., GetSenderAddressByVin failed) // TODO(revamp): simplify this function -func GetBtcEvent( +func GetBtcEventWithoutWitness( rpcClient interfaces.BTCRPCClient, tx btcjson.TxRawResult, tssAddress string, diff --git a/zetaclient/chains/bitcoin/observer/inbound_test.go b/zetaclient/chains/bitcoin/observer/inbound_test.go index 2b7a333501..8b01e222a1 100644 --- a/zetaclient/chains/bitcoin/observer/inbound_test.go +++ b/zetaclient/chains/bitcoin/observer/inbound_test.go @@ -189,13 +189,13 @@ func TestGetSenderAddressByVin(t *testing.T) { }) } -func TestGetBtcEvent(t *testing.T) { +func TestGetBtcEventWithoutWitness(t *testing.T) { // load archived inbound P2WPKH raw result // https://mempool.space/tx/847139aa65aa4a5ee896375951cbf7417cfc8a4d6f277ec11f40cd87319f04aa txHash := "847139aa65aa4a5ee896375951cbf7417cfc8a4d6f277ec11f40cd87319f04aa" chain := chains.BitcoinMainnet - // GetBtcEvent arguments + // GetBtcEventWithoutWitness arguments tx := testutils.LoadBTCInboundRawResult(t, TestDataDir, chain.ChainId, txHash, false) tssAddress := testutils.TSSAddressBTCMainnet blockNumber := uint64(835640) @@ -227,7 +227,15 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := testrpc.CreateBTCRPCAndLoadTx(t, TestDataDir, chain.ChainId, preHash) // get BTC event - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -243,7 +251,15 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := testrpc.CreateBTCRPCAndLoadTx(t, TestDataDir, chain.ChainId, preHash) // get BTC event - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -259,7 +275,15 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := testrpc.CreateBTCRPCAndLoadTx(t, TestDataDir, chain.ChainId, preHash) // get BTC event - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -275,7 +299,15 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := testrpc.CreateBTCRPCAndLoadTx(t, TestDataDir, chain.ChainId, preHash) // get BTC event - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -291,7 +323,15 @@ func TestGetBtcEvent(t *testing.T) { rpcClient := testrpc.CreateBTCRPCAndLoadTx(t, TestDataDir, chain.ChainId, preHash) // get BTC event - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Equal(t, eventExpected, event) }) @@ -303,7 +343,15 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewBTCRPCClient(t) - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Nil(t, event) }) @@ -315,13 +363,29 @@ func TestGetBtcEvent(t *testing.T) { // modify the tx to have Vout[0] a P2SH output tx.Vout[0].ScriptPubKey.Hex = strings.Replace(tx.Vout[0].ScriptPubKey.Hex, "0014", "a914", 1) - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Nil(t, event) // append 1 byte to script to make it longer than 22 bytes tx.Vout[0].ScriptPubKey.Hex = tx.Vout[0].ScriptPubKey.Hex + "00" - event, err = observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err = observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Nil(t, event) }) @@ -333,7 +397,15 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewBTCRPCClient(t) - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Nil(t, event) }) @@ -345,7 +417,15 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewBTCRPCClient(t) - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Nil(t, event) }) @@ -357,7 +437,15 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewBTCRPCClient(t) - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Nil(t, event) }) @@ -369,7 +457,15 @@ func TestGetBtcEvent(t *testing.T) { // get BTC event rpcClient := mocks.NewBTCRPCClient(t) - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Nil(t, event) }) @@ -392,7 +488,15 @@ func TestGetBtcEvent(t *testing.T) { rpcClient.On("GetRawTransaction", mock.Anything).Return(btcutil.NewTx(msgTx), nil) // get BTC event - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.NoError(t, err) require.Nil(t, event) }) @@ -417,7 +521,15 @@ func TestGetBtcEventErrors(t *testing.T) { // get BTC event rpcClient := mocks.NewBTCRPCClient(t) - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.Error(t, err) require.Nil(t, event) }) @@ -429,7 +541,15 @@ func TestGetBtcEventErrors(t *testing.T) { // get BTC event rpcClient := mocks.NewBTCRPCClient(t) - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.ErrorContains(t, err, "no input found") require.Nil(t, event) }) @@ -443,8 +563,94 @@ func TestGetBtcEventErrors(t *testing.T) { rpcClient.On("GetRawTransaction", mock.Anything).Return(nil, errors.New("rpc error")) // get BTC event - event, err := observer.GetBtcEvent(rpcClient, *tx, tssAddress, blockNumber, log.Logger, net, depositorFee) + event, err := observer.GetBtcEventWithoutWitness( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) require.ErrorContains(t, err, "error getting sender address") require.Nil(t, event) }) } + +func TestGetBtcEvent(t *testing.T) { + t.Run("should not decode inbound event with witness with mainnet chain", func(t *testing.T) { + // load archived inbound P2WPKH raw result + // https://mempool.space/tx/847139aa65aa4a5ee896375951cbf7417cfc8a4d6f277ec11f40cd87319f04aa + chain := chains.BitcoinMainnet + tssAddress := testutils.TSSAddressBTCMainnet + blockNumber := uint64(835640) + net := &chaincfg.MainNetParams + // 2.992e-05, see avgFeeRate https://mempool.space/api/v1/blocks/835640 + depositorFee := bitcoin.DepositorFee(22 * clientcommon.BTCOutboundGasPriceMultiplier) + txHash2 := "37777defed8717c581b4c0509329550e344bdc14ac38f71fc050096887e535c8" + tx := testutils.LoadBTCInboundRawResult(t, TestDataDir, chain.ChainId, txHash2, false) + rpcClient := mocks.NewBTCRPCClient(t) + // get BTC event + event, err := observer.GetBtcEvent( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) + require.NoError(t, err) + require.Equal(t, (*observer.BTCInboundEvent)(nil), event) + }) + + t.Run("should support legacy BTC inbound event parsing for mainnet", func(t *testing.T) { + // load archived inbound P2WPKH raw result + // https://mempool.space/tx/847139aa65aa4a5ee896375951cbf7417cfc8a4d6f277ec11f40cd87319f04aa + txHash := "847139aa65aa4a5ee896375951cbf7417cfc8a4d6f277ec11f40cd87319f04aa" + chain := chains.BitcoinMainnet + + // GetBtcEventWithoutWitness arguments + tx := testutils.LoadBTCInboundRawResult(t, TestDataDir, chain.ChainId, txHash, false) + tssAddress := testutils.TSSAddressBTCMainnet + blockNumber := uint64(835640) + net := &chaincfg.MainNetParams + + // fee rate of above tx is 28 sat/vB + depositorFee := bitcoin.DepositorFee(28 * clientcommon.BTCOutboundGasPriceMultiplier) + + // expected result + memo, err := hex.DecodeString(tx.Vout[1].ScriptPubKey.Hex[4:]) + require.NoError(t, err) + eventExpected := &observer.BTCInboundEvent{ + FromAddress: "bc1q68kxnq52ahz5vd6c8czevsawu0ux9nfrzzrh6e", + ToAddress: tssAddress, + Value: tx.Vout[0].Value - depositorFee, // 6192 sataoshis + DepositorFee: depositorFee, + MemoBytes: memo, + BlockNumber: blockNumber, + TxHash: tx.Txid, + } + + // https://mempool.space/tx/c5d224963832fc0b9a597251c2342a17b25e481a88cc9119008e8f8296652697 + preHash := "c5d224963832fc0b9a597251c2342a17b25e481a88cc9119008e8f8296652697" + tx.Vin[0].Txid = preHash + tx.Vin[0].Vout = 2 + eventExpected.FromAddress = "bc1q68kxnq52ahz5vd6c8czevsawu0ux9nfrzzrh6e" + // load previous raw tx so so mock rpc client can return it + rpcClient := testrpc.CreateBTCRPCAndLoadTx(t, TestDataDir, chain.ChainId, preHash) + + // get BTC event + event, err := observer.GetBtcEvent( + rpcClient, + *tx, + tssAddress, + blockNumber, + log.Logger, + net, + depositorFee, + ) + require.NoError(t, err) + require.Equal(t, eventExpected, event) + }) +} diff --git a/zetaclient/chains/bitcoin/observer/witness.go b/zetaclient/chains/bitcoin/observer/witness.go index 696629b59a..86b22f95cf 100644 --- a/zetaclient/chains/bitcoin/observer/witness.go +++ b/zetaclient/chains/bitcoin/observer/witness.go @@ -58,7 +58,7 @@ func GetBtcEventWithWitness( memo = candidate logger.Debug().Msgf("GetBtcEventWithWitness: found inscription memo %s in tx %s", hex.EncodeToString(memo), tx.Txid) } else { - return nil, errors.Errorf("error getting memo for inbound: %s", tx.Txid) + return nil, nil } // event found, get sender address From 45a9b0594131ec70f0dd10b3ba8e96cc7c0cdb50 Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Tue, 8 Oct 2024 13:17:41 +0200 Subject: [PATCH 15/36] refactor: add error field in cctx (#2952) * feat: add error field in cctx * feat: divide messages into status and error * fix unit tests * add function to update error messages * add query to get cctx error message * fix error messages * reviews suggestions * include new generated files * make every msg lowercase * applied suggestions --- changelog.md | 1 + docs/openapi/openapi.swagger.yaml | 8 + e2e/e2etests/test_eth_deposit_call.go | 4 +- e2e/e2etests/test_solana_deposit_refund.go | 4 +- .../zetacore/crosschain/cross_chain_tx.proto | 7 +- testutil/sample/crosschain.go | 1 + .../crosschain/cross_chain_tx_pb.d.ts | 11 + x/crosschain/keeper/cctx_gateway_observers.go | 2 +- x/crosschain/keeper/cctx_gateway_zevm.go | 4 +- .../cctx_orchestrator_validate_outbound.go | 26 +- x/crosschain/keeper/cctx_test.go | 1 - x/crosschain/keeper/initiate_outbound_test.go | 20 +- .../keeper/msg_server_migrate_tss_funds.go | 3 +- .../keeper/msg_server_vote_inbound_tx_test.go | 4 +- .../keeper/msg_server_vote_outbound_tx.go | 2 +- x/crosschain/migrations/v5/migrate.go | 1 + x/crosschain/types/cctx.go | 21 +- x/crosschain/types/cctx_test.go | 14 +- x/crosschain/types/cross_chain_tx.pb.go | 236 +++++++++++------- x/crosschain/types/keys.go | 6 +- x/crosschain/types/rate_limiter_flags_test.go | 3 +- x/crosschain/types/status.go | 47 ++-- x/crosschain/types/status_test.go | 18 +- 23 files changed, 278 insertions(+), 166 deletions(-) diff --git a/changelog.md b/changelog.md index 78b9ab0b59..5de0dbd846 100644 --- a/changelog.md +++ b/changelog.md @@ -26,6 +26,7 @@ * [2826](https://github.com/zeta-chain/node/pull/2826) - remove unused code from emissions module and add new parameter for fixed block reward amount * [2890](https://github.com/zeta-chain/node/pull/2890) - refactor `MsgUpdateChainInfo` to accept a single chain, and add `MsgRemoveChainInfo` to remove a chain * [2899](https://github.com/zeta-chain/node/pull/2899) - remove btc deposit fee v1 and improve unit tests +* [2952](https://github.com/zeta-chain/node/pull/2952) - add error_message to cctx.status ### Tests diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index a8c0a2516e..461b8566cc 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -58446,6 +58446,14 @@ definitions: $ref: '#/definitions/crosschainCctxStatus' status_message: type: string + description: |- + status_message carries information about the status transitions: + why they were triggered, old and new status. + error_message: + type: string + description: |- + error_message carries information about the error that caused the tx + to be PendingRevert, Reverted or Aborted. lastUpdate_timestamp: type: string format: int64 diff --git a/e2e/e2etests/test_eth_deposit_call.go b/e2e/e2etests/test_eth_deposit_call.go index 570e7b05eb..46805f9f81 100644 --- a/e2e/e2etests/test_eth_deposit_call.go +++ b/e2e/e2etests/test_eth_deposit_call.go @@ -87,6 +87,6 @@ func TestEtherDepositAndCall(r *runner.E2ERunner, args []string) { r.Logger.Info("Cross-chain call to reverter reverted") - // check the status message contains revert error hash in case of revert - require.Contains(r, cctx.CctxStatus.StatusMessage, utils.ErrHashRevertFoo) + // Check the error carries the revert executed. + require.Contains(r, cctx.CctxStatus.ErrorMessage, "revert executed") } diff --git a/e2e/e2etests/test_solana_deposit_refund.go b/e2e/e2etests/test_solana_deposit_refund.go index e9155c9ddd..3176edee78 100644 --- a/e2e/e2etests/test_solana_deposit_refund.go +++ b/e2e/e2etests/test_solana_deposit_refund.go @@ -31,6 +31,6 @@ func TestSolanaDepositAndCallRefund(r *runner.E2ERunner, args []string) { r.Logger.CCTX(*cctx, "solana_deposit_and_refund") utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_Reverted) - // check the status message contains revert error hash in case of revert - require.Contains(r, cctx.CctxStatus.StatusMessage, utils.ErrHashRevertFoo) + // Check the error carries the revert executed. + require.Contains(r, cctx.CctxStatus.ErrorMessage, "revert executed") } diff --git a/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto b/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto index 0ca1f56f7d..9b634a6378 100644 --- a/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto +++ b/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto @@ -17,7 +17,7 @@ enum CctxStatus { Reverted = 5; // inbound reverted. Aborted = 6; // inbound tx error or invalid paramters and cannot revert; just abort. - // But the amount can be refunded to zetachain using and admin proposal + // But the amount can be refunded to zetachain using and admin proposal } enum TxFinalizationStatus { @@ -94,7 +94,12 @@ message OutboundParams { message Status { CctxStatus status = 1; + // status_message carries information about the status transitions: + // why they were triggered, old and new status. string status_message = 2; + // error_message carries information about the error that caused the tx + // to be PendingRevert, Reverted or Aborted. + string error_message = 6; int64 lastUpdate_timestamp = 3; bool isAbortRefunded = 4; // when the CCTX was created. only populated on new transactions. diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index 8f09271e23..ff17525734 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -191,6 +191,7 @@ func Status(t *testing.T, index string) *types.Status { return &types.Status{ Status: types.CctxStatus(r.Intn(100)), StatusMessage: String(), + ErrorMessage: String(), CreatedTimestamp: createdAt, LastUpdateTimestamp: createdAt, } diff --git a/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts b/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts index 1ffa04eaca..e5295ee133 100644 --- a/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts +++ b/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts @@ -355,10 +355,21 @@ export declare class Status extends Message { status: CctxStatus; /** + * status_message carries information about the status transitions: + * why they were triggered, old and new status. + * * @generated from field: string status_message = 2; */ statusMessage: string; + /** + * error_message carries information about the error that caused the tx + * to be PendingRevert, Reverted or Aborted. + * + * @generated from field: string error_message = 6; + */ + errorMessage: string; + /** * @generated from field: int64 lastUpdate_timestamp = 3; */ diff --git a/x/crosschain/keeper/cctx_gateway_observers.go b/x/crosschain/keeper/cctx_gateway_observers.go index 39a33f4edc..9576bcfe32 100644 --- a/x/crosschain/keeper/cctx_gateway_observers.go +++ b/x/crosschain/keeper/cctx_gateway_observers.go @@ -75,7 +75,7 @@ func (c CCTXGatewayObservers) InitiateOutbound( }() if err != nil { // do not commit anything here as the CCTX should be aborted - config.CCTX.SetAbort(err.Error()) + config.CCTX.SetAbort("internal error", err.Error()) return types.CctxStatus_Aborted, err } commit() diff --git a/x/crosschain/keeper/cctx_gateway_zevm.go b/x/crosschain/keeper/cctx_gateway_zevm.go index 81366d6af3..fc247ad7a4 100644 --- a/x/crosschain/keeper/cctx_gateway_zevm.go +++ b/x/crosschain/keeper/cctx_gateway_zevm.go @@ -28,7 +28,9 @@ func (c CCTXGatewayZEVM) InitiateOutbound( if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX - config.CCTX.SetAbort(err.Error()) + config.CCTX.SetAbort( + "error during deposit that is not smart contract revert", + err.Error()) return types.CctxStatus_Aborted, err } diff --git a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go index 17c848613a..2f3acdd744 100644 --- a/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go +++ b/x/crosschain/keeper/cctx_orchestrator_validate_outbound.go @@ -53,7 +53,9 @@ func (k Keeper) ValidateOutboundZEVM( cctx.InboundParams.Amount, ) if err != nil { - cctx.SetAbort(fmt.Sprintf("%s : %s", depositErr, err.Error())) + cctx.SetAbort( + "revert failed", + fmt.Sprintf("deposit error: %s, processing error: %s", depositErr.Error(), err.Error())) return types.CctxStatus_Aborted } @@ -122,7 +124,7 @@ func (k Keeper) processFailedOutboundObservers(ctx sdk.Context, cctx *types.Cros if cctx.InboundParams.CoinType == coin.CoinType_Cmd { // if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.SetAbort("Outbound failed, cmd cctx reverted") + cctx.SetAbort("", "outbound failed for admin tx") } else if chains.IsZetaChain(cctx.InboundParams.SenderChainId, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) { switch cctx.InboundParams.CoinType { // Try revert if the coin-type is ZETA @@ -137,7 +139,7 @@ func (k Keeper) processFailedOutboundObservers(ctx sdk.Context, cctx *types.Cros default: { cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.SetAbort("Outbound failed for non-ZETA cctx") + cctx.SetAbort("", "outbound failed for non-ZETA cctx") } } } else { @@ -195,10 +197,10 @@ func (k Keeper) processFailedOutboundOnExternalChain( return err } // Not setting the finalization status here, the required changes have been made while creating the revert tx - cctx.SetPendingRevert(revertMsg) + cctx.SetPendingRevert("", revertMsg) case types.CctxStatus_PendingRevert: cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.SetAbort("Outbound failed: revert failed; abort TX") + cctx.SetAbort("aborted while processing failed outbound", "outbound and revert failed") } return nil } @@ -225,9 +227,9 @@ func (k Keeper) processSuccessfulOutbound( oldStatus := cctx.CctxStatus.Status switch oldStatus { case types.CctxStatus_PendingRevert: - cctx.SetReverted("Outbound succeeded, revert executed") + cctx.SetReverted("", "revert executed") case types.CctxStatus_PendingOutbound: - cctx.SetOutboundMined("Outbound succeeded, mined") + cctx.SetOutboundMined("") default: return } @@ -256,7 +258,7 @@ func (k Keeper) processFailedZETAOutboundOnZEVM(ctx sdk.Context, cctx *types.Cro } // Trying to revert the transaction this would get set to a finalized status in the same block as this does not need a TSS singing - cctx.SetPendingRevert("Outbound failed, trying revert") + cctx.SetPendingRevert("", "outbound failed") data, err := base64.StdEncoding.DecodeString(cctx.RelayedMessage) if err != nil { return fmt.Errorf("failed decoding relayed message: %s", err.Error()) @@ -290,7 +292,7 @@ func (k Keeper) processFailedZETAOutboundOnZEVM(ctx sdk.Context, cctx *types.Cro return fmt.Errorf("failed ZETARevertAndCallContract: %s", err.Error()) } - cctx.SetReverted("Outbound failed, revert executed") + cctx.SetReverted("", "outbound failed") if len(ctx.TxBytes()) > 0 { // add event for tendermint transaction hash format hash := tmbytes.HexBytes(tmtypes.Tx(ctx.TxBytes()).Hash()) @@ -336,7 +338,7 @@ func (k Keeper) processFailedOutboundV2(ctx sdk.Context, cctx *types.CrossChainT } // update status - cctx.SetPendingRevert("Outbound failed, trying revert") + cctx.SetPendingRevert("", "outbound failed") // process the revert on ZEVM if err := k.fungibleKeeper.ProcessV2RevertDeposit( @@ -354,7 +356,7 @@ func (k Keeper) processFailedOutboundV2(ctx sdk.Context, cctx *types.CrossChainT } // tx is reverted - cctx.SetReverted("Outbound failed, revert executed") + cctx.SetReverted("", "outbound failed") // add event for tendermint transaction hash format if len(ctx.TxBytes()) > 0 { @@ -367,7 +369,7 @@ func (k Keeper) processFailedOutboundV2(ctx sdk.Context, cctx *types.CrossChainT cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed case types.CctxStatus_PendingRevert: cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed - cctx.SetAbort("Outbound failed: revert failed; abort TX") + cctx.SetAbort("aborted while processing failed outbound", "outbound and revert failed") } return nil } diff --git a/x/crosschain/keeper/cctx_test.go b/x/crosschain/keeper/cctx_test.go index 8a51b4cf2a..d1e3f6fafc 100644 --- a/x/crosschain/keeper/cctx_test.go +++ b/x/crosschain/keeper/cctx_test.go @@ -170,7 +170,6 @@ func TestCCTXs(t *testing.T) { require.True(t, found) require.Equal(t, s, send) } - }) } } diff --git a/x/crosschain/keeper/initiate_outbound_test.go b/x/crosschain/keeper/initiate_outbound_test.go index 55ca3e36f8..204179bea5 100644 --- a/x/crosschain/keeper/initiate_outbound_test.go +++ b/x/crosschain/keeper/initiate_outbound_test.go @@ -76,7 +76,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { require.ErrorContains(t, err, "deposit error") require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) require.Equal(t, types.CctxStatus_Aborted, newStatus) - require.Equal(t, "deposit error", cctx.CctxStatus.StatusMessage) + require.Equal(t, "deposit error", cctx.CctxStatus.ErrorMessage) }) t.Run( @@ -111,7 +111,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { require.Equal(t, types.CctxStatus_Aborted, newStatus) require.Contains( t, - cctx.CctxStatus.StatusMessage, + cctx.CctxStatus.ErrorMessage, "chain not supported", ) }, @@ -151,7 +151,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { require.Equal(t, types.CctxStatus_Aborted, newStatus) require.Contains( t, - cctx.CctxStatus.StatusMessage, + cctx.CctxStatus.ErrorMessage, "GetRevertGasLimit: foreign coin not found for sender chain", ) }) @@ -194,7 +194,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { require.Equal(t, types.CctxStatus_Aborted, newStatus) require.Contains( t, - cctx.CctxStatus.StatusMessage, + cctx.CctxStatus.ErrorMessage, "chain not supported", ) }, @@ -239,7 +239,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { require.Equal(t, types.CctxStatus_Aborted, newStatus) require.Contains( t, - cctx.CctxStatus.StatusMessage, + cctx.CctxStatus.ErrorMessage, "chain not supported", ) }, @@ -284,7 +284,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { require.NoError(t, err) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) require.Equal(t, types.CctxStatus_Aborted, newStatus) - require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") + require.Contains(t, cctx.CctxStatus.ErrorMessage, "cannot find receiver chain nonce") }) t.Run("unable to process zevm deposit HandleEVMDeposit revert successfully", func(t *testing.T) { @@ -321,7 +321,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { require.NoError(t, err) require.Equal(t, types.CctxStatus_PendingRevert, cctx.CctxStatus.Status) require.Equal(t, types.CctxStatus_PendingRevert, newStatus) - require.Equal(t, errDeposit.Error(), cctx.CctxStatus.StatusMessage) + require.Equal(t, errDeposit.Error(), cctx.CctxStatus.ErrorMessage) require.Equal(t, updatedNonce, cctx.GetCurrentOutboundParam().TssNonce) }) @@ -361,7 +361,7 @@ func TestKeeper_InitiateOutboundZEVMDeposit(t *testing.T) { require.Equal(t, types.CctxStatus_Aborted, newStatus) require.Contains( t, - cctx.CctxStatus.StatusMessage, + cctx.CctxStatus.ErrorMessage, "cannot revert a revert tx", ) }, @@ -427,7 +427,7 @@ func TestKeeper_InitiateOutboundProcessCrosschainMsgPassing(t *testing.T) { require.ErrorIs(t, err, observertypes.ErrSupportedChains) require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) require.Equal(t, types.CctxStatus_Aborted, newStatus) - require.Equal(t, observertypes.ErrSupportedChains.Error(), cctx.CctxStatus.StatusMessage) + require.Equal(t, observertypes.ErrSupportedChains.Error(), cctx.CctxStatus.ErrorMessage) }) t.Run("unable to process crosschain msg passing UpdateNonce fails", func(t *testing.T) { @@ -456,7 +456,7 @@ func TestKeeper_InitiateOutboundProcessCrosschainMsgPassing(t *testing.T) { require.ErrorContains(t, err, "cannot find receiver chain nonce") require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) require.Equal(t, types.CctxStatus_Aborted, newStatus) - require.Contains(t, cctx.CctxStatus.StatusMessage, "cannot find receiver chain nonce") + require.Contains(t, cctx.CctxStatus.ErrorMessage, "cannot find receiver chain nonce") }) } diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds.go b/x/crosschain/keeper/msg_server_migrate_tss_funds.go index c285033f02..8ecc4c47ff 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds.go @@ -9,7 +9,6 @@ import ( tmbytes "github.com/cometbft/cometbft/libs/bytes" tmtypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/errors" authoritytypes "github.com/zeta-chain/node/x/authority/types" "github.com/zeta-chain/node/x/crosschain/types" @@ -26,7 +25,7 @@ func (k msgServer) MigrateTssFunds( // check if authorized err := k.GetAuthorityKeeper().CheckAuthorization(ctx, msg) if err != nil { - return nil, errors.Wrap(authoritytypes.ErrUnauthorized, err.Error()) + return nil, errorsmod.Wrap(authoritytypes.ErrUnauthorized, err.Error()) } if k.zetaObserverKeeper.IsInboundEnabled(ctx) { diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index e824a01707..5aa70be3bd 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -265,7 +265,7 @@ func TestKeeper_VoteInbound(t *testing.T) { }) } -func TestStatus_ChangeStatus(t *testing.T) { +func TestStatus_UpdateCctxStatus(t *testing.T) { tt := []struct { Name string Status types.Status @@ -302,7 +302,7 @@ func TestStatus_ChangeStatus(t *testing.T) { for _, test := range tt { test := test t.Run(test.Name, func(t *testing.T) { - test.Status.ChangeStatus(test.NonErrStatus, test.Msg) + test.Status.UpdateStatusAndErrorMessages(test.NonErrStatus, test.Msg, "") if test.IsErr { require.Equal(t, test.ErrStatus, test.Status.Status) } else { diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 6682c2c705..4bb65a3c8f 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -185,7 +185,7 @@ SaveFailedOutbound saves a failed outbound transaction.It does the following thi */ func (k Keeper) SaveFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, errMessage string, tssPubkey string) { - cctx.SetAbort(errMessage) + cctx.SetAbort("", errMessage) ctx.Logger().Error(errMessage) k.SaveOutbound(ctx, cctx, tssPubkey) } diff --git a/x/crosschain/migrations/v5/migrate.go b/x/crosschain/migrations/v5/migrate.go index aeeb22451f..0f21d8646b 100644 --- a/x/crosschain/migrations/v5/migrate.go +++ b/x/crosschain/migrations/v5/migrate.go @@ -137,6 +137,7 @@ func SetZetaAccounting( return nil } + func GetAbortedAmount(cctx types.CrossChainTx) sdkmath.Uint { if cctx.OutboundParams != nil && !cctx.GetCurrentOutboundParam().Amount.IsZero() { return cctx.GetCurrentOutboundParam().Amount diff --git a/x/crosschain/types/cctx.go b/x/crosschain/types/cctx.go index 0a235dffae..91004511d4 100644 --- a/x/crosschain/types/cctx.go +++ b/x/crosschain/types/cctx.go @@ -171,28 +171,28 @@ func (m *CrossChainTx) AddOutbound( } // SetAbort sets the CCTX status to Aborted with the given error message. -func (m CrossChainTx) SetAbort(message string) { - m.CctxStatus.ChangeStatus(CctxStatus_Aborted, message) +func (m CrossChainTx) SetAbort(statusMsg, errorMsg string) { + m.CctxStatus.UpdateStatusAndErrorMessages(CctxStatus_Aborted, statusMsg, errorMsg) } // SetPendingRevert sets the CCTX status to PendingRevert with the given error message. -func (m CrossChainTx) SetPendingRevert(message string) { - m.CctxStatus.ChangeStatus(CctxStatus_PendingRevert, message) +func (m CrossChainTx) SetPendingRevert(statusMsg, errorMsg string) { + m.CctxStatus.UpdateStatusAndErrorMessages(CctxStatus_PendingRevert, statusMsg, errorMsg) } // SetPendingOutbound sets the CCTX status to PendingOutbound with the given error message. -func (m CrossChainTx) SetPendingOutbound(message string) { - m.CctxStatus.ChangeStatus(CctxStatus_PendingOutbound, message) +func (m CrossChainTx) SetPendingOutbound(statusMsg string) { + m.CctxStatus.UpdateStatusAndErrorMessages(CctxStatus_PendingOutbound, statusMsg, "") } // SetOutboundMined sets the CCTX status to OutboundMined with the given error message. -func (m CrossChainTx) SetOutboundMined(message string) { - m.CctxStatus.ChangeStatus(CctxStatus_OutboundMined, message) +func (m CrossChainTx) SetOutboundMined(statusMsg string) { + m.CctxStatus.UpdateStatusAndErrorMessages(CctxStatus_OutboundMined, statusMsg, "") } // SetReverted sets the CCTX status to Reverted with the given error message. -func (m CrossChainTx) SetReverted(message string) { - m.CctxStatus.ChangeStatus(CctxStatus_Reverted, message) +func (m CrossChainTx) SetReverted(statusMsg, errorMsg string) { + m.CctxStatus.UpdateStatusAndErrorMessages(CctxStatus_Reverted, statusMsg, errorMsg) } func (m CrossChainTx) GetCCTXIndexBytes() ([32]byte, error) { @@ -259,6 +259,7 @@ func NewCCTX(ctx sdk.Context, msg MsgVoteInbound, tssPubkey string) (CrossChainT status := &Status{ Status: CctxStatus_PendingInbound, StatusMessage: "", + ErrorMessage: "", CreatedTimestamp: ctx.BlockHeader().Time.Unix(), LastUpdateTimestamp: ctx.BlockHeader().Time.Unix(), IsAbortRefunded: false, diff --git a/x/crosschain/types/cctx_test.go b/x/crosschain/types/cctx_test.go index 00fbe2ac66..f49768f8a0 100644 --- a/x/crosschain/types/cctx_test.go +++ b/x/crosschain/types/cctx_test.go @@ -150,17 +150,20 @@ func Test_SetRevertOutboundValues(t *testing.T) { func TestCrossChainTx_SetAbort(t *testing.T) { cctx := sample.CrossChainTx(t, "test") - cctx.SetAbort("test") + cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound + cctx.SetAbort("test", "test") require.Equal(t, types.CctxStatus_Aborted, cctx.CctxStatus.Status) - require.Equal(t, "test", "test") + require.Contains(t, cctx.CctxStatus.StatusMessage, "test") + require.Contains(t, cctx.CctxStatus.ErrorMessage, "test") } func TestCrossChainTx_SetPendingRevert(t *testing.T) { cctx := sample.CrossChainTx(t, "test") cctx.CctxStatus.Status = types.CctxStatus_PendingOutbound - cctx.SetPendingRevert("test") + cctx.SetPendingRevert("test", "test") require.Equal(t, types.CctxStatus_PendingRevert, cctx.CctxStatus.Status) require.Contains(t, cctx.CctxStatus.StatusMessage, "test") + require.Contains(t, cctx.CctxStatus.ErrorMessage, "test") } func TestCrossChainTx_SetPendingOutbound(t *testing.T) { @@ -169,6 +172,7 @@ func TestCrossChainTx_SetPendingOutbound(t *testing.T) { cctx.SetPendingOutbound("test") require.Equal(t, types.CctxStatus_PendingOutbound, cctx.CctxStatus.Status) require.Contains(t, cctx.CctxStatus.StatusMessage, "test") + require.NotContains(t, cctx.CctxStatus.ErrorMessage, "test") } func TestCrossChainTx_SetOutboundMined(t *testing.T) { @@ -177,12 +181,14 @@ func TestCrossChainTx_SetOutboundMined(t *testing.T) { cctx.SetOutboundMined("test") require.Equal(t, types.CctxStatus_OutboundMined, cctx.CctxStatus.Status) require.Contains(t, cctx.CctxStatus.StatusMessage, "test") + require.NotContains(t, cctx.CctxStatus.ErrorMessage, "test") } func TestCrossChainTx_SetReverted(t *testing.T) { cctx := sample.CrossChainTx(t, "test") cctx.CctxStatus.Status = types.CctxStatus_PendingRevert - cctx.SetReverted("test") + cctx.SetReverted("test", "test") require.Equal(t, types.CctxStatus_Reverted, cctx.CctxStatus.Status) require.Contains(t, cctx.CctxStatus.StatusMessage, "test") + require.Contains(t, cctx.CctxStatus.ErrorMessage, "test") } diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index 842ba310ba..23923a9cbf 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -488,10 +488,15 @@ func (m *OutboundParams) GetCallOptions() *CallOptions { } type Status struct { - Status CctxStatus `protobuf:"varint,1,opt,name=status,proto3,enum=zetachain.zetacore.crosschain.CctxStatus" json:"status,omitempty"` - StatusMessage string `protobuf:"bytes,2,opt,name=status_message,json=statusMessage,proto3" json:"status_message,omitempty"` - LastUpdateTimestamp int64 `protobuf:"varint,3,opt,name=lastUpdate_timestamp,json=lastUpdateTimestamp,proto3" json:"lastUpdate_timestamp,omitempty"` - IsAbortRefunded bool `protobuf:"varint,4,opt,name=isAbortRefunded,proto3" json:"isAbortRefunded,omitempty"` + Status CctxStatus `protobuf:"varint,1,opt,name=status,proto3,enum=zetachain.zetacore.crosschain.CctxStatus" json:"status,omitempty"` + // status_message carries information about the status transitions: + // why they were triggered, old and new status. + StatusMessage string `protobuf:"bytes,2,opt,name=status_message,json=statusMessage,proto3" json:"status_message,omitempty"` + // error_message carries information about the error that caused the tx + // to be PendingRevert, Reverted or Aborted. + ErrorMessage string `protobuf:"bytes,6,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"` + LastUpdateTimestamp int64 `protobuf:"varint,3,opt,name=lastUpdate_timestamp,json=lastUpdateTimestamp,proto3" json:"lastUpdate_timestamp,omitempty"` + IsAbortRefunded bool `protobuf:"varint,4,opt,name=isAbortRefunded,proto3" json:"isAbortRefunded,omitempty"` // when the CCTX was created. only populated on new transactions. CreatedTimestamp int64 `protobuf:"varint,5,opt,name=created_timestamp,json=createdTimestamp,proto3" json:"created_timestamp,omitempty"` } @@ -543,6 +548,13 @@ func (m *Status) GetStatusMessage() string { return "" } +func (m *Status) GetErrorMessage() string { + if m != nil { + return m.ErrorMessage + } + return "" +} + func (m *Status) GetLastUpdateTimestamp() int64 { if m != nil { return m.LastUpdateTimestamp @@ -753,92 +765,93 @@ func init() { } var fileDescriptor_d4c1966807fb5cb2 = []byte{ - // 1348 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0x4d, 0x6f, 0x1b, 0x37, - 0x13, 0xf6, 0xda, 0xb2, 0x2c, 0x8d, 0x3e, 0xbc, 0xa6, 0x15, 0x67, 0xe3, 0x17, 0x51, 0xfc, 0xaa, - 0x75, 0xa2, 0xb8, 0xb5, 0x84, 0x28, 0x40, 0x51, 0xf4, 0x66, 0x1b, 0x71, 0xe2, 0xb6, 0x89, 0x8d, - 0x8d, 0x63, 0x20, 0x39, 0x74, 0x4b, 0xed, 0xd2, 0x12, 0xe1, 0xd5, 0x52, 0x5d, 0x52, 0x86, 0x14, - 0xf4, 0xd6, 0x73, 0x81, 0xfe, 0x88, 0x1e, 0x7a, 0xec, 0xcf, 0xc8, 0x31, 0xc7, 0xa2, 0x87, 0x20, - 0x48, 0xfe, 0x41, 0xcf, 0x3d, 0x14, 0xfc, 0x92, 0xac, 0xc0, 0xb5, 0xd3, 0xb4, 0x27, 0x71, 0x66, - 0x38, 0xcf, 0xcc, 0x0e, 0xe7, 0x19, 0x52, 0xd0, 0x7a, 0x4e, 0x04, 0x0e, 0xbb, 0x98, 0x26, 0x4d, - 0xb5, 0x62, 0x29, 0x69, 0x86, 0x29, 0xe3, 0x5c, 0xeb, 0xd4, 0x32, 0x50, 0xeb, 0x40, 0x0c, 0x1b, - 0xfd, 0x94, 0x09, 0x86, 0xae, 0x8f, 0x7d, 0x1a, 0xd6, 0xa7, 0x31, 0xf1, 0x59, 0xad, 0x74, 0x58, - 0x87, 0xa9, 0x9d, 0x4d, 0xb9, 0xd2, 0x4e, 0xab, 0x37, 0xcf, 0x09, 0xd4, 0x3f, 0xe9, 0x34, 0x43, - 0x26, 0xc3, 0x30, 0x9a, 0xe8, 0x7d, 0xb5, 0x5f, 0x33, 0x50, 0xda, 0x4b, 0xda, 0x6c, 0x90, 0x44, - 0x07, 0x38, 0xc5, 0x3d, 0x8e, 0x56, 0x20, 0xcb, 0x49, 0x12, 0x91, 0xd4, 0x73, 0xd6, 0x9c, 0x7a, - 0xde, 0x37, 0x12, 0xba, 0x09, 0x8b, 0x7a, 0x65, 0xf2, 0xa3, 0x91, 0x37, 0xbb, 0xe6, 0xd4, 0xe7, - 0xfc, 0x92, 0x56, 0xef, 0x48, 0xed, 0x5e, 0x84, 0xfe, 0x07, 0x79, 0x31, 0x0c, 0x58, 0x4a, 0x3b, - 0x34, 0xf1, 0xe6, 0x14, 0x44, 0x4e, 0x0c, 0xf7, 0x95, 0x8c, 0xb6, 0x21, 0x2f, 0x83, 0x07, 0x62, - 0xd4, 0x27, 0x5e, 0x66, 0xcd, 0xa9, 0x97, 0x5b, 0xeb, 0x8d, 0x73, 0xbe, 0xaf, 0x7f, 0xd2, 0x69, - 0xa8, 0x2c, 0x77, 0x18, 0x4d, 0x0e, 0x47, 0x7d, 0xe2, 0xe7, 0x42, 0xb3, 0x42, 0x15, 0x98, 0xc7, - 0x9c, 0x13, 0xe1, 0xcd, 0x2b, 0x70, 0x2d, 0xa0, 0xfb, 0x90, 0xc5, 0x3d, 0x36, 0x48, 0x84, 0x97, - 0x95, 0xea, 0xed, 0xe6, 0x8b, 0x57, 0x37, 0x66, 0x7e, 0x7f, 0x75, 0xe3, 0x56, 0x87, 0x8a, 0xee, - 0xa0, 0xdd, 0x08, 0x59, 0xaf, 0x19, 0x32, 0xde, 0x63, 0xdc, 0xfc, 0x6c, 0xf2, 0xe8, 0xa4, 0x29, - 0xf3, 0xe0, 0x8d, 0x27, 0x34, 0x11, 0xbe, 0x71, 0x47, 0x1f, 0x41, 0x89, 0xb5, 0x39, 0x49, 0x4f, - 0x49, 0x14, 0x74, 0x31, 0xef, 0x7a, 0x0b, 0x2a, 0x4c, 0xd1, 0x2a, 0x1f, 0x60, 0xde, 0x45, 0x9f, - 0x83, 0x37, 0xde, 0x44, 0x86, 0x82, 0xa4, 0x09, 0x8e, 0x83, 0x2e, 0xa1, 0x9d, 0xae, 0xf0, 0x72, - 0x6b, 0x4e, 0x3d, 0xe3, 0xaf, 0x58, 0xfb, 0x3d, 0x63, 0x7e, 0xa0, 0xac, 0xe8, 0xff, 0x50, 0x6c, - 0xe3, 0x38, 0x66, 0x22, 0xa0, 0x49, 0x44, 0x86, 0x5e, 0x5e, 0xa1, 0x17, 0xb4, 0x6e, 0x4f, 0xaa, - 0x50, 0x0b, 0xae, 0x1c, 0xd3, 0x04, 0xc7, 0xf4, 0x39, 0x89, 0x02, 0x59, 0x12, 0x8b, 0x0c, 0x0a, - 0x79, 0x79, 0x6c, 0x7c, 0x46, 0x04, 0x36, 0xb0, 0x14, 0x56, 0xc4, 0x30, 0x30, 0x16, 0x2c, 0x28, - 0x4b, 0x02, 0x2e, 0xb0, 0x18, 0x70, 0xaf, 0xa0, 0xaa, 0x7c, 0xb7, 0x71, 0x61, 0x17, 0x35, 0x0e, - 0x87, 0xbb, 0x67, 0x7c, 0x1f, 0x2b, 0x57, 0xbf, 0x22, 0xce, 0xd1, 0xd6, 0xbe, 0x83, 0xb2, 0x0c, - 0xbc, 0x15, 0x86, 0xb2, 0x5e, 0x34, 0xe9, 0xa0, 0x00, 0x96, 0x71, 0x9b, 0xa5, 0xc2, 0xa6, 0x6b, - 0x0e, 0xc2, 0xf9, 0xb0, 0x83, 0x58, 0x32, 0x58, 0x2a, 0x88, 0x42, 0xaa, 0x1d, 0x41, 0x61, 0x07, - 0xc7, 0xf1, 0x7e, 0x5f, 0xa6, 0xc1, 0x65, 0x8b, 0x75, 0x30, 0x0f, 0x62, 0xda, 0xa3, 0x3a, 0x4a, - 0xc6, 0xcf, 0x75, 0x30, 0xff, 0x5a, 0xca, 0x68, 0x03, 0x96, 0x28, 0x0f, 0x70, 0xda, 0xa6, 0x22, - 0xc5, 0xe9, 0x28, 0x08, 0x71, 0x1c, 0xab, 0x4e, 0xcd, 0xf9, 0x8b, 0x94, 0x6f, 0x59, 0xbd, 0xc4, - 0xab, 0xbd, 0xce, 0x42, 0x79, 0x7f, 0x20, 0xce, 0xb6, 0xff, 0x2a, 0xe4, 0x52, 0x12, 0x12, 0x7a, - 0x3a, 0x26, 0xc0, 0x58, 0x46, 0xb7, 0xc1, 0xb5, 0x6b, 0x4d, 0x82, 0x3d, 0xcb, 0x81, 0x45, 0xab, - 0xb7, 0x2c, 0x98, 0x6a, 0xf4, 0xb9, 0x0f, 0x6b, 0xf4, 0x49, 0x4b, 0x67, 0xfe, 0x5d, 0x4b, 0x4b, - 0x4a, 0x72, 0x1e, 0x24, 0x2c, 0x09, 0x89, 0x62, 0x4d, 0xc6, 0xcf, 0x09, 0xce, 0x1f, 0x49, 0x79, - 0xba, 0x98, 0xd9, 0x77, 0x8a, 0x69, 0x8c, 0xfd, 0x94, 0x86, 0xc4, 0x10, 0x41, 0x1a, 0x0f, 0xa4, - 0x8c, 0xea, 0xe0, 0x1a, 0x23, 0x4b, 0xa9, 0x18, 0x05, 0xc7, 0x84, 0x78, 0x57, 0xd5, 0x9e, 0xb2, - 0xde, 0xa3, 0xd4, 0xbb, 0x84, 0x20, 0x04, 0x19, 0x45, 0xa5, 0x9c, 0xb2, 0xaa, 0xf5, 0xfb, 0x10, - 0xe1, 0x22, 0x96, 0xc1, 0x85, 0x2c, 0xbb, 0x06, 0x32, 0xcd, 0x60, 0xc0, 0x49, 0xe4, 0x55, 0xd4, - 0xce, 0x85, 0x0e, 0xe6, 0x4f, 0x38, 0x89, 0xd0, 0x37, 0xb0, 0x4c, 0x8e, 0x8f, 0x49, 0x28, 0xe8, - 0x29, 0x09, 0x26, 0x1f, 0x77, 0x45, 0x95, 0xb8, 0x61, 0x4a, 0x7c, 0xf3, 0x3d, 0x4a, 0xbc, 0x27, - 0x7b, 0x75, 0x0c, 0x75, 0xdf, 0x56, 0xa5, 0xf1, 0x2e, 0xbe, 0xae, 0xec, 0x8a, 0xca, 0x62, 0x6a, - 0xbf, 0x2e, 0xf1, 0x75, 0x00, 0x79, 0x38, 0xfd, 0x41, 0xfb, 0x84, 0x8c, 0x14, 0x5b, 0xf3, 0xbe, - 0x3c, 0xae, 0x03, 0xa5, 0xb8, 0x80, 0xd8, 0xc5, 0xff, 0x98, 0xd8, 0xe8, 0x21, 0x14, 0x25, 0x59, - 0x02, 0xa6, 0x69, 0xe6, 0x79, 0x6b, 0x4e, 0xbd, 0xd0, 0xda, 0xb8, 0x24, 0xc0, 0x19, 0x62, 0xfa, - 0x85, 0x70, 0x22, 0x7c, 0x99, 0xc9, 0x95, 0xdc, 0x4a, 0xed, 0x4f, 0x07, 0xb2, 0x06, 0x7f, 0x0b, - 0xb2, 0x26, 0x75, 0x47, 0xa5, 0x7e, 0xfb, 0x32, 0xe4, 0x50, 0x0c, 0x4d, 0xc2, 0xc6, 0x11, 0xad, - 0x43, 0x59, 0xaf, 0x82, 0x1e, 0xe1, 0x1c, 0x77, 0x88, 0xe2, 0x5f, 0xde, 0x2f, 0x69, 0xed, 0x43, - 0xad, 0x44, 0x77, 0xa0, 0x12, 0x63, 0x2e, 0x9e, 0xf4, 0x23, 0x2c, 0x48, 0x20, 0x68, 0x8f, 0x70, - 0x81, 0x7b, 0x7d, 0x45, 0xc4, 0x39, 0x7f, 0x79, 0x62, 0x3b, 0xb4, 0x26, 0x54, 0x07, 0x39, 0x1d, - 0xe4, 0xe4, 0xf1, 0xc9, 0xf1, 0x20, 0x89, 0x48, 0xa4, 0x58, 0xa7, 0x87, 0xc6, 0x59, 0x35, 0xfa, - 0x04, 0x96, 0xc2, 0x94, 0x60, 0x39, 0xed, 0x26, 0xc8, 0xf3, 0x0a, 0xd9, 0x35, 0x86, 0x31, 0x6c, - 0xed, 0x87, 0x59, 0x28, 0xf9, 0xe4, 0x94, 0xa4, 0xc2, 0x0e, 0xaf, 0x75, 0x28, 0xa7, 0x4a, 0x11, - 0xe0, 0x28, 0x4a, 0x09, 0xe7, 0x66, 0xcc, 0x94, 0xb4, 0x76, 0x4b, 0x2b, 0xd1, 0xc7, 0x50, 0xd6, - 0x87, 0x91, 0x04, 0xda, 0x60, 0x66, 0x98, 0x3a, 0xa2, 0xfd, 0x44, 0x63, 0xca, 0xcb, 0x4a, 0x4d, - 0xcb, 0x31, 0x96, 0xbe, 0x70, 0x8b, 0x4a, 0x69, 0xa1, 0x26, 0x11, 0x6d, 0xd1, 0xe4, 0x97, 0x15, - 0x6d, 0x44, 0x5b, 0xb4, 0xa7, 0x72, 0xba, 0xa9, 0x6d, 0x93, 0xae, 0x9d, 0xff, 0xb0, 0xc1, 0x63, - 0xe2, 0xd9, 0x1e, 0xaf, 0xfd, 0x38, 0x0f, 0xc5, 0x1d, 0x79, 0xb0, 0x6a, 0x3c, 0x1e, 0x0e, 0x91, - 0x07, 0x0b, 0xaa, 0x54, 0xcc, 0x0e, 0x59, 0x2b, 0xca, 0xdb, 0x5d, 0xcf, 0x03, 0x7d, 0xb0, 0x5a, - 0x40, 0xdf, 0x42, 0x5e, 0xdd, 0x2c, 0xc7, 0x84, 0x70, 0x93, 0xd4, 0xce, 0x3f, 0x4c, 0xea, 0x8f, - 0x57, 0x37, 0xdc, 0x11, 0xee, 0xc5, 0x5f, 0xd4, 0xc6, 0x48, 0x35, 0x3f, 0x27, 0xd7, 0xbb, 0x84, - 0x70, 0x74, 0x0b, 0x16, 0x53, 0x12, 0xe3, 0x11, 0x89, 0xc6, 0x55, 0xca, 0xea, 0x59, 0x66, 0xd4, - 0xb6, 0x4c, 0xbb, 0x50, 0x08, 0x43, 0x31, 0xb4, 0x2c, 0xcc, 0x29, 0x92, 0xac, 0x5f, 0xd2, 0xca, - 0xa6, 0x8d, 0x21, 0x1c, 0xb7, 0x34, 0x7a, 0x0c, 0x65, 0xaa, 0x1f, 0x5e, 0x41, 0x5f, 0x5d, 0x3d, - 0x6a, 0x02, 0x16, 0x5a, 0x9f, 0x5e, 0x02, 0x35, 0xf5, 0x5a, 0xf3, 0x4b, 0x74, 0xea, 0xf1, 0x76, - 0x04, 0x8b, 0xcc, 0xdc, 0x67, 0x16, 0x15, 0xd6, 0xe6, 0xea, 0x85, 0xd6, 0xe6, 0x25, 0xa8, 0xd3, - 0xb7, 0xa0, 0x5f, 0x66, 0xd3, 0xb7, 0x62, 0x0a, 0xd7, 0xd4, 0x7b, 0x31, 0x64, 0x71, 0x10, 0xb2, - 0x44, 0xa4, 0x38, 0x14, 0xc1, 0x29, 0x49, 0x39, 0x65, 0x89, 0x79, 0x61, 0x7c, 0x76, 0x49, 0x84, - 0x03, 0xe3, 0xbf, 0x63, 0xdc, 0x8f, 0xb4, 0xb7, 0x7f, 0xb5, 0x7f, 0xbe, 0x01, 0x3d, 0x1d, 0xb7, - 0xad, 0x1d, 0x48, 0xc5, 0xf7, 0x2a, 0xd0, 0x14, 0xdd, 0xb6, 0x33, 0xb2, 0x4d, 0x6c, 0xab, 0x1b, - 0xe5, 0xc6, 0xf7, 0x00, 0x93, 0xe1, 0x82, 0x10, 0x94, 0x0f, 0x48, 0x12, 0xd1, 0xa4, 0x63, 0x6a, - 0xeb, 0xce, 0xa0, 0x65, 0x58, 0x34, 0x3a, 0x5b, 0x19, 0xd7, 0x41, 0x4b, 0x50, 0xb2, 0xd2, 0x43, - 0x9a, 0x90, 0xc8, 0x9d, 0x93, 0x2a, 0xb3, 0x4f, 0x87, 0x75, 0x33, 0xa8, 0x08, 0x39, 0xbd, 0x26, - 0x91, 0x3b, 0x8f, 0x0a, 0xb0, 0xb0, 0xa5, 0xdf, 0x33, 0x6e, 0x76, 0x35, 0xf3, 0xcb, 0xcf, 0x55, - 0x67, 0xe3, 0x2b, 0xa8, 0x9c, 0x37, 0x95, 0x91, 0x0b, 0xc5, 0x47, 0x4c, 0xec, 0xda, 0xd7, 0x9d, - 0x3b, 0x83, 0x4a, 0x90, 0x9f, 0x88, 0x8e, 0x44, 0xbe, 0x37, 0x24, 0xe1, 0x40, 0x82, 0xcd, 0x1a, - 0xb0, 0x26, 0x5c, 0xfd, 0x9b, 0xca, 0xa2, 0x2c, 0xcc, 0x1e, 0xdd, 0x71, 0x67, 0xd4, 0x6f, 0xcb, - 0x75, 0xb4, 0xc3, 0xf6, 0xfd, 0x17, 0x6f, 0xaa, 0xce, 0xcb, 0x37, 0x55, 0xe7, 0xf5, 0x9b, 0xaa, - 0xf3, 0xd3, 0xdb, 0xea, 0xcc, 0xcb, 0xb7, 0xd5, 0x99, 0xdf, 0xde, 0x56, 0x67, 0x9e, 0x6d, 0x9e, - 0x61, 0x92, 0x2c, 0xec, 0xa6, 0xfe, 0xff, 0x90, 0xb0, 0x88, 0x34, 0x87, 0x67, 0xff, 0xa6, 0x28, - 0x52, 0xb5, 0xb3, 0xea, 0xe0, 0xee, 0xfe, 0x15, 0x00, 0x00, 0xff, 0xff, 0x94, 0x4b, 0x30, 0xb4, - 0xd4, 0x0c, 0x00, 0x00, + // 1361 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcf, 0x6e, 0x1b, 0xb7, + 0x13, 0xf6, 0xda, 0xb2, 0x2c, 0x8d, 0xfe, 0x78, 0x4d, 0x2b, 0xce, 0xc6, 0x3f, 0x44, 0xf1, 0x4f, + 0xad, 0x13, 0xc5, 0xad, 0x25, 0x44, 0x01, 0x8a, 0xa2, 0x37, 0xdb, 0x88, 0x13, 0xb7, 0x4d, 0x6c, + 0x6c, 0x1c, 0x03, 0xc9, 0xa1, 0x5b, 0x6a, 0x97, 0x96, 0x08, 0xaf, 0x96, 0xea, 0x92, 0x32, 0xa4, + 0xa0, 0xb7, 0x9e, 0x0b, 0xf4, 0x15, 0x0a, 0xf4, 0xd0, 0x63, 0x1f, 0x23, 0xc7, 0x1c, 0x8b, 0x1e, + 0x82, 0x20, 0x79, 0x83, 0x3e, 0x41, 0xc1, 0x7f, 0x92, 0x15, 0xb8, 0x76, 0x9a, 0xf6, 0x24, 0xf2, + 0x1b, 0xf2, 0x9b, 0xd9, 0xe1, 0x7c, 0x43, 0x0a, 0x5a, 0xcf, 0x89, 0xc0, 0x61, 0x17, 0xd3, 0xa4, + 0xa9, 0x46, 0x2c, 0x25, 0xcd, 0x30, 0x65, 0x9c, 0x6b, 0x4c, 0x0d, 0x03, 0x35, 0x0e, 0xc4, 0xb0, + 0xd1, 0x4f, 0x99, 0x60, 0xe8, 0xfa, 0x78, 0x4f, 0xc3, 0xee, 0x69, 0x4c, 0xf6, 0xac, 0x56, 0x3a, + 0xac, 0xc3, 0xd4, 0xca, 0xa6, 0x1c, 0xe9, 0x4d, 0xab, 0x37, 0xcf, 0x71, 0xd4, 0x3f, 0xe9, 0x34, + 0x43, 0x26, 0xdd, 0x30, 0x9a, 0xe8, 0x75, 0xb5, 0xdf, 0x32, 0x50, 0xda, 0x4b, 0xda, 0x6c, 0x90, + 0x44, 0x07, 0x38, 0xc5, 0x3d, 0x8e, 0x56, 0x20, 0xcb, 0x49, 0x12, 0x91, 0xd4, 0x73, 0xd6, 0x9c, + 0x7a, 0xde, 0x37, 0x33, 0x74, 0x13, 0x16, 0xf5, 0xc8, 0xc4, 0x47, 0x23, 0x6f, 0x76, 0xcd, 0xa9, + 0xcf, 0xf9, 0x25, 0x0d, 0xef, 0x48, 0x74, 0x2f, 0x42, 0xff, 0x83, 0xbc, 0x18, 0x06, 0x2c, 0xa5, + 0x1d, 0x9a, 0x78, 0x73, 0x8a, 0x22, 0x27, 0x86, 0xfb, 0x6a, 0x8e, 0xb6, 0x21, 0x2f, 0x9d, 0x07, + 0x62, 0xd4, 0x27, 0x5e, 0x66, 0xcd, 0xa9, 0x97, 0x5b, 0xeb, 0x8d, 0x73, 0xbe, 0xaf, 0x7f, 0xd2, + 0x69, 0xa8, 0x28, 0x77, 0x18, 0x4d, 0x0e, 0x47, 0x7d, 0xe2, 0xe7, 0x42, 0x33, 0x42, 0x15, 0x98, + 0xc7, 0x9c, 0x13, 0xe1, 0xcd, 0x2b, 0x72, 0x3d, 0x41, 0xf7, 0x21, 0x8b, 0x7b, 0x6c, 0x90, 0x08, + 0x2f, 0x2b, 0xe1, 0xed, 0xe6, 0x8b, 0x57, 0x37, 0x66, 0xfe, 0x78, 0x75, 0xe3, 0x56, 0x87, 0x8a, + 0xee, 0xa0, 0xdd, 0x08, 0x59, 0xaf, 0x19, 0x32, 0xde, 0x63, 0xdc, 0xfc, 0x6c, 0xf2, 0xe8, 0xa4, + 0x29, 0xe3, 0xe0, 0x8d, 0x27, 0x34, 0x11, 0xbe, 0xd9, 0x8e, 0x3e, 0x82, 0x12, 0x6b, 0x73, 0x92, + 0x9e, 0x92, 0x28, 0xe8, 0x62, 0xde, 0xf5, 0x16, 0x94, 0x9b, 0xa2, 0x05, 0x1f, 0x60, 0xde, 0x45, + 0x9f, 0x83, 0x37, 0x5e, 0x44, 0x86, 0x82, 0xa4, 0x09, 0x8e, 0x83, 0x2e, 0xa1, 0x9d, 0xae, 0xf0, + 0x72, 0x6b, 0x4e, 0x3d, 0xe3, 0xaf, 0x58, 0xfb, 0x3d, 0x63, 0x7e, 0xa0, 0xac, 0xe8, 0xff, 0x50, + 0x6c, 0xe3, 0x38, 0x66, 0x22, 0xa0, 0x49, 0x44, 0x86, 0x5e, 0x5e, 0xb1, 0x17, 0x34, 0xb6, 0x27, + 0x21, 0xd4, 0x82, 0x2b, 0xc7, 0x34, 0xc1, 0x31, 0x7d, 0x4e, 0xa2, 0x40, 0xa6, 0xc4, 0x32, 0x83, + 0x62, 0x5e, 0x1e, 0x1b, 0x9f, 0x11, 0x81, 0x0d, 0x2d, 0x85, 0x15, 0x31, 0x0c, 0x8c, 0x05, 0x0b, + 0xca, 0x92, 0x80, 0x0b, 0x2c, 0x06, 0xdc, 0x2b, 0xa8, 0x2c, 0xdf, 0x6d, 0x5c, 0x58, 0x45, 0x8d, + 0xc3, 0xe1, 0xee, 0x99, 0xbd, 0x8f, 0xd5, 0x56, 0xbf, 0x22, 0xce, 0x41, 0x6b, 0xdf, 0x41, 0x59, + 0x3a, 0xde, 0x0a, 0x43, 0x99, 0x2f, 0x9a, 0x74, 0x50, 0x00, 0xcb, 0xb8, 0xcd, 0x52, 0x61, 0xc3, + 0x35, 0x07, 0xe1, 0x7c, 0xd8, 0x41, 0x2c, 0x19, 0x2e, 0xe5, 0x44, 0x31, 0xd5, 0x8e, 0xa0, 0xb0, + 0x83, 0xe3, 0x78, 0xbf, 0x2f, 0xc3, 0xe0, 0xb2, 0xc4, 0x3a, 0x98, 0x07, 0x31, 0xed, 0x51, 0xed, + 0x25, 0xe3, 0xe7, 0x3a, 0x98, 0x7f, 0x2d, 0xe7, 0x68, 0x03, 0x96, 0x28, 0x0f, 0x70, 0xda, 0xa6, + 0x22, 0xc5, 0xe9, 0x28, 0x08, 0x71, 0x1c, 0xab, 0x4a, 0xcd, 0xf9, 0x8b, 0x94, 0x6f, 0x59, 0x5c, + 0xf2, 0xd5, 0x5e, 0x67, 0xa1, 0xbc, 0x3f, 0x10, 0x67, 0xcb, 0x7f, 0x15, 0x72, 0x29, 0x09, 0x09, + 0x3d, 0x1d, 0x0b, 0x60, 0x3c, 0x47, 0xb7, 0xc1, 0xb5, 0x63, 0x2d, 0x82, 0x3d, 0xab, 0x81, 0x45, + 0x8b, 0x5b, 0x15, 0x4c, 0x15, 0xfa, 0xdc, 0x87, 0x15, 0xfa, 0xa4, 0xa4, 0x33, 0xff, 0xae, 0xa4, + 0xa5, 0x24, 0x39, 0x0f, 0x12, 0x96, 0x84, 0x44, 0xa9, 0x26, 0xe3, 0xe7, 0x04, 0xe7, 0x8f, 0xe4, + 0x7c, 0x3a, 0x99, 0xd9, 0x77, 0x92, 0x69, 0x8c, 0xfd, 0x94, 0x86, 0xc4, 0x08, 0x41, 0x1a, 0x0f, + 0xe4, 0x1c, 0xd5, 0xc1, 0x35, 0x46, 0x96, 0x52, 0x31, 0x0a, 0x8e, 0x09, 0xf1, 0xae, 0xaa, 0x35, + 0x65, 0xbd, 0x46, 0xc1, 0xbb, 0x84, 0x20, 0x04, 0x19, 0x25, 0xa5, 0x9c, 0xb2, 0xaa, 0xf1, 0xfb, + 0x08, 0xe1, 0x22, 0x95, 0xc1, 0x85, 0x2a, 0xbb, 0x06, 0x32, 0xcc, 0x60, 0xc0, 0x49, 0xe4, 0x55, + 0xd4, 0xca, 0x85, 0x0e, 0xe6, 0x4f, 0x38, 0x89, 0xd0, 0x37, 0xb0, 0x4c, 0x8e, 0x8f, 0x49, 0x28, + 0xe8, 0x29, 0x09, 0x26, 0x1f, 0x77, 0x45, 0xa5, 0xb8, 0x61, 0x52, 0x7c, 0xf3, 0x3d, 0x52, 0xbc, + 0x27, 0x6b, 0x75, 0x4c, 0x75, 0xdf, 0x66, 0xa5, 0xf1, 0x2e, 0xbf, 0xce, 0xec, 0x8a, 0x8a, 0x62, + 0x6a, 0xbd, 0x4e, 0xf1, 0x75, 0x00, 0x79, 0x38, 0xfd, 0x41, 0xfb, 0x84, 0x8c, 0x94, 0x5a, 0xf3, + 0xbe, 0x3c, 0xae, 0x03, 0x05, 0x5c, 0x20, 0xec, 0xe2, 0x7f, 0x2c, 0x6c, 0xf4, 0x10, 0x8a, 0x52, + 0x2c, 0x01, 0xd3, 0x32, 0xf3, 0xbc, 0x35, 0xa7, 0x5e, 0x68, 0x6d, 0x5c, 0xe2, 0xe0, 0x8c, 0x30, + 0xfd, 0x42, 0x38, 0x99, 0x7c, 0x99, 0xc9, 0x95, 0xdc, 0x4a, 0xed, 0xe7, 0x59, 0xc8, 0x1a, 0xfe, + 0x2d, 0xc8, 0x9a, 0xd0, 0x1d, 0x15, 0xfa, 0xed, 0xcb, 0x98, 0x43, 0x31, 0x34, 0x01, 0x9b, 0x8d, + 0x68, 0x1d, 0xca, 0x7a, 0x14, 0xf4, 0x08, 0xe7, 0xb8, 0x43, 0x94, 0xfe, 0xf2, 0x7e, 0x49, 0xa3, + 0x0f, 0x35, 0x28, 0x7b, 0x38, 0x49, 0x53, 0x96, 0x8e, 0x57, 0x65, 0x75, 0x0f, 0x57, 0xa0, 0x5d, + 0x74, 0x07, 0x2a, 0x31, 0xe6, 0xe2, 0x49, 0x3f, 0xc2, 0x82, 0x04, 0x82, 0xf6, 0x08, 0x17, 0xb8, + 0xd7, 0x57, 0x6a, 0x9d, 0xf3, 0x97, 0x27, 0xb6, 0x43, 0x6b, 0x42, 0x75, 0x90, 0x2d, 0x44, 0xb6, + 0x27, 0x9f, 0x1c, 0x0f, 0x92, 0x88, 0x44, 0x4a, 0x9a, 0xba, 0xb3, 0x9c, 0x85, 0xd1, 0x27, 0xb0, + 0x14, 0xa6, 0x04, 0xcb, 0x96, 0x38, 0x61, 0x9e, 0x57, 0xcc, 0xae, 0x31, 0x8c, 0x69, 0x6b, 0x3f, + 0xcc, 0x42, 0xc9, 0x27, 0xa7, 0x24, 0x15, 0xb6, 0xc3, 0xad, 0x43, 0x39, 0x55, 0x40, 0x80, 0xa3, + 0x28, 0x25, 0x9c, 0x9b, 0x5e, 0x54, 0xd2, 0xe8, 0x96, 0x06, 0xd1, 0xc7, 0x50, 0xd6, 0x27, 0x96, + 0x04, 0xda, 0x60, 0x1a, 0x9d, 0x3a, 0xc7, 0xfd, 0x44, 0x73, 0xca, 0x6c, 0xa8, 0x96, 0x3a, 0xe6, + 0xd2, 0xb7, 0x72, 0x51, 0x81, 0x96, 0x6a, 0xe2, 0xd1, 0xe6, 0x4c, 0x7e, 0x59, 0xd1, 0x7a, 0xb4, + 0x49, 0x7b, 0x2a, 0x5b, 0xa0, 0x5a, 0x36, 0x29, 0xed, 0xf9, 0x0f, 0xeb, 0x4e, 0xc6, 0x9f, 0x15, + 0x42, 0xed, 0xc7, 0x79, 0x28, 0xee, 0xc8, 0xd3, 0x57, 0x3d, 0xf4, 0x70, 0x88, 0x3c, 0x58, 0x50, + 0xa9, 0x62, 0xb6, 0x13, 0xdb, 0xa9, 0x7c, 0x02, 0xe8, 0xa6, 0xa1, 0x4f, 0x5f, 0x4f, 0xd0, 0xb7, + 0x90, 0x57, 0xd7, 0xcf, 0x31, 0x21, 0xdc, 0x04, 0xb5, 0xf3, 0x0f, 0x83, 0xfa, 0xf3, 0xd5, 0x0d, + 0x77, 0x84, 0x7b, 0xf1, 0x17, 0xb5, 0x31, 0x53, 0xcd, 0xcf, 0xc9, 0xf1, 0x2e, 0x21, 0x1c, 0xdd, + 0x82, 0xc5, 0x94, 0xc4, 0x78, 0x44, 0xa2, 0x77, 0x2a, 0xab, 0x6c, 0x60, 0x9b, 0xa6, 0x5d, 0x28, + 0x84, 0xa1, 0x18, 0x5a, 0xa9, 0xe6, 0x94, 0x92, 0xd6, 0x2f, 0xa9, 0x77, 0x53, 0xeb, 0x10, 0x8e, + 0xeb, 0x1e, 0x3d, 0x86, 0x32, 0xd5, 0xaf, 0xb3, 0xa0, 0xaf, 0xee, 0x27, 0xd5, 0x26, 0x0b, 0xad, + 0x4f, 0x2f, 0xa1, 0x9a, 0x7a, 0xd2, 0xf9, 0x25, 0x3a, 0xf5, 0xc2, 0x3b, 0x82, 0x45, 0x66, 0x2e, + 0x3d, 0xcb, 0x0a, 0x6b, 0x73, 0xf5, 0x42, 0x6b, 0xf3, 0x12, 0xd6, 0xe9, 0xab, 0xd2, 0x2f, 0xb3, + 0xe9, 0xab, 0x33, 0x85, 0x6b, 0xea, 0x51, 0x19, 0xb2, 0x38, 0x08, 0x59, 0x22, 0x52, 0x1c, 0x8a, + 0xe0, 0x94, 0xa4, 0x9c, 0xb2, 0xc4, 0x3c, 0x43, 0x3e, 0xbb, 0xc4, 0xc3, 0x81, 0xd9, 0xbf, 0x63, + 0xb6, 0x1f, 0xe9, 0xdd, 0xfe, 0xd5, 0xfe, 0xf9, 0x06, 0xf4, 0x74, 0x5c, 0xb6, 0xb6, 0x6b, 0x15, + 0xdf, 0x2b, 0x41, 0x53, 0x72, 0xdb, 0xce, 0xc8, 0x32, 0xb1, 0xa5, 0x6e, 0xc0, 0x8d, 0xef, 0x01, + 0x26, 0x1d, 0x08, 0x21, 0x28, 0x1f, 0x90, 0x24, 0xa2, 0x49, 0xc7, 0xe4, 0xd6, 0x9d, 0x41, 0xcb, + 0xb0, 0x68, 0x30, 0x9b, 0x19, 0xd7, 0x41, 0x4b, 0x50, 0xb2, 0xb3, 0x87, 0x34, 0x21, 0x91, 0x3b, + 0x27, 0x21, 0xb3, 0x4e, 0xbb, 0x75, 0x33, 0xa8, 0x08, 0x39, 0x3d, 0x26, 0x91, 0x3b, 0x8f, 0x0a, + 0xb0, 0xb0, 0xa5, 0x1f, 0x3d, 0x6e, 0x76, 0x35, 0xf3, 0xeb, 0x2f, 0x55, 0x67, 0xe3, 0x2b, 0xa8, + 0x9c, 0xd7, 0xba, 0x91, 0x0b, 0xc5, 0x47, 0x4c, 0xec, 0xda, 0x27, 0xa0, 0x3b, 0x83, 0x4a, 0x90, + 0x9f, 0x4c, 0x1d, 0xc9, 0x7c, 0x6f, 0x48, 0xc2, 0x81, 0x24, 0x9b, 0x35, 0x64, 0x4d, 0xb8, 0xfa, + 0x37, 0x99, 0x45, 0x59, 0x98, 0x3d, 0xba, 0xe3, 0xce, 0xa8, 0xdf, 0x96, 0xeb, 0xe8, 0x0d, 0xdb, + 0xf7, 0x5f, 0xbc, 0xa9, 0x3a, 0x2f, 0xdf, 0x54, 0x9d, 0xd7, 0x6f, 0xaa, 0xce, 0x4f, 0x6f, 0xab, + 0x33, 0x2f, 0xdf, 0x56, 0x67, 0x7e, 0x7f, 0x5b, 0x9d, 0x79, 0xb6, 0x79, 0x46, 0x49, 0x32, 0xb1, + 0x9b, 0xfa, 0x4f, 0x46, 0xc2, 0x22, 0xd2, 0x1c, 0x9e, 0xfd, 0x2f, 0xa3, 0x44, 0xd5, 0xce, 0xaa, + 0x83, 0xbb, 0xfb, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x84, 0x70, 0x56, 0x74, 0xf9, 0x0c, 0x00, + 0x00, } func (m *InboundParams) Marshal() (dAtA []byte, err error) { @@ -1172,6 +1185,13 @@ func (m *Status) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ErrorMessage) > 0 { + i -= len(m.ErrorMessage) + copy(dAtA[i:], m.ErrorMessage) + i = encodeVarintCrossChainTx(dAtA, i, uint64(len(m.ErrorMessage))) + i-- + dAtA[i] = 0x32 + } if m.CreatedTimestamp != 0 { i = encodeVarintCrossChainTx(dAtA, i, uint64(m.CreatedTimestamp)) i-- @@ -1548,6 +1568,10 @@ func (m *Status) Size() (n int) { if m.CreatedTimestamp != 0 { n += 1 + sovCrossChainTx(uint64(m.CreatedTimestamp)) } + l = len(m.ErrorMessage) + if l > 0 { + n += 1 + l + sovCrossChainTx(uint64(l)) + } return n } @@ -2773,6 +2797,38 @@ func (m *Status) Unmarshal(dAtA []byte) error { break } } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorMessage", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + 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 ErrInvalidLengthCrossChainTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCrossChainTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ErrorMessage = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) diff --git a/x/crosschain/types/keys.go b/x/crosschain/types/keys.go index d9fea4a77d..76d343dd3e 100644 --- a/x/crosschain/types/keys.go +++ b/x/crosschain/types/keys.go @@ -3,7 +3,7 @@ package types import ( "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" + "cosmossdk.io/math" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/common" ) @@ -29,8 +29,8 @@ const ( CCTXIndexLength = 66 ) -func GetProtocolFee() sdk.Uint { - return sdk.NewUint(ProtocolFee) +func GetProtocolFee() math.Uint { + return math.NewUint(ProtocolFee) } func KeyPrefix(p string) []byte { diff --git a/x/crosschain/types/rate_limiter_flags_test.go b/x/crosschain/types/rate_limiter_flags_test.go index 8531a34105..545ef708a7 100644 --- a/x/crosschain/types/rate_limiter_flags_test.go +++ b/x/crosschain/types/rate_limiter_flags_test.go @@ -6,7 +6,6 @@ import ( "testing" "cosmossdk.io/math" - sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -263,7 +262,7 @@ func TestConvertCctxValue(t *testing.T) { erc20AssetRates map[int64]map[string]types.AssetRate // output - expectedValue sdkmath.Int + expectedValue math.Int }{ { name: "should convert cctx ZETA value correctly", diff --git a/x/crosschain/types/status.go b/x/crosschain/types/status.go index cdaf5b0aae..00c08bf6f7 100644 --- a/x/crosschain/types/status.go +++ b/x/crosschain/types/status.go @@ -9,28 +9,45 @@ func (m *Status) AbortRefunded() { m.StatusMessage = "CCTX aborted and Refunded" } -// ChangeStatus changes the status of the cross chain transaction -// empty msg does not overwrite old status message -func (m *Status) ChangeStatus(newStatus CctxStatus, msg string) { - if len(msg) > 0 { - if m.StatusMessage != "" { - m.StatusMessage = fmt.Sprintf("%s : %s", m.StatusMessage, msg) - } else { - m.StatusMessage = msg - } +// UpdateStatusAndErrorMessages transitions the Status and Error messages. +func (m *Status) UpdateStatusAndErrorMessages(newStatus CctxStatus, statusMsg, errorMsg string) { + m.UpdateStatus(newStatus, statusMsg) + + if newStatus == CctxStatus_Aborted || newStatus == CctxStatus_Reverted || newStatus == CctxStatus_PendingRevert { + m.UpdateErrorMessage(errorMsg) } - if !m.ValidateTransition(newStatus) { +} + +// UpdateStatus updates the cctx status and cctx.status.status_message. +func (m *Status) UpdateStatus(newStatus CctxStatus, statusMsg string) { + if m.ValidateTransition(newStatus) { + m.StatusMessage = fmt.Sprintf("Status changed from %s to %s", m.Status.String(), newStatus.String()) + m.Status = newStatus + } else { m.StatusMessage = fmt.Sprintf( - "Failed to transition : OldStatus %s , NewStatus %s , MSG : %s :", + "Failed to transition status from %s to %s", m.Status.String(), newStatus.String(), - msg, ) + m.Status = CctxStatus_Aborted - return } - m.Status = newStatus -} //nolint:typecheck + + if statusMsg != "" { + m.StatusMessage += fmt.Sprintf(": %s", statusMsg) + } +} + +// UpdateErrorMessage updates cctx.status.error_message. +func (m *Status) UpdateErrorMessage(errorMsg string) { + errMsg := errorMsg + + if errMsg == "" { + errMsg = "unknown error" + } + + m.ErrorMessage = errMsg +} func (m *Status) ValidateTransition(newStatus CctxStatus) bool { stateTransitionMap := stateTransitionMap() diff --git a/x/crosschain/types/status_test.go b/x/crosschain/types/status_test.go index 88013a41a9..5bb272d522 100644 --- a/x/crosschain/types/status_test.go +++ b/x/crosschain/types/status_test.go @@ -140,31 +140,35 @@ func TestStatus_ChangeStatus(t *testing.T) { t.Run("should change status and msg if transition is valid", func(t *testing.T) { s := types.Status{Status: types.CctxStatus_PendingInbound} - s.ChangeStatus(types.CctxStatus_PendingOutbound, "msg") + s.UpdateStatus(types.CctxStatus_PendingOutbound, "msg") assert.Equal(t, s.Status, types.CctxStatus_PendingOutbound) - assert.Equal(t, s.StatusMessage, "msg") + assert.Equal(t, s.StatusMessage, "Status changed from PendingInbound to PendingOutbound: msg") }) t.Run("should change status if transition is valid", func(t *testing.T) { s := types.Status{Status: types.CctxStatus_PendingInbound} - s.ChangeStatus(types.CctxStatus_PendingOutbound, "") + s.UpdateStatus(types.CctxStatus_PendingOutbound, "") + fmt.Printf("%+v\n", s) assert.Equal(t, s.Status, types.CctxStatus_PendingOutbound) - assert.Equal(t, s.StatusMessage, "") + assert.Equal(t, s.StatusMessage, fmt.Sprintf( + "Status changed from %s to %s", + types.CctxStatus_PendingInbound.String(), + types.CctxStatus_PendingOutbound.String()), + ) }) t.Run("should change status to aborted and msg if transition is invalid", func(t *testing.T) { s := types.Status{Status: types.CctxStatus_PendingOutbound} - s.ChangeStatus(types.CctxStatus_PendingInbound, "msg") + s.UpdateStatus(types.CctxStatus_PendingInbound, "msg") assert.Equal(t, s.Status, types.CctxStatus_Aborted) assert.Equal( t, fmt.Sprintf( - "Failed to transition : OldStatus %s , NewStatus %s , MSG : %s :", + "Failed to transition status from %s to %s: msg", types.CctxStatus_PendingOutbound.String(), types.CctxStatus_PendingInbound.String(), - "msg", ), s.StatusMessage, ) From 1470fdceadb43c4fcf64b135d5881be5f53e2571 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Wed, 9 Oct 2024 08:51:57 -0700 Subject: [PATCH 16/36] fix: ensure NODE_VERSION and NODE_COMMIT are set for upgrade builds (#2981) --- Makefile | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 36e414f012..7b01eafb41 100644 --- a/Makefile +++ b/Makefile @@ -296,15 +296,24 @@ start-v2-test: zetanode ############################################################################### # build from source only if requested +# NODE_VERSION and NODE_COMMIT must be set as old-runtime depends on lastest-runtime ifdef UPGRADE_TEST_FROM_SOURCE zetanode-upgrade: zetanode @echo "Building zetanode-upgrade from source" - $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime-source --build-arg OLD_VERSION='release/v20' . + $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime-source \ + --build-arg OLD_VERSION='release/v20' \ + --build-arg NODE_VERSION=$(NODE_VERSION) \ + --build-arg NODE_COMMIT=$(NODE_COMMIT) + . .PHONY: zetanode-upgrade else zetanode-upgrade: zetanode @echo "Building zetanode-upgrade from binaries" - $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime --build-arg OLD_VERSION='https://github.com/zeta-chain/node/releases/download/v20.0.2' . + $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime \ + --build-arg OLD_VERSION='https://github.com/zeta-chain/node/releases/download/v20.0.2' \ + --build-arg NODE_VERSION=$(NODE_VERSION) \ + --build-arg NODE_COMMIT=$(NODE_COMMIT) \ + . .PHONY: zetanode-upgrade endif From b20c3f15decf1de85e3c7192852b07f98f8dbb8c Mon Sep 17 00:00:00 2001 From: Dmitry S <11892559+swift1337@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:24:31 +0200 Subject: [PATCH 17/36] =?UTF-8?q?feat(ton):=20TON=20observer=20?= =?UTF-8?q?=F0=9F=92=8E=20(#2896)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use chainParams from base observer * Improve base observer Start() semantics * Add pkg/ticker options * Add TON to pkg/chains & protos * Add liteapi wrapper client; locate first tx * Add TON tx scraper * Add client.GetTransactionsUntil * Gateway WIP * Implement Gateway inbound tx parsing * Add Gateway tx filtration * Add GetBlockHeader cache; Add masterchain seqno. Implement watchInbound * Improve ton contracts pkg * Add IsTONChain() * Refactor Gateway package * Implement samples for TON * Add liteClient mocks * Add unit tests for inbound TON observer * Localnet: add TON ZRC20 * Wire the TON observer into the orchestrator * Add TON chain params of the fly! * TON deposits E2E wip * Fix bugs during cctx; * TON Deposits E2E 🫡✅ * TON Deposit And Call E2E * Merge fixes * Update changelog * gosec * Improve testing * Simplify ticker.Stop(). Leverage ctx.cancel() * Simplify E2E * Simplify liteapi semantics * Fix comments * Update zetaclient/chains/base/observer.go Co-authored-by: Francisco de Borja Aranda Castillejo * Add gw explanatory comments; address PR comments * Apply fixes for AI suggestions * Fix upgrade tests --------- Co-authored-by: Francisco de Borja Aranda Castillejo --- changelog.md | 1 + cmd/zetae2e/config/config.go | 1 + cmd/zetae2e/config/contracts.go | 11 + cmd/zetae2e/local/local.go | 1 + cmd/zetae2e/local/ton.go | 1 + docs/openapi/openapi.swagger.yaml | 4 + e2e/config/config.go | 1 + e2e/e2etests/e2etests.go | 13 +- e2e/e2etests/helpers.go | 5 + e2e/e2etests/test_ton_deposit.go | 60 +++- e2e/e2etests/test_ton_deposit_and_call.go | 69 ++++ e2e/runner/runner.go | 12 +- e2e/runner/setup_ton.go | 68 +++- e2e/runner/setup_zeta.go | 23 ++ e2e/runner/ton.go | 59 ++++ e2e/runner/ton/accounts.go | 14 +- e2e/runner/zeta.go | 50 ++- e2e/txserver/zeta_tx_server.go | 73 ++-- pkg/chains/chain.go | 18 + pkg/chains/chain_test.go | 19 +- pkg/chains/chains.go | 48 ++- pkg/chains/chains.pb.go | 130 +++---- pkg/chains/chains_test.go | 17 + pkg/contracts/ton/gateway.go | 258 ++++++++++++++ pkg/contracts/ton/gateway_op.go | 115 ++++++ pkg/contracts/ton/gateway_send.go | 72 ++++ pkg/contracts/ton/gateway_test.go | 313 +++++++++++++++++ pkg/contracts/ton/gateway_tx.go | 51 +++ pkg/contracts/ton/testdata/00-donation.json | 8 + pkg/contracts/ton/testdata/01-deposit.json | 8 + .../ton/testdata/02-deposit-and-call.json | 8 + pkg/contracts/ton/testdata/03-failed-tx.json | 8 + .../ton/testdata/04-bounced-msg.json | 8 + pkg/contracts/ton/testdata/long-call-data.txt | 28 ++ pkg/contracts/ton/testdata/readme.md | 29 ++ pkg/contracts/ton/testdata/scraper.go | 131 +++++++ pkg/contracts/ton/tlb.go | 79 +++++ pkg/ticker/ticker.go | 86 +++-- pkg/ticker/ticker_test.go | 54 ++- .../zetacore/pkg/chains/chains.proto | 3 + testutil/sample/sample_ton.go | 272 ++++++++++++++ testutil/sample/sample_ton_test.go | 94 +++++ .../zetacore/pkg/chains/chains_pb.d.ts | 17 + x/crosschain/keeper/evm_deposit.go | 2 +- x/observer/keeper/msg_server_vote_blame.go | 6 +- zetaclient/chains/base/observer.go | 64 ++-- zetaclient/chains/base/observer_test.go | 9 - zetaclient/chains/bitcoin/observer/inbound.go | 8 +- .../chains/bitcoin/observer/observer.go | 36 +- .../chains/bitcoin/observer/outbound.go | 4 +- .../chains/bitcoin/observer/rpc_status.go | 2 +- zetaclient/chains/evm/observer/inbound.go | 32 +- zetaclient/chains/evm/observer/observer.go | 28 +- .../chains/evm/observer/observer_gas.go | 8 +- zetaclient/chains/evm/observer/outbound.go | 4 +- .../chains/evm/observer/outbound_test.go | 2 +- zetaclient/chains/evm/observer/rpc_status.go | 2 +- zetaclient/chains/interfaces/interfaces.go | 18 +- zetaclient/chains/solana/observer/inbound.go | 2 +- .../chains/solana/observer/inbound_tracker.go | 4 +- zetaclient/chains/solana/observer/observer.go | 18 +- .../chains/solana/observer/observer_gas.go | 8 +- zetaclient/chains/solana/observer/outbound.go | 4 +- .../chains/solana/observer/rpc_status.go | 2 +- zetaclient/chains/ton/config.go | 14 + zetaclient/chains/ton/liteapi/client.go | 230 ++++++++++++ .../chains/ton/liteapi/client_live_test.go | 198 +++++++++++ zetaclient/chains/ton/liteapi/client_test.go | 100 ++++++ zetaclient/chains/ton/observer/inbound.go | 260 ++++++++++++++ .../chains/ton/observer/inbound_test.go | 331 ++++++++++++++++++ zetaclient/chains/ton/observer/observer.go | 80 +++++ .../chains/ton/observer/observer_test.go | 195 ++++++++--- zetaclient/config/config_chain.go | 8 + zetaclient/config/types.go | 16 + zetaclient/config/types_test.go | 4 +- zetaclient/context/chain.go | 4 + zetaclient/logs/fields.go | 13 +- zetaclient/orchestrator/bootstap_test.go | 33 +- zetaclient/orchestrator/bootstrap.go | 70 +++- zetaclient/orchestrator/orchestrator.go | 41 +-- zetaclient/orchestrator/orchestrator_test.go | 6 +- zetaclient/testutils/mocks/chain_clients.go | 30 +- zetaclient/testutils/mocks/ton_liteclient.go | 127 +++++++ zetaclient/testutils/testrpc/rpc.go | 2 +- 84 files changed, 3943 insertions(+), 422 deletions(-) create mode 100644 e2e/e2etests/test_ton_deposit_and_call.go create mode 100644 e2e/runner/ton.go create mode 100644 pkg/contracts/ton/gateway.go create mode 100644 pkg/contracts/ton/gateway_op.go create mode 100644 pkg/contracts/ton/gateway_send.go create mode 100644 pkg/contracts/ton/gateway_test.go create mode 100644 pkg/contracts/ton/gateway_tx.go create mode 100644 pkg/contracts/ton/testdata/00-donation.json create mode 100644 pkg/contracts/ton/testdata/01-deposit.json create mode 100644 pkg/contracts/ton/testdata/02-deposit-and-call.json create mode 100644 pkg/contracts/ton/testdata/03-failed-tx.json create mode 100644 pkg/contracts/ton/testdata/04-bounced-msg.json create mode 100644 pkg/contracts/ton/testdata/long-call-data.txt create mode 100644 pkg/contracts/ton/testdata/readme.md create mode 100644 pkg/contracts/ton/testdata/scraper.go create mode 100644 pkg/contracts/ton/tlb.go create mode 100644 testutil/sample/sample_ton.go create mode 100644 testutil/sample/sample_ton_test.go create mode 100644 zetaclient/chains/ton/liteapi/client.go create mode 100644 zetaclient/chains/ton/liteapi/client_live_test.go create mode 100644 zetaclient/chains/ton/liteapi/client_test.go create mode 100644 zetaclient/chains/ton/observer/inbound.go create mode 100644 zetaclient/chains/ton/observer/inbound_test.go create mode 100644 zetaclient/chains/ton/observer/observer.go create mode 100644 zetaclient/testutils/mocks/ton_liteclient.go diff --git a/changelog.md b/changelog.md index 5de0dbd846..e25f46e129 100644 --- a/changelog.md +++ b/changelog.md @@ -17,6 +17,7 @@ * [2904](https://github.com/zeta-chain/node/pull/2904) - integrate authenticated calls smart contract functionality into protocol * [2919](https://github.com/zeta-chain/node/pull/2919) - add inbound sender to revert context * [2957](https://github.com/zeta-chain/node/pull/2957) - enable Bitcoin inscription support on testnet +* [2896](https://github.com/zeta-chain/node/pull/2896) - add TON inbound observation ### Refactor diff --git a/cmd/zetae2e/config/config.go b/cmd/zetae2e/config/config.go index 8e87e63bef..0cea78af39 100644 --- a/cmd/zetae2e/config/config.go +++ b/cmd/zetae2e/config/config.go @@ -68,6 +68,7 @@ func ExportContractsFromRunner(r *runner.E2ERunner, conf config.Config) config.C conf.Contracts.ZEVM.ERC20ZRC20Addr = config.DoubleQuotedString(r.ERC20ZRC20Addr.Hex()) conf.Contracts.ZEVM.BTCZRC20Addr = config.DoubleQuotedString(r.BTCZRC20Addr.Hex()) conf.Contracts.ZEVM.SOLZRC20Addr = config.DoubleQuotedString(r.SOLZRC20Addr.Hex()) + conf.Contracts.ZEVM.TONZRC20Addr = config.DoubleQuotedString(r.TONZRC20Addr.Hex()) conf.Contracts.ZEVM.UniswapFactoryAddr = config.DoubleQuotedString(r.UniswapV2FactoryAddr.Hex()) conf.Contracts.ZEVM.UniswapRouterAddr = config.DoubleQuotedString(r.UniswapV2RouterAddr.Hex()) conf.Contracts.ZEVM.ConnectorZEVMAddr = config.DoubleQuotedString(r.ConnectorZEVMAddr.Hex()) diff --git a/cmd/zetae2e/config/contracts.go b/cmd/zetae2e/config/contracts.go index d6cba953a5..9af3ccd812 100644 --- a/cmd/zetae2e/config/contracts.go +++ b/cmd/zetae2e/config/contracts.go @@ -135,6 +135,17 @@ func setContractsFromConfig(r *runner.E2ERunner, conf config.Config) error { } } + if c := conf.Contracts.ZEVM.TONZRC20Addr; c != "" { + r.TONZRC20Addr, err = c.AsEVMAddress() + if err != nil { + return fmt.Errorf("invalid TONZRC20Addr: %w", err) + } + r.TONZRC20, err = zrc20.NewZRC20(r.TONZRC20Addr, r.ZEVMClient) + if err != nil { + return err + } + } + if c := conf.Contracts.ZEVM.UniswapFactoryAddr; c != "" { r.UniswapV2FactoryAddr, err = c.AsEVMAddress() if err != nil { diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 4a7fbef39c..23a7f6b866 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -407,6 +407,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { tonTests := []string{ e2etests.TestTONDepositName, + e2etests.TestTONDepositAndCallName, } eg.Go(tonTestRoutine(conf, deployerRunner, verbose, tonTests...)) diff --git a/cmd/zetae2e/local/ton.go b/cmd/zetae2e/local/ton.go index 000c872b25..bbbbd991de 100644 --- a/cmd/zetae2e/local/ton.go +++ b/cmd/zetae2e/local/ton.go @@ -25,6 +25,7 @@ func tonTestRoutine( deployerRunner, conf.DefaultAccount, runner.NewLogger(verbose, color.FgCyan, "ton"), + runner.WithZetaTxServer(deployerRunner.ZetaTxServer), ) if err != nil { return errors.Wrap(err, "unable to init ton test runner") diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 461b8566cc..dfa9349794 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -56998,7 +56998,9 @@ definitions: - bitcoin - op_stack - solana_consensus + - catchain_consensus default: ethereum + description: '- catchain_consensus: ton' title: |- Consensus represents the consensus algorithm used by the chain this can represent the consensus of a L1 @@ -57014,6 +57016,7 @@ definitions: - optimism - base - solana + - ton default: eth title: |- Network represents the network of the chain @@ -57048,6 +57051,7 @@ definitions: - no_vm - evm - svm + - tvm default: no_vm title: |- Vm represents the virtual machine type of the chain to support smart diff --git a/e2e/config/config.go b/e2e/config/config.go index 089ea39b70..32a799c027 100644 --- a/e2e/config/config.go +++ b/e2e/config/config.go @@ -141,6 +141,7 @@ type ZEVM struct { ERC20ZRC20Addr DoubleQuotedString `yaml:"erc20_zrc20"` BTCZRC20Addr DoubleQuotedString `yaml:"btc_zrc20"` SOLZRC20Addr DoubleQuotedString `yaml:"sol_zrc20"` + TONZRC20Addr DoubleQuotedString `yaml:"ton_zrc20"` UniswapFactoryAddr DoubleQuotedString `yaml:"uniswap_factory"` UniswapRouterAddr DoubleQuotedString `yaml:"uniswap_router"` ConnectorZEVMAddr DoubleQuotedString `yaml:"connector_zevm"` diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index 004271c696..2d6eea998f 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -65,7 +65,8 @@ const ( /** * TON tests */ - TestTONDepositName = "ton_deposit" + TestTONDepositName = "ton_deposit" + TestTONDepositAndCallName = "ton_deposit_and_call" /* Bitcoin tests @@ -445,10 +446,18 @@ var AllE2ETests = []runner.E2ETest{ TestTONDepositName, "deposit TON into ZEVM", []runner.ArgDefinition{ - {Description: "amount in nano tons", DefaultValue: "900000000"}, // 0.9 TON + {Description: "amount in nano tons", DefaultValue: "1000000000"}, // 1.0 TON }, TestTONDeposit, ), + runner.NewE2ETest( + TestTONDepositAndCallName, + "deposit TON into ZEVM and call a contract", + []runner.ArgDefinition{ + {Description: "amount in nano tons", DefaultValue: "1000000000"}, // 1.0 TON + }, + TestTONDepositAndCall, + ), /* Bitcoin tests */ diff --git a/e2e/e2etests/helpers.go b/e2e/e2etests/helpers.go index e3ab963354..64f0920c2a 100644 --- a/e2e/e2etests/helpers.go +++ b/e2e/e2etests/helpers.go @@ -4,6 +4,7 @@ import ( "math/big" "strconv" + "cosmossdk.io/math" "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -144,6 +145,10 @@ func parseBigInt(t require.TestingT, s string) *big.Int { return v } +func parseUint(t require.TestingT, s string) math.Uint { + return math.NewUintFromBigInt(parseBigInt(t, s)) +} + // bigIntFromFloat64 takes float64 (e.g. 0.001) that represents btc amount // and converts it to big.Int for downstream usage. func btcAmountFromFloat64(t require.TestingT, amount float64) *big.Int { diff --git a/e2e/e2etests/test_ton_deposit.go b/e2e/e2etests/test_ton_deposit.go index a2e8df09d0..73860629df 100644 --- a/e2e/e2etests/test_ton_deposit.go +++ b/e2e/e2etests/test_ton_deposit.go @@ -1,42 +1,64 @@ package e2etests import ( + "time" + "cosmossdk.io/math" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/stretchr/testify/require" "github.com/zeta-chain/node/e2e/runner" "github.com/zeta-chain/node/e2e/runner/ton" + "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/testutil/sample" + cctypes "github.com/zeta-chain/node/x/crosschain/types" ) -// TestTONDeposit (!) This boilerplate is a demonstration of E2E capabilities for TON integration -// Actual Deposit test is not implemented yet. -func TestTONDeposit(r *runner.E2ERunner, _ []string) { - ctx, deployer := r.Ctx, r.TONDeployer +func TestTONDeposit(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) // Given deployer - deployerBalance, err := deployer.GetBalance(ctx) - require.NoError(r, err, "failed to get deployer balance") - require.NotZero(r, deployerBalance, "deployer balance is zero") + ctx, deployer, chain := r.Ctx, r.TONDeployer, chains.TONLocalnet + + // Given amount + amount := parseUint(r, args[0]) + + // https://github.com/zeta-chain/protocol-contracts-ton/blob/main/contracts/gateway.fc#L28 + // (will be optimized & dynamic in the future) + depositFee := math.NewUint(10_000_000) // Given sample wallet with a balance of 50 TON sender, err := deployer.CreateWallet(ctx, ton.TONCoins(50)) require.NoError(r, err) - // That was funded (again) but the faucet - _, err = deployer.Fund(ctx, sender.GetAddress(), ton.TONCoins(30)) + // Given sample EVM address + recipient := sample.EthAddress() + + // ACT + err = r.TONDeposit(sender, amount, recipient) + + // ASSERT require.NoError(r, err) - // Check sender balance - sb, err := sender.GetBalance(ctx) + // Wait for CCTX mining + filter := func(cctx *cctypes.CrossChainTx) bool { + return cctx.InboundParams.SenderChainId == chain.ChainId && + cctx.InboundParams.Sender == sender.GetAddress().ToRaw() + } + + cctx := r.WaitForSpecificCCTX(filter, time.Minute) + + // Check CCTX + expectedDeposit := amount.Sub(depositFee) + + require.Equal(r, sender.GetAddress().ToRaw(), cctx.InboundParams.Sender) + require.Equal(r, expectedDeposit.Uint64(), cctx.InboundParams.Amount.Uint64()) + + // Check receiver's balance + balance, err := r.TONZRC20.BalanceOf(&bind.CallOpts{}, recipient) require.NoError(r, err) - senderBalance := math.NewUint(sb) + r.Logger.Info("Recipient's zEVM TON balance after deposit: %d", balance.Uint64()) - // note that it's not exactly 80 TON, but 79.99... due to gas fees - // We'll tackle gas math later. - r.Logger.Print( - "Balance of sender (%s): %s", - sender.GetAddress().ToHuman(false, true), - ton.FormatCoins(senderBalance), - ) + require.Equal(r, expectedDeposit.Uint64(), balance.Uint64()) } diff --git a/e2e/e2etests/test_ton_deposit_and_call.go b/e2e/e2etests/test_ton_deposit_and_call.go new file mode 100644 index 0000000000..43e5dcc4e0 --- /dev/null +++ b/e2e/e2etests/test_ton_deposit_and_call.go @@ -0,0 +1,69 @@ +package e2etests + +import ( + "time" + + "cosmossdk.io/math" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" + + "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/runner/ton" + "github.com/zeta-chain/node/e2e/utils" + "github.com/zeta-chain/node/pkg/chains" + testcontract "github.com/zeta-chain/node/testutil/contracts" + cctypes "github.com/zeta-chain/node/x/crosschain/types" +) + +func TestTONDepositAndCall(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) + + // Given deployer + ctx, deployer, chain := r.Ctx, r.TONDeployer, chains.TONLocalnet + + // Given amount + amount := parseUint(r, args[0]) + + // https://github.com/zeta-chain/protocol-contracts-ton/blob/main/contracts/gateway.fc#L28 + // (will be optimized & dynamic in the future) + depositFee := math.NewUint(10_000_000) + + // Given sample wallet with a balance of 50 TON + sender, err := deployer.CreateWallet(ctx, ton.TONCoins(50)) + require.NoError(r, err) + + // Given sample zEVM contract + contractAddr, _, contract, err := testcontract.DeployExample(r.ZEVMAuth, r.ZEVMClient) + require.NoError(r, err) + r.Logger.Info("Example zevm contract deployed at: %s", contractAddr.String()) + + // Given call data + callData := []byte("hello from TON!") + + // ACT + err = r.TONDepositAndCall(sender, amount, contractAddr, callData) + + // ASSERT + require.NoError(r, err) + + // Wait for CCTX mining + filter := func(cctx *cctypes.CrossChainTx) bool { + return cctx.InboundParams.SenderChainId == chain.ChainId && + cctx.InboundParams.Sender == sender.GetAddress().ToRaw() + } + + r.WaitForSpecificCCTX(filter, time.Minute) + + expectedDeposit := amount.Sub(depositFee) + + // check if example contract has been called, bar value should be set to amount + utils.MustHaveCalledExampleContract(r, contract, expectedDeposit.BigInt()) + + // Check receiver's balance + balance, err := r.TONZRC20.BalanceOf(&bind.CallOpts{}, contractAddr) + require.NoError(r, err) + + r.Logger.Info("Contract's zEVM TON balance after deposit: %d", balance.Uint64()) + + require.Equal(r, expectedDeposit.Uint64(), balance.Uint64()) +} diff --git a/e2e/runner/runner.go b/e2e/runner/runner.go index 57e5ab9a24..03cafb6fc4 100644 --- a/e2e/runner/runner.go +++ b/e2e/runner/runner.go @@ -18,7 +18,6 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" - "github.com/tonkeeper/tongo/ton" "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/erc20custody.sol" zetaeth "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zeta.eth.sol" zetaconnectoreth "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zetaconnector.eth.sol" @@ -40,6 +39,7 @@ import ( "github.com/zeta-chain/node/e2e/txserver" "github.com/zeta-chain/node/e2e/utils" "github.com/zeta-chain/node/pkg/contracts/testdappv2" + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" authoritytypes "github.com/zeta-chain/node/x/authority/types" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" fungibletypes "github.com/zeta-chain/node/x/fungible/types" @@ -73,7 +73,7 @@ type E2ERunner struct { BTCDeployerAddress *btcutil.AddressWitnessPubKeyHash SolanaDeployerAddress solana.PublicKey TONDeployer *tonrunner.Deployer - TONGateway ton.AccountID + TONGateway *toncontracts.Gateway // all clients. // a reference to this type is required to enable creating a new E2ERunner. @@ -127,6 +127,8 @@ type E2ERunner struct { BTCZRC20 *zrc20.ZRC20 SOLZRC20Addr ethcommon.Address SOLZRC20 *zrc20.ZRC20 + TONZRC20Addr ethcommon.Address + TONZRC20 *zrc20.ZRC20 UniswapV2FactoryAddr ethcommon.Address UniswapV2Factory *uniswapv2factory.UniswapV2Factory UniswapV2RouterAddr ethcommon.Address @@ -230,6 +232,7 @@ func (r *E2ERunner) CopyAddressesFrom(other *E2ERunner) (err error) { r.ETHZRC20Addr = other.ETHZRC20Addr r.BTCZRC20Addr = other.BTCZRC20Addr r.SOLZRC20Addr = other.SOLZRC20Addr + r.TONZRC20Addr = other.TONZRC20Addr r.UniswapV2FactoryAddr = other.UniswapV2FactoryAddr r.UniswapV2RouterAddr = other.UniswapV2RouterAddr r.ConnectorZEVMAddr = other.ConnectorZEVMAddr @@ -275,6 +278,10 @@ func (r *E2ERunner) CopyAddressesFrom(other *E2ERunner) (err error) { if err != nil { return err } + r.TONZRC20, err = zrc20.NewZRC20(r.TONZRC20Addr, r.ZEVMClient) + if err != nil { + return err + } r.UniswapV2Factory, err = uniswapv2factory.NewUniswapV2Factory(r.UniswapV2FactoryAddr, r.ZEVMClient) if err != nil { return err @@ -359,6 +366,7 @@ func (r *E2ERunner) PrintContractAddresses() { r.Logger.Print("ERC20ZRC20: %s", r.ERC20ZRC20Addr.Hex()) r.Logger.Print("BTCZRC20: %s", r.BTCZRC20Addr.Hex()) r.Logger.Print("SOLZRC20: %s", r.SOLZRC20Addr.Hex()) + r.Logger.Print("TONZRC20: %s", r.TONZRC20Addr.Hex()) r.Logger.Print("UniswapFactory: %s", r.UniswapV2FactoryAddr.Hex()) r.Logger.Print("UniswapRouter: %s", r.UniswapV2RouterAddr.Hex()) r.Logger.Print("ConnectorZEVM: %s", r.ConnectorZEVMAddr.Hex()) diff --git a/e2e/runner/setup_ton.go b/e2e/runner/setup_ton.go index 9b744401ad..62d89c3329 100644 --- a/e2e/runner/setup_ton.go +++ b/e2e/runner/setup_ton.go @@ -2,10 +2,16 @@ package runner import ( "fmt" + "time" "github.com/pkg/errors" "github.com/zeta-chain/node/e2e/runner/ton" + "github.com/zeta-chain/node/e2e/utils" + "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/pkg/constant" + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" + observertypes "github.com/zeta-chain/node/x/observer/types" ) // SetupTON setups TON deployer and deploys Gateway contract @@ -42,7 +48,12 @@ func (r *E2ERunner) SetupTON() error { return errors.Wrapf(err, "unable to deploy TON gateway") } - r.Logger.Print("💎TON Gateway deployed %s (%s)", gwAccount.ID.ToRaw(), gwAccount.ID.ToHuman(false, true)) + r.Logger.Print( + "💎TON Gateway deployed %s (%s) with TSS address %s", + gwAccount.ID.ToRaw(), + gwAccount.ID.ToHuman(false, true), + r.TSSAddress.Hex(), + ) // 3. Check that the gateway indeed was deployed and has desired TON balance. gwBalance, err := deployer.GetBalanceOf(ctx, gwAccount.ID) @@ -55,7 +66,58 @@ func (r *E2ERunner) SetupTON() error { } r.TONDeployer = deployer - r.TONGateway = gwAccount.ID + r.TONGateway = toncontracts.NewGateway(gwAccount.ID) - return nil + return r.ensureTONChainParams(gwAccount) +} + +func (r *E2ERunner) ensureTONChainParams(gw *ton.AccountInit) error { + if r.ZetaTxServer == nil { + return errors.New("ZetaTxServer is not initialized") + } + + creator := r.ZetaTxServer.MustGetAccountAddressFromName(utils.OperationalPolicyName) + + chainID := chains.TONLocalnet.ChainId + + chainParams := &observertypes.ChainParams{ + ChainId: chainID, + ConfirmationCount: 1, + GasPriceTicker: 5, + InboundTicker: 5, + OutboundTicker: 5, + ZetaTokenContractAddress: constant.EVMZeroAddress, + ConnectorContractAddress: constant.EVMZeroAddress, + Erc20CustodyContractAddress: constant.EVMZeroAddress, + OutboundScheduleInterval: 2, + OutboundScheduleLookahead: 5, + BallotThreshold: observertypes.DefaultBallotThreshold, + MinObserverDelegation: observertypes.DefaultMinObserverDelegation, + IsSupported: true, + GatewayAddress: gw.ID.ToRaw(), + } + + msg := observertypes.NewMsgUpdateChainParams(creator, chainParams) + + if _, err := r.ZetaTxServer.BroadcastTx(utils.OperationalPolicyName, msg); err != nil { + return errors.Wrap(err, "unable to broadcast TON chain params tx") + } + + r.Logger.Print("💎Voted for adding TON chain params (localnet). Waiting for confirmation") + + query := &observertypes.QueryGetChainParamsForChainRequest{ChainId: chainID} + + const duration = 2 * time.Second + + for i := 0; i < 10; i++ { + _, err := r.ObserverClient.GetChainParamsForChain(r.Ctx, query) + if err == nil { + r.Logger.Print("💎TON chain params are set") + return nil + } + + time.Sleep(duration) + } + + return errors.New("unable to set TON chain params") } diff --git a/e2e/runner/setup_zeta.go b/e2e/runner/setup_zeta.go index ffab5db811..1d1db47108 100644 --- a/e2e/runner/setup_zeta.go +++ b/e2e/runner/setup_zeta.go @@ -179,6 +179,7 @@ func (r *E2ERunner) SetZEVMZRC20s() { e2eutils.OperationalPolicyName, e2eutils.AdminPolicyName, r.ERC20Addr.Hex(), + r.skipChainOperations, ) require.NoError(r, err) @@ -191,6 +192,7 @@ func (r *E2ERunner) SetZEVMZRC20s() { r.SetupETHZRC20() r.SetupBTCZRC20() r.SetupSOLZRC20() + r.SetupTONZRC20() } // SetupETHZRC20 sets up the ETH ZRC20 in the runner from the values queried from the chain @@ -242,6 +244,27 @@ func (r *E2ERunner) SetupSOLZRC20() { r.SOLZRC20 = SOLZRC20 } +// SetupTONZRC20 sets up the TON ZRC20 in the runner from the values queried from the chain +func (r *E2ERunner) SetupTONZRC20() { + chainID := chains.TONLocalnet.ChainId + + // noop + if r.skipChainOperations(chainID) { + return + } + + TONZRC20Addr, err := r.SystemContract.GasCoinZRC20ByChainId(&bind.CallOpts{}, big.NewInt(chainID)) + require.NoError(r, err) + + r.TONZRC20Addr = TONZRC20Addr + r.Logger.Info("TON ZRC20 address: %s", TONZRC20Addr.Hex()) + + TONZRC20, err := zrc20.NewZRC20(TONZRC20Addr, r.ZEVMClient) + require.NoError(r, err) + + r.TONZRC20 = TONZRC20 +} + // EnableHeaderVerification enables the header verification for the given chain IDs func (r *E2ERunner) EnableHeaderVerification(chainIDList []int64) error { r.Logger.Print("⚙️ enabling verification flags for block headers") diff --git a/e2e/runner/ton.go b/e2e/runner/ton.go new file mode 100644 index 0000000000..8746e25977 --- /dev/null +++ b/e2e/runner/ton.go @@ -0,0 +1,59 @@ +package runner + +import ( + "cosmossdk.io/math" + eth "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/tonkeeper/tongo/wallet" + + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" +) + +// we need to use this send mode due to how wallet V5 works +// +// https://github.com/tonkeeper/w5/blob/main/contracts/wallet_v5.fc#L82 +// https://docs.ton.org/develop/smart-contracts/guidelines/message-modes-cookbook +const tonDepositSendCode = toncontracts.SendFlagSeparateFees + toncontracts.SendFlagIgnoreErrors + +// TONDeposit deposit TON to Gateway contract +func (r *E2ERunner) TONDeposit(sender *wallet.Wallet, amount math.Uint, zevmRecipient eth.Address) error { + require.NotNil(r, r.TONGateway, "TON Gateway is not initialized") + + require.NotNil(r, sender, "Sender wallet is nil") + require.False(r, amount.IsZero()) + require.NotEqual(r, (eth.Address{}).String(), zevmRecipient.String()) + + r.Logger.Info( + "Sending deposit of %s TON from %s to zEVM %s", + amount.String(), + sender.GetAddress().ToRaw(), + zevmRecipient.Hex(), + ) + + return r.TONGateway.SendDeposit(r.Ctx, sender, amount, zevmRecipient, tonDepositSendCode) +} + +// TONDepositAndCall deposit TON to Gateway contract with call data. +func (r *E2ERunner) TONDepositAndCall( + sender *wallet.Wallet, + amount math.Uint, + zevmRecipient eth.Address, + callData []byte, +) error { + require.NotNil(r, r.TONGateway, "TON Gateway is not initialized") + + require.NotNil(r, sender, "Sender wallet is nil") + require.False(r, amount.IsZero()) + require.NotEqual(r, (eth.Address{}).String(), zevmRecipient.String()) + require.NotEmpty(r, callData) + + r.Logger.Info( + "Sending deposit of %s TON from %s to zEVM %s and calling contract with %q", + amount.String(), + sender.GetAddress().ToRaw(), + zevmRecipient.Hex(), + string(callData), + ) + + return r.TONGateway.SendDepositAndCall(r.Ctx, sender, amount, zevmRecipient, callData, tonDepositSendCode) +} diff --git a/e2e/runner/ton/accounts.go b/e2e/runner/ton/accounts.go index f1a3fea659..3ffd8c0907 100644 --- a/e2e/runner/ton/accounts.go +++ b/e2e/runner/ton/accounts.go @@ -12,6 +12,8 @@ import ( "github.com/tonkeeper/tongo/ton" "github.com/tonkeeper/tongo/wallet" "golang.org/x/crypto/ed25519" + + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" ) const workchainID = 0 @@ -138,7 +140,7 @@ func buildGatewayData(tss eth.Address) (*boc.Cell, error) { cell = boc.NewCell() ) - err := errCollect( + err := toncontracts.ErrCollect( cell.WriteBit(true), // deposits_enabled zeroCoins.MarshalTLB(cell, enc), // total_locked zeroCoins.MarshalTLB(cell, enc), // fees @@ -153,16 +155,6 @@ func buildGatewayData(tss eth.Address) (*boc.Cell, error) { return cell, nil } -func errCollect(errs ...error) error { - for i, err := range errs { - if err != nil { - return errors.Wrapf(err, "error at index %d", i) - } - } - - return nil -} - // copied from tongo wallets_common.go func generateStateInit(code, data *boc.Cell) *tlb.StateInit { return &tlb.StateInit{ diff --git a/e2e/runner/zeta.go b/e2e/runner/zeta.go index bdada4763c..1df7e676e3 100644 --- a/e2e/runner/zeta.go +++ b/e2e/runner/zeta.go @@ -6,6 +6,7 @@ import ( "time" "github.com/cenkalti/backoff/v4" + query "github.com/cosmos/cosmos-sdk/types/query" ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" @@ -13,6 +14,7 @@ import ( connectorzevm "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/zevm/zetaconnectorzevm.sol" "github.com/zeta-chain/node/e2e/utils" + "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/retry" "github.com/zeta-chain/node/x/crosschain/types" observertypes "github.com/zeta-chain/node/x/observer/types" @@ -96,12 +98,47 @@ func (r *E2ERunner) WaitForMinedCCTX(txHash ethcommon.Hash) { } // WaitForMinedCCTXFromIndex waits for a cctx to be mined from its index -func (r *E2ERunner) WaitForMinedCCTXFromIndex(index string) { +func (r *E2ERunner) WaitForMinedCCTXFromIndex(index string) *types.CrossChainTx { r.Lock() defer r.Unlock() cctx := utils.WaitCCTXMinedByIndex(r.Ctx, index, r.CctxClient, r.Logger, r.CctxTimeout) utils.RequireCCTXStatus(r, cctx, types.CctxStatus_OutboundMined) + + return cctx +} + +// WaitForSpecificCCTX scans for cctx by filters and ensures it's mined +func (r *E2ERunner) WaitForSpecificCCTX( + filter func(*types.CrossChainTx) bool, + timeout time.Duration, +) *types.CrossChainTx { + var ( + ctx = r.Ctx + start = time.Now() + reqQuery = &types.QueryAllCctxRequest{ + Pagination: &query.PageRequest{Reverse: true}, + } + ) + + for time.Since(start) < timeout { + res, err := r.CctxClient.CctxAll(ctx, reqQuery) + require.NoError(r, err) + + for i := range res.CrossChainTx { + tx := res.CrossChainTx[i] + if filter(tx) { + return r.WaitForMinedCCTXFromIndex(tx.Index) + } + } + + time.Sleep(time.Second) + } + + r.Logger.Error("WaitForSpecificCCTX: No CCTX found. Timed out") + r.FailNow() + + return nil } // SendZetaOnEvm sends ZETA to an address on EVM @@ -279,3 +316,14 @@ func (r *E2ERunner) WithdrawERC20(amount *big.Int) *ethtypes.Transaction { return tx } + +// skipChainOperations checks if the chain operations should be skipped for E2E +func (r *E2ERunner) skipChainOperations(chainID int64) bool { + skip := r.IsRunningUpgrade() && chains.IsTONChain(chainID, nil) + + if skip { + r.Logger.Print("Skipping chain operations for chain %d", chainID) + } + + return skip +} diff --git a/e2e/txserver/zeta_tx_server.go b/e2e/txserver/zeta_tx_server.go index 9ba7e5315a..a79c5af098 100644 --- a/e2e/txserver/zeta_tx_server.go +++ b/e2e/txserver/zeta_tx_server.go @@ -408,6 +408,7 @@ func (zts ZetaTxServer) DeploySystemContracts( // returns the addresses of erc20 zrc20 func (zts ZetaTxServer) DeployZRC20s( accountOperational, accountAdmin, erc20Addr string, + skipChain func(chainID int64) bool, ) (string, error) { // retrieve account accOperational, err := zts.clientCtx.Keyring.Key(accountOperational) @@ -441,8 +442,31 @@ func (zts ZetaTxServer) DeployZRC20s( deployerAddr = addrOperational.String() } + deploy := func(msg *fungibletypes.MsgDeployFungibleCoinZRC20) (string, error) { + // noop + if skipChain(msg.ForeignChainId) { + return "", nil + } + + res, err := zts.BroadcastTx(deployerAccount, msg) + if err != nil { + return "", fmt.Errorf("failed to deploy eth zrc20: %w", err) + } + + addr, err := fetchZRC20FromDeployResponse(res) + if err != nil { + return "", fmt.Errorf("unable to fetch zrc20 from deploy response: %w", err) + } + + if err := zts.InitializeLiquidityCap(addr); err != nil { + return "", fmt.Errorf("unable to initialize liquidity cap: %w", err) + } + + return addr, nil + } + // deploy eth zrc20 - res, err := zts.BroadcastTx(deployerAccount, fungibletypes.NewMsgDeployFungibleCoinZRC20( + _, err = deploy(fungibletypes.NewMsgDeployFungibleCoinZRC20( deployerAddr, "", chains.GoerliLocalnet.ChainId, @@ -455,16 +479,9 @@ func (zts ZetaTxServer) DeployZRC20s( if err != nil { return "", fmt.Errorf("failed to deploy eth zrc20: %s", err.Error()) } - zrc20, err := fetchZRC20FromDeployResponse(res) - if err != nil { - return "", err - } - if err := zts.InitializeLiquidityCap(zrc20); err != nil { - return "", err - } // deploy btc zrc20 - res, err = zts.BroadcastTx(deployerAccount, fungibletypes.NewMsgDeployFungibleCoinZRC20( + _, err = deploy(fungibletypes.NewMsgDeployFungibleCoinZRC20( deployerAddr, "", chains.BitcoinRegtest.ChainId, @@ -477,16 +494,9 @@ func (zts ZetaTxServer) DeployZRC20s( if err != nil { return "", fmt.Errorf("failed to deploy btc zrc20: %s", err.Error()) } - zrc20, err = fetchZRC20FromDeployResponse(res) - if err != nil { - return "", err - } - if err := zts.InitializeLiquidityCap(zrc20); err != nil { - return "", err - } // deploy sol zrc20 - res, err = zts.BroadcastTx(deployerAccount, fungibletypes.NewMsgDeployFungibleCoinZRC20( + _, err = deploy(fungibletypes.NewMsgDeployFungibleCoinZRC20( deployerAddr, "", chains.SolanaLocalnet.ChainId, @@ -499,16 +509,24 @@ func (zts ZetaTxServer) DeployZRC20s( if err != nil { return "", fmt.Errorf("failed to deploy sol zrc20: %s", err.Error()) } - zrc20, err = fetchZRC20FromDeployResponse(res) + + // deploy ton zrc20 + _, err = deploy(fungibletypes.NewMsgDeployFungibleCoinZRC20( + deployerAddr, + "", + chains.TONLocalnet.ChainId, + 9, + "TON", + "TON", + coin.CoinType_Gas, + 100_000, + )) if err != nil { - return "", err - } - if err := zts.InitializeLiquidityCap(zrc20); err != nil { - return "", err + return "", fmt.Errorf("failed to deploy ton zrc20: %w", err) } // deploy erc20 zrc20 - res, err = zts.BroadcastTx(deployerAccount, fungibletypes.NewMsgDeployFungibleCoinZRC20( + erc20zrc20Addr, err := deploy(fungibletypes.NewMsgDeployFungibleCoinZRC20( deployerAddr, erc20Addr, chains.GoerliLocalnet.ChainId, @@ -522,15 +540,6 @@ func (zts ZetaTxServer) DeployZRC20s( return "", fmt.Errorf("failed to deploy erc20 zrc20: %s", err.Error()) } - // fetch the erc20 zrc20 contract address and remove the quotes - erc20zrc20Addr, err := fetchZRC20FromDeployResponse(res) - if err != nil { - return "", err - } - if err := zts.InitializeLiquidityCap(erc20zrc20Addr); err != nil { - return "", err - } - return erc20zrc20Addr, nil } diff --git a/pkg/chains/chain.go b/pkg/chains/chain.go index f5f6ee605d..665251eb39 100644 --- a/pkg/chains/chain.go +++ b/pkg/chains/chain.go @@ -7,6 +7,7 @@ import ( "github.com/btcsuite/btcd/chaincfg" ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/tonkeeper/tongo/ton" ) // Validate checks whether the chain is valid @@ -93,6 +94,10 @@ func (chain Chain) IsBitcoinChain() bool { return chain.Consensus == Consensus_bitcoin } +func (chain Chain) IsTONChain() bool { + return chain.Consensus == Consensus_catchain_consensus +} + // DecodeAddressFromChainID decode the address string to bytes // additionalChains is a list of additional chains to search from // in practice, it is used in the protocol to dynamically support new chains without doing an upgrade @@ -104,6 +109,14 @@ func DecodeAddressFromChainID(chainID int64, addr string, additionalChains []Cha return []byte(addr), nil case IsSolanaChain(chainID, additionalChains): return []byte(addr), nil + case IsTONChain(chainID, additionalChains): + // e.g. `0:55798cb7b87168251a7c39f6806b8c202f6caa0f617a76f4070b3fdacfd056a1` + acc, err := ton.ParseAccountID(addr) + if err != nil { + return nil, fmt.Errorf("invalid TON address %q: %w", addr, err) + } + + return []byte(acc.ToRaw()), nil default: return nil, fmt.Errorf("chain (%d) not supported", chainID) } @@ -132,6 +145,11 @@ func IsSolanaChain(chainID int64, additionalChains []Chain) bool { return ChainIDInChainList(chainID, ChainListByNetwork(Network_solana, additionalChains)) } +// IsTONChain returns true is the chain is TON chain +func IsTONChain(chainID int64, additionalChains []Chain) bool { + return ChainIDInChainList(chainID, ChainListByNetwork(Network_ton, additionalChains)) +} + // IsEthereumChain returns true if the chain is an Ethereum chain // additionalChains is a list of additional chains to search from // in practice, it is used in the protocol to dynamically support new chains without doing an upgrade diff --git a/pkg/chains/chain_test.go b/pkg/chains/chain_test.go index 349651e7b9..4da81c7eee 100644 --- a/pkg/chains/chain_test.go +++ b/pkg/chains/chain_test.go @@ -73,7 +73,7 @@ func TestChain_Validate(t *testing.T) { chain: chains.Chain{ ChainId: 42, Name: "foo", - Network: chains.Network_solana + 1, + Network: chains.Network_ton + 1, NetworkType: chains.NetworkType_testnet, Vm: chains.Vm_evm, Consensus: chains.Consensus_op_stack, @@ -101,7 +101,7 @@ func TestChain_Validate(t *testing.T) { Name: "foo", Network: chains.Network_base, NetworkType: chains.NetworkType_devnet, - Vm: chains.Vm_svm + 1, + Vm: chains.Vm_tvm + 1, Consensus: chains.Consensus_op_stack, IsExternal: true, }, @@ -115,7 +115,7 @@ func TestChain_Validate(t *testing.T) { Network: chains.Network_base, NetworkType: chains.NetworkType_devnet, Vm: chains.Vm_evm, - Consensus: chains.Consensus_solana_consensus + 1, + Consensus: chains.Consensus_catchain_consensus + 1, IsExternal: true, }, errStr: "invalid consensus", @@ -301,6 +301,19 @@ func TestDecodeAddressFromChainID(t *testing.T) { addr: "DCAK36VfExkPdAkYUQg6ewgxyinvcEyPLyHjRbmveKFw", want: []byte("DCAK36VfExkPdAkYUQg6ewgxyinvcEyPLyHjRbmveKFw"), }, + { + name: "TON", + chainID: chains.TONMainnet.ChainId, + addr: "0:55798cb7b87168251a7c39f6806b8c202f6caa0f617a76f4070b3fdacfd056a1", + want: []byte("0:55798cb7b87168251a7c39f6806b8c202f6caa0f617a76f4070b3fdacfd056a1"), + }, + { + name: "TON", + chainID: chains.TONMainnet.ChainId, + // human friendly address should be always represented in raw format + addr: "EQB3ncyBUTjZUA5EnFKR5_EnOMI9V1tTEAAPaiU71gc4TiUt", + want: []byte("0:779dcc815138d9500e449c5291e7f12738c23d575b5310000f6a253bd607384e"), + }, { name: "Non-supported chain", chainID: 9999, diff --git a/pkg/chains/chains.go b/pkg/chains/chains.go index addd6a14df..70692ccc9c 100644 --- a/pkg/chains/chains.go +++ b/pkg/chains/chains.go @@ -113,6 +113,18 @@ var ( Name: "solana_mainnet", } + TONMainnet = Chain{ + // T[20] O[15] N[14] mainnet[0] :) + ChainId: 2015140, + Network: Network_ton, + NetworkType: NetworkType_mainnet, + Vm: Vm_tvm, + Consensus: Consensus_catchain_consensus, + IsExternal: true, + CctxGateway: CCTXGateway_observers, + Name: "ton_mainnet", + } + /** * Testnet chains */ @@ -249,6 +261,17 @@ var ( Name: "solana_devnet", } + TONTestnet = Chain{ + ChainId: 2015141, + Network: Network_ton, + NetworkType: NetworkType_testnet, + Vm: Vm_tvm, + Consensus: Consensus_catchain_consensus, + IsExternal: true, + CctxGateway: CCTXGateway_observers, + Name: "ton_testnet", + } + /** * Devnet chains */ @@ -325,6 +348,17 @@ var ( Name: "solana_localnet", } + TONLocalnet = Chain{ + ChainId: 2015142, + Network: Network_ton, + NetworkType: NetworkType_privnet, + Vm: Vm_tvm, + Consensus: Consensus_catchain_consensus, + IsExternal: true, + CctxGateway: CCTXGateway_observers, + Name: "ton_localnet", + } + /** * Deprecated chains */ @@ -392,6 +426,9 @@ func DefaultChainsList() []Chain { SolanaMainnet, SolanaDevnet, SolanaLocalnet, + TONMainnet, + TONTestnet, + TONLocalnet, } } @@ -449,17 +486,6 @@ func ChainListByGateway(gateway CCTXGateway, additionalChains []Chain) []Chain { return chainList } -// ChainListForHeaderSupport returns a list of chains that support headers -func ChainListForHeaderSupport(additionalChains []Chain) []Chain { - var chainList []Chain - for _, chain := range CombineDefaultChainsList(additionalChains) { - if chain.Consensus == Consensus_ethereum || chain.Consensus == Consensus_bitcoin { - chainList = append(chainList, chain) - } - } - return chainList -} - // ZetaChainFromCosmosChainID returns a ZetaChain chain object from a Cosmos chain ID func ZetaChainFromCosmosChainID(chainID string) (Chain, error) { ethChainID, err := CosmosToEthChainID(chainID) diff --git a/pkg/chains/chains.pb.go b/pkg/chains/chains.pb.go index 217ad55328..ad5ec2f77a 100644 --- a/pkg/chains/chains.pb.go +++ b/pkg/chains/chains.pb.go @@ -156,6 +156,7 @@ const ( Network_optimism Network = 5 Network_base Network = 6 Network_solana Network = 7 + Network_ton Network = 8 ) var Network_name = map[int32]string{ @@ -167,6 +168,7 @@ var Network_name = map[int32]string{ 5: "optimism", 6: "base", 7: "solana", + 8: "ton", } var Network_value = map[string]int32{ @@ -178,6 +180,7 @@ var Network_value = map[string]int32{ "optimism": 5, "base": 6, "solana": 7, + "ton": 8, } func (x Network) String() string { @@ -229,18 +232,21 @@ const ( Vm_no_vm Vm = 0 Vm_evm Vm = 1 Vm_svm Vm = 2 + Vm_tvm Vm = 3 ) var Vm_name = map[int32]string{ 0: "no_vm", 1: "evm", 2: "svm", + 3: "tvm", } var Vm_value = map[string]int32{ "no_vm": 0, "evm": 1, "svm": 2, + "tvm": 3, } func (x Vm) String() string { @@ -257,11 +263,12 @@ func (Vm) EnumDescriptor() ([]byte, []int) { type Consensus int32 const ( - Consensus_ethereum Consensus = 0 - Consensus_tendermint Consensus = 1 - Consensus_bitcoin Consensus = 2 - Consensus_op_stack Consensus = 3 - Consensus_solana_consensus Consensus = 4 + Consensus_ethereum Consensus = 0 + Consensus_tendermint Consensus = 1 + Consensus_bitcoin Consensus = 2 + Consensus_op_stack Consensus = 3 + Consensus_solana_consensus Consensus = 4 + Consensus_catchain_consensus Consensus = 5 ) var Consensus_name = map[int32]string{ @@ -270,14 +277,16 @@ var Consensus_name = map[int32]string{ 2: "bitcoin", 3: "op_stack", 4: "solana_consensus", + 5: "catchain_consensus", } var Consensus_value = map[string]int32{ - "ethereum": 0, - "tendermint": 1, - "bitcoin": 2, - "op_stack": 3, - "solana_consensus": 4, + "ethereum": 0, + "tendermint": 1, + "bitcoin": 2, + "op_stack": 3, + "solana_consensus": 4, + "catchain_consensus": 5, } func (x Consensus) String() string { @@ -455,56 +464,57 @@ func init() { } var fileDescriptor_236b85e7bff6130d = []byte{ - // 770 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0xcd, 0x8e, 0xe4, 0x34, - 0x10, 0xee, 0x24, 0xfd, 0x5b, 0x3d, 0x3f, 0x5e, 0xef, 0x00, 0x61, 0x25, 0x9a, 0x01, 0x09, 0x68, - 0x8d, 0xa0, 0x47, 0xc0, 0x91, 0x03, 0x68, 0x47, 0x2c, 0x42, 0x88, 0x3d, 0x84, 0xd5, 0x0a, 0x71, - 0x69, 0xdc, 0xee, 0x22, 0x6d, 0x75, 0x6c, 0x47, 0xb1, 0x3b, 0xbb, 0xcd, 0x53, 0xf0, 0x10, 0x1c, - 0x90, 0x78, 0x11, 0x8e, 0x7b, 0xe4, 0x88, 0x66, 0x1e, 0x04, 0x64, 0xc7, 0x49, 0x0f, 0x97, 0x9d, - 0x39, 0xc5, 0xfe, 0xf2, 0x7d, 0x55, 0x5f, 0x55, 0xd9, 0x86, 0x8b, 0x5f, 0xd1, 0x32, 0xbe, 0x61, - 0x42, 0x5d, 0xfa, 0x95, 0xae, 0xf0, 0xb2, 0xdc, 0xe6, 0x97, 0x1e, 0x32, 0xe1, 0xb3, 0x28, 0x2b, - 0x6d, 0x35, 0x7d, 0xa7, 0xe3, 0x2e, 0x5a, 0xee, 0xa2, 0xdc, 0xe6, 0x8b, 0x86, 0xf4, 0xe8, 0x2c, - 0xd7, 0xb9, 0xf6, 0xcc, 0x4b, 0xb7, 0x6a, 0x44, 0xef, 0xff, 0x9b, 0xc0, 0xe0, 0xca, 0x11, 0xe8, - 0xdb, 0x30, 0xf6, 0xcc, 0xa5, 0x58, 0xa7, 0xf1, 0x79, 0x34, 0x4f, 0xb2, 0x91, 0xdf, 0x7f, 0xbb, - 0xa6, 0xdf, 0x01, 0x34, 0xbf, 0x14, 0x93, 0x98, 0x46, 0xe7, 0xd1, 0xfc, 0xe4, 0xb3, 0xf9, 0xe2, - 0xb5, 0xe9, 0x16, 0x3e, 0xe8, 0x53, 0x26, 0xf1, 0x71, 0x9c, 0x46, 0xd9, 0x84, 0xb7, 0x5b, 0xfa, - 0x15, 0x8c, 0x14, 0xda, 0x17, 0xba, 0xda, 0xa6, 0x89, 0x8f, 0xf4, 0xe1, 0x1d, 0x91, 0x9e, 0x36, - 0xec, 0xac, 0x95, 0xd1, 0xef, 0xe1, 0x28, 0x2c, 0x97, 0x76, 0x5f, 0x62, 0xda, 0xf7, 0x61, 0x2e, - 0xee, 0x17, 0xe6, 0xd9, 0xbe, 0xc4, 0x6c, 0xaa, 0x0e, 0x1b, 0xfa, 0x29, 0xc4, 0xb5, 0x4c, 0x07, - 0x3e, 0xc8, 0x7b, 0x77, 0x04, 0x79, 0x2e, 0xb3, 0xb8, 0x96, 0xf4, 0x09, 0x4c, 0xb8, 0x56, 0x06, - 0x95, 0xd9, 0x99, 0x74, 0x78, 0xbf, 0x7e, 0xb4, 0xfc, 0xec, 0x20, 0xa5, 0xef, 0xc2, 0x54, 0x98, - 0x25, 0xbe, 0xb4, 0x58, 0x29, 0x56, 0xa4, 0xa3, 0xf3, 0x68, 0x3e, 0xce, 0x40, 0x98, 0xaf, 0x03, - 0xe2, 0x4a, 0xe5, 0xdc, 0xbe, 0x5c, 0xe6, 0xcc, 0xe2, 0x0b, 0xb6, 0x4f, 0xc7, 0xf7, 0x2a, 0xf5, - 0xea, 0xea, 0xd9, 0x8f, 0xdf, 0x34, 0x8a, 0x6c, 0xea, 0xf4, 0x61, 0x43, 0x29, 0xf4, 0xfd, 0x08, - 0x27, 0xe7, 0xd1, 0x7c, 0x92, 0xf9, 0xf5, 0xc5, 0x17, 0x70, 0x9c, 0x21, 0x47, 0x51, 0xe3, 0x0f, - 0x96, 0xd9, 0x9d, 0xa1, 0x53, 0x18, 0xf1, 0x0a, 0x99, 0xc5, 0x35, 0xe9, 0xb9, 0x8d, 0xd9, 0x71, - 0x8e, 0xc6, 0x90, 0x88, 0x02, 0x0c, 0x7f, 0x61, 0xa2, 0xc0, 0x35, 0x89, 0x1f, 0xf5, 0xff, 0xf8, - 0x7d, 0x16, 0x5d, 0xfc, 0x99, 0xc0, 0xa4, 0x9b, 0x34, 0x9d, 0xc0, 0x00, 0x65, 0x69, 0xf7, 0xa4, - 0x47, 0x4f, 0x61, 0x8a, 0x76, 0xb3, 0x94, 0x4c, 0x28, 0x85, 0x96, 0x44, 0x94, 0xc0, 0x91, 0xb3, - 0xda, 0x21, 0xb1, 0xa3, 0xac, 0x2c, 0xef, 0x80, 0x84, 0x3e, 0x84, 0xd3, 0x52, 0x17, 0xfb, 0x5c, - 0xab, 0x0e, 0xec, 0x7b, 0x96, 0x39, 0xb0, 0x06, 0x94, 0xc2, 0x49, 0xae, 0xb1, 0x2a, 0xc4, 0xd2, - 0xa2, 0xb1, 0x0e, 0x1b, 0x3a, 0x4c, 0xee, 0xe4, 0x8a, 0x1d, 0xb0, 0x51, 0x2b, 0x6c, 0x01, 0xe8, - 0x1c, 0xb4, 0xc8, 0xb4, 0x75, 0xd0, 0x02, 0x47, 0xce, 0x81, 0xc1, 0x52, 0x17, 0xe2, 0xc0, 0x3a, - 0x76, 0x60, 0x48, 0x58, 0x68, 0xce, 0x0a, 0x07, 0x9e, 0xb4, 0xd2, 0x0a, 0x73, 0x47, 0x24, 0xa7, - 0x2e, 0x3a, 0x93, 0x7a, 0xdf, 0xe9, 0x08, 0x3d, 0x03, 0xa2, 0x4b, 0x2b, 0xa4, 0x30, 0xb2, 0xb3, - 0xff, 0xe0, 0x7f, 0x68, 0xc8, 0x45, 0xa8, 0x53, 0xaf, 0x98, 0xc1, 0x8e, 0xf7, 0xb0, 0x43, 0x5a, - 0xce, 0x99, 0x2b, 0xd2, 0xe8, 0x82, 0xa9, 0x43, 0x0f, 0xdf, 0xa0, 0x0f, 0xe0, 0x38, 0x60, 0x6b, - 0xac, 0x1d, 0xf4, 0xa6, 0xaf, 0xa1, 0x81, 0x3a, 0xbb, 0x6f, 0x85, 0x69, 0x21, 0x8c, 0xc2, 0x2d, - 0xa0, 0x23, 0x48, 0xd0, 0x6e, 0x48, 0x8f, 0x8e, 0xa1, 0xef, 0xba, 0x42, 0x22, 0x07, 0xad, 0x2c, - 0x27, 0xb1, 0x9b, 0x79, 0x98, 0x03, 0x49, 0x3c, 0x6a, 0x38, 0xe9, 0xd3, 0x23, 0x18, 0xb7, 0xc6, - 0xc9, 0xc0, 0xc9, 0x9c, 0x3d, 0x32, 0x74, 0x87, 0xa2, 0xc9, 0x47, 0x46, 0x21, 0xcd, 0x13, 0x98, - 0xde, 0xba, 0x6c, 0x2e, 0x5c, 0x6b, 0xd8, 0x9f, 0xa7, 0xb6, 0x43, 0x91, 0x4f, 0x54, 0x89, 0xba, - 0x39, 0x0e, 0x00, 0xc3, 0x50, 0x43, 0x12, 0xe2, 0x7c, 0x04, 0xf1, 0x73, 0xe9, 0x0e, 0x95, 0xd2, - 0xcb, 0x5a, 0x92, 0x9e, 0x37, 0x5d, 0xcb, 0xc6, 0xaa, 0xa9, 0x65, 0x77, 0x0a, 0x7f, 0x86, 0x49, - 0x77, 0xbd, 0x9c, 0x4f, 0xb4, 0x1b, 0xac, 0x70, 0xe7, 0x24, 0x27, 0x00, 0x16, 0xd5, 0x1a, 0x2b, - 0x29, 0x54, 0x48, 0xb9, 0x12, 0x96, 0x6b, 0xa1, 0x48, 0xdc, 0x94, 0xb4, 0x34, 0x96, 0xf1, 0x2d, - 0x49, 0xdc, 0x64, 0x42, 0xe3, 0xba, 0x0b, 0x4a, 0xfa, 0x21, 0xc3, 0xc7, 0x30, 0xbd, 0x75, 0xa9, - 0x9a, 0xa6, 0x79, 0x4b, 0xc7, 0x30, 0xd1, 0x2b, 0x83, 0x55, 0x8d, 0x95, 0x21, 0x51, 0xc3, 0x7e, - 0xfc, 0xe5, 0x5f, 0xd7, 0xb3, 0xe8, 0xd5, 0xf5, 0x2c, 0xfa, 0xe7, 0x7a, 0x16, 0xfd, 0x76, 0x33, - 0xeb, 0xbd, 0xba, 0x99, 0xf5, 0xfe, 0xbe, 0x99, 0xf5, 0x7e, 0xfa, 0x20, 0x17, 0x76, 0xb3, 0x5b, - 0x2d, 0xb8, 0x96, 0xfe, 0x41, 0xff, 0xa4, 0x79, 0xdb, 0x95, 0x5e, 0xdf, 0x7e, 0xd7, 0x57, 0x43, - 0xff, 0x38, 0x7f, 0xfe, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x86, 0x0b, 0xc3, 0x03, 0xff, 0x05, - 0x00, 0x00, + // 789 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0xcd, 0x8e, 0x23, 0x35, + 0x10, 0x4e, 0x77, 0xe7, 0xb7, 0x32, 0x3f, 0x5e, 0xef, 0xb0, 0x34, 0x2b, 0x11, 0x06, 0x24, 0x50, + 0x34, 0x82, 0x0c, 0x3f, 0x47, 0x0e, 0xa0, 0x1d, 0xb1, 0x08, 0x21, 0xf6, 0xd0, 0xac, 0x56, 0x88, + 0x4b, 0xe4, 0x38, 0x45, 0xc7, 0x4a, 0xdb, 0x6e, 0xb5, 0x9d, 0xde, 0x09, 0x4f, 0xc1, 0x43, 0x70, + 0x40, 0xe2, 0x45, 0x38, 0xee, 0x91, 0x23, 0x9a, 0x79, 0x10, 0x90, 0xdd, 0xee, 0xce, 0x70, 0xd9, + 0x9d, 0x53, 0xec, 0x2f, 0xdf, 0x57, 0xf5, 0x55, 0x95, 0xed, 0x86, 0x8b, 0x5f, 0xd1, 0x32, 0xbe, + 0x61, 0x42, 0x5d, 0xfa, 0x95, 0xae, 0xf0, 0xb2, 0xdc, 0xe6, 0x97, 0x1e, 0x32, 0xe1, 0x67, 0x51, + 0x56, 0xda, 0x6a, 0xfa, 0x6e, 0xc7, 0x5d, 0xb4, 0xdc, 0x45, 0xb9, 0xcd, 0x17, 0x0d, 0xe9, 0xf1, + 0x59, 0xae, 0x73, 0xed, 0x99, 0x97, 0x6e, 0xd5, 0x88, 0x3e, 0xf8, 0x37, 0x81, 0xc1, 0x95, 0x23, + 0xd0, 0x77, 0x60, 0xec, 0x99, 0x4b, 0xb1, 0x4e, 0xe3, 0xf3, 0x68, 0x9e, 0x64, 0x23, 0xbf, 0xff, + 0x6e, 0x4d, 0xbf, 0x07, 0x68, 0xfe, 0x52, 0x4c, 0x62, 0x1a, 0x9d, 0x47, 0xf3, 0x93, 0xcf, 0xe7, + 0x8b, 0xd7, 0xa6, 0x5b, 0xf8, 0xa0, 0xcf, 0x98, 0xc4, 0x27, 0x71, 0x1a, 0x65, 0x13, 0xde, 0x6e, + 0xe9, 0xd7, 0x30, 0x52, 0x68, 0x5f, 0xea, 0x6a, 0x9b, 0x26, 0x3e, 0xd2, 0x47, 0x6f, 0x88, 0xf4, + 0xac, 0x61, 0x67, 0xad, 0x8c, 0xfe, 0x00, 0x47, 0x61, 0xb9, 0xb4, 0xfb, 0x12, 0xd3, 0xbe, 0x0f, + 0x73, 0x71, 0xbf, 0x30, 0xcf, 0xf7, 0x25, 0x66, 0x53, 0x75, 0xd8, 0xd0, 0xcf, 0x20, 0xae, 0x65, + 0x3a, 0xf0, 0x41, 0xde, 0x7f, 0x43, 0x90, 0x17, 0x32, 0x8b, 0x6b, 0x49, 0x9f, 0xc2, 0x84, 0x6b, + 0x65, 0x50, 0x99, 0x9d, 0x49, 0x87, 0xf7, 0xeb, 0x47, 0xcb, 0xcf, 0x0e, 0x52, 0xfa, 0x1e, 0x4c, + 0x85, 0x59, 0xe2, 0xb5, 0xc5, 0x4a, 0xb1, 0x22, 0x1d, 0x9d, 0x47, 0xf3, 0x71, 0x06, 0xc2, 0x7c, + 0x13, 0x10, 0x57, 0x2a, 0xe7, 0xf6, 0x7a, 0x99, 0x33, 0x8b, 0x2f, 0xd9, 0x3e, 0x1d, 0xdf, 0xab, + 0xd4, 0xab, 0xab, 0xe7, 0x3f, 0x7d, 0xdb, 0x28, 0xb2, 0xa9, 0xd3, 0x87, 0x0d, 0xa5, 0xd0, 0xf7, + 0x23, 0x9c, 0x9c, 0x47, 0xf3, 0x49, 0xe6, 0xd7, 0x17, 0x5f, 0xc2, 0x71, 0x86, 0x1c, 0x45, 0x8d, + 0x3f, 0x5a, 0x66, 0x77, 0x86, 0x4e, 0x61, 0xc4, 0x2b, 0x64, 0x16, 0xd7, 0xa4, 0xe7, 0x36, 0x66, + 0xc7, 0x39, 0x1a, 0x43, 0x22, 0x0a, 0x30, 0xfc, 0x85, 0x89, 0x02, 0xd7, 0x24, 0x7e, 0xdc, 0xff, + 0xe3, 0xf7, 0x59, 0x74, 0xf1, 0x67, 0x02, 0x93, 0x6e, 0xd2, 0x74, 0x02, 0x03, 0x94, 0xa5, 0xdd, + 0x93, 0x1e, 0x3d, 0x85, 0x29, 0xda, 0xcd, 0x52, 0x32, 0xa1, 0x14, 0x5a, 0x12, 0x51, 0x02, 0x47, + 0xce, 0x6a, 0x87, 0xc4, 0x8e, 0xb2, 0xb2, 0xbc, 0x03, 0x12, 0xfa, 0x10, 0x4e, 0x4b, 0x5d, 0xec, + 0x73, 0xad, 0x3a, 0xb0, 0xef, 0x59, 0xe6, 0xc0, 0x1a, 0x50, 0x0a, 0x27, 0xb9, 0xc6, 0xaa, 0x10, + 0x4b, 0x8b, 0xc6, 0x3a, 0x6c, 0xe8, 0x30, 0xb9, 0x93, 0x2b, 0x76, 0xc0, 0x46, 0xad, 0xb0, 0x05, + 0xa0, 0x73, 0xd0, 0x22, 0xd3, 0xd6, 0x41, 0x0b, 0x1c, 0x39, 0x07, 0x06, 0x4b, 0x5d, 0x88, 0x03, + 0xeb, 0xd8, 0x81, 0x21, 0x61, 0xa1, 0x39, 0x2b, 0x1c, 0x78, 0xd2, 0x4a, 0x2b, 0xcc, 0x1d, 0x91, + 0x9c, 0xba, 0xe8, 0x4c, 0xea, 0x7d, 0xa7, 0x23, 0xf4, 0x0c, 0x88, 0x2e, 0xad, 0x90, 0xc2, 0xc8, + 0xce, 0xfe, 0x83, 0xff, 0xa1, 0x21, 0x17, 0xa1, 0x4e, 0xbd, 0x62, 0x06, 0x3b, 0xde, 0xc3, 0x0e, + 0x69, 0x39, 0x67, 0xae, 0x48, 0xa3, 0x0b, 0xa6, 0x0e, 0x3d, 0x7c, 0x8b, 0x3e, 0x80, 0xe3, 0x80, + 0xad, 0xb1, 0x76, 0xd0, 0x23, 0x5f, 0x43, 0x03, 0x75, 0x76, 0xdf, 0x0e, 0xd3, 0x52, 0x30, 0x0a, + 0xb7, 0x80, 0x8e, 0x20, 0x41, 0xbb, 0x21, 0x3d, 0x3a, 0x86, 0xbe, 0xeb, 0x0a, 0x89, 0x1c, 0xb4, + 0xb2, 0x9c, 0xc4, 0x6e, 0xe6, 0x61, 0x0e, 0x24, 0xf1, 0xa8, 0xe1, 0xa4, 0x4f, 0x8f, 0x60, 0xdc, + 0x1a, 0x27, 0x03, 0x27, 0x73, 0xf6, 0xc8, 0xd0, 0x1d, 0x8a, 0x26, 0x1f, 0x19, 0x39, 0xb2, 0xd5, + 0x8a, 0x8c, 0x43, 0xbe, 0xa7, 0x30, 0xbd, 0x73, 0xeb, 0x5c, 0xdc, 0xd6, 0xb9, 0x3f, 0x58, 0x6d, + 0xab, 0x22, 0x9f, 0xb1, 0x12, 0x75, 0x73, 0x2e, 0x00, 0x86, 0xa1, 0x98, 0x24, 0xc4, 0xf9, 0x14, + 0xe2, 0x17, 0xd2, 0x9d, 0x2e, 0xa5, 0x97, 0xb5, 0x24, 0x3d, 0xef, 0xbe, 0x96, 0x8d, 0x67, 0x53, + 0x4b, 0x12, 0xfb, 0xcc, 0xb5, 0xec, 0x14, 0xd7, 0x30, 0xe9, 0x2e, 0x9c, 0x73, 0x8e, 0x76, 0x83, + 0x15, 0xee, 0x9c, 0xf6, 0x04, 0xc0, 0xa2, 0x5a, 0x63, 0x25, 0x85, 0x0a, 0xb9, 0x57, 0xc2, 0x72, + 0x2d, 0x14, 0x89, 0x9b, 0x22, 0x97, 0xc6, 0x32, 0xbe, 0x25, 0x89, 0x9b, 0x55, 0x68, 0x65, 0x77, + 0x65, 0x49, 0x9f, 0x3e, 0x02, 0xca, 0x99, 0x6d, 0x1e, 0xc4, 0x03, 0x3e, 0x08, 0x99, 0x3f, 0x86, + 0xe9, 0x9d, 0xeb, 0xd7, 0xb4, 0xd7, 0x7b, 0x3e, 0x86, 0x89, 0x5e, 0x19, 0xac, 0x6a, 0xac, 0x0c, + 0x89, 0x1a, 0xf6, 0x93, 0xaf, 0xfe, 0xba, 0x99, 0x45, 0xaf, 0x6e, 0x66, 0xd1, 0x3f, 0x37, 0xb3, + 0xe8, 0xb7, 0xdb, 0x59, 0xef, 0xd5, 0xed, 0xac, 0xf7, 0xf7, 0xed, 0xac, 0xf7, 0xf3, 0x87, 0xb9, + 0xb0, 0x9b, 0xdd, 0x6a, 0xc1, 0xb5, 0xf4, 0x4f, 0xff, 0x27, 0xcd, 0x57, 0x40, 0xe9, 0xf5, 0xdd, + 0x2f, 0xc0, 0x6a, 0xe8, 0x9f, 0xf1, 0x2f, 0xfe, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xb9, 0xaa, 0xd0, + 0x56, 0x29, 0x06, 0x00, 0x00, } func (m *Chain) Marshal() (dAtA []byte, err error) { diff --git a/pkg/chains/chains_test.go b/pkg/chains/chains_test.go index 90545bee1c..73c3521ffa 100644 --- a/pkg/chains/chains_test.go +++ b/pkg/chains/chains_test.go @@ -36,6 +36,7 @@ func TestChainListByNetworkType(t *testing.T) { chains.OptimismMainnet, chains.BaseMainnet, chains.SolanaMainnet, + chains.TONMainnet, }, }, { @@ -54,6 +55,7 @@ func TestChainListByNetworkType(t *testing.T) { chains.OptimismSepolia, chains.BaseSepolia, chains.SolanaDevnet, + chains.TONTestnet, }, }, { @@ -64,6 +66,7 @@ func TestChainListByNetworkType(t *testing.T) { chains.BitcoinRegtest, chains.GoerliLocalnet, chains.SolanaLocalnet, + chains.TONLocalnet, }, }, } @@ -132,6 +135,11 @@ func TestChainListByNetwork(t *testing.T) { chains.Network_solana, []chains.Chain{chains.SolanaMainnet, chains.SolanaDevnet, chains.SolanaLocalnet}, }, + { + "TON", + chains.Network_ton, + []chains.Chain{chains.TONMainnet, chains.TONTestnet, chains.TONLocalnet}, + }, } for _, lt := range listTests { @@ -168,6 +176,9 @@ func TestDefaultChainList(t *testing.T) { chains.SolanaMainnet, chains.SolanaDevnet, chains.SolanaLocalnet, + chains.TONMainnet, + chains.TONTestnet, + chains.TONLocalnet, }, chains.DefaultChainsList()) } @@ -202,6 +213,9 @@ func TestChainListByGateway(t *testing.T) { chains.SolanaMainnet, chains.SolanaDevnet, chains.SolanaLocalnet, + chains.TONMainnet, + chains.TONTestnet, + chains.TONLocalnet, }, }, { @@ -246,6 +260,9 @@ func TestExternalChainList(t *testing.T) { chains.SolanaMainnet, chains.SolanaDevnet, chains.SolanaLocalnet, + chains.TONMainnet, + chains.TONTestnet, + chains.TONLocalnet, }, chains.ExternalChainList([]chains.Chain{})) } diff --git a/pkg/contracts/ton/gateway.go b/pkg/contracts/ton/gateway.go new file mode 100644 index 0000000000..33ca2c7977 --- /dev/null +++ b/pkg/contracts/ton/gateway.go @@ -0,0 +1,258 @@ +// Package ton provider bindings for TON blockchain including Gateway contract wrapper. +package ton + +import ( + "cosmossdk.io/math" + "github.com/pkg/errors" + "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" +) + +// Gateway represents bindings for Zeta Gateway contract on TON +// +// Gateway.ParseTransaction parses Gateway transaction. +// The parser reads tx body cell and decodes it based on Operation code (op) +// - inbound transactions: deposit, donate, depositAndCall +// - outbound transactions: not implemented yet +// - errors for all other transactions +// +// `Send*` methods work the same way by constructing (& signing) tx body cell that is expected by the contract +// +// @see https://github.com/zeta-chain/protocol-contracts-ton/blob/main/contracts/gateway.fc +type Gateway struct { + accountID ton.AccountID +} + +const ( + sizeOpCode = 32 + sizeQueryID = 64 +) + +var ( + ErrParse = errors.New("unable to parse tx") + ErrUnknownOp = errors.New("unknown op") + ErrCast = errors.New("unable to cast tx content") +) + +// NewGateway Gateway constructor +func NewGateway(accountID ton.AccountID) *Gateway { + return &Gateway{accountID} +} + +// AccountID returns gateway address +func (gw *Gateway) AccountID() ton.AccountID { + return gw.accountID +} + +// ParseTransaction parses transaction to Transaction +func (gw *Gateway) ParseTransaction(tx ton.Transaction) (*Transaction, error) { + if !tx.IsSuccess() { + exitCode := tx.Description.TransOrd.ComputePh.TrPhaseComputeVm.Vm.ExitCode + return nil, errors.Wrapf(ErrParse, "tx %s is not successful (exit code %d)", tx.Hash().Hex(), exitCode) + } + + if tx.Msgs.InMsg.Exists { + inbound, err := gw.parseInbound(tx) + if err != nil { + return nil, errors.Wrapf(err, "unable to parse inbound tx %s", tx.Hash().Hex()) + } + + return inbound, nil + } + + outbound, err := gw.parseOutbound(tx) + if err != nil { + return nil, errors.Wrapf(err, "unable to parse outbound tx %s", tx.Hash().Hex()) + } + + return outbound, nil +} + +// ParseAndFilter parses transaction and applies filter to it. Returns (tx, skip?, error) +// If parse fails due to known error, skip is set to true +func (gw *Gateway) ParseAndFilter(tx ton.Transaction, filter func(*Transaction) bool) (*Transaction, bool, error) { + parsedTX, err := gw.ParseTransaction(tx) + switch { + case errors.Is(err, ErrParse): + return nil, true, nil + case errors.Is(err, ErrUnknownOp): + return nil, true, nil + case err != nil: + return nil, false, err + } + + if !filter(parsedTX) { + return nil, true, nil + } + + return parsedTX, false, nil +} + +// FilterInbounds filters transactions with deposit operations +func FilterInbounds(tx *Transaction) bool { return tx.IsInbound() } + +func (gw *Gateway) parseInbound(tx ton.Transaction) (*Transaction, error) { + body, err := parseInternalMessageBody(tx) + if err != nil { + return nil, errors.Wrap(err, "unable to parse body") + } + + intMsgInfo := tx.Msgs.InMsg.Value.Value.Info.IntMsgInfo + if intMsgInfo == nil { + return nil, errors.Wrap(ErrParse, "no internal message info") + } + + sourceID, err := ton.AccountIDFromTlb(intMsgInfo.Src) + if err != nil { + return nil, errors.Wrap(err, "unable to parse source account") + } + + destinationID, err := ton.AccountIDFromTlb(intMsgInfo.Dest) + if err != nil { + return nil, errors.Wrap(err, "unable to parse destination account") + } + + if gw.accountID != *destinationID { + return nil, errors.Wrap(ErrParse, "destination account is not gateway") + } + + op, err := body.ReadUint(sizeOpCode) + if err != nil { + return nil, errors.Wrap(err, "unable to read op code") + } + + var ( + sender = *sourceID + opCode = Op(op) + + content any + errContent error + ) + + switch opCode { + case OpDonate: + amount := intMsgInfo.Value.Grams - tx.TotalFees.Grams + content = Donation{Sender: sender, Amount: GramsToUint(amount)} + case OpDeposit: + content, errContent = parseDeposit(tx, sender, body) + case OpDepositAndCall: + content, errContent = parseDepositAndCall(tx, sender, body) + default: + // #nosec G115 always in range + return nil, errors.Wrapf(ErrUnknownOp, "op code %d", int64(op)) + } + + if errContent != nil { + // #nosec G115 always in range + return nil, errors.Wrapf(ErrParse, "unable to parse content for op code %d: %s", int64(op), errContent.Error()) + } + + return &Transaction{ + Transaction: tx, + Operation: opCode, + + content: content, + inbound: true, + }, nil +} + +func parseDeposit(tx ton.Transaction, sender ton.AccountID, body *boc.Cell) (Deposit, error) { + // skip query id + if err := body.Skip(sizeQueryID); err != nil { + return Deposit{}, err + } + + recipient, err := UnmarshalEVMAddress(body) + if err != nil { + return Deposit{}, errors.Wrap(err, "unable to read recipient") + } + + dl, err := parseDepositLog(tx) + if err != nil { + return Deposit{}, errors.Wrap(err, "unable to parse deposit log") + } + + return Deposit{ + Sender: sender, + Amount: dl.Amount, + Recipient: recipient, + }, nil +} + +type depositLog struct { + Amount math.Uint +} + +func parseDepositLog(tx ton.Transaction) (depositLog, error) { + messages := tx.Msgs.OutMsgs.Values() + if len(messages) == 0 { + return depositLog{}, errors.Wrap(ErrParse, "no out messages") + } + + // stored as ref + // cell log = begin_cell() + // .store_uint(op::internal::deposit, size::op_code_size) + // .store_uint(0, size::query_id_size) + // .store_slice(sender) + // .store_coins(deposit_amount) + // .store_uint(evm_recipient, size::evm_address) + // .end_cell(); + + var ( + bodyValue = boc.Cell(messages[0].Value.Body.Value) + body = &bodyValue + ) + + if err := body.Skip(sizeOpCode + sizeQueryID); err != nil { + return depositLog{}, errors.Wrap(err, "unable to skip bits") + } + + // skip msg address (ton sender) + if err := UnmarshalTLB(&tlb.MsgAddress{}, body); err != nil { + return depositLog{}, errors.Wrap(err, "unable to read sender address") + } + + var deposited tlb.Grams + if err := UnmarshalTLB(&deposited, body); err != nil { + return depositLog{}, errors.Wrap(err, "unable to read deposited amount") + } + + return depositLog{Amount: GramsToUint(deposited)}, nil +} + +func parseDepositAndCall(tx ton.Transaction, sender ton.AccountID, body *boc.Cell) (DepositAndCall, error) { + deposit, err := parseDeposit(tx, sender, body) + if err != nil { + return DepositAndCall{}, err + } + + callDataCell, err := body.NextRef() + if err != nil { + return DepositAndCall{}, errors.Wrap(err, "unable to read call data cell") + } + + callData, err := UnmarshalSnakeCell(callDataCell) + if err != nil { + return DepositAndCall{}, errors.Wrap(err, "unable to unmarshal call data") + } + + return DepositAndCall{Deposit: deposit, CallData: callData}, nil +} + +func (gw *Gateway) parseOutbound(_ ton.Transaction) (*Transaction, error) { + return nil, errors.New("not implemented") +} + +func parseInternalMessageBody(tx ton.Transaction) (*boc.Cell, error) { + if !tx.Msgs.InMsg.Exists { + return nil, errors.Wrap(ErrParse, "tx should have an internal message") + } + + var ( + inMsg = tx.Msgs.InMsg.Value.Value + body = boc.Cell(inMsg.Body.Value) + ) + + return &body, nil +} diff --git a/pkg/contracts/ton/gateway_op.go b/pkg/contracts/ton/gateway_op.go new file mode 100644 index 0000000000..7d711ab89c --- /dev/null +++ b/pkg/contracts/ton/gateway_op.go @@ -0,0 +1,115 @@ +package ton + +import ( + "errors" + + "cosmossdk.io/math" + eth "github.com/ethereum/go-ethereum/common" + "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/ton" +) + +// Op operation code +type Op uint32 + +// github.com/zeta-chain/protocol-contracts-ton/blob/main/contracts/gateway.fc +// Inbound operations +const ( + OpDonate Op = 100 + iota + OpDeposit + OpDepositAndCall +) + +// Outbound operations +const ( + OpWithdraw Op = 200 + iota + SetDepositsEnabled + UpdateTSS + UpdateCode +) + +// Donation represents a donation operation +type Donation struct { + Sender ton.AccountID + Amount math.Uint +} + +// AsBody casts struct as internal message body. +func (d Donation) AsBody() (*boc.Cell, error) { + b := boc.NewCell() + err := ErrCollect( + b.WriteUint(uint64(OpDonate), sizeOpCode), + b.WriteUint(0, sizeQueryID), + ) + + return b, err +} + +// Deposit represents a deposit operation +type Deposit struct { + Sender ton.AccountID + Amount math.Uint + Recipient eth.Address +} + +// Memo casts deposit to memo bytes +func (d Deposit) Memo() []byte { + return d.Recipient.Bytes() +} + +// AsBody casts struct as internal message body. +func (d Deposit) AsBody() (*boc.Cell, error) { + b := boc.NewCell() + + return b, writeDepositBody(b, d.Recipient) +} + +// DepositAndCall represents a deposit and call operation +type DepositAndCall struct { + Deposit + CallData []byte +} + +// Memo casts deposit to call to memo bytes +func (d DepositAndCall) Memo() []byte { + recipient := d.Recipient.Bytes() + out := make([]byte, 0, len(recipient)+len(d.CallData)) + + out = append(out, recipient...) + out = append(out, d.CallData...) + + return out +} + +// AsBody casts struct to internal message body. +func (d DepositAndCall) AsBody() (*boc.Cell, error) { + b := boc.NewCell() + + return b, writeDepositAndCallBody(b, d.Recipient, d.CallData) +} + +func writeDepositBody(b *boc.Cell, recipient eth.Address) error { + return ErrCollect( + b.WriteUint(uint64(OpDeposit), sizeOpCode), + b.WriteUint(0, sizeQueryID), + b.WriteBytes(recipient.Bytes()), + ) +} + +func writeDepositAndCallBody(b *boc.Cell, recipient eth.Address, callData []byte) error { + if len(callData) == 0 { + return errors.New("call data is empty") + } + + callDataCell, err := MarshalSnakeCell(callData) + if err != nil { + return err + } + + return ErrCollect( + b.WriteUint(uint64(OpDepositAndCall), sizeOpCode), + b.WriteUint(0, sizeQueryID), + b.WriteBytes(recipient.Bytes()), + b.AddRef(callDataCell), + ) +} diff --git a/pkg/contracts/ton/gateway_send.go b/pkg/contracts/ton/gateway_send.go new file mode 100644 index 0000000000..5dd9c21340 --- /dev/null +++ b/pkg/contracts/ton/gateway_send.go @@ -0,0 +1,72 @@ +package ton + +import ( + "context" + + "cosmossdk.io/math" + eth "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/wallet" +) + +// Sender TON tx sender. +type Sender interface { + Send(ctx context.Context, messages ...wallet.Sendable) error +} + +// see https://docs.ton.org/develop/smart-contracts/messages#message-modes +const ( + SendFlagSeparateFees = uint8(1) + SendFlagIgnoreErrors = uint8(2) +) + +// SendDeposit sends a deposit operation to the gateway on behalf of the sender. +func (gw *Gateway) SendDeposit( + ctx context.Context, + s Sender, + amount math.Uint, + zevmRecipient eth.Address, + sendMode uint8, +) error { + body := boc.NewCell() + + if err := writeDepositBody(body, zevmRecipient); err != nil { + return errors.Wrap(err, "failed to write deposit body") + } + + return gw.send(ctx, s, amount, body, sendMode) +} + +// SendDepositAndCall sends a deposit operation to the gateway on behalf of the sender +// with a callData to the recipient. +func (gw *Gateway) SendDepositAndCall( + ctx context.Context, + s Sender, + amount math.Uint, + zevmRecipient eth.Address, + callData []byte, + sendMode uint8, +) error { + body := boc.NewCell() + + if err := writeDepositAndCallBody(body, zevmRecipient, callData); err != nil { + return errors.Wrap(err, "failed to write depositAndCall body") + } + + return gw.send(ctx, s, amount, body, sendMode) +} + +func (gw *Gateway) send(ctx context.Context, s Sender, amount math.Uint, body *boc.Cell, sendMode uint8) error { + if body == nil { + return errors.New("body is nil") + } + + return s.Send(ctx, wallet.Message{ + Amount: tlb.Coins(amount.Uint64()), + Address: gw.accountID, + Body: body, + Mode: sendMode, + }) +} diff --git a/pkg/contracts/ton/gateway_test.go b/pkg/contracts/ton/gateway_test.go new file mode 100644 index 0000000000..dc680761ff --- /dev/null +++ b/pkg/contracts/ton/gateway_test.go @@ -0,0 +1,313 @@ +package ton + +import ( + "embed" + "encoding/json" + "fmt" + "strings" + "testing" + + "github.com/samber/lo" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" +) + +func TestParsing(t *testing.T) { + swapBodyAndParse := func(gw *Gateway, tx ton.Transaction, body *boc.Cell) *Transaction { + tx.Msgs.InMsg.Value.Value.Body.Value = tlb.Any(*body) + + parsed, err := gw.ParseTransaction(tx) + require.NoError(t, err) + + return parsed + } + + t.Run("Donate", func(t *testing.T) { + // ARRANGE + // Given a tx + tx, fx := getFixtureTX(t, "00-donation") + + // Given a gateway contract + gw := NewGateway(ton.MustParseAccountID(fx.Account)) + + // ACT + parsedTX, err := gw.ParseTransaction(tx) + + // ASSERT + require.NoError(t, err) + + assert.Equal(t, int(OpDonate), int(parsedTX.Operation)) + assert.Equal(t, true, parsedTX.IsInbound()) + + const ( + expectedSender = "0:9594c719ec4c95f66683b2fb1ca0b09de4a41f6fb087ba4c8d265b96a4cce50f" + expectedDonation = 1_499_432_947 // 1.49... TON + ) + + donation, err := parsedTX.Donation() + assert.NoError(t, err) + assert.Equal(t, expectedSender, donation.Sender.ToRaw()) + assert.Equal(t, expectedDonation, int(donation.Amount.Uint64())) + + // Check that AsBody works + var ( + parsedTX2 = swapBodyAndParse(gw, tx, lo.Must(donation.AsBody())) + donation2 = lo.Must(parsedTX2.Donation()) + ) + + assert.Equal(t, donation, donation2) + }) + + t.Run("Deposit", func(t *testing.T) { + // ARRANGE + // Given a tx + tx, fx := getFixtureTX(t, "01-deposit") + + // Given a gateway contract + gw := NewGateway(ton.MustParseAccountID(fx.Account)) + + // ACT + parsedTX, err := gw.ParseTransaction(tx) + + // ASSERT + require.NoError(t, err) + + // Check tx props + assert.Equal(t, int(OpDeposit), int(parsedTX.Operation)) + + // Check deposit + deposit, err := parsedTX.Deposit() + assert.NoError(t, err) + + const ( + expectedSender = "0:9594c719ec4c95f66683b2fb1ca0b09de4a41f6fb087ba4c8d265b96a4cce50f" + vitalikDotETH = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + expectedDeposit = 990_000_000 // 0.99 TON + ) + + assert.Equal(t, expectedSender, deposit.Sender.ToRaw()) + assert.Equal(t, expectedDeposit, int(deposit.Amount.Uint64())) + assert.Equal(t, vitalikDotETH, deposit.Recipient.Hex()) + + // Check that other casting fails + _, err = parsedTX.Donation() + assert.ErrorIs(t, err, ErrCast) + + // Check that AsBody works + var ( + parsedTX2 = swapBodyAndParse(gw, tx, lo.Must(deposit.AsBody())) + deposit2 = lo.Must(parsedTX2.Deposit()) + ) + + assert.Equal(t, deposit, deposit2) + }) + + t.Run("Deposit and call", func(t *testing.T) { + // ARRANGE + // Given a tx + tx, fx := getFixtureTX(t, "02-deposit-and-call") + + // Given a gateway contract + gw := NewGateway(ton.MustParseAccountID(fx.Account)) + + // ACT + parsedTX, err := gw.ParseTransaction(tx) + + // ASSERT + require.NoError(t, err) + + // Check tx props + assert.Equal(t, int(OpDepositAndCall), int(parsedTX.Operation)) + + // Check deposit and call + depositAndCall, err := parsedTX.DepositAndCall() + assert.NoError(t, err) + + const ( + expectedSender = "0:9594c719ec4c95f66683b2fb1ca0b09de4a41f6fb087ba4c8d265b96a4cce50f" + vitalikDotETH = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" + expectedDeposit = 490_000_000 // 0.49 TON + ) + + expectedCallData := readFixtureFile(t, "testdata/long-call-data.txt") + + assert.Equal(t, expectedSender, depositAndCall.Sender.ToRaw()) + assert.Equal(t, expectedDeposit, int(depositAndCall.Amount.Uint64())) + assert.Equal(t, vitalikDotETH, depositAndCall.Recipient.Hex()) + assert.Equal(t, expectedCallData, depositAndCall.CallData) + + // Check that AsBody works + var ( + parsedTX2 = swapBodyAndParse(gw, tx, lo.Must(depositAndCall.AsBody())) + depositAndCall2 = lo.Must(parsedTX2.DepositAndCall()) + ) + + assert.Equal(t, depositAndCall, depositAndCall2) + }) + + t.Run("Irrelevant tx", func(t *testing.T) { + t.Run("Failed tx", func(t *testing.T) { + // ARRANGE + // Given a tx + tx, fx := getFixtureTX(t, "03-failed-tx") + + // Given a gateway contract + gw := NewGateway(ton.MustParseAccountID(fx.Account)) + + // ACT + _, err := gw.ParseTransaction(tx) + + assert.ErrorIs(t, err, ErrParse) + + // 102 is 'unknown op' + // https://github.com/zeta-chain/protocol-contracts-ton/blob/main/contracts/common/errors.fc + assert.ErrorContains(t, err, "is not successful (exit code 102)") + }) + + t.Run("not a deposit nor withdrawal", func(t *testing.T) { + // actually, it's a bounce of the previous tx + + // ARRANGE + // Given a tx + tx, fx := getFixtureTX(t, "04-bounced-msg") + + // Given a gateway contract + gw := NewGateway(ton.MustParseAccountID(fx.Account)) + + // ACT + _, err := gw.ParseTransaction(tx) + assert.Error(t, err) + }) + }) +} + +func TestFiltering(t *testing.T) { + t.Run("Inbound", func(t *testing.T) { + for _, tt := range []struct { + name string + skip bool + error bool + }{ + // Should be parsed and filtered + {"00-donation", false, false}, + {"01-deposit", false, false}, + {"02-deposit-and-call", false, false}, + + // Should be skipped + {"03-failed-tx", true, false}, + {"04-bounced-msg", true, false}, + } { + t.Run(tt.name, func(t *testing.T) { + // ARRANGE + // Given a tx + tx, fx := getFixtureTX(t, tt.name) + + // Given a gateway + gw := NewGateway(ton.MustParseAccountID(fx.Account)) + + // ACT + parsedTX, skip, err := gw.ParseAndFilter(tx, FilterInbounds) + + if tt.error { + require.Error(t, err) + assert.False(t, skip) + assert.Nil(t, parsedTX) + return + } + + require.NoError(t, err) + assert.Equal(t, tt.skip, skip) + + if tt.skip { + assert.Nil(t, parsedTX) + return + } + + assert.NotNil(t, parsedTX) + }) + } + }) +} + +func TestFixtures(t *testing.T) { + // ACT + tx, _ := getFixtureTX(t, "01-deposit") + + // ASSERT + require.Equal(t, uint64(26023788000003), tx.Lt) + require.Equal(t, "cbd6e2261334d08120e2fef428ecbb4e7773606ced878d0e6da204f2b4bf42bf", tx.Hash().Hex()) +} + +func TestSnakeData(t *testing.T) { + for _, tt := range []string{ + "Hello world", + "123", + strings.Repeat(`ZetaChain `, 300), + string(readFixtureFile(t, "testdata/long-call-data.txt")), + } { + a := []byte(tt) + + cell, err := MarshalSnakeCell(a) + require.NoError(t, err) + + b, err := UnmarshalSnakeCell(cell) + require.NoError(t, err) + + t.Logf(string(b)) + + assert.Equal(t, a, b, tt) + } +} + +//go:embed testdata +var fixtures embed.FS + +type fixture struct { + Account string `json:"account"` + BOC string `json:"boc"` + Description string `json:"description"` + Hash string `json:"hash"` + LogicalTime uint64 `json:"logicalTime"` + Test bool `json:"test"` +} + +// testdata/$name.json tx +func getFixtureTX(t *testing.T, name string) (ton.Transaction, fixture) { + t.Helper() + + var ( + filename = fmt.Sprintf("testdata/%s.json", name) + b = readFixtureFile(t, filename) + ) + + // bag of cells + var fx fixture + + require.NoError(t, json.Unmarshal(b, &fx)) + + cells, err := boc.DeserializeBocHex(fx.BOC) + require.NoError(t, err) + require.Len(t, cells, 1) + + cell := cells[0] + + var tx ton.Transaction + + require.NoError(t, tx.UnmarshalTLB(cell, &tlb.Decoder{})) + + t.Logf("Loaded fixture %s\n%s", filename, fx.Description) + + return tx, fx +} + +func readFixtureFile(t *testing.T, filename string) []byte { + t.Helper() + + b, err := fixtures.ReadFile(filename) + require.NoError(t, err, filename) + + return b +} diff --git a/pkg/contracts/ton/gateway_tx.go b/pkg/contracts/ton/gateway_tx.go new file mode 100644 index 0000000000..75c12c8eff --- /dev/null +++ b/pkg/contracts/ton/gateway_tx.go @@ -0,0 +1,51 @@ +package ton + +import ( + "cosmossdk.io/errors" + "cosmossdk.io/math" + "github.com/tonkeeper/tongo/ton" +) + +// Transaction represents a Gateway transaction. +type Transaction struct { + ton.Transaction + Operation Op + + content any + inbound bool +} + +// IsInbound returns true if the transaction is inbound. +func (tx *Transaction) IsInbound() bool { + return tx.inbound +} + +// GasUsed returns the amount of gas used by the transaction. +func (tx *Transaction) GasUsed() math.Uint { + return math.NewUint(uint64(tx.TotalFees.Grams)) +} + +// Donation casts the transaction content to a Donation. +func (tx *Transaction) Donation() (Donation, error) { + return retrieveContent[Donation](tx) +} + +// Deposit casts the transaction content to a Deposit. +func (tx *Transaction) Deposit() (Deposit, error) { + return retrieveContent[Deposit](tx) +} + +// DepositAndCall casts the transaction content to a DepositAndCall. +func (tx *Transaction) DepositAndCall() (DepositAndCall, error) { + return retrieveContent[DepositAndCall](tx) +} + +func retrieveContent[T any](tx *Transaction) (T, error) { + typed, ok := tx.content.(T) + if !ok { + var tt T + return tt, errors.Wrapf(ErrCast, "not a %T (op %d)", tt, int(tx.Operation)) + } + + return typed, nil +} diff --git a/pkg/contracts/ton/testdata/00-donation.json b/pkg/contracts/ton/testdata/00-donation.json new file mode 100644 index 0000000000..867f096a90 --- /dev/null +++ b/pkg/contracts/ton/testdata/00-donation.json @@ -0,0 +1,8 @@ +{ + "account": "0:997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b", + "boc": "b5ee9c72010207010001a10003b57997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b000017d46c458143cbd6e2261334d08120e2fef428ecbb4e7773606ced878d0e6da204f2b4bf42bf000017ab22a3b30366f17efd000146114e1a80102030101a00400827213c7e41677dcade29f2b424cdad8712132fbd5465b37df2e1763369e2fb12da0a7b38b0f8722a81351a279e9d229e4f5d92a5d91aed6c197ab4b5ef756b042cc021b04c0731749165a0bc01860db5611050600c968012b298e33d8992beccd0765f63941613bc9483edf610f74991a4cb72d4999ca1f00265f62272056bab08711fe1ab838e0e0fbf0f0d18c19d60bd898eb5231685216d165a0bc000608235a00002fa8d88b0284cde2fdfa00000032000000000000000040009e408c6c3d090000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005bc00000000000000000000000012d452da449e50b8cf7dd27861f146122afe1b546bb8b70fc8216f0c614139f8e04", + "description": "Sample donation to gw contract. https://testnet.tonviewer.com/transaction/d9339c9e78a55ee9ea0cd46cab798926c139db2a7c17a002041c3db90a80d5ea", + "hash": "d9339c9e78a55ee9ea0cd46cab798926c139db2a7c17a002041c3db90a80d5ea", + "logicalTime": 26201117000003, + "test": true +} \ No newline at end of file diff --git a/pkg/contracts/ton/testdata/01-deposit.json b/pkg/contracts/ton/testdata/01-deposit.json new file mode 100644 index 0000000000..d22170ddf0 --- /dev/null +++ b/pkg/contracts/ton/testdata/01-deposit.json @@ -0,0 +1,8 @@ +{ + "account": "0:997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b", + "boc": "b5ee9c7201020a0100023d0003b57997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b000017ab22a3b3031b48df020aa3647a59163a25772d81991916a2bf523b771d89deec9e5be15d58000017ab20f8740366ead1e30003465b1d0080102030201e004050082723e346a6461f48fab691e87d9fd5954595eb15351fa1c536486a863d9708b79c313c7e41677dcade29f2b424cdad8712132fbd5465b37df2e1763369e2fb12da0021904222490ee6b28018646dca110080900f168012b298e33d8992beccd0765f63941613bc9483edf610f74991a4cb72d4999ca1f00265f62272056bab08711fe1ab838e0e0fbf0f0d18c19d60bd898eb5231685216d0ee6b28000608235a00002f5645476604cdd5a3c60000003280000000000000006c6d35f934b257cebf76cf01f29a0ae9bd54b022c00101df06015de004cbec44e40ad75610e23fc357071c1c1f7e1e1a31833ac17b131d6a462d0a42d800002f5645476608cdd5a3c6c007008b0000006500000000000000008012b298e33d8992beccd0765f63941613bc9483edf610f74991a4cb72d4999ca1e876046701b1b4d7e4d2c95f3afddb3c07ca682ba6f552c08b009e42d5ac3d090000000000000000007e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006fc98510184c2880c0000000000002000000000003da7f47a5d1898330bd18801617ae23a388cbaf527c312921718ef36ce9cf8c4e40901d04", + "description": "Sample deposit to gw contract. https://testnet.tonviewer.com/transaction/cbd6e2261334d08120e2fef428ecbb4e7773606ced878d0e6da204f2b4bf42bf", + "hash": "cbd6e2261334d08120e2fef428ecbb4e7773606ced878d0e6da204f2b4bf42bf", + "logicalTime": 26023788000003, + "test": true +} diff --git a/pkg/contracts/ton/testdata/02-deposit-and-call.json b/pkg/contracts/ton/testdata/02-deposit-and-call.json new file mode 100644 index 0000000000..60f824a828 --- /dev/null +++ b/pkg/contracts/ton/testdata/02-deposit-and-call.json @@ -0,0 +1,8 @@ +{ + "account": "0:997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b", + "boc": "b5ee9c7201021a01000a040003b57997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b000017d4acf14a83d9339c9e78a55ee9ea0cd46cab798926c139db2a7c17a002041c3db90a80d5ea000017d46c45814366f1896b000347487d2080102030201e00405008272a7b38b0f8722a81351a279e9d229e4f5d92a5d91aed6c197ab4b5ef756b042ccdb7075fb2e3f1dc397aa3c93d8dd352cbe54af9fb033df63082875f03a70947102190480b409077359401866309211181901f168012b298e33d8992beccd0765f63941613bc9483edf610f74991a4cb72d4999ca1f00265f62272056bab08711fe1ab838e0e0fbf0f0d18c19d60bd898eb5231685216d077359400069397a000002fa959e29504cde312d60000003300000000000000006c6d35f934b257cebf76cf01f29a0ae9bd54b022c0080101df06015de004cbec44e40ad75610e23fc357071c1c1f7e1e1a31833ac17b131d6a462d0a42d800002fa959e29508cde312d6c007018b0000006600000000000000008012b298e33d8992beccd0765f63941613bc9483edf610f74991a4cb72d4999ca1e83a699d01b1b4d7e4d2c95f3afddb3c07ca682ba6f552c08b0801fe57686174206973204c6f72656d20497073756d3f2028617070726f782032204b696c6f6279746573290a0a4c6f72656d20497073756d2069732073696d706c792064756d6d792074657874206f6620746865207072696e74696e6720616e64207479706573657474696e6720696e6475737472792e0a4c6f72656d204970730901fe756d20686173206265656e2074686520696e6475737472792773207374616e646172642064756d6d79207465787420657665722073696e6365207468652031353030732c207768656e20616e20756e6b6e6f776e207072696e74657220746f6f6b0a612067616c6c6579206f66207479706520616e6420736372616d626c650a01fe6420697420746f206d616b65206120747970652073706563696d656e20626f6f6b2e20497420686173207375727669766564206e6f74206f6e6c7920666976652063656e7475726965732c0a62757420616c736f20746865206c65617020696e746f20656c656374726f6e6963207479706573657474696e672c2072656d610b01fe696e696e6720657373656e7469616c6c7920756e6368616e6765642e0a0a49742077617320706f70756c61726973656420696e207468652031393630732077697468207468652072656c65617365206f66204c657472617365742073686565747320636f6e7461696e696e67204c6f72656d20497073756d207061737361670c01fe65732c0a616e64206d6f726520726563656e746c792077697468206465736b746f70207075626c697368696e6720736f667477617265206c696b6520416c64757320506167654d616b657220696e636c7564696e672076657273696f6e73206f66204c6f72656d20497073756d2e0a0a57687920646f2077652075736520690d01fe743f0a0a49742069732061206c6f6e672d65737461626c6973686564206661637420746861742061207265616465722077696c6c206265206469737472616374656420627920746865207265616461626c6520636f6e74656e74206f6620612070616765207768656e0a6c6f6f6b696e6720617420697473206c61796f75740e01fe2e2054686520706f696e74206f66207573696e67204c6f72656d20497073756d2069732074686174206974206861732061206d6f72652d6f722d6c657373206e6f726d616c20646973747269627574696f6e206f66206c6574746572732c0a6173206f70706f73656420746f207573696e672027436f6e74656e74206865720f01fe652c20636f6e74656e742068657265272c206d616b696e67206974206c6f6f6b206c696b65207265616461626c6520456e676c6973682e204d616e79206465736b746f70207075626c697368696e670a7061636b6167657320616e6420776562207061676520656469746f7273206e6f7720757365204c6f72656d204970731001fe756d2061732074686569722064656661756c74206d6f64656c20746578742c20616e6420612073656172636820666f7220276c6f72656d20697073756d270a77696c6c20756e636f766572206d616e7920776562207369746573207374696c6c20696e20746865697220696e66616e63792e20566172696f757320766572731101fe696f6e7320686176652065766f6c766564206f766572207468652079656172732c20736f6d6574696d65730a6279206163636964656e742c20736f6d6574696d6573206f6e20707572706f73652028696e6a65637465642068756d6f757220616e6420746865206c696b65292e0a0a576865726520646f657320697420636f1201fe6d652066726f6d3f0a0a436f6e747261727920746f20706f70756c61722062656c6965662c204c6f72656d20497073756d206973206e6f742073696d706c792072616e646f6d20746578742e2049742068617320726f6f747320696e2061207069656365206f6620636c6173736963616c0a4c6174696e206c6974657261741301fe7572652066726f6d2034352042432c206d616b696e67206974206f7665722032303030207965617273206f6c642e2052696368617264204d63436c696e746f636b2c2061204c6174696e2070726f666573736f720a61742048616d7064656e2d5379646e657920436f6c6c65676520696e2056697267696e69612c206c6f6f1401fe6b6564207570206f6e65206f6620746865206d6f7265206f627363757265204c6174696e20776f7264732c20636f6e73656374657475722c0a66726f6d2061204c6f72656d20497073756d20706173736167652c20616e6420676f696e67207468726f75676820746865206369746573206f662074686520776f726420696e1501fe20636c6173736963616c206c6974657261747572652c20646973636f76657265640a74686520756e646f75627461626c6520736f757263652e204c6f72656d20497073756d20636f6d65732066726f6d2073656374696f6e7320312e31302e333220616e6420312e31302e3333206f66202264652046696e6962757320426f1601fe6e6f72756d206574204d616c6f72756d220a285468652045787472656d6573206f6620476f6f6420616e64204576696c292062792043696365726f2c207772697474656e20696e2034352042432e205468697320626f6f6b2069732061207472656174697365206f6e20746865207468656f7279206f66206574686963732c17004a0a7665727920706f70756c617220647572696e67207468652052656e61697373616e63652e009e43f62c3d090000000000000000009b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006fc9b95b984dcadcc0000000000002000000000003fa4c79ea2219e757506c681b3ab938299662dccbcef3f334edcddee1cd13bade44920284", + "description": "Sample deposit-and-call to gw contract. https://testnet.tonviewer.com/transaction/3647f17cc28e4a70404a10c62ad6262fbf67aa72579acde449d66cc0d0fd7ca8", + "hash": "3647f17cc28e4a70404a10c62ad6262fbf67aa72579acde449d66cc0d0fd7ca8", + "logicalTime": 26202202000003, + "test": true +} \ No newline at end of file diff --git a/pkg/contracts/ton/testdata/03-failed-tx.json b/pkg/contracts/ton/testdata/03-failed-tx.json new file mode 100644 index 0000000000..0fa772b7fe --- /dev/null +++ b/pkg/contracts/ton/testdata/03-failed-tx.json @@ -0,0 +1,8 @@ +{ + "account": "0:997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b", + "boc": "b5ee9c72010208010001e90003b57997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b000017d5af81eb033647f17cc28e4a70404a10c62ad6262fbf67aa72579acde449d66cc0d0fd7ca8000017d4acf14a8366f1b2b00003461489a480102030201e00405008272db7075fb2e3f1dc397aa3c93d8dd352cbe54af9fb033df63082875f03a709471f41d1551f3ff76f22096fabf1806f354a5437a60a611df452f2a78e6dbd9adab01290482c7c9017d78401061061c0e0181046998208d6a0700cb68012b298e33d8992beccd0765f63941613bc9483edf610f74991a4cb72d4999ca1f00265f62272056bab08711fe1ab838e0e0fbf0f0d18c19d60bd898eb5231685216d017d784000608235a00002fab5f03d604cde365602432b6363796102bb7b9363210c00101df0600d3580132fb113902b5d584388ff0d5c1c70707df87868c60ceb05ec4c75a918b4290b700256531c67b13257d99a0ecbec7282c27792907dbec21ee93234996e5a9333943d0179e56800608235a00002fab5f03d608cde365607fffffffa432b6363796102bb7b9363210c0009e40a7cc0f424000000000cc0000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "description": "failed tx with body='Hello, World!'; https://testnet.tonviewer.com/transaction/653d37cfbff76585d336fb74a0eaa7fe6d1a2b3cae56d5e5f9609a821c9f1e45", + "hash": "653d37cfbff76585d336fb74a0eaa7fe6d1a2b3cae56d5e5f9609a821c9f1e45", + "logicalTime": 26206540000003, + "test": true +} diff --git a/pkg/contracts/ton/testdata/04-bounced-msg.json b/pkg/contracts/ton/testdata/04-bounced-msg.json new file mode 100644 index 0000000000..9887db3123 --- /dev/null +++ b/pkg/contracts/ton/testdata/04-bounced-msg.json @@ -0,0 +1,8 @@ +{ + "account": "0:9594c719ec4c95f66683b2fb1ca0b09de4a41f6fb087ba4c8d265b96a4cce50f", + "boc": "b5ee9c72010207010001a30003b579594c719ec4c95f66683b2fb1ca0b09de4a41f6fb087ba4c8d265b96a4cce50f000017d5af81eb05b4269279feefdc3ea4220465ec2bce20c6e7f0a8c09b51dac55b90aef3c342c6000017d5af81eb0166f1b2b0000146097f4080102030101a0040082727682d6ce21cbeaec70573e8d6ab7dc6357b875cbffc8c50608035fda3fe3bc378db05a075336855e0ae2db0067bf7de2341a87b9d555e968d64b216fe5491aba02150c090179e568186097f411050600d3580132fb113902b5d584388ff0d5c1c70707df87868c60ceb05ec4c75a918b4290b700256531c67b13257d99a0ecbec7282c27792907dbec21ee93234996e5a9333943d0179e56800608235a00002fab5f03d608cde365607fffffffa432b6363796102bb7b9363210c0009e40614c0f1da800000000000000001700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005bc00000000000000000000000012d452da449e50b8cf7dd27861f146122afe1b546bb8b70fc8216f0c614139f8e04", + "description": "Sample bounced message. This address is not even a gw. https://testnet.tonviewer.com/transaction/b3c46f5faf8aee7348083e7adbbc9a60ab1c8e0eac09133d64e2c4eb831e607b", + "hash": "b3c46f5faf8aee7348083e7adbbc9a60ab1c8e0eac09133d64e2c4eb831e607b", + "logicalTime": 26206540000005, + "test": true +} diff --git a/pkg/contracts/ton/testdata/long-call-data.txt b/pkg/contracts/ton/testdata/long-call-data.txt new file mode 100644 index 0000000000..d66c4d103a --- /dev/null +++ b/pkg/contracts/ton/testdata/long-call-data.txt @@ -0,0 +1,28 @@ +What is Lorem Ipsum? (approx 2 Kilobytes) + +Lorem Ipsum is simply dummy text of the printing and typesetting industry. +Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took +a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, +but also the leap into electronic typesetting, remaining essentially unchanged. + +It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, +and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. + +Why do we use it? + +It is a long-established fact that a reader will be distracted by the readable content of a page when +looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, +as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing +packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' +will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes +by accident, sometimes on purpose (injected humour and the like). + +Where does it come from? + +Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical +Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor +at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, +from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered +the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" +(The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, +very popular during the Renaissance. \ No newline at end of file diff --git a/pkg/contracts/ton/testdata/readme.md b/pkg/contracts/ton/testdata/readme.md new file mode 100644 index 0000000000..8695f06982 --- /dev/null +++ b/pkg/contracts/ton/testdata/readme.md @@ -0,0 +1,29 @@ +# TON transaction scraper + +`scraper.go` represents a handy tool that allows to fetch transactions from TON blockchain +for further usage in test cases. + +`go run pkg/contracts/ton/testdata/scraper.go
[--testnet]` + +## Example usage + +```sh +go run pkg/contracts/ton/testdata/scraper.go -testnet \ + kQCZfYicgVrqwhxH-Grg44OD78PDRjBnWC9iY61IxaFIW77M \ + 26023788000003 \ + cbd6e2261334d08120e2fef428ecbb4e7773606ced878d0e6da204f2b4bf42bf | jq +``` + +Returns + +```json +{ + "account": "0:997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b", + "boc": "b5ee9c7201020a0100023d0003b57997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b000017ab22a3b3031b48df020aa3647a59163a25772d81991916a2bf523b771d89deec9e5be15d58000017ab20f8740366ead1e30003465b1d0080102030201e004050082723e346a6461f48fab691e87d9fd5954595eb15351fa1c536486a863d9708b79c313c7e41677dcade29f2b424cdad8712132fbd5465b37df2e1763369e2fb12da0021904222490ee6b28018646dca110080900f168012b298e33d8992beccd0765f63941613bc9483edf610f74991a4cb72d4999ca1f00265f62272056bab08711fe1ab838e0e0fbf0f0d18c19d60bd898eb5231685216d0ee6b28000608235a00002f5645476604cdd5a3c60000003280000000000000006c6d35f934b257cebf76cf01f29a0ae9bd54b022c00101df06015de004cbec44e40ad75610e23fc357071c1c1f7e1e1a31833ac17b131d6a462d0a42d800002f5645476608cdd5a3c6c007008b0000006500000000000000008012b298e33d8992beccd0765f63941613bc9483edf610f74991a4cb72d4999ca1e876046701b1b4d7e4d2c95f3afddb3c07ca682ba6f552c08b009e42d5ac3d090000000000000000007e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006fc98510184c2880c0000000000002000000000003da7f47a5d1898330bd18801617ae23a388cbaf527c312921718ef36ce9cf8c4e40901d04", + "description": "Lorem Ipsum", + "hash": "cbd6e2261334d08120e2fef428ecbb4e7773606ced878d0e6da204f2b4bf42bf", + "logicalTime": 26023788000003, + "test": true +} +``` + diff --git a/pkg/contracts/ton/testdata/scraper.go b/pkg/contracts/ton/testdata/scraper.go new file mode 100644 index 0000000000..efe76ca3aa --- /dev/null +++ b/pkg/contracts/ton/testdata/scraper.go @@ -0,0 +1,131 @@ +package main + +import ( + "context" + "encoding/json" + "flag" + "fmt" + "log" + "strconv" + + "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/liteapi" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" +) + +func main() { + var testnet bool + + flag.BoolVar(&testnet, "testnet", false, "Use testnet network") + flag.Parse() + + if len(flag.Args()) < 3 { + log.Fatalf("Usage: go run scraper.go [-testnet] ") + } + + // Parse account + acc, err := ton.ParseAccountID(flag.Arg(0)) + must(err, "Unable to parse account") + + // Parse LT + lt, err := strconv.ParseUint(flag.Arg(1), 10, 64) + must(err, "Unable to parse logical time") + + // Parse hash + var hash ton.Bits256 + + must(hash.FromHex(flag.Arg(2)), "Unable to parse hash") + + ctx, client := context.Background(), getClient(testnet) + + state, err := client.GetAccountState(ctx, acc) + must(err, "Unable to get account state") + + if state.Account.Status() != tlb.AccountActive { + fail("account %s is not active", acc.ToRaw()) + } + + txs, err := client.GetTransactions(ctx, 1, acc, lt, hash) + must(err, "Unable to get transactions") + + switch { + case len(txs) == 0: + fail("Not found") + case len(txs) > 1: + fail("invalid tx list length (got %d, want 1); lt %d, hash %s", len(txs), lt, hash.Hex()) + } + + // Print the transaction + tx := txs[0] + + cell, err := transactionToCell(tx) + must(err, "unable to convert tx to cell") + + bocRaw, err := cell.MarshalJSON() + must(err, "unable to marshal cell to JSON") + + printAny(map[string]any{ + "test": testnet, + "account": acc.ToRaw(), + "description": "todo", + "logicalTime": lt, + "hash": hash.Hex(), + "boc": json.RawMessage(bocRaw), + }) +} + +func getClient(testnet bool) *liteapi.Client { + if testnet { + c, err := liteapi.NewClientWithDefaultTestnet() + must(err, "unable to create testnet lite client") + + return c + } + + c, err := liteapi.NewClientWithDefaultMainnet() + must(err, "unable to create mainnet lite client") + + return c +} + +func printAny(v any) { + b, err := json.MarshalIndent(v, "", " ") + must(err, "unable marshal data") + + fmt.Println(string(b)) +} + +func transactionToCell(tx ton.Transaction) (*boc.Cell, error) { + b, err := tx.SourceBoc() + if err != nil { + return nil, err + } + + cells, err := boc.DeserializeBoc(b) + if err != nil { + return nil, err + } + + if len(cells) != 1 { + return nil, fmt.Errorf("invalid cell count: %d", len(cells)) + } + + return cells[0], nil +} + +func must(err error, msg string) { + if err == nil { + return + } + + if msg == "" { + log.Fatalf("Error: %s", err.Error()) + } + + log.Fatalf("%s; error: %s", msg, err.Error()) +} + +func fail(msg string, args ...any) { + must(fmt.Errorf(msg, args...), "FAIL") +} diff --git a/pkg/contracts/ton/tlb.go b/pkg/contracts/ton/tlb.go new file mode 100644 index 0000000000..0ee3aea98a --- /dev/null +++ b/pkg/contracts/ton/tlb.go @@ -0,0 +1,79 @@ +package ton + +import ( + "bytes" + + "cosmossdk.io/math" + eth "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/tlb" +) + +// MarshalTLB encodes entity to BOC +func MarshalTLB(v tlb.MarshalerTLB) (*boc.Cell, error) { + cell := boc.NewCell() + + if err := v.MarshalTLB(cell, &tlb.Encoder{}); err != nil { + return nil, err + } + + return cell, nil +} + +// UnmarshalTLB decodes entity from BOC +func UnmarshalTLB(t tlb.UnmarshalerTLB, cell *boc.Cell) error { + return t.UnmarshalTLB(cell, &tlb.Decoder{}) +} + +// UnmarshalSnakeCell decodes TLB cell to []byte using snake-cell encoding +func UnmarshalSnakeCell(cell *boc.Cell) ([]byte, error) { + var sd tlb.SnakeData + + if err := UnmarshalTLB(&sd, cell); err != nil { + return nil, err + } + + cd := boc.BitString(sd) + + // TLB operates with bits, so we (might) need to trim some "leftovers" (null chars) + return bytes.Trim(cd.Buffer(), "\x00"), nil +} + +// MarshalSnakeCell encodes []byte to TLB using snake-cell encoding +func MarshalSnakeCell(data []byte) (*boc.Cell, error) { + b := boc.NewCell() + + wrapped := tlb.Bytes(data) + if err := wrapped.MarshalTLB(b, &tlb.Encoder{}); err != nil { + return nil, err + } + + return b, nil +} + +// UnmarshalEVMAddress decodes eth.Address from BOC +func UnmarshalEVMAddress(cell *boc.Cell) (eth.Address, error) { + const evmAddrBits = 20 * 8 + + s, err := cell.ReadBits(evmAddrBits) + if err != nil { + return eth.Address{}, err + } + + return eth.BytesToAddress(s.Buffer()), nil +} + +func GramsToUint(g tlb.Grams) math.Uint { + return math.NewUint(uint64(g)) +} + +func ErrCollect(errs ...error) error { + for i, err := range errs { + if err != nil { + return errors.Wrapf(err, "error at index %d", i) + } + } + + return nil +} diff --git a/pkg/ticker/ticker.go b/pkg/ticker/ticker.go index 94fc9ab2fb..2a5a7edff1 100644 --- a/pkg/ticker/ticker.go +++ b/pkg/ticker/ticker.go @@ -34,16 +34,18 @@ import ( "sync" "time" - "cosmossdk.io/errors" + "github.com/rs/zerolog" ) +// Task is a function that will be called by the Ticker +type Task func(ctx context.Context, t *Ticker) error + // Ticker represents a ticker that will run a function periodically. // It also invokes BEFORE ticker starts. type Ticker struct { - interval time.Duration - ticker *time.Ticker - task Task - signalChan chan struct{} + interval time.Duration + ticker *time.Ticker + task Task // runnerMu is a mutex to prevent double run runnerMu sync.Mutex @@ -51,25 +53,47 @@ type Ticker struct { // stateMu is a mutex to prevent concurrent SetInterval calls stateMu sync.Mutex - stopped bool + stopped bool + ctxCancel context.CancelFunc + + externalStopChan <-chan struct{} + logger zerolog.Logger } -// Task is a function that will be called by the Ticker -type Task func(ctx context.Context, t *Ticker) error +// Opt is a configuration option for the Ticker. +type Opt func(*Ticker) -// New creates a new Ticker. -func New(interval time.Duration, runner Task) *Ticker { - return &Ticker{interval: interval, task: runner} +// WithLogger sets the logger for the Ticker. +func WithLogger(log zerolog.Logger, name string) Opt { + return func(t *Ticker) { + t.logger = log.With().Str("ticker_name", name).Logger() + } } -// Run creates and runs a new Ticker. -func Run(ctx context.Context, interval time.Duration, task Task) error { - return New(interval, task).Run(ctx) +// WithStopChan sets the stop channel for the Ticker. +// Please note that stopChan is NOT signalChan. +// Stop channel is a trigger for invoking ticker.Stop(); +func WithStopChan(stopChan <-chan struct{}) Opt { + return func(cfg *Ticker) { cfg.externalStopChan = stopChan } } -// SecondsFromUint64 converts uint64 to time.Duration in seconds. -func SecondsFromUint64(d uint64) time.Duration { - return time.Duration(d) * time.Second +// New creates a new Ticker. +func New(interval time.Duration, task Task, opts ...Opt) *Ticker { + t := &Ticker{ + interval: interval, + task: task, + } + + for _, opt := range opts { + opt(t) + } + + return t +} + +// Run creates and runs a new Ticker. +func Run(ctx context.Context, interval time.Duration, task Task, opts ...Opt) error { + return New(interval, task, opts...).Run(ctx) } // Run runs the ticker by blocking current goroutine. It also invokes BEFORE ticker starts. @@ -96,24 +120,33 @@ func (t *Ticker) Run(ctx context.Context) (err error) { defer t.runnerMu.Unlock() // setup + ctx, t.ctxCancel = context.WithCancel(ctx) t.ticker = time.NewTicker(t.interval) - t.signalChan = make(chan struct{}) t.stopped = false // initial run if err := t.task(ctx, t); err != nil { - return errors.Wrap(err, "ticker task failed") + t.Stop() + return fmt.Errorf("ticker task failed (initial run): %w", err) } for { select { case <-ctx.Done(): + // if task is finished (i.e. last tick completed BEFORE ticker.Stop(), + // then we need to return nil) + if t.stopped { + return nil + } return ctx.Err() case <-t.ticker.C: + // If another goroutine calls ticker.Stop() while the current tick is running, + // Then it's okay to return ctx error if err := t.task(ctx, t); err != nil { - return errors.Wrap(err, "ticker task failed") + return fmt.Errorf("ticker task failed: %w", err) } - case <-t.signalChan: + case <-t.externalStopChan: + t.Stop() return nil } } @@ -139,11 +172,18 @@ func (t *Ticker) Stop() { defer t.stateMu.Unlock() // noop - if t.stopped || t.signalChan == nil { + if t.stopped { return } - close(t.signalChan) + t.ctxCancel() t.stopped = true t.ticker.Stop() + + t.logger.Info().Msgf("Ticker stopped") +} + +// SecondsFromUint64 converts uint64 to time.Duration in seconds. +func SecondsFromUint64(d uint64) time.Duration { + return time.Duration(d) * time.Second } diff --git a/pkg/ticker/ticker_test.go b/pkg/ticker/ticker_test.go index 4d890bf051..60d6c74dc8 100644 --- a/pkg/ticker/ticker_test.go +++ b/pkg/ticker/ticker_test.go @@ -1,12 +1,15 @@ package ticker import ( + "bytes" "context" "fmt" "testing" "time" + "github.com/rs/zerolog" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestTicker(t *testing.T) { @@ -148,7 +151,7 @@ func TestTicker(t *testing.T) { // ASSERT assert.ErrorContains(t, err, "panic during ticker run: oops") // assert that we get error with the correct line number - assert.ErrorContains(t, err, "ticker_test.go:142") + assert.ErrorContains(t, err, "ticker_test.go:145") }) t.Run("Nil panic", func(t *testing.T) { @@ -173,7 +176,7 @@ func TestTicker(t *testing.T) { "panic during ticker run: runtime error: invalid memory address or nil pointer dereference", ) // assert that we get error with the correct line number - assert.ErrorContains(t, err, "ticker_test.go:162") + assert.ErrorContains(t, err, "ticker_test.go:165") }) t.Run("Run as a single call", func(t *testing.T) { @@ -197,4 +200,51 @@ func TestTicker(t *testing.T) { assert.ErrorIs(t, err, context.DeadlineExceeded) assert.Equal(t, 2, counter) }) + + t.Run("With stop channel", func(t *testing.T) { + // ARRANGE + var ( + tickerInterval = 100 * time.Millisecond + counter = 0 + + stopChan = make(chan struct{}) + sleepBeforeStop = 5*tickerInterval + (10 * time.Millisecond) + ) + + task := func(ctx context.Context, _ *Ticker) error { + t.Logf("Tick %d", counter) + counter++ + + return nil + } + + // ACT + go func() { + time.Sleep(sleepBeforeStop) + close(stopChan) + }() + + err := Run(context.Background(), tickerInterval, task, WithStopChan(stopChan)) + + // ASSERT + require.NoError(t, err) + require.Equal(t, 6, counter) // initial tick + 5 more ticks + }) + + t.Run("With logger", func(t *testing.T) { + // ARRANGE + out := &bytes.Buffer{} + logger := zerolog.New(out) + + // ACT + task := func(ctx context.Context, _ *Ticker) error { + return fmt.Errorf("hey") + } + + err := Run(context.Background(), time.Second, task, WithLogger(logger, "my-task")) + + // ARRANGE + require.ErrorContains(t, err, "hey") + require.Contains(t, out.String(), `{"level":"info","ticker_name":"my-task","message":"Ticker stopped"}`) + }) } diff --git a/proto/zetachain/zetacore/pkg/chains/chains.proto b/proto/zetachain/zetacore/pkg/chains/chains.proto index 63b146cf42..dca1db9fa8 100644 --- a/proto/zetachain/zetacore/pkg/chains/chains.proto +++ b/proto/zetachain/zetacore/pkg/chains/chains.proto @@ -63,6 +63,7 @@ enum Network { optimism = 5; base = 6; solana = 7; + ton = 8; } // NetworkType represents the network type of the chain @@ -82,6 +83,7 @@ enum Vm { no_vm = 0; evm = 1; svm = 2; + tvm = 3; } // Consensus represents the consensus algorithm used by the chain @@ -94,6 +96,7 @@ enum Consensus { bitcoin = 2; op_stack = 3; solana_consensus = 4; + catchain_consensus = 5; // ton } // CCTXGateway describes for the chain the gateway used to handle CCTX outbounds diff --git a/testutil/sample/sample_ton.go b/testutil/sample/sample_ton.go new file mode 100644 index 0000000000..01ce8724c5 --- /dev/null +++ b/testutil/sample/sample_ton.go @@ -0,0 +1,272 @@ +package sample + +import ( + "crypto/rand" + "reflect" + "testing" + "time" + "unsafe" + + "cosmossdk.io/math" + eth "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/tonkeeper/tongo/boc" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" + + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" +) + +const ( + tonWorkchainID = 0 + tonShardID = 123 + tonDepositFee = 10_000_000 // 0.01 TON + tonSampleGasUsage = 50_000_000 // 0.05 TON +) + +type TONTransactionProps struct { + Account ton.AccountID + GasUsed uint64 + BlockID ton.BlockIDExt + + // For simplicity let's have only one input + // and one output (both optional) + Input *tlb.Message + Output *tlb.Message +} + +type intMsgInfo struct { + IhrDisabled bool + Bounce bool + Bounced bool + Src tlb.MsgAddress + Dest tlb.MsgAddress + Value tlb.CurrencyCollection + IhrFee tlb.Grams + FwdFee tlb.Grams + CreatedLt uint64 + CreatedAt uint32 +} + +func TONDonation(t *testing.T, acc ton.AccountID, d toncontracts.Donation) ton.Transaction { + return TONTransaction(t, TONDonateProps(t, acc, d)) +} + +func TONDonateProps(t *testing.T, acc ton.AccountID, d toncontracts.Donation) TONTransactionProps { + body, err := d.AsBody() + require.NoError(t, err) + + deposited := tonSampleGasUsage + d.Amount.Uint64() + + return TONTransactionProps{ + Account: acc, + Input: &tlb.Message{ + Info: internalMessageInfo(&intMsgInfo{ + Bounce: true, + Src: d.Sender.ToMsgAddress(), + Dest: acc.ToMsgAddress(), + Value: tlb.CurrencyCollection{Grams: tlb.Grams(deposited)}, + }), + Body: tlb.EitherRef[tlb.Any]{Value: tlb.Any(*body)}, + }, + } +} + +func TONDeposit(t *testing.T, acc ton.AccountID, d toncontracts.Deposit) ton.Transaction { + return TONTransaction(t, TONDepositProps(t, acc, d)) +} + +func TONDepositProps(t *testing.T, acc ton.AccountID, d toncontracts.Deposit) TONTransactionProps { + body, err := d.AsBody() + require.NoError(t, err) + + logBody := depositLogMock(t, d.Sender, d.Amount.Uint64(), d.Recipient, nil) + + return TONTransactionProps{ + Account: acc, + Input: &tlb.Message{ + Info: internalMessageInfo(&intMsgInfo{ + Bounce: true, + Src: d.Sender.ToMsgAddress(), + Dest: acc.ToMsgAddress(), + Value: tlb.CurrencyCollection{Grams: fakeDepositAmount(d.Amount)}, + }), + Body: tlb.EitherRef[tlb.Any]{Value: tlb.Any(*body)}, + }, + Output: &tlb.Message{ + Body: tlb.EitherRef[tlb.Any]{IsRight: true, Value: tlb.Any(*logBody)}, + }, + } +} + +func TONDepositAndCall(t *testing.T, acc ton.AccountID, d toncontracts.DepositAndCall) ton.Transaction { + return TONTransaction(t, TONDepositAndCallProps(t, acc, d)) +} + +func TONDepositAndCallProps(t *testing.T, acc ton.AccountID, d toncontracts.DepositAndCall) TONTransactionProps { + body, err := d.AsBody() + require.NoError(t, err) + + logBody := depositLogMock(t, d.Sender, d.Amount.Uint64(), d.Recipient, d.CallData) + + return TONTransactionProps{ + Account: acc, + Input: &tlb.Message{ + Info: internalMessageInfo(&intMsgInfo{ + Bounce: true, + Src: d.Sender.ToMsgAddress(), + Dest: acc.ToMsgAddress(), + Value: tlb.CurrencyCollection{Grams: fakeDepositAmount(d.Amount)}, + }), + Body: tlb.EitherRef[tlb.Any]{Value: tlb.Any(*body)}, + }, + Output: &tlb.Message{ + Body: tlb.EitherRef[tlb.Any]{IsRight: true, Value: tlb.Any(*logBody)}, + }, + } +} + +// TONTransaction creates a sample TON transaction. +func TONTransaction(t *testing.T, p TONTransactionProps) ton.Transaction { + require.False(t, p.Account.IsZero(), "account address is empty") + require.False(t, p.Input == nil && p.Output == nil, "both input and output are empty") + + now := time.Now().UTC() + + if p.GasUsed == 0 { + p.GasUsed = tonSampleGasUsage + } + + if p.BlockID.BlockID.Seqno == 0 { + p.BlockID = tonBlockID(now) + } + + // Simulate logical time as `2 * now()` + lt := uint64(2 * now.Unix()) + + input := tlb.Maybe[tlb.Ref[tlb.Message]]{} + if p.Input != nil { + input.Exists = true + input.Value.Value = *p.Input + } + + var outputs tlb.HashmapE[tlb.Uint15, tlb.Ref[tlb.Message]] + if p.Output != nil { + outputs = tlb.NewHashmapE( + []tlb.Uint15{0}, + []tlb.Ref[tlb.Message]{{*p.Output}}, + ) + } + + type messages struct { + InMsg tlb.Maybe[tlb.Ref[tlb.Message]] + OutMsgs tlb.HashmapE[tlb.Uint15, tlb.Ref[tlb.Message]] + } + + tx := ton.Transaction{ + BlockID: p.BlockID, + Transaction: tlb.Transaction{ + AccountAddr: p.Account.Address, + Lt: lt, + Now: uint32(now.Unix()), + OutMsgCnt: tlb.Uint15(len(outputs.Keys())), + TotalFees: tlb.CurrencyCollection{Grams: tlb.Grams(p.GasUsed)}, + Msgs: messages{InMsg: input, OutMsgs: outputs}, + }, + } + + setTXHash(&tx.Transaction, Hash()) + + return tx +} + +func GenerateTONAccountID() ton.AccountID { + var addr [32]byte + + //nolint:errcheck // test code + rand.Read(addr[:]) + + return *ton.NewAccountID(0, addr) +} + +func internalMessageInfo(info *intMsgInfo) tlb.CommonMsgInfo { + return tlb.CommonMsgInfo{ + SumType: "IntMsgInfo", + IntMsgInfo: (*struct { + IhrDisabled bool + Bounce bool + Bounced bool + Src tlb.MsgAddress + Dest tlb.MsgAddress + Value tlb.CurrencyCollection + IhrFee tlb.Grams + FwdFee tlb.Grams + CreatedLt uint64 + CreatedAt uint32 + })(info), + } +} + +func tonBlockID(now time.Time) ton.BlockIDExt { + // simulate shard seqno as unix timestamp + seqno := uint32(now.Unix()) + + return ton.BlockIDExt{ + BlockID: ton.BlockID{ + Workchain: tonWorkchainID, + Shard: tonShardID, + Seqno: seqno, + }, + } +} + +func fakeDepositAmount(v math.Uint) tlb.Grams { + return tlb.Grams(v.Uint64() + tonDepositFee) +} + +func depositLogMock( + t *testing.T, + sender ton.AccountID, + amount uint64, + recipient eth.Address, + callData []byte, +) *boc.Cell { + // cell log = begin_cell() + // .store_uint(op::internal::deposit_and_call, size::op_code_size) + // .store_uint(0, size::query_id_size) + // .store_slice(sender) + // .store_coins(deposit_amount) + // .store_uint(evm_recipient, size::evm_address) + // .store_ref(call_data) // only for DepositAndCall + // .end_cell(); + + b := boc.NewCell() + require.NoError(t, b.WriteUint(0, 32+64)) + + // skip + msgAddr := sender.ToMsgAddress() + require.NoError(t, tlb.Marshal(b, msgAddr)) + + coins := tlb.Grams(amount) + require.NoError(t, coins.MarshalTLB(b, nil)) + + require.NoError(t, b.WriteBytes(recipient.Bytes())) + + if callData != nil { + callDataCell, err := toncontracts.MarshalSnakeCell(callData) + require.NoError(t, err) + require.NoError(t, b.AddRef(callDataCell)) + } + + return b +} + +// well, tlb.Transaction has unexported field `hash` that we need to set OUTSIDE tlb package. +// It's a hack, but it works for testing purposes. +func setTXHash(tx *tlb.Transaction, hash [32]byte) { + field := reflect.ValueOf(tx).Elem().FieldByName("hash") + ptr := unsafe.Pointer(field.UnsafeAddr()) + + arrPtr := (*[32]byte)(ptr) + *arrPtr = hash +} diff --git a/testutil/sample/sample_ton_test.go b/testutil/sample/sample_ton_test.go new file mode 100644 index 0000000000..73474db0d4 --- /dev/null +++ b/testutil/sample/sample_ton_test.go @@ -0,0 +1,94 @@ +package sample + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + "github.com/stretchr/testify/require" + "github.com/tonkeeper/tongo/ton" + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" +) + +func TestTONSamples(t *testing.T) { + var ( + gatewayID = ton.MustParseAccountID("0:997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b") + gw = toncontracts.NewGateway(gatewayID) + ) + + t.Run("Donate", func(t *testing.T) { + // ARRANGE + d := toncontracts.Donation{ + Sender: GenerateTONAccountID(), + Amount: sdkmath.NewUint(100_000_000), + } + + tx := TONTransaction(t, TONDonateProps(t, gatewayID, d)) + + // ACT + parsedTX, err := gw.ParseTransaction(tx) + + // ASSERT + require.NoError(t, err) + + d2, err := parsedTX.Donation() + require.NoError(t, err) + + require.Equal(t, int(d.Amount.Uint64()), int(d2.Amount.Uint64())) + require.Equal(t, d.Sender.ToRaw(), d2.Sender.ToRaw()) + }) + + t.Run("Deposit", func(t *testing.T) { + // ARRANGE + d := toncontracts.Deposit{ + Sender: GenerateTONAccountID(), + Amount: sdkmath.NewUint(200_000_000), + Recipient: EthAddress(), + } + + tx := TONTransaction(t, TONDepositProps(t, gatewayID, d)) + + // ACT + parsedTX, err := gw.ParseTransaction(tx) + + // ASSERT + require.NoError(t, err) + + d2, err := parsedTX.Deposit() + require.NoError(t, err) + + require.Equal(t, int(d.Amount.Uint64()), int(d2.Amount.Uint64())) + require.Equal(t, d.Sender.ToRaw(), d2.Sender.ToRaw()) + require.Equal(t, d.Recipient.Hex(), d2.Recipient.Hex()) + require.Equal(t, d.Memo(), d2.Memo()) + }) + + t.Run("Deposit and call", func(t *testing.T) { + // ARRANGE + d := toncontracts.DepositAndCall{ + Deposit: toncontracts.Deposit{ + Sender: GenerateTONAccountID(), + Amount: sdkmath.NewUint(300_000_000), + Recipient: EthAddress(), + }, + CallData: []byte("Evidently, the most known and used kind of dictionaries in TON is hashmap."), + } + + tx := TONTransaction(t, TONDepositAndCallProps(t, gatewayID, d)) + + // ACT + parsedTX, err := gw.ParseTransaction(tx) + + // ASSERT + require.NoError(t, err) + + d2, err := parsedTX.DepositAndCall() + require.NoError(t, err) + + require.Equal(t, int(d.Amount.Uint64()), int(d2.Amount.Uint64())) + require.Equal(t, d.Sender.ToRaw(), d2.Sender.ToRaw()) + require.Equal(t, d.Recipient.Hex(), d2.Recipient.Hex()) + require.Equal(t, d.CallData, d2.CallData) + require.Equal(t, d.Memo(), d2.Memo()) + }) + +} diff --git a/typescript/zetachain/zetacore/pkg/chains/chains_pb.d.ts b/typescript/zetachain/zetacore/pkg/chains/chains_pb.d.ts index af161efd7b..9e68854962 100644 --- a/typescript/zetachain/zetacore/pkg/chains/chains_pb.d.ts +++ b/typescript/zetachain/zetacore/pkg/chains/chains_pb.d.ts @@ -197,6 +197,11 @@ export declare enum Network { * @generated from enum value: solana = 7; */ solana = 7, + + /** + * @generated from enum value: ton = 8; + */ + ton = 8, } /** @@ -248,6 +253,11 @@ export declare enum Vm { * @generated from enum value: svm = 2; */ svm = 2, + + /** + * @generated from enum value: tvm = 3; + */ + tvm = 3, } /** @@ -282,6 +292,13 @@ export declare enum Consensus { * @generated from enum value: solana_consensus = 4; */ solana_consensus = 4, + + /** + * ton + * + * @generated from enum value: catchain_consensus = 5; + */ + catchain_consensus = 5, } /** diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index c873e9b636..c672686c1a 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -96,7 +96,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo from, err := chains.DecodeAddressFromChainID(inboundSenderChainID, inboundSender, k.GetAuthorityKeeper().GetAdditionalChainList(ctx)) if err != nil { - return false, fmt.Errorf("HandleEVMDeposit: unable to decode address: %s", err.Error()) + return false, fmt.Errorf("HandleEVMDeposit: unable to decode address: %w", err) } evmTxResponse, contractCall, err := k.fungibleKeeper.ZRC20DepositAndCallContract( diff --git a/x/observer/keeper/msg_server_vote_blame.go b/x/observer/keeper/msg_server_vote_blame.go index 74a3654657..d320ff54db 100644 --- a/x/observer/keeper/msg_server_vote_blame.go +++ b/x/observer/keeper/msg_server_vote_blame.go @@ -6,7 +6,7 @@ import ( sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - crosschainTypes "github.com/zeta-chain/node/x/crosschain/types" + cctypes "github.com/zeta-chain/node/x/crosschain/types" "github.com/zeta-chain/node/x/observer/types" ) @@ -21,9 +21,7 @@ func (k msgServer) VoteBlame( // GetChainFromChainID makes sure we are getting only supported chains , if a chain support has been turned on using gov proposal, this function returns nil observationChain, found := k.GetSupportedChainFromChainID(ctx, msg.ChainId) if !found { - return nil, sdkerrors.Wrapf( - crosschainTypes.ErrUnsupportedChain, - "%s, ChainID %d", voteBlameID, msg.ChainId) + return nil, sdkerrors.Wrapf(cctypes.ErrUnsupportedChain, "%s, ChainID %d", voteBlameID, msg.ChainId) } if ok := k.IsNonTombstonedObserver(ctx, msg.Creator); !ok { diff --git a/zetaclient/chains/base/observer.go b/zetaclient/chains/base/observer.go index 6cf8af9de6..f089f26815 100644 --- a/zetaclient/chains/base/observer.go +++ b/zetaclient/chains/base/observer.go @@ -135,19 +135,19 @@ func NewObserver( return &ob, nil } -// Start starts the observer. Returns true if the observer was already started (noop). +// Start starts the observer. Returns false if it's already started (noop). func (ob *Observer) Start() bool { ob.mu.Lock() defer ob.Mu().Unlock() // noop if ob.started { - return true + return false } ob.started = true - return false + return true } // Stop notifies all goroutines to stop and closes the database. @@ -186,13 +186,18 @@ func (ob *Observer) WithChain(chain chains.Chain) *Observer { // ChainParams returns the chain params for the observer. func (ob *Observer) ChainParams() observertypes.ChainParams { + ob.mu.Lock() + defer ob.mu.Unlock() + return ob.chainParams } -// WithChainParams attaches a new chain params to the observer. -func (ob *Observer) WithChainParams(params observertypes.ChainParams) *Observer { +// SetChainParams attaches a new chain params to the observer. +func (ob *Observer) SetChainParams(params observertypes.ChainParams) { + ob.mu.Lock() + defer ob.mu.Unlock() + ob.chainParams = params - return ob } // ZetacoreClient returns the zetacore client for the observer. @@ -329,7 +334,12 @@ func (ob *Observer) Logger() *ObserverLogger { // WithLogger attaches a new logger to the observer. func (ob *Observer) WithLogger(logger Logger) *Observer { - chainLogger := logger.Std.With().Int64(logs.FieldChain, ob.chain.ChainId).Logger() + chainLogger := logger.Std. + With(). + Int64(logs.FieldChain, ob.chain.ChainId). + Str(logs.FieldChainNetwork, ob.chain.Network.String()). + Logger() + ob.logger = ObserverLogger{ Chain: chainLogger, Inbound: chainLogger.With().Str(logs.FieldModule, logs.ModNameInbound).Logger(), @@ -338,6 +348,7 @@ func (ob *Observer) WithLogger(logger Logger) *Observer { Headers: chainLogger.With().Str(logs.FieldModule, logs.ModNameHeaders).Logger(), Compliance: logger.Compliance, } + return ob } @@ -461,22 +472,35 @@ func (ob *Observer) PostVoteInbound( msg *crosschaintypes.MsgVoteInbound, retryGasLimit uint64, ) (string, error) { - txHash := msg.InboundHash - coinType := msg.CoinType - chainID := ob.Chain().ChainId - zetaHash, ballot, err := ob.ZetacoreClient(). - PostVoteInbound(ctx, zetacore.PostVoteInboundGasLimit, retryGasLimit, msg) - if err != nil { - ob.logger.Inbound.Err(err). - Msgf("inbound detected: error posting vote for chain %d token %s inbound %s", chainID, coinType, txHash) + const gasLimit = zetacore.PostVoteInboundGasLimit + + var ( + txHash = msg.InboundHash + coinType = msg.CoinType + chainID = ob.Chain().ChainId + ) + + zetaHash, ballot, err := ob.ZetacoreClient().PostVoteInbound(ctx, gasLimit, retryGasLimit, msg) + + lf := map[string]any{ + "inbound.chain_id": chainID, + "inbound.coin_type": coinType.String(), + "inbound.external_tx_hash": txHash, + "inbound.ballot_index": ballot, + "inbound.zeta_tx_hash": zetaHash, + } + + switch { + case err != nil: + ob.logger.Inbound.Error().Err(err).Fields(lf).Msg("inbound detected: error posting vote") return "", err - } else if zetaHash != "" { - ob.logger.Inbound.Info().Msgf("inbound detected: chain %d token %s inbound %s vote %s ballot %s", chainID, coinType, txHash, zetaHash, ballot) - } else { - ob.logger.Inbound.Info().Msgf("inbound detected: chain %d token %s inbound %s already voted on ballot %s", chainID, coinType, txHash, ballot) + case zetaHash == "": + ob.logger.Inbound.Info().Fields(lf).Msg("inbound detected: already voted on ballot") + default: + ob.logger.Inbound.Info().Fields(lf).Msgf("inbound detected: vote posted") } - return ballot, err + return ballot, nil } // AlertOnRPCLatency prints an alert if the RPC latency exceeds the threshold. diff --git a/zetaclient/chains/base/observer_test.go b/zetaclient/chains/base/observer_test.go index 0e772e31f9..0c53bea35c 100644 --- a/zetaclient/chains/base/observer_test.go +++ b/zetaclient/chains/base/observer_test.go @@ -175,15 +175,6 @@ func TestObserverGetterAndSetter(t *testing.T) { require.Equal(t, newChain, ob.Chain()) }) - t.Run("should be able to update chain params", func(t *testing.T) { - ob := createObserver(t, chain, defaultAlertLatency) - - // update chain params - newChainParams := *sample.ChainParams(chains.BscMainnet.ChainId) - ob = ob.WithChainParams(newChainParams) - require.True(t, observertypes.ChainParamsEqual(newChainParams, ob.ChainParams())) - }) - t.Run("should be able to update zetacore client", func(t *testing.T) { ob := createObserver(t, chain, defaultAlertLatency) diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index d31715db9a..fad3c87230 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -59,7 +59,7 @@ func (ob *Observer) WatchInbound(ctx context.Context) error { return err } - ticker, err := types.NewDynamicTicker("Bitcoin_WatchInbound", ob.GetChainParams().InboundTicker) + ticker, err := types.NewDynamicTicker("Bitcoin_WatchInbound", ob.ChainParams().InboundTicker) if err != nil { ob.logger.Inbound.Error().Err(err).Msg("error creating ticker") return err @@ -89,7 +89,7 @@ func (ob *Observer) WatchInbound(ctx context.Context) error { ob.logger.Inbound.Debug().Err(err).Msg("WatchInbound: Bitcoin node is not enabled") } } - ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.logger.Inbound) + ticker.UpdateInterval(ob.ChainParams().InboundTicker, ob.logger.Inbound) case <-ob.StopChannel(): ob.logger.Inbound.Info().Msgf("WatchInbound stopped for chain %d", ob.Chain().ChainId) return nil @@ -205,7 +205,7 @@ func (ob *Observer) WatchInboundTracker(ctx context.Context) error { return err } - ticker, err := types.NewDynamicTicker("Bitcoin_WatchInboundTracker", ob.GetChainParams().InboundTicker) + ticker, err := types.NewDynamicTicker("Bitcoin_WatchInboundTracker", ob.ChainParams().InboundTicker) if err != nil { ob.logger.Inbound.Err(err).Msg("error creating ticker") return err @@ -224,7 +224,7 @@ func (ob *Observer) WatchInboundTracker(ctx context.Context) error { Err(err). Msgf("error observing inbound tracker for chain %d", ob.Chain().ChainId) } - ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.logger.Inbound) + ticker.UpdateInterval(ob.ChainParams().InboundTicker, ob.logger.Inbound) case <-ob.StopChannel(): ob.logger.Inbound.Info().Msgf("WatchInboundTracker stopped for chain %d", ob.Chain().ChainId) return nil diff --git a/zetaclient/chains/bitcoin/observer/observer.go b/zetaclient/chains/bitcoin/observer/observer.go index 80781fdd33..f78d81af9c 100644 --- a/zetaclient/chains/bitcoin/observer/observer.go +++ b/zetaclient/chains/bitcoin/observer/observer.go @@ -162,25 +162,9 @@ func (ob *Observer) WithBtcClient(client interfaces.BTCRPCClient) { ob.btcClient = client } -// SetChainParams sets the chain params for the observer -// Note: chain params is accessed concurrently -func (ob *Observer) SetChainParams(params observertypes.ChainParams) { - ob.Mu().Lock() - defer ob.Mu().Unlock() - ob.WithChainParams(params) -} - -// GetChainParams returns the chain params for the observer -// Note: chain params is accessed concurrently -func (ob *Observer) GetChainParams() observertypes.ChainParams { - ob.Mu().Lock() - defer ob.Mu().Unlock() - return ob.ChainParams() -} - // Start starts the Go routine processes to observe the Bitcoin chain func (ob *Observer) Start(ctx context.Context) { - if noop := ob.Observer.Start(); noop { + if ok := ob.Observer.Start(); !ok { ob.Logger().Chain.Info().Msgf("observer is already started for chain %d", ob.Chain().ChainId) return } @@ -219,12 +203,12 @@ func (ob *Observer) ConfirmationsThreshold(amount *big.Int) int64 { if amount.Cmp(big.NewInt(BigValueSats)) >= 0 { return BigValueConfirmationCount } - if BigValueConfirmationCount < ob.GetChainParams().ConfirmationCount { + if BigValueConfirmationCount < ob.ChainParams().ConfirmationCount { return BigValueConfirmationCount } // #nosec G115 always in range - return int64(ob.GetChainParams().ConfirmationCount) + return int64(ob.ChainParams().ConfirmationCount) } // WatchGasPrice watches Bitcoin chain for gas rate and post to zetacore @@ -238,25 +222,25 @@ func (ob *Observer) WatchGasPrice(ctx context.Context) error { } // start gas price ticker - ticker, err := clienttypes.NewDynamicTicker("Bitcoin_WatchGasPrice", ob.GetChainParams().GasPriceTicker) + ticker, err := clienttypes.NewDynamicTicker("Bitcoin_WatchGasPrice", ob.ChainParams().GasPriceTicker) if err != nil { return errors.Wrapf(err, "NewDynamicTicker error") } ob.logger.GasPrice.Info().Msgf("WatchGasPrice started for chain %d with interval %d", - ob.Chain().ChainId, ob.GetChainParams().GasPriceTicker) + ob.Chain().ChainId, ob.ChainParams().GasPriceTicker) defer ticker.Stop() for { select { case <-ticker.C(): - if !ob.GetChainParams().IsSupported { + if !ob.ChainParams().IsSupported { continue } err := ob.PostGasPrice(ctx) if err != nil { ob.logger.GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.Chain().ChainId) } - ticker.UpdateInterval(ob.GetChainParams().GasPriceTicker, ob.logger.GasPrice) + ticker.UpdateInterval(ob.ChainParams().GasPriceTicker, ob.logger.GasPrice) case <-ob.StopChannel(): ob.logger.GasPrice.Info().Msgf("WatchGasPrice stopped for chain %d", ob.Chain().ChainId) return nil @@ -316,7 +300,7 @@ func (ob *Observer) PostGasPrice(ctx context.Context) error { // WatchUTXOs watches bitcoin chain for UTXOs owned by the TSS address // TODO(revamp): move ticker related functions to a specific file func (ob *Observer) WatchUTXOs(ctx context.Context) error { - ticker, err := clienttypes.NewDynamicTicker("Bitcoin_WatchUTXOs", ob.GetChainParams().WatchUtxoTicker) + ticker, err := clienttypes.NewDynamicTicker("Bitcoin_WatchUTXOs", ob.ChainParams().WatchUtxoTicker) if err != nil { ob.logger.UTXOs.Error().Err(err).Msg("error creating ticker") return err @@ -326,7 +310,7 @@ func (ob *Observer) WatchUTXOs(ctx context.Context) error { for { select { case <-ticker.C(): - if !ob.GetChainParams().IsSupported { + if !ob.ChainParams().IsSupported { continue } err := ob.FetchUTXOs(ctx) @@ -341,7 +325,7 @@ func (ob *Observer) WatchUTXOs(ctx context.Context) error { ob.logger.UTXOs.Debug().Err(err).Msg("No wallet is loaded") } } - ticker.UpdateInterval(ob.GetChainParams().WatchUtxoTicker, ob.logger.UTXOs) + ticker.UpdateInterval(ob.ChainParams().WatchUtxoTicker, ob.logger.UTXOs) case <-ob.StopChannel(): ob.logger.UTXOs.Info().Msgf("WatchUTXOs stopped for chain %d", ob.Chain().ChainId) return nil diff --git a/zetaclient/chains/bitcoin/observer/outbound.go b/zetaclient/chains/bitcoin/observer/outbound.go index 3b25d8c0c1..16c8d24b81 100644 --- a/zetaclient/chains/bitcoin/observer/outbound.go +++ b/zetaclient/chains/bitcoin/observer/outbound.go @@ -32,7 +32,7 @@ func (ob *Observer) WatchOutbound(ctx context.Context) error { return errors.Wrap(err, "unable to get app from context") } - ticker, err := types.NewDynamicTicker("Bitcoin_WatchOutbound", ob.GetChainParams().OutboundTicker) + ticker, err := types.NewDynamicTicker("Bitcoin_WatchOutbound", ob.ChainParams().OutboundTicker) if err != nil { return errors.Wrap(err, "unable to create dynamic ticker") } @@ -106,7 +106,7 @@ func (ob *Observer) WatchOutbound(ctx context.Context) error { ob.logger.Outbound.Error().Msgf("WatchOutbound: included multiple (%d) outbound for chain %d nonce %d", txCount, chainID, tracker.Nonce) } } - ticker.UpdateInterval(ob.GetChainParams().OutboundTicker, ob.logger.Outbound) + ticker.UpdateInterval(ob.ChainParams().OutboundTicker, ob.logger.Outbound) case <-ob.StopChannel(): ob.logger.Outbound.Info().Msgf("WatchOutbound stopped for chain %d", chainID) return nil diff --git a/zetaclient/chains/bitcoin/observer/rpc_status.go b/zetaclient/chains/bitcoin/observer/rpc_status.go index e0fc3c651d..03688f4aa4 100644 --- a/zetaclient/chains/bitcoin/observer/rpc_status.go +++ b/zetaclient/chains/bitcoin/observer/rpc_status.go @@ -16,7 +16,7 @@ func (ob *Observer) watchRPCStatus(_ context.Context) error { for { select { case <-ticker.C: - if !ob.GetChainParams().IsSupported { + if !ob.ChainParams().IsSupported { continue } diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index 0e1cb6b84d..c662fc2d60 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -20,7 +20,6 @@ import ( "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zetaconnector.non-eth.sol" - "github.com/zeta-chain/node/pkg/bg" "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/pkg/constant" @@ -39,23 +38,20 @@ import ( // TODO(revamp): move ticker function to a separate file func (ob *Observer) WatchInbound(ctx context.Context) error { sampledLogger := ob.Logger().Inbound.Sample(&zerolog.BasicSampler{N: 10}) - interval := ticker.SecondsFromUint64(ob.GetChainParams().InboundTicker) + interval := ticker.SecondsFromUint64(ob.ChainParams().InboundTicker) task := func(ctx context.Context, t *ticker.Ticker) error { return ob.watchInboundOnce(ctx, t, sampledLogger) } - t := ticker.New(interval, task) - - bg.Work(ctx, func(_ context.Context) error { - <-ob.StopChannel() - t.Stop() - ob.Logger().Inbound.Info().Msg("WatchInbound stopped") - return nil - }) - ob.Logger().Inbound.Info().Msgf("WatchInbound started") - return t.Run(ctx) + return ticker.Run( + ctx, + interval, + task, + ticker.WithStopChan(ob.StopChannel()), + ticker.WithLogger(ob.Logger().Inbound, "WatchInbound"), + ) } func (ob *Observer) watchInboundOnce(ctx context.Context, t *ticker.Ticker, sampledLogger zerolog.Logger) error { @@ -74,7 +70,7 @@ func (ob *Observer) watchInboundOnce(ctx context.Context, t *ticker.Ticker, samp ob.Logger().Inbound.Err(err).Msg("WatchInbound: observeInbound error") } - newInterval := ticker.SecondsFromUint64(ob.GetChainParams().InboundTicker) + newInterval := ticker.SecondsFromUint64(ob.ChainParams().InboundTicker) t.SetInterval(newInterval) return nil @@ -91,7 +87,7 @@ func (ob *Observer) WatchInboundTracker(ctx context.Context) error { ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("EVM_WatchInboundTracker_%d", ob.Chain().ChainId), - ob.GetChainParams().InboundTicker, + ob.ChainParams().InboundTicker, ) if err != nil { ob.Logger().Inbound.Err(err).Msg("error creating ticker") @@ -110,7 +106,7 @@ func (ob *Observer) WatchInboundTracker(ctx context.Context) error { if err != nil { ob.Logger().Inbound.Err(err).Msg("ProcessInboundTrackers error") } - ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.Logger().Inbound) + ticker.UpdateInterval(ob.ChainParams().InboundTicker, ob.Logger().Inbound) case <-ob.StopChannel(): ob.Logger().Inbound.Info().Msgf("WatchInboundTracker stopped for chain %d", ob.Chain().ChainId) return nil @@ -191,10 +187,10 @@ func (ob *Observer) ObserveInbound(ctx context.Context, sampledLogger zerolog.Lo metrics.GetBlockByNumberPerChain.WithLabelValues(ob.Chain().Name).Inc() // skip if current height is too low - if blockNumber < ob.GetChainParams().ConfirmationCount { + if blockNumber < ob.ChainParams().ConfirmationCount { return fmt.Errorf("observeInbound: skipping observer, current block number %d is too low", blockNumber) } - confirmedBlockNum := blockNumber - ob.GetChainParams().ConfirmationCount + confirmedBlockNum := blockNumber - ob.ChainParams().ConfirmationCount // skip if no new block is confirmed lastScanned := ob.LastBlockScanned() @@ -615,7 +611,7 @@ func (ob *Observer) CheckAndVoteInboundTokenGas( // HasEnoughConfirmations checks if the given receipt has enough confirmations func (ob *Observer) HasEnoughConfirmations(receipt *ethtypes.Receipt, lastHeight uint64) bool { - confHeight := receipt.BlockNumber.Uint64() + ob.GetChainParams().ConfirmationCount + confHeight := receipt.BlockNumber.Uint64() + ob.ChainParams().ConfirmationCount return lastHeight >= confHeight } diff --git a/zetaclient/chains/evm/observer/observer.go b/zetaclient/chains/evm/observer/observer.go index 39de0eedea..8823b13c47 100644 --- a/zetaclient/chains/evm/observer/observer.go +++ b/zetaclient/chains/evm/observer/observer.go @@ -116,39 +116,23 @@ func (ob *Observer) WithEvmJSONRPC(client interfaces.EVMJSONRPCClient) { ob.evmJSONRPC = client } -// SetChainParams sets the chain params for the observer -// Note: chain params is accessed concurrently -func (ob *Observer) SetChainParams(params observertypes.ChainParams) { - ob.Mu().Lock() - defer ob.Mu().Unlock() - ob.WithChainParams(params) -} - -// GetChainParams returns the chain params for the observer -// Note: chain params is accessed concurrently -func (ob *Observer) GetChainParams() observertypes.ChainParams { - ob.Mu().Lock() - defer ob.Mu().Unlock() - return ob.ChainParams() -} - // GetConnectorContract returns the non-Eth connector address and binder func (ob *Observer) GetConnectorContract() (ethcommon.Address, *zetaconnector.ZetaConnectorNonEth, error) { - addr := ethcommon.HexToAddress(ob.GetChainParams().ConnectorContractAddress) + addr := ethcommon.HexToAddress(ob.ChainParams().ConnectorContractAddress) contract, err := zetaconnector.NewZetaConnectorNonEth(addr, ob.evmClient) return addr, contract, err } // GetConnectorContractEth returns the Eth connector address and binder func (ob *Observer) GetConnectorContractEth() (ethcommon.Address, *zetaconnectoreth.ZetaConnectorEth, error) { - addr := ethcommon.HexToAddress(ob.GetChainParams().ConnectorContractAddress) + addr := ethcommon.HexToAddress(ob.ChainParams().ConnectorContractAddress) contract, err := FetchConnectorContractEth(addr, ob.evmClient) return addr, contract, err } // GetERC20CustodyContract returns ERC20Custody contract address and binder func (ob *Observer) GetERC20CustodyContract() (ethcommon.Address, *erc20custody.ERC20Custody, error) { - addr := ethcommon.HexToAddress(ob.GetChainParams().Erc20CustodyContractAddress) + addr := ethcommon.HexToAddress(ob.ChainParams().Erc20CustodyContractAddress) contract, err := erc20custody.NewERC20Custody(addr, ob.evmClient) return addr, contract, err } @@ -158,14 +142,14 @@ func (ob *Observer) GetERC20CustodyContract() (ethcommon.Address, *erc20custody. // this simplify the migration process v1 will be completely removed in the future // currently the ABI for withdraw is identical, therefore both contract instances can be used func (ob *Observer) GetERC20CustodyV2Contract() (ethcommon.Address, *erc20custodyv2.ERC20Custody, error) { - addr := ethcommon.HexToAddress(ob.GetChainParams().Erc20CustodyContractAddress) + addr := ethcommon.HexToAddress(ob.ChainParams().Erc20CustodyContractAddress) contract, err := erc20custodyv2.NewERC20Custody(addr, ob.evmClient) return addr, contract, err } // GetGatewayContract returns the gateway contract address and binder func (ob *Observer) GetGatewayContract() (ethcommon.Address, *gatewayevm.GatewayEVM, error) { - addr := ethcommon.HexToAddress(ob.GetChainParams().GatewayAddress) + addr := ethcommon.HexToAddress(ob.ChainParams().GatewayAddress) contract, err := gatewayevm.NewGatewayEVM(addr, ob.evmClient) return addr, contract, err } @@ -190,7 +174,7 @@ func FetchZetaTokenContract( // Start all observation routines for the evm chain func (ob *Observer) Start(ctx context.Context) { - if noop := ob.Observer.Start(); noop { + if ok := ob.Observer.Start(); !ok { ob.Logger().Chain.Info().Msgf("observer is already started for chain %d", ob.Chain().ChainId) return } diff --git a/zetaclient/chains/evm/observer/observer_gas.go b/zetaclient/chains/evm/observer/observer_gas.go index 754f0349c5..3ebca1d3a9 100644 --- a/zetaclient/chains/evm/observer/observer_gas.go +++ b/zetaclient/chains/evm/observer/observer_gas.go @@ -22,27 +22,27 @@ func (ob *Observer) WatchGasPrice(ctx context.Context) error { // start gas price ticker ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("EVM_WatchGasPrice_%d", ob.Chain().ChainId), - ob.GetChainParams().GasPriceTicker, + ob.ChainParams().GasPriceTicker, ) if err != nil { ob.Logger().GasPrice.Error().Err(err).Msg("NewDynamicTicker error") return err } ob.Logger().GasPrice.Info().Msgf("WatchGasPrice started for chain %d with interval %d", - ob.Chain().ChainId, ob.GetChainParams().GasPriceTicker) + ob.Chain().ChainId, ob.ChainParams().GasPriceTicker) defer ticker.Stop() for { select { case <-ticker.C(): - if !ob.GetChainParams().IsSupported { + if !ob.ChainParams().IsSupported { continue } err = ob.PostGasPrice(ctx) if err != nil { ob.Logger().GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.Chain().ChainId) } - ticker.UpdateInterval(ob.GetChainParams().GasPriceTicker, ob.Logger().GasPrice) + ticker.UpdateInterval(ob.ChainParams().GasPriceTicker, ob.Logger().GasPrice) case <-ob.StopChannel(): ob.Logger().GasPrice.Info().Msg("WatchGasPrice stopped") return nil diff --git a/zetaclient/chains/evm/observer/outbound.go b/zetaclient/chains/evm/observer/outbound.go index 2534c47aab..0bab913592 100644 --- a/zetaclient/chains/evm/observer/outbound.go +++ b/zetaclient/chains/evm/observer/outbound.go @@ -44,7 +44,7 @@ func (ob *Observer) WatchOutbound(ctx context.Context) error { chainID := ob.Chain().ChainId ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("EVM_WatchOutbound_%d", ob.Chain().ChainId), - ob.GetChainParams().OutboundTicker, + ob.ChainParams().OutboundTicker, ) if err != nil { ob.Logger().Outbound.Error().Err(err).Msg("error creating ticker") @@ -72,7 +72,7 @@ func (ob *Observer) WatchOutbound(ctx context.Context) error { Msgf("WatchOutbound: error ProcessOutboundTrackers for chain %d", chainID) } - ticker.UpdateInterval(ob.GetChainParams().OutboundTicker, ob.Logger().Outbound) + ticker.UpdateInterval(ob.ChainParams().OutboundTicker, ob.Logger().Outbound) case <-ob.StopChannel(): ob.Logger().Outbound.Info().Msg("WatchOutbound: stopped") return nil diff --git a/zetaclient/chains/evm/observer/outbound_test.go b/zetaclient/chains/evm/observer/outbound_test.go index 7b8e47f40f..5011e5660a 100644 --- a/zetaclient/chains/evm/observer/outbound_test.go +++ b/zetaclient/chains/evm/observer/outbound_test.go @@ -105,7 +105,7 @@ func Test_IsOutboundProcessed(t *testing.T) { ob.SetTxNReceipt(nonce, receipt, outbound) // set connector contract address to an arbitrary address to make event parsing fail - chainParamsNew := ob.GetChainParams() + chainParamsNew := ob.ChainParams() chainParamsNew.ConnectorContractAddress = sample.EthAddress().Hex() ob.SetChainParams(chainParamsNew) continueKeysign, err := ob.VoteOutboundIfConfirmed(ctx, cctx) diff --git a/zetaclient/chains/evm/observer/rpc_status.go b/zetaclient/chains/evm/observer/rpc_status.go index c63e9e775a..68c7629523 100644 --- a/zetaclient/chains/evm/observer/rpc_status.go +++ b/zetaclient/chains/evm/observer/rpc_status.go @@ -17,7 +17,7 @@ func (ob *Observer) watchRPCStatus(ctx context.Context) error { for { select { case <-ticker.C: - if !ob.GetChainParams().IsSupported { + if !ob.ChainParams().IsSupported { continue } diff --git a/zetaclient/chains/interfaces/interfaces.go b/zetaclient/chains/interfaces/interfaces.go index ab58456de6..c89a77e4b8 100644 --- a/zetaclient/chains/interfaces/interfaces.go +++ b/zetaclient/chains/interfaces/interfaces.go @@ -39,15 +39,21 @@ const ( // ChainObserver is the interface for chain observer type ChainObserver interface { + // Start starts the observer Start(ctx context.Context) + + // Stop stops the observer Stop() - VoteOutboundIfConfirmed( - ctx context.Context, - cctx *crosschaintypes.CrossChainTx, - ) (bool, error) + + // ChainParams returns observer chain params (might be out of date with zetacore) + ChainParams() observertypes.ChainParams + + // SetChainParams sets observer chain params SetChainParams(observertypes.ChainParams) - GetChainParams() observertypes.ChainParams - WatchInboundTracker(ctx context.Context) error + + // VoteOutboundIfConfirmed checks outbound status and returns (continueKeySign, error) + // todo we should make this simpler. + VoteOutboundIfConfirmed(ctx context.Context, cctx *crosschaintypes.CrossChainTx) (bool, error) } // ChainSigner is the interface to sign transactions for a chain diff --git a/zetaclient/chains/solana/observer/inbound.go b/zetaclient/chains/solana/observer/inbound.go index d9819bd53c..1441150ada 100644 --- a/zetaclient/chains/solana/observer/inbound.go +++ b/zetaclient/chains/solana/observer/inbound.go @@ -38,7 +38,7 @@ func (ob *Observer) WatchInbound(ctx context.Context) error { ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("Solana_WatchInbound_%d", ob.Chain().ChainId), - ob.GetChainParams().InboundTicker, + ob.ChainParams().InboundTicker, ) if err != nil { ob.Logger().Inbound.Error().Err(err).Msg("error creating ticker") diff --git a/zetaclient/chains/solana/observer/inbound_tracker.go b/zetaclient/chains/solana/observer/inbound_tracker.go index 70b6e9702f..19f8d26d04 100644 --- a/zetaclient/chains/solana/observer/inbound_tracker.go +++ b/zetaclient/chains/solana/observer/inbound_tracker.go @@ -21,7 +21,7 @@ func (ob *Observer) WatchInboundTracker(ctx context.Context) error { ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("Solana_WatchInboundTracker_%d", ob.Chain().ChainId), - ob.GetChainParams().InboundTicker, + ob.ChainParams().InboundTicker, ) if err != nil { ob.Logger().Inbound.Err(err).Msg("error creating ticker") @@ -42,7 +42,7 @@ func (ob *Observer) WatchInboundTracker(ctx context.Context) error { Err(err). Msgf("WatchInboundTracker: error ProcessInboundTrackers for chain %d", ob.Chain().ChainId) } - ticker.UpdateInterval(ob.GetChainParams().InboundTicker, ob.Logger().Inbound) + ticker.UpdateInterval(ob.ChainParams().InboundTicker, ob.Logger().Inbound) case <-ob.StopChannel(): ob.Logger().Inbound.Info().Msgf("WatchInboundTracker stopped for chain %d", ob.Chain().ChainId) return nil diff --git a/zetaclient/chains/solana/observer/observer.go b/zetaclient/chains/solana/observer/observer.go index 634bdfd635..0548fcd6d3 100644 --- a/zetaclient/chains/solana/observer/observer.go +++ b/zetaclient/chains/solana/observer/observer.go @@ -96,25 +96,9 @@ func (ob *Observer) WithSolClient(client interfaces.SolanaRPCClient) { ob.solClient = client } -// SetChainParams sets the chain params for the observer -// Note: chain params is accessed concurrently -func (ob *Observer) SetChainParams(params observertypes.ChainParams) { - ob.Mu().Lock() - defer ob.Mu().Unlock() - ob.WithChainParams(params) -} - -// GetChainParams returns the chain params for the observer -// Note: chain params is accessed concurrently -func (ob *Observer) GetChainParams() observertypes.ChainParams { - ob.Mu().Lock() - defer ob.Mu().Unlock() - return ob.ChainParams() -} - // Start starts the Go routine processes to observe the Solana chain func (ob *Observer) Start(ctx context.Context) { - if noop := ob.Observer.Start(); noop { + if ok := ob.Observer.Start(); !ok { ob.Logger().Chain.Info().Msgf("observer is already started for chain %d", ob.Chain().ChainId) return } diff --git a/zetaclient/chains/solana/observer/observer_gas.go b/zetaclient/chains/solana/observer/observer_gas.go index 80747e2efb..03291d6a54 100644 --- a/zetaclient/chains/solana/observer/observer_gas.go +++ b/zetaclient/chains/solana/observer/observer_gas.go @@ -42,26 +42,26 @@ func (ob *Observer) WatchGasPrice(ctx context.Context) error { // start gas price ticker ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("Solana_WatchGasPrice_%d", ob.Chain().ChainId), - ob.GetChainParams().GasPriceTicker, + ob.ChainParams().GasPriceTicker, ) if err != nil { return errors.Wrapf(err, "NewDynamicTicker error") } ob.Logger().GasPrice.Info().Msgf("WatchGasPrice started for chain %d with interval %d", - ob.Chain().ChainId, ob.GetChainParams().GasPriceTicker) + ob.Chain().ChainId, ob.ChainParams().GasPriceTicker) defer ticker.Stop() for { select { case <-ticker.C(): - if !ob.GetChainParams().IsSupported { + if !ob.ChainParams().IsSupported { continue } err = ob.PostGasPrice(ctx) if err != nil { ob.Logger().GasPrice.Error().Err(err).Msgf("PostGasPrice error for chain %d", ob.Chain().ChainId) } - ticker.UpdateInterval(ob.GetChainParams().GasPriceTicker, ob.Logger().GasPrice) + ticker.UpdateInterval(ob.ChainParams().GasPriceTicker, ob.Logger().GasPrice) case <-ob.StopChannel(): ob.Logger().GasPrice.Info().Msgf("WatchGasPrice stopped for chain %d", ob.Chain().ChainId) return nil diff --git a/zetaclient/chains/solana/observer/outbound.go b/zetaclient/chains/solana/observer/outbound.go index 7ff968ea93..e185b1a27d 100644 --- a/zetaclient/chains/solana/observer/outbound.go +++ b/zetaclient/chains/solana/observer/outbound.go @@ -36,7 +36,7 @@ func (ob *Observer) WatchOutbound(ctx context.Context) error { chainID := ob.Chain().ChainId ticker, err := clienttypes.NewDynamicTicker( fmt.Sprintf("Solana_WatchOutbound_%d", chainID), - ob.GetChainParams().OutboundTicker, + ob.ChainParams().OutboundTicker, ) if err != nil { ob.Logger().Outbound.Error().Err(err).Msg("error creating ticker") @@ -63,7 +63,7 @@ func (ob *Observer) WatchOutbound(ctx context.Context) error { Msgf("WatchOutbound: error ProcessOutboundTrackers for chain %d", chainID) } - ticker.UpdateInterval(ob.GetChainParams().OutboundTicker, ob.Logger().Outbound) + ticker.UpdateInterval(ob.ChainParams().OutboundTicker, ob.Logger().Outbound) case <-ob.StopChannel(): ob.Logger().Outbound.Info().Msgf("WatchOutbound: watcher stopped for chain %d", chainID) return nil diff --git a/zetaclient/chains/solana/observer/rpc_status.go b/zetaclient/chains/solana/observer/rpc_status.go index ff3d02f679..1b16492076 100644 --- a/zetaclient/chains/solana/observer/rpc_status.go +++ b/zetaclient/chains/solana/observer/rpc_status.go @@ -17,7 +17,7 @@ func (ob *Observer) watchRPCStatus(ctx context.Context) error { for { select { case <-ticker.C: - if !ob.GetChainParams().IsSupported { + if !ob.ChainParams().IsSupported { continue } diff --git a/zetaclient/chains/ton/config.go b/zetaclient/chains/ton/config.go index ee7eaac701..731287756e 100644 --- a/zetaclient/chains/ton/config.go +++ b/zetaclient/chains/ton/config.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "net/url" "time" "github.com/tonkeeper/tongo/config" @@ -38,3 +39,16 @@ func ConfigFromURL(ctx context.Context, url string) (*GlobalConfigurationFile, e return config.ParseConfig(res.Body) } + +func ConfigFromPath(path string) (*GlobalConfigurationFile, error) { + return config.ParseConfigFile(path) +} + +// ConfigFromSource returns a parsed configuration file from a URL or a file path. +func ConfigFromSource(ctx context.Context, urlOrPath string) (*GlobalConfigurationFile, error) { + if u, err := url.Parse(urlOrPath); err == nil { + return ConfigFromURL(ctx, u.String()) + } + + return ConfigFromPath(urlOrPath) +} diff --git a/zetaclient/chains/ton/liteapi/client.go b/zetaclient/chains/ton/liteapi/client.go new file mode 100644 index 0000000000..25b0efcf39 --- /dev/null +++ b/zetaclient/chains/ton/liteapi/client.go @@ -0,0 +1,230 @@ +package liteapi + +import ( + "context" + "fmt" + "slices" + "strconv" + "strings" + + lru "github.com/hashicorp/golang-lru" + "github.com/pkg/errors" + "github.com/tonkeeper/tongo/liteapi" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" + + zetaton "github.com/zeta-chain/node/zetaclient/chains/ton" +) + +// Client extends liteapi.Client with some high-level tools +// Reference: https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl +type Client struct { + *liteapi.Client + blockCache *lru.Cache +} + +const ( + pageSize = 200 + blockCacheSize = 250 +) + +// New Client constructor. +func New(client *liteapi.Client) *Client { + blockCache, _ := lru.New(blockCacheSize) + + return &Client{Client: client, blockCache: blockCache} +} + +// NewFromSource creates a new client from a URL or a file path. +func NewFromSource(ctx context.Context, urlOrPath string) (*Client, error) { + cfg, err := zetaton.ConfigFromSource(ctx, urlOrPath) + if err != nil { + return nil, errors.Wrap(err, "unable to get config") + } + + client, err := liteapi.NewClient( + liteapi.WithConfigurationFile(*cfg), + liteapi.WithDetectArchiveNodes(), + ) + if err != nil { + return nil, errors.Wrap(err, "unable to create client") + } + + return New(client), nil +} + +// GetBlockHeader returns block header by block ID. +// Uses LRU cache for network efficiency. +// I haven't found what mode means but `0` works fine. +func (c *Client) GetBlockHeader(ctx context.Context, blockID ton.BlockIDExt, mode uint32) (tlb.BlockInfo, error) { + if c.blockCache == nil { + return tlb.BlockInfo{}, errors.New("block cache is not initialized") + } + + cached, ok := c.getBlockHeaderCache(blockID) + if ok { + return cached, nil + } + + header, err := c.Client.GetBlockHeader(ctx, blockID, mode) + if err != nil { + return tlb.BlockInfo{}, err + } + + c.setBlockHeaderCache(blockID, header) + + return header, nil +} + +func (c *Client) getBlockHeaderCache(blockID ton.BlockIDExt) (tlb.BlockInfo, bool) { + raw, ok := c.blockCache.Get(blockID.String()) + if !ok { + return tlb.BlockInfo{}, false + } + + header, ok := raw.(tlb.BlockInfo) + + return header, ok +} + +func (c *Client) setBlockHeaderCache(blockID ton.BlockIDExt, header tlb.BlockInfo) { + c.blockCache.Add(blockID.String(), header) +} + +// GetFirstTransaction scrolls through the transactions of the given account to find the first one. +// Note that it might fail w/o using an archival node. Also returns the number of +// scrolled transactions for this account i.e. total transactions +func (c *Client) GetFirstTransaction(ctx context.Context, acc ton.AccountID) (*ton.Transaction, int, error) { + lt, hash, err := c.getLastTransactionHash(ctx, acc) + if err != nil { + return nil, 0, err + } + + var ( + tx *ton.Transaction + scrolled int + ) + + for { + hashBits := ton.Bits256(hash) + + txs, err := c.GetTransactions(ctx, pageSize, acc, lt, hashBits) + if err != nil { + return nil, scrolled, errors.Wrapf(err, "unable to get transactions [lt %d, hash %s]", lt, hashBits.Hex()) + } + + if len(txs) == 0 { + break + } + + scrolled += len(txs) + + tx = &txs[len(txs)-1] + + // Not we take the latest item in the list (oldest tx in the page) + // and set it as the new last tx + lt, hash = tx.PrevTransLt, tx.PrevTransHash + } + + if tx == nil { + return nil, scrolled, fmt.Errorf("no transactions found [lt %d, hash %s]", lt, ton.Bits256(hash).Hex()) + } + + return tx, scrolled, nil +} + +// GetTransactionsSince returns all account transactions since the given logicalTime and hash (exclusive). +// The result is ordered from oldest to newest. Used to detect new txs to observe. +func (c *Client) GetTransactionsSince( + ctx context.Context, + acc ton.AccountID, + oldestLT uint64, + oldestHash ton.Bits256, +) ([]ton.Transaction, error) { + lt, hash, err := c.getLastTransactionHash(ctx, acc) + if err != nil { + return nil, err + } + + var result []ton.Transaction + + for { + hashBits := ton.Bits256(hash) + + // note that ton liteapi works in the reverse order. + // Here we go from the LATEST txs to the oldest at N txs per page + txs, err := c.GetTransactions(ctx, pageSize, acc, lt, hashBits) + if err != nil { + return nil, errors.Wrapf(err, "unable to get transactions [lt %d, hash %s]", lt, hashBits.Hex()) + } + + if len(txs) == 0 { + break + } + + for i := range txs { + found := txs[i].Lt == oldestLT && txs[i].Hash() == tlb.Bits256(oldestHash) + if !found { + continue + } + + // early exit + result = append(result, txs[:i]...) + + return result, nil + } + + // otherwise, append all page results + result = append(result, txs...) + + // prepare pagination params for the next page + oldestIndex := len(txs) - 1 + + lt, hash = txs[oldestIndex].PrevTransLt, txs[oldestIndex].PrevTransHash + } + + // reverse the result to get the oldest tx first + slices.Reverse(result) + + return result, nil +} + +// getLastTransactionHash returns logical time and hash of the last transaction +func (c *Client) getLastTransactionHash(ctx context.Context, acc ton.AccountID) (uint64, tlb.Bits256, error) { + state, err := c.GetAccountState(ctx, acc) + if err != nil { + return 0, tlb.Bits256{}, errors.Wrap(err, "unable to get account state") + } + + if state.Account.Status() != tlb.AccountActive { + return 0, tlb.Bits256{}, errors.New("account is not active") + } + + return state.LastTransLt, state.LastTransHash, nil +} + +// TransactionHashToString converts logicalTime and hash to string +func TransactionHashToString(lt uint64, hash ton.Bits256) string { + return fmt.Sprintf("%d:%s", lt, hash.Hex()) +} + +// TransactionHashFromString parses encoded string into logicalTime and hash +func TransactionHashFromString(encoded string) (uint64, ton.Bits256, error) { + parts := strings.Split(encoded, ":") + if len(parts) != 2 { + return 0, ton.Bits256{}, fmt.Errorf("invalid encoded string format") + } + + lt, err := strconv.ParseUint(parts[0], 10, 64) + if err != nil { + return 0, ton.Bits256{}, fmt.Errorf("invalid logical time: %w", err) + } + + var hashBits ton.Bits256 + + if err = hashBits.FromHex(parts[1]); err != nil { + return 0, ton.Bits256{}, fmt.Errorf("invalid hash: %w", err) + } + + return lt, hashBits, nil +} diff --git a/zetaclient/chains/ton/liteapi/client_live_test.go b/zetaclient/chains/ton/liteapi/client_live_test.go new file mode 100644 index 0000000000..ed3c850dd8 --- /dev/null +++ b/zetaclient/chains/ton/liteapi/client_live_test.go @@ -0,0 +1,198 @@ +package liteapi + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tonkeeper/tongo/config" + "github.com/tonkeeper/tongo/liteapi" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" + "github.com/zeta-chain/node/zetaclient/common" +) + +func TestClient(t *testing.T) { + if !common.LiveTestEnabled() { + t.Skip("Live tests are disabled") + } + + var ( + ctx = context.Background() + client = New(mustCreateClient(t)) + ) + + t.Run("GetFirstTransaction", func(t *testing.T) { + t.Run("Account doesn't exist", func(t *testing.T) { + // ARRANGE + accountID, err := ton.ParseAccountID("0:55798cb7b87168251a7c39f6806b8c202f6caa0f617a76f4070b3fdacfd056a2") + require.NoError(t, err) + + // ACT + tx, scrolled, err := client.GetFirstTransaction(ctx, accountID) + + // ASSERT + require.ErrorContains(t, err, "account is not active") + require.Zero(t, scrolled) + require.Nil(t, tx) + }) + + t.Run("All good", func(t *testing.T) { + // ARRANGE + // Given sample account id (a dev wallet) + // https://tonviewer.com/UQCVlMcZ7EyV9maDsvscoLCd5KQfb7CHukyNJluWpMzlD0vr?section=transactions + accountID, err := ton.ParseAccountID("UQCVlMcZ7EyV9maDsvscoLCd5KQfb7CHukyNJluWpMzlD0vr") + require.NoError(t, err) + + // Given expected hash for the first tx + const expect = "b73df4853ca02a040df46f56635d6b8f49b554d5f556881ab389111bbfce4498" + + // as of 2024-09-18 + const expectedTransactions = 23 + + start := time.Now() + + // ACT + tx, scrolled, err := client.GetFirstTransaction(ctx, accountID) + + finish := time.Since(start) + + // ASSERT + require.NoError(t, err) + + assert.GreaterOrEqual(t, scrolled, expectedTransactions) + assert.Equal(t, expect, tx.Hash().Hex()) + + t.Logf("Time taken %s; transactions scanned: %d", finish.String(), scrolled) + }) + }) + + t.Run("GetTransactionsUntil", func(t *testing.T) { + // ARRANGE + // Given sample account id (dev wallet) + // https://tonviewer.com/UQCVlMcZ7EyV9maDsvscoLCd5KQfb7CHukyNJluWpMzlD0vr?section=transactions + accountID, err := ton.ParseAccountID("UQCVlMcZ7EyV9maDsvscoLCd5KQfb7CHukyNJluWpMzlD0vr") + require.NoError(t, err) + + const getUntilLT = uint64(48645164000001) + const getUntilHash = `2e107215e634bbc3492bdf4b1466d59432623295072f59ab526d15737caa9531` + + // as of 2024-09-20 + const expectedTX = 3 + + var hash ton.Bits256 + require.NoError(t, hash.FromHex(getUntilHash)) + + start := time.Now() + + // ACT + // https://tonviewer.com/UQCVlMcZ7EyV9maDsvscoLCd5KQfb7CHukyNJluWpMzlD0vr?section=transactions + txs, err := client.GetTransactionsSince(ctx, accountID, getUntilLT, hash) + + finish := time.Since(start) + + // ASSERT + require.NoError(t, err) + + t.Logf("Time taken %s; transactions fetched: %d", finish.String(), len(txs)) + for _, tx := range txs { + printTx(t, tx) + } + + mustContainTX(t, txs, "a6672a0e80193c1f705ef1cf45a5883441b8252523b1d08f7656c80e400c74a8") + assert.GreaterOrEqual(t, len(txs), expectedTX) + }) + + t.Run("GetBlockHeader", func(t *testing.T) { + // ARRANGE + // Given sample account id (dev wallet) + // https://tonscan.org/address/UQCVlMcZ7EyV9maDsvscoLCd5KQfb7CHukyNJluWpMzlD0vr + accountID, err := ton.ParseAccountID("UQCVlMcZ7EyV9maDsvscoLCd5KQfb7CHukyNJluWpMzlD0vr") + require.NoError(t, err) + + const getUntilLT = uint64(48645164000001) + const getUntilHash = `2e107215e634bbc3492bdf4b1466d59432623295072f59ab526d15737caa9531` + + var hash ton.Bits256 + require.NoError(t, hash.FromHex(getUntilHash)) + + txs, err := client.GetTransactions(ctx, 1, accountID, getUntilLT, hash) + require.NoError(t, err) + require.Len(t, txs, 1) + + // Given a block + blockID := txs[0].BlockID + + // ACT + header, err := client.GetBlockHeader(ctx, blockID, 0) + + // ASSERT + require.NoError(t, err) + require.NotZero(t, header.MinRefMcSeqno) + require.Equal(t, header.MinRefMcSeqno, header.MasterRef.Master.SeqNo) + }) +} + +func mustCreateClient(t *testing.T) *liteapi.Client { + client, err := liteapi.NewClient( + liteapi.WithConfigurationFile(mustFetchConfig(t)), + liteapi.WithDetectArchiveNodes(), + ) + + require.NoError(t, err) + + return client +} + +func mustFetchConfig(t *testing.T) config.GlobalConfigurationFile { + // archival light client for mainnet + const url = "https://api.tontech.io/ton/archive-mainnet.autoconf.json" + + res, err := http.Get(url) + require.NoError(t, err) + require.Equal(t, http.StatusOK, res.StatusCode) + + defer res.Body.Close() + + conf, err := config.ParseConfig(res.Body) + require.NoError(t, err) + + return *conf +} + +func mustContainTX(t *testing.T, txs []ton.Transaction, hash string) { + var h ton.Bits256 + require.NoError(t, h.FromHex(hash)) + + for _, tx := range txs { + if tx.Hash() == tlb.Bits256(h) { + return + } + } + + t.Fatalf("transaction %q not found", hash) +} + +func printTx(t *testing.T, tx ton.Transaction) { + b, err := json.MarshalIndent(simplifyTx(tx), "", " ") + require.NoError(t, err) + + t.Logf("TX %s", string(b)) +} + +func simplifyTx(tx ton.Transaction) map[string]any { + return map[string]any{ + "block": fmt.Sprintf("shard: %d, seqno: %d", tx.BlockID.Shard, tx.BlockID.Seqno), + "hash": tx.Hash().Hex(), + "logicalTime": tx.Lt, + "unixTime": time.Unix(int64(tx.Transaction.Now), 0).UTC().String(), + "outMessagesCount": tx.OutMsgCnt, + // "inMessageInfo": tx.Msgs.InMsg.Value.Value.Info.IntMsgInfo, + // "outMessages": tx.Msgs.OutMsgs, + } +} diff --git a/zetaclient/chains/ton/liteapi/client_test.go b/zetaclient/chains/ton/liteapi/client_test.go new file mode 100644 index 0000000000..a1148540be --- /dev/null +++ b/zetaclient/chains/ton/liteapi/client_test.go @@ -0,0 +1,100 @@ +package liteapi + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestHashes(t *testing.T) { + const sample = `48644940000001:e02b8c7cec103e08175ade8106619a8908707623c31451df2a68497c7d23d15a` + + lt, hash, err := TransactionHashFromString(sample) + require.NoError(t, err) + + require.Equal(t, uint64(48644940000001), lt) + require.Equal(t, "e02b8c7cec103e08175ade8106619a8908707623c31451df2a68497c7d23d15a", hash.Hex()) + require.Equal(t, sample, TransactionHashToString(lt, hash)) +} + +func TestTransactionHashFromString(t *testing.T) { + for _, tt := range []struct { + name string + raw string + error bool + lt uint64 + hash string + }{ + { + name: "real example", + raw: "163000003:d0415f655644db6ee1260b1fa48e9f478e938823e8b293054fbae1f3511b77c5", + lt: 163000003, + hash: "d0415f655644db6ee1260b1fa48e9f478e938823e8b293054fbae1f3511b77c5", + }, + { + name: "zero lt", + raw: "0:0000000000000000000000000000000000000000000000000000000000000000", + lt: 0, + hash: "0000000000000000000000000000000000000000000000000000000000000000", + }, + { + name: "big lt", + raw: "999999999999:fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", + lt: 999_999_999_999, + hash: "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0", + }, + { + name: "missing colon", + raw: "123456abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef", + error: true, + }, + { + name: "missing logical time", + raw: ":abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef", + error: true, + }, + { + name: "hash length", + raw: "123456:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcde", + error: true, + }, + { + name: "non-numeric logical time", + raw: "notanumber:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef", + error: true, + }, + { + name: "non-hex hash", + raw: "123456:xyz123xyz123xyz123xyz123xyz123xyz123xyz123xyz123xyz123xyz123xyz123", + error: true, + }, + { + name: "empty string", + raw: "", + error: true, + }, + { + name: "Invalid - only logical time, no hash", + raw: "123456:", + error: true, + }, + { + name: "Invalid - too many parts (extra colon)", + raw: "123456:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef:extra", + error: true, + }, + } { + t.Run(tt.name, func(t *testing.T) { + lt, hash, err := TransactionHashFromString(tt.raw) + + if tt.error { + require.Error(t, err) + return + } + + require.NoError(t, err) + require.Equal(t, tt.lt, lt) + require.Equal(t, hash.Hex(), tt.hash) + }) + } +} diff --git a/zetaclient/chains/ton/observer/inbound.go b/zetaclient/chains/ton/observer/inbound.go new file mode 100644 index 0000000000..95f9a510d7 --- /dev/null +++ b/zetaclient/chains/ton/observer/inbound.go @@ -0,0 +1,260 @@ +package observer + +import ( + "context" + "encoding/hex" + "fmt" + + "cosmossdk.io/math" + "github.com/pkg/errors" + "github.com/rs/zerolog" + "github.com/tonkeeper/tongo/ton" + + "github.com/zeta-chain/node/pkg/coin" + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" + "github.com/zeta-chain/node/pkg/ticker" + "github.com/zeta-chain/node/zetaclient/chains/ton/liteapi" + zctx "github.com/zeta-chain/node/zetaclient/context" + "github.com/zeta-chain/node/zetaclient/zetacore" +) + +const ( + // MaxTransactionsPerTick is the maximum number of transactions to process on a ticker + MaxTransactionsPerTick = 100 +) + +func (ob *Observer) watchInbound(ctx context.Context) error { + app, err := zctx.FromContext(ctx) + if err != nil { + return err + } + + var ( + chainID = ob.Chain().ChainId + initialInterval = ticker.SecondsFromUint64(ob.ChainParams().InboundTicker) + sampledLogger = ob.Logger().Inbound.Sample(&zerolog.BasicSampler{N: 10}) + ) + + ob.Logger().Inbound.Info().Msgf("WatchInbound started for chain %d", chainID) + + task := func(ctx context.Context, t *ticker.Ticker) error { + if !app.IsInboundObservationEnabled() { + sampledLogger.Info().Msgf("WatchInbound: inbound observation is disabled for chain %d", chainID) + return nil + } + + if err := ob.observeInbound(ctx); err != nil { + ob.Logger().Inbound.Err(err).Msg("WatchInbound: observeInbound error") + } + + newInterval := ticker.SecondsFromUint64(ob.ChainParams().InboundTicker) + t.SetInterval(newInterval) + + return nil + } + + return ticker.Run( + ctx, + initialInterval, + task, + ticker.WithStopChan(ob.StopChannel()), + ticker.WithLogger(ob.Logger().Inbound, "WatchInbound"), + ) +} + +func (ob *Observer) observeInbound(ctx context.Context) error { + if err := ob.ensureLastScannedTX(ctx); err != nil { + return errors.Wrap(err, "unable to ensure last scanned tx") + } + + // extract logicalTime and tx hash from last scanned tx + lt, hashBits, err := liteapi.TransactionHashFromString(ob.LastTxScanned()) + if err != nil { + return errors.Wrapf(err, "unable to parse last scanned tx %q", ob.LastTxScanned()) + } + + txs, err := ob.client.GetTransactionsSince(ctx, ob.gateway.AccountID(), lt, hashBits) + if err != nil { + return errors.Wrap(err, "unable to get transactions") + } + + switch { + case len(txs) == 0: + // noop + return nil + case len(txs) > MaxTransactionsPerTick: + ob.Logger().Inbound.Info(). + Msgf("observeInbound: got %d transactions. Taking first %d", len(txs), MaxTransactionsPerTick) + + txs = txs[:MaxTransactionsPerTick] + default: + ob.Logger().Inbound.Info().Msgf("observeInbound: got %d transactions", len(txs)) + } + + for i := range txs { + tx := txs[i] + + parsedTX, skip, err := ob.gateway.ParseAndFilter(tx, toncontracts.FilterInbounds) + if err != nil { + return errors.Wrap(err, "unable to parse and filter tx") + } + + if skip { + ob.Logger().Inbound.Info().Fields(txLogFields(&tx)).Msg("observeInbound: skipping tx") + ob.setLastScannedTX(&tx) + + continue + } + + if _, err := ob.voteInbound(ctx, parsedTX); err != nil { + ob.Logger().Inbound. + Error().Err(err). + Fields(txLogFields(&tx)). + Msg("observeInbound: unable to vote for tx") + + return errors.Wrapf(err, "unable to vote for inbound tx %s", tx.Hash().Hex()) + } + + ob.setLastScannedTX(&parsedTX.Transaction) + } + + return nil +} + +func (ob *Observer) voteInbound(ctx context.Context, tx *toncontracts.Transaction) (string, error) { + // noop + if tx.Operation == toncontracts.OpDonate { + ob.Logger().Inbound.Info(). + Uint64("tx.lt", tx.Lt). + Str("tx.hash", tx.Hash().Hex()). + Msg("Thank you rich folk for your donation!") + + return "", nil + } + + // TODO: Add compliance check + // https://github.com/zeta-chain/node/issues/2916 + + blockHeader, err := ob.client.GetBlockHeader(ctx, tx.BlockID, 0) + if err != nil { + return "", errors.Wrapf(err, "unable to get block header %s", tx.BlockID.String()) + } + + sender, amount, memo, err := extractInboundData(tx) + if err != nil { + return "", err + } + + seqno := blockHeader.MinRefMcSeqno + + return ob.voteDeposit(ctx, tx, sender, amount, memo, seqno) +} + +// extractInboundData parses Gateway tx into deposit (TON sender, amount, memo) +func extractInboundData(tx *toncontracts.Transaction) (string, math.Uint, []byte, error) { + switch tx.Operation { + case toncontracts.OpDeposit: + d, err := tx.Deposit() + if err != nil { + return "", math.NewUint(0), nil, err + } + + return d.Sender.ToRaw(), d.Amount, d.Memo(), nil + case toncontracts.OpDepositAndCall: + d, err := tx.DepositAndCall() + if err != nil { + return "", math.NewUint(0), nil, err + } + + return d.Sender.ToRaw(), d.Amount, d.Memo(), nil + default: + return "", math.NewUint(0), nil, fmt.Errorf("unknown operation %d", tx.Operation) + } +} + +func (ob *Observer) voteDeposit( + ctx context.Context, + tx *toncontracts.Transaction, + sender string, + amount math.Uint, + memo []byte, + seqno uint32, +) (string, error) { + const ( + eventIndex = 0 // not a smart contract call + coinType = coin.CoinType_Gas + asset = "" // empty for gas coin + gasLimit = 0 + retryGasLimit = zetacore.PostVoteInboundExecutionGasLimit + ) + + var ( + operatorAddress = ob.ZetacoreClient().GetKeys().GetOperatorAddress() + inboundHash = liteapi.TransactionHashToString(tx.Lt, ton.Bits256(tx.Hash())) + ) + + // TODO: use protocol contract v2 for deposit + // https://github.com/zeta-chain/node/issues/2967 + + msg := zetacore.GetInboundVoteMessage( + sender, + ob.Chain().ChainId, + sender, + sender, + ob.ZetacoreClient().Chain().ChainId, + amount, + hex.EncodeToString(memo), + inboundHash, + uint64(seqno), + gasLimit, + coinType, + asset, + operatorAddress.String(), + eventIndex, + ) + + return ob.PostVoteInbound(ctx, msg, retryGasLimit) +} + +func (ob *Observer) ensureLastScannedTX(ctx context.Context) error { + // noop + if ob.LastTxScanned() != "" { + return nil + } + + tx, _, err := ob.client.GetFirstTransaction(ctx, ob.gateway.AccountID()) + if err != nil { + return err + } + + ob.setLastScannedTX(tx) + + return nil +} + +func (ob *Observer) setLastScannedTX(tx *ton.Transaction) { + txHash := liteapi.TransactionHashToString(tx.Lt, ton.Bits256(tx.Hash())) + + ob.WithLastTxScanned(txHash) + + if err := ob.WriteLastTxScannedToDB(txHash); err != nil { + ob.Logger().Inbound.Error(). + Err(err). + Fields(txLogFields(tx)). + Msgf("setLastScannedTX: unable to WriteLastTxScannedToDB") + + return + } + + ob.Logger().Inbound.Info(). + Fields(txLogFields(tx)). + Msg("setLastScannedTX: WriteLastTxScannedToDB") +} + +func txLogFields(tx *ton.Transaction) map[string]any { + return map[string]any{ + "inbound.ton.lt": tx.Lt, + "inbound.ton.hash": tx.Hash().Hex(), + "inbound.ton.block_id": tx.BlockID.BlockID.String(), + } +} diff --git a/zetaclient/chains/ton/observer/inbound_test.go b/zetaclient/chains/ton/observer/inbound_test.go new file mode 100644 index 0000000000..281db44f79 --- /dev/null +++ b/zetaclient/chains/ton/observer/inbound_test.go @@ -0,0 +1,331 @@ +package observer + +import ( + "encoding/hex" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" + "github.com/zeta-chain/node/testutil/sample" + "github.com/zeta-chain/node/zetaclient/chains/ton/liteapi" +) + +func TestInbound(t *testing.T) { + gw := toncontracts.NewGateway( + ton.MustParseAccountID("0:997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b"), + ) + + t.Run("No gateway provided", func(t *testing.T) { + ts := newTestSuite(t) + + _, err := New(ts.baseObserver, ts.liteClient, nil) + require.Error(t, err) + }) + + t.Run("Ensure last scanned tx", func(t *testing.T) { + t.Run("Unable to get first tx", func(t *testing.T) { + // ARRANGE + ts := newTestSuite(t) + + // Given observer + ob, err := New(ts.baseObserver, ts.liteClient, gw) + require.NoError(t, err) + + // Given mocked lite client call + ts.OnGetFirstTransaction(gw.AccountID(), nil, 0, errors.New("oops")).Once() + + // ACT + // Observe inbounds once + err = ob.observeInbound(ts.ctx) + + // ASSERT + assert.ErrorContains(t, err, "unable to ensure last scanned tx") + assert.Empty(t, ob.LastTxScanned()) + }) + + t.Run("All good", func(t *testing.T) { + // ARRANGE + ts := newTestSuite(t) + + // Given mocked lite client calls + firstTX := sample.TONDonation(t, gw.AccountID(), toncontracts.Donation{ + Sender: sample.GenerateTONAccountID(), + Amount: tonCoins(t, "1"), + }) + + ts.OnGetFirstTransaction(gw.AccountID(), &firstTX, 0, nil).Once() + ts.OnGetTransactionsSince(gw.AccountID(), firstTX.Lt, txHash(firstTX), nil, nil).Once() + + // Given observer + ob, err := New(ts.baseObserver, ts.liteClient, gw) + require.NoError(t, err) + + // ACT + // Observe inbounds once + err = ob.observeInbound(ts.ctx) + + // ASSERT + assert.NoError(t, err) + + // Check that last scanned tx is set and is valid + lastScanned, err := ob.ReadLastTxScannedFromDB() + assert.NoError(t, err) + assert.Equal(t, ob.LastTxScanned(), lastScanned) + + lt, hash, err := liteapi.TransactionHashFromString(lastScanned) + assert.NoError(t, err) + assert.Equal(t, firstTX.Lt, lt) + assert.Equal(t, firstTX.Hash().Hex(), hash.Hex()) + }) + }) + + t.Run("Donation", func(t *testing.T) { + // ARRANGE + ts := newTestSuite(t) + + // Given observer + ob, err := New(ts.baseObserver, ts.liteClient, gw) + require.NoError(t, err) + + lastScanned := ts.SetupLastScannedTX(gw.AccountID()) + + // Given mocked lite client calls + donation := sample.TONDonation(t, gw.AccountID(), toncontracts.Donation{ + Sender: sample.GenerateTONAccountID(), + Amount: tonCoins(t, "12"), + }) + + txs := []ton.Transaction{donation} + + ts. + OnGetTransactionsSince(gw.AccountID(), lastScanned.Lt, txHash(lastScanned), txs, nil). + Once() + + // ACT + // Observe inbounds once + err = ob.observeInbound(ts.ctx) + + // ASSERT + assert.NoError(t, err) + + // nothing happened, but tx scanned + lt, hash, err := liteapi.TransactionHashFromString(ob.LastTxScanned()) + assert.NoError(t, err) + assert.Equal(t, donation.Lt, lt) + assert.Equal(t, donation.Hash().Hex(), hash.Hex()) + }) + + t.Run("Deposit", func(t *testing.T) { + // ARRANGE + ts := newTestSuite(t) + + // Given observer + ob, err := New(ts.baseObserver, ts.liteClient, gw) + require.NoError(t, err) + + lastScanned := ts.SetupLastScannedTX(gw.AccountID()) + + // Given mocked lite client calls + deposit := toncontracts.Deposit{ + Sender: sample.GenerateTONAccountID(), + Amount: tonCoins(t, "12"), + Recipient: sample.EthAddress(), + } + + depositTX := sample.TONDeposit(t, gw.AccountID(), deposit) + txs := []ton.Transaction{depositTX} + + ts. + OnGetTransactionsSince(gw.AccountID(), lastScanned.Lt, txHash(lastScanned), txs, nil). + Once() + + ts.MockGetBlockHeader(depositTX.BlockID) + + // ACT + // Observe inbounds once + err = ob.observeInbound(ts.ctx) + + // ASSERT + assert.NoError(t, err) + + // Check that cctx was sent to zetacore + require.Len(t, ts.votesBag, 1) + + // Check CCTX + cctx := ts.votesBag[0] + + assert.NotNil(t, cctx) + + assert.Equal(t, deposit.Sender.ToRaw(), cctx.Sender) + assert.Equal(t, ts.chain.ChainId, cctx.SenderChainId) + + assert.Equal(t, "", cctx.Asset) + assert.Equal(t, deposit.Amount.Uint64(), cctx.Amount.Uint64()) + assert.Equal(t, hex.EncodeToString(deposit.Recipient.Bytes()), cctx.Message) + + // Check hash & block height + expectedHash := liteapi.TransactionHashToString(depositTX.Lt, txHash(depositTX)) + assert.Equal(t, expectedHash, cctx.InboundHash) + + blockInfo, err := ts.liteClient.GetBlockHeader(ts.ctx, depositTX.BlockID, 0) + require.NoError(t, err) + + assert.Equal(t, uint64(blockInfo.MinRefMcSeqno), cctx.InboundBlockHeight) + }) + + t.Run("Deposit and call", func(t *testing.T) { + // ARRANGE + ts := newTestSuite(t) + + // Given observer + ob, err := New(ts.baseObserver, ts.liteClient, gw) + require.NoError(t, err) + + lastScanned := ts.SetupLastScannedTX(gw.AccountID()) + + // Given mocked lite client calls + const callData = "hey there" + depositAndCall := toncontracts.DepositAndCall{ + Deposit: toncontracts.Deposit{ + Sender: sample.GenerateTONAccountID(), + Amount: tonCoins(t, "4"), + Recipient: sample.EthAddress(), + }, + CallData: []byte(callData), + } + + depositAndCallTX := sample.TONDepositAndCall(t, gw.AccountID(), depositAndCall) + txs := []ton.Transaction{depositAndCallTX} + + ts. + OnGetTransactionsSince(gw.AccountID(), lastScanned.Lt, txHash(lastScanned), txs, nil). + Once() + + ts.MockGetBlockHeader(depositAndCallTX.BlockID) + + // ACT + // Observe inbounds once + err = ob.observeInbound(ts.ctx) + + // ASSERT + assert.NoError(t, err) + + // Check that cctx was sent to zetacore + require.Len(t, ts.votesBag, 1) + + // Check CCTX + cctx := ts.votesBag[0] + + assert.NotNil(t, cctx) + + assert.Equal(t, depositAndCall.Sender.ToRaw(), cctx.Sender) + assert.Equal(t, ts.chain.ChainId, cctx.SenderChainId) + + assert.Equal(t, "", cctx.Asset) + assert.Equal(t, depositAndCall.Amount.Uint64(), cctx.Amount.Uint64()) + + expectedMessage := hex.EncodeToString(append( + depositAndCall.Recipient.Bytes(), + []byte(callData)..., + )) + + assert.Equal(t, expectedMessage, cctx.Message) + + // Check hash & block height + expectedHash := liteapi.TransactionHashToString(depositAndCallTX.Lt, txHash(depositAndCallTX)) + assert.Equal(t, expectedHash, cctx.InboundHash) + + blockInfo, err := ts.liteClient.GetBlockHeader(ts.ctx, depositAndCallTX.BlockID, 0) + require.NoError(t, err) + + assert.Equal(t, uint64(blockInfo.MinRefMcSeqno), cctx.InboundBlockHeight) + }) + + t.Run("Multiple transactions", func(t *testing.T) { + // ARRANGE + ts := newTestSuite(t) + + // Given observer + ob, err := New(ts.baseObserver, ts.liteClient, gw) + require.NoError(t, err) + + lastScanned := ts.SetupLastScannedTX(gw.AccountID()) + + // Given several transactions + txs := []ton.Transaction{ + // should be skipped + sample.TONDonation(t, gw.AccountID(), toncontracts.Donation{ + Sender: sample.GenerateTONAccountID(), + Amount: tonCoins(t, "1"), + }), + // should be voted + sample.TONDeposit(t, gw.AccountID(), toncontracts.Deposit{ + Sender: sample.GenerateTONAccountID(), + Amount: tonCoins(t, "3"), + Recipient: sample.EthAddress(), + }), + // should be skipped (invalid inbound message) + sample.TONTransaction(t, sample.TONTransactionProps{ + Account: gw.AccountID(), + Input: &tlb.Message{}, + }), + // should be voted + sample.TONDeposit(t, gw.AccountID(), toncontracts.Deposit{ + Sender: sample.GenerateTONAccountID(), + Amount: tonCoins(t, "3"), + Recipient: sample.EthAddress(), + }), + // should be skipped (invalid inbound/outbound messages) + sample.TONTransaction(t, sample.TONTransactionProps{ + Account: gw.AccountID(), + Input: &tlb.Message{}, + Output: &tlb.Message{}, + }), + } + + ts. + OnGetTransactionsSince(gw.AccountID(), lastScanned.Lt, txHash(lastScanned), txs, nil). + Once() + + for _, tx := range txs { + ts.MockGetBlockHeader(tx.BlockID) + } + + // ACT + // Observe inbounds once + err = ob.observeInbound(ts.ctx) + + // ASSERT + assert.NoError(t, err) + + // Check that cctx was sent to zetacore + assert.Equal(t, 2, len(ts.votesBag)) + + var ( + hash1 = liteapi.TransactionHashToString(txs[1].Lt, txHash(txs[1])) + hash2 = liteapi.TransactionHashToString(txs[3].Lt, txHash(txs[3])) + ) + + assert.Equal(t, hash1, ts.votesBag[0].InboundHash) + assert.Equal(t, hash2, ts.votesBag[1].InboundHash) + + // Check that last scanned tx points to the last tx in a list (even if it was skipped) + var ( + lastTX = txs[len(txs)-1] + lastScannedHash = ob.LastTxScanned() + ) + + lastLT, lastHash, err := liteapi.TransactionHashFromString(lastScannedHash) + assert.NoError(t, err) + assert.Equal(t, lastTX.Lt, lastLT) + assert.Equal(t, lastTX.Hash().Hex(), lastHash.Hex()) + }) +} + +func txHash(tx ton.Transaction) ton.Bits256 { + return ton.Bits256(tx.Hash()) +} diff --git a/zetaclient/chains/ton/observer/observer.go b/zetaclient/chains/ton/observer/observer.go new file mode 100644 index 0000000000..e20742116a --- /dev/null +++ b/zetaclient/chains/ton/observer/observer.go @@ -0,0 +1,80 @@ +package observer + +import ( + "context" + "errors" + + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" + + "github.com/zeta-chain/node/pkg/bg" + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" + "github.com/zeta-chain/node/x/crosschain/types" + "github.com/zeta-chain/node/zetaclient/chains/base" + "github.com/zeta-chain/node/zetaclient/chains/interfaces" +) + +// Observer is a TON observer. +type Observer struct { + *base.Observer + + client LiteClient + gateway *toncontracts.Gateway +} + +// LiteClient represents a TON client +// +//go:generate mockery --name LiteClient --filename ton_liteclient.go --case underscore --output ../../../testutils/mocks +type LiteClient interface { + GetBlockHeader(ctx context.Context, blockID ton.BlockIDExt, mode uint32) (tlb.BlockInfo, error) + GetTransactionsSince(ctx context.Context, acc ton.AccountID, lt uint64, bits ton.Bits256) ([]ton.Transaction, error) + GetFirstTransaction(ctx context.Context, id ton.AccountID) (*ton.Transaction, int, error) +} + +var _ interfaces.ChainObserver = (*Observer)(nil) + +// New constructor for TON Observer. +func New(bo *base.Observer, client LiteClient, gateway *toncontracts.Gateway) (*Observer, error) { + switch { + case !bo.Chain().IsTONChain(): + return nil, errors.New("base observer chain is not TON") + case client == nil: + return nil, errors.New("liteapi client is nil") + case gateway == nil: + return nil, errors.New("gateway is nil") + } + + bo.LoadLastTxScanned() + + return &Observer{ + Observer: bo, + client: client, + gateway: gateway, + }, nil +} + +// Start starts the observer. This method is NOT blocking. +func (ob *Observer) Start(ctx context.Context) { + if ok := ob.Observer.Start(); !ok { + ob.Logger().Chain.Info().Msgf("observer is already started for chain %d", ob.Chain().ChainId) + return + } + + ob.Logger().Chain.Info().Msgf("observer is starting for chain %d", ob.Chain().ChainId) + + // Note that each `watch*` method has a ticker that will stop as soon as + // baseObserver.Stop() was called (ticker.WithStopChan) + + // watch for incoming txs and post votes to zetacore + bg.Work(ctx, ob.watchInbound, bg.WithName("WatchInbound"), bg.WithLogger(ob.Logger().Inbound)) + + // TODO: watchInboundTracker + // https://github.com/zeta-chain/node/issues/2935 + + // TODO: outbounds/withdrawals: (watchOutbound, watchGasPrice, watchRPCStatus) + // https://github.com/zeta-chain/node/issues/2807 +} + +func (ob *Observer) VoteOutboundIfConfirmed(_ context.Context, _ *types.CrossChainTx) (bool, error) { + return false, errors.New("not implemented") +} diff --git a/zetaclient/chains/ton/observer/observer_test.go b/zetaclient/chains/ton/observer/observer_test.go index e978a589b9..38c032eb4a 100644 --- a/zetaclient/chains/ton/observer/observer_test.go +++ b/zetaclient/chains/ton/observer/observer_test.go @@ -2,62 +2,171 @@ package observer import ( "context" - "encoding/json" - "strings" + "strconv" "testing" + "cosmossdk.io/math" + "github.com/rs/zerolog" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/tonkeeper/tongo/config" - "github.com/tonkeeper/tongo/liteapi" + "github.com/tonkeeper/tongo/tlb" + "github.com/tonkeeper/tongo/ton" + "github.com/zeta-chain/node/pkg/chains" + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" + "github.com/zeta-chain/node/testutil/sample" + cctxtypes "github.com/zeta-chain/node/x/crosschain/types" + observertypes "github.com/zeta-chain/node/x/observer/types" + "github.com/zeta-chain/node/zetaclient/chains/base" + "github.com/zeta-chain/node/zetaclient/chains/ton/liteapi" + "github.com/zeta-chain/node/zetaclient/db" + "github.com/zeta-chain/node/zetaclient/keys" + "github.com/zeta-chain/node/zetaclient/testutils/mocks" ) -// todo tmp (will be resolved automatically) -// taken from ton:8000/lite-client.json -const configRaw = `{"@type":"config.global","dht":{"@type":"dht.config.global","k":3,"a":3,"static_nodes": -{"@type":"dht.nodes","nodes":[]}},"liteservers":[{"id":{"key":"+DjLFqH/N5jO1ZO8PYVYU6a6e7EnnsF0GWFsteE+qy8=","@type": -"pub.ed25519"},"port":4443,"ip":2130706433}],"validator":{"@type":"validator.config.global","zero_state": -{"workchain":-1,"shard":-9223372036854775808,"seqno":0,"root_hash":"rR8EFZNlyj3rfYlMyQC8gT0A6ghDrbKe4aMmodiNw6I=", -"file_hash":"fT2hXGv1OF7XDhraoAELrYz6wX3ue16QpSoWTiPrUAE="},"init_block":{"workchain":-1,"shard":-9223372036854775808, -"seqno":0,"root_hash":"rR8EFZNlyj3rfYlMyQC8gT0A6ghDrbKe4aMmodiNw6I=", -"file_hash":"fT2hXGv1OF7XDhraoAELrYz6wX3ue16QpSoWTiPrUAE="}}}` +type testSuite struct { + ctx context.Context + t *testing.T -func TestObserver(t *testing.T) { - t.Skip("skip test") + chain chains.Chain + chainParams *observertypes.ChainParams - ctx := context.Background() + liteClient *mocks.LiteClient - cfg, err := config.ParseConfig(strings.NewReader(configRaw)) - require.NoError(t, err) + zetacore *mocks.ZetacoreClient + tss *mocks.TSS + database *db.DB + + baseObserver *base.Observer + + votesBag []*cctxtypes.MsgVoteInbound +} + +func newTestSuite(t *testing.T) *testSuite { + var ( + ctx = context.Background() - client, err := liteapi.NewClient(liteapi.WithConfigurationFile(*cfg)) + chain = chains.TONTestnet + chainParams = sample.ChainParams(chain.ChainId) + + liteClient = mocks.NewLiteClient(t) + + tss = mocks.NewTSSAthens3() + zetacore = mocks.NewZetacoreClient(t).WithKeys(&keys.Keys{}) + + testLogger = zerolog.New(zerolog.NewTestWriter(t)) + logger = base.Logger{Std: testLogger, Compliance: testLogger} + ) + + database, err := db.NewFromSqliteInMemory(true) require.NoError(t, err) - res, err := client.GetMasterchainInfo(ctx) + baseObserver, err := base.NewObserver( + chain, + *chainParams, + zetacore, + tss, + 1, + 1, + 60, + nil, + database, + logger, + ) + require.NoError(t, err) - // Outputs: - // { - // "Last": { - // "Workchain": 4294967295, - // "Shard": 9223372036854775808, - // "Seqno": 915, - // "RootHash": "2e9e312c5bd3b7b96d23ce1342ac76e5486012c9aac44781c2c25dbc55f5c8ad", - // "FileHash": "d3745319bfaeebb168d9db6bb5b4752b6b28ab9041735c81d4a02fc820040851" - // }, - // "StateRootHash": "02538fb9dc802004012285a90a7af9ba279706e2deea9ca635decd80e94a7045", - // "Init": { - // "Workchain": 4294967295, - // "RootHash": "ad1f04159365ca3deb7d894cc900bc813d00ea0843adb29ee1a326a1d88dc3a2", - // "FileHash": "7d3da15c6bf5385ed70e1adaa0010bad8cfac17dee7b5e90a52a164e23eb5001" - // } - // } - t.Logf("Masterchain info") - logJSON(t, res) -} - -func logJSON(t *testing.T, v any) { - b, err := json.MarshalIndent(v, "", " ") + ts := &testSuite{ + ctx: ctx, + t: t, + + chain: chain, + chainParams: chainParams, + + liteClient: liteClient, + + zetacore: zetacore, + tss: tss, + database: database, + + baseObserver: baseObserver, + } + + // Setup mocks + ts.zetacore.On("Chain").Return(chain).Maybe() + + setupVotesBag(ts) + + return ts +} + +func (ts *testSuite) SetupLastScannedTX(gw ton.AccountID) ton.Transaction { + lastScannedTX := sample.TONDonation(ts.t, gw, toncontracts.Donation{ + Sender: sample.GenerateTONAccountID(), + Amount: tonCoins(ts.t, "1"), + }) + + txHash := liteapi.TransactionHashToString(lastScannedTX.Lt, ton.Bits256(lastScannedTX.Hash())) + + ts.baseObserver.WithLastTxScanned(txHash) + require.NoError(ts.t, ts.baseObserver.WriteLastTxScannedToDB(txHash)) + + return lastScannedTX +} + +func (ts *testSuite) OnGetFirstTransaction(acc ton.AccountID, tx *ton.Transaction, scanned int, err error) *mock.Call { + return ts.liteClient. + On("GetFirstTransaction", ts.ctx, acc). + Return(tx, scanned, err) +} + +func (ts *testSuite) OnGetTransactionsSince( + acc ton.AccountID, + lt uint64, + hash ton.Bits256, + txs []ton.Transaction, + err error, +) *mock.Call { + return ts.liteClient. + On("GetTransactionsSince", mock.Anything, acc, lt, hash). + Return(txs, err) +} + +func (ts *testSuite) MockGetBlockHeader(id ton.BlockIDExt) *mock.Call { + // let's pretend that block's masterchain ref has the same seqno + blockInfo := tlb.BlockInfo{ + BlockInfoPart: tlb.BlockInfoPart{MinRefMcSeqno: id.Seqno}, + } + + return ts.liteClient. + On("GetBlockHeader", mock.Anything, id, uint32(0)). + Return(blockInfo, nil) +} + +// parses string to TON +func tonCoins(t *testing.T, raw string) math.Uint { + t.Helper() + + const oneTON = 1_000_000_000 + + f, err := strconv.ParseFloat(raw, 64) require.NoError(t, err) - t.Log(string(b)) + f *= oneTON + + return math.NewUint(uint64(f)) +} + +func setupVotesBag(ts *testSuite) { + catcher := func(args mock.Arguments) { + vote := args.Get(3) + cctx, ok := vote.(*cctxtypes.MsgVoteInbound) + require.True(ts.t, ok, "unexpected cctx type") + + ts.votesBag = append(ts.votesBag, cctx) + } + ts.zetacore. + On("PostVoteInbound", ts.ctx, mock.Anything, mock.Anything, mock.Anything). + Maybe(). + Run(catcher). + Return("", "", nil) // zeta hash, ballot index, error } diff --git a/zetaclient/config/config_chain.go b/zetaclient/config/config_chain.go index ca0234c126..6f17153b52 100644 --- a/zetaclient/config/config_chain.go +++ b/zetaclient/config/config_chain.go @@ -23,6 +23,7 @@ func New(setDefaults bool) Config { cfg.EVMChainConfigs = evmChainsConfigs() cfg.BTCChainConfigs = btcChainsConfigs() cfg.SolanaConfig = solanaConfigLocalnet() + cfg.TONConfig = tonConfigLocalnet() } return cfg @@ -47,6 +48,13 @@ func solanaConfigLocalnet() SolanaConfig { } } +func tonConfigLocalnet() TONConfig { + return TONConfig{ + LiteClientConfigURL: "http://ton:8000/lite-client.json", + RPCAlertLatency: 60, + } +} + // evmChainsConfigs contains EVM chain configs // it contains list of EVM chains with empty endpoint except for localnet func evmChainsConfigs() map[int64]EVMConfig { diff --git a/zetaclient/config/types.go b/zetaclient/config/types.go index bf225b97f4..a60875b5e8 100644 --- a/zetaclient/config/types.go +++ b/zetaclient/config/types.go @@ -60,6 +60,13 @@ type SolanaConfig struct { RPCAlertLatency int64 } +// TONConfig is the config for TON chain +type TONConfig struct { + // Can be either URL of local file path + LiteClientConfigURL string `json:"liteClientConfigURL"` + RPCAlertLatency int64 `json:"rpcAlertLatency"` +} + // ComplianceConfig is the config for compliance type ComplianceConfig struct { LogPath string `json:"LogPath"` @@ -97,6 +104,7 @@ type Config struct { // Deprecated: the 'BitcoinConfig' will be removed once the 'BTCChainConfigs' is fully adopted BitcoinConfig BTCConfig `json:"BitcoinConfig"` SolanaConfig SolanaConfig `json:"SolanaConfig"` + TONConfig TONConfig `json:"TONConfig"` // compliance config ComplianceConfig ComplianceConfig `json:"ComplianceConfig"` @@ -149,6 +157,14 @@ func (c Config) GetSolanaConfig() (SolanaConfig, bool) { return c.SolanaConfig, c.SolanaConfig != (SolanaConfig{}) } +// GetTONConfig returns the TONConfig and a bool indicating if it's present. +func (c Config) GetTONConfig() (TONConfig, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + + return c.TONConfig, c.TONConfig != TONConfig{} +} + // StringMasked returns the string representation of the config with sensitive fields masked. // Currently only the endpoints and bitcoin credentials are masked. func (c Config) StringMasked() string { diff --git a/zetaclient/config/types_test.go b/zetaclient/config/types_test.go index c57fd002e0..02f7eb5a6f 100644 --- a/zetaclient/config/types_test.go +++ b/zetaclient/config/types_test.go @@ -128,6 +128,8 @@ func Test_StringMasked(t *testing.T) { // create config with defaults cfg := config.New(true) + cfg.SolanaConfig.Endpoint += "?api-key=123" + // mask the config JSON string masked := cfg.StringMasked() require.NotEmpty(t, masked) @@ -137,5 +139,5 @@ func Test_StringMasked(t *testing.T) { require.Contains(t, masked, "BTCChainConfigs") // should not contain endpoint - require.NotContains(t, masked, "http") + require.NotContains(t, masked, "?api-key=123") } diff --git a/zetaclient/context/chain.go b/zetaclient/context/chain.go index 117b921168..6d05d97371 100644 --- a/zetaclient/context/chain.go +++ b/zetaclient/context/chain.go @@ -165,6 +165,10 @@ func (c Chain) IsSolana() bool { return chains.IsSolanaChain(c.ID(), c.registry.additionalChains) } +func (c Chain) IsTON() bool { + return chains.IsTONChain(c.ID(), c.registry.additionalChains) +} + // RelayerKeyPassword returns the relayer key password for the chain func (c Chain) RelayerKeyPassword() string { network := c.RawChain().Network diff --git a/zetaclient/logs/fields.go b/zetaclient/logs/fields.go index 497690ffa4..78b95fc7e0 100644 --- a/zetaclient/logs/fields.go +++ b/zetaclient/logs/fields.go @@ -3,12 +3,13 @@ package logs // A group of predefined field keys and module names for zetaclient logs const ( // field keys - FieldModule = "module" - FieldMethod = "method" - FieldChain = "chain" - FieldNonce = "nonce" - FieldTx = "tx" - FieldCctx = "cctx" + FieldModule = "module" + FieldMethod = "method" + FieldChain = "chain" + FieldChainNetwork = "chain_network" + FieldNonce = "nonce" + FieldTx = "tx" + FieldCctx = "cctx" // module names ModNameInbound = "inbound" diff --git a/zetaclient/orchestrator/bootstap_test.go b/zetaclient/orchestrator/bootstap_test.go index 73f47d21cf..eaae3a8e6d 100644 --- a/zetaclient/orchestrator/bootstap_test.go +++ b/zetaclient/orchestrator/bootstap_test.go @@ -21,7 +21,11 @@ import ( "github.com/zeta-chain/node/zetaclient/testutils/testrpc" ) -const solanaGatewayAddress = "2kJndCL9NBR36ySiQ4bmArs4YgWQu67LmCDfLzk5Gb7s" +const ( + solanaGatewayAddress = "2kJndCL9NBR36ySiQ4bmArs4YgWQu67LmCDfLzk5Gb7s" + tonGatewayAddress = "0:997d889c815aeac21c47f86ae0e38383efc3c3463067582f6263ad48c5a1485b" + tonMainnet = "https://ton.org/global-config.json" +) func TestCreateSignerMap(t *testing.T) { var ( @@ -211,9 +215,12 @@ func TestCreateChainObserverMap(t *testing.T) { evmServer := testrpc.NewEVMServer(t) evmServer.SetBlockNumber(100) - // Given generic SOL RPC + // Given SOL config _, solConfig := testrpc.NewSolanaServer(t) + // Given TON config + tonConfig := config.TONConfig{LiteClientConfigURL: tonMainnet, RPCAlertLatency: 1} + // Given a zetaclient config with ETH, MATIC, and BTC chains cfg := config.New(false) @@ -229,6 +236,7 @@ func TestCreateChainObserverMap(t *testing.T) { cfg.BTCChainConfigs[chains.BitcoinMainnet.ChainId] = btcConfig cfg.SolanaConfig = solConfig + cfg.TONConfig = tonConfig // Given AppContext app := zctx.New(cfg, nil, log) @@ -239,6 +247,7 @@ func TestCreateChainObserverMap(t *testing.T) { mustUpdateAppContextChainParams(t, app, []chains.Chain{ chains.Ethereum, chains.BitcoinMainnet, + chains.TONMainnet, }) // ACT @@ -249,11 +258,12 @@ func TestCreateChainObserverMap(t *testing.T) { assert.NotEmpty(t, observers) // Okay, now we want to check that signers for EVM and BTC were created - assert.Equal(t, 2, len(observers)) + assert.Equal(t, 3, len(observers)) hasObserver(t, observers, chains.Ethereum.ChainId) hasObserver(t, observers, chains.BitcoinMainnet.ChainId) + hasObserver(t, observers, chains.TONMainnet.ChainId) - t.Run("Add polygon in the runtime", func(t *testing.T) { + t.Run("Add polygon and remove TON in the runtime", func(t *testing.T) { // ARRANGE mustUpdateAppContextChainParams(t, app, []chains.Chain{ chains.Ethereum, chains.BitcoinMainnet, chains.Polygon, @@ -265,7 +275,7 @@ func TestCreateChainObserverMap(t *testing.T) { // ASSERT assert.NoError(t, err) assert.Equal(t, 1, added) - assert.Equal(t, 0, removed) + assert.Equal(t, 1, removed) hasObserver(t, observers, chains.Ethereum.ChainId) hasObserver(t, observers, chains.Polygon.ChainId) @@ -400,6 +410,11 @@ func chainParams(supportedChains []chains.Chain) ([]chains.Chain, map[int64]*obs continue } + if chains.IsEVMChain(chainID, nil) { + params[chainID] = ptr.Ptr(mocks.MockChainParams(chainID, 100)) + continue + } + if chains.IsSolanaChain(chainID, nil) { p := mocks.MockChainParams(chainID, 100) p.GatewayAddress = solanaGatewayAddress @@ -407,10 +422,14 @@ func chainParams(supportedChains []chains.Chain) ([]chains.Chain, map[int64]*obs continue } - if chains.IsEVMChain(chainID, nil) { - params[chainID] = ptr.Ptr(mocks.MockChainParams(chainID, 100)) + if chains.IsTONChain(chainID, nil) { + p := mocks.MockChainParams(chainID, 100) + p.GatewayAddress = tonGatewayAddress + params[chainID] = &p continue } + + panic("unknown chain: " + chain.String()) } return supportedChains, params diff --git a/zetaclient/orchestrator/bootstrap.go b/zetaclient/orchestrator/bootstrap.go index 08d625548f..34c94bf77d 100644 --- a/zetaclient/orchestrator/bootstrap.go +++ b/zetaclient/orchestrator/bootstrap.go @@ -9,7 +9,9 @@ import ( solrpc "github.com/gagliardetto/solana-go/rpc" ethrpc2 "github.com/onrik/ethrpc" "github.com/pkg/errors" + "github.com/tonkeeper/tongo/ton" + toncontracts "github.com/zeta-chain/node/pkg/contracts/ton" "github.com/zeta-chain/node/zetaclient/chains/base" btcobserver "github.com/zeta-chain/node/zetaclient/chains/bitcoin/observer" "github.com/zeta-chain/node/zetaclient/chains/bitcoin/rpc" @@ -19,9 +21,12 @@ import ( "github.com/zeta-chain/node/zetaclient/chains/interfaces" solbserver "github.com/zeta-chain/node/zetaclient/chains/solana/observer" solanasigner "github.com/zeta-chain/node/zetaclient/chains/solana/signer" + "github.com/zeta-chain/node/zetaclient/chains/ton/liteapi" + tonobserver "github.com/zeta-chain/node/zetaclient/chains/ton/observer" zctx "github.com/zeta-chain/node/zetaclient/context" "github.com/zeta-chain/node/zetaclient/db" "github.com/zeta-chain/node/zetaclient/keys" + "github.com/zeta-chain/node/zetaclient/logs" "github.com/zeta-chain/node/zetaclient/metrics" ) @@ -71,7 +76,7 @@ func syncSignerMap( presentChainIDs = make([]int64, 0) onAfterAdd = func(chainID int64, _ interfaces.ChainSigner) { - logger.Std.Info().Msgf("Added signer for chain %d", chainID) + logger.Std.Info().Int64(logs.FieldChain, chainID).Msg("Added signer") added++ } @@ -80,7 +85,7 @@ func syncSignerMap( } onBeforeRemove = func(chainID int64, _ interfaces.ChainSigner) { - logger.Std.Info().Msgf("Removing signer for chain %d", chainID) + logger.Std.Info().Int64(logs.FieldChain, chainID).Msg("Removing signer") removed++ } ) @@ -181,6 +186,9 @@ func syncSignerMap( } addSigner(chainID, signer) + case chain.IsTON(): + logger.Std.Error().Err(err).Msgf("TON signer is not implemented yet for chain id %d", chainID) + continue default: logger.Std.Warn(). Int64("signer.chain_id", chain.ID()). @@ -238,7 +246,8 @@ func syncObserverMap( presentChainIDs = make([]int64, 0) - onAfterAdd = func(_ int64, ob interfaces.ChainObserver) { + onAfterAdd = func(chainID int64, ob interfaces.ChainObserver) { + logger.Std.Info().Int64(logs.FieldChain, chainID).Msg("Added observer") ob.Start(ctx) added++ } @@ -247,7 +256,8 @@ func syncObserverMap( mapSet[int64, interfaces.ChainObserver](observerMap, chainID, ob, onAfterAdd) } - onBeforeRemove = func(_ int64, ob interfaces.ChainObserver) { + onBeforeRemove = func(chainID int64, ob interfaces.ChainObserver) { + logger.Std.Info().Int64(logs.FieldChain, chainID).Msg("Removing observer") ob.Stop() removed++ } @@ -394,6 +404,58 @@ func syncObserverMap( } addObserver(chainID, solObserver) + case chain.IsTON(): + cfg, found := app.Config().GetTONConfig() + if !found { + logger.Std.Warn().Msgf("Unable to find chain params for TON chain %d", chainID) + continue + } + + database, err := db.NewFromSqlite(dbpath, chainName, true) + if err != nil { + logger.Std.Error().Err(err).Msgf("unable to open database for TON chain %d", chainID) + continue + } + + baseObserver, err := base.NewObserver( + *rawChain, + *params, + client, + tss, + base.DefaultBlockCacheSize, + base.DefaultHeaderCacheSize, + cfg.RPCAlertLatency, + ts, + database, + logger, + ) + + if err != nil { + logger.Std.Error().Err(err).Msgf("Unable to create base observer for TON chain %d", chainID) + continue + } + + tonClient, err := liteapi.NewFromSource(ctx, cfg.LiteClientConfigURL) + if err != nil { + logger.Std.Error().Err(err).Msgf("Unable to create TON liteapi for chain %d", chainID) + continue + } + + gatewayID, err := ton.ParseAccountID(params.GatewayAddress) + if err != nil { + logger.Std.Error().Err(err). + Msgf("Unable to parse gateway address %q for chain %d", params.GatewayAddress, chainID) + continue + } + + gw := toncontracts.NewGateway(gatewayID) + tonObserver, err := tonobserver.New(baseObserver, tonClient, gw) + if err != nil { + logger.Std.Error().Err(err).Msgf("Unable to create TON observer for chain %d", chainID) + continue + } + + addObserver(chainID, tonObserver) default: logger.Std.Warn(). Int64("observer.chain_id", chain.ID()). diff --git a/zetaclient/orchestrator/orchestrator.go b/zetaclient/orchestrator/orchestrator.go index dd0ef1eaab..698a520fcf 100644 --- a/zetaclient/orchestrator/orchestrator.go +++ b/zetaclient/orchestrator/orchestrator.go @@ -17,6 +17,7 @@ import ( "github.com/zeta-chain/node/pkg/bg" "github.com/zeta-chain/node/pkg/constant" zetamath "github.com/zeta-chain/node/pkg/math" + "github.com/zeta-chain/node/pkg/ticker" "github.com/zeta-chain/node/x/crosschain/types" observertypes "github.com/zeta-chain/node/x/observer/types" "github.com/zeta-chain/node/zetaclient/chains/base" @@ -228,7 +229,7 @@ func (oc *Orchestrator) resolveObserver(app *zctx.AppContext, chainID int64) (in // update chain observer chain parameters var ( - curParams = observer.GetChainParams() + curParams = observer.ChainParams() freshParams = chain.Params() ) @@ -447,11 +448,11 @@ func (oc *Orchestrator) ScheduleCctxEVM( for _, v := range res { trackerMap[v.Nonce] = true } - outboundScheduleLookahead := observer.GetChainParams().OutboundScheduleLookahead + outboundScheduleLookahead := observer.ChainParams().OutboundScheduleLookahead // #nosec G115 always in range outboundScheduleLookback := uint64(float64(outboundScheduleLookahead) * evmOutboundLookbackFactor) // #nosec G115 positive - outboundScheduleInterval := uint64(observer.GetChainParams().OutboundScheduleInterval) + outboundScheduleInterval := uint64(observer.ChainParams().OutboundScheduleInterval) criticalInterval := uint64(10) // for critical pending outbound we reduce re-try interval nonCriticalInterval := outboundScheduleInterval * 2 // for non-critical pending outbound we increase re-try interval @@ -546,8 +547,8 @@ func (oc *Orchestrator) ScheduleCctxBTC( return } // #nosec G115 positive - interval := uint64(observer.GetChainParams().OutboundScheduleInterval) - lookahead := observer.GetChainParams().OutboundScheduleLookahead + interval := uint64(observer.ChainParams().OutboundScheduleInterval) + lookahead := observer.ChainParams().OutboundScheduleLookahead // schedule at most one keysign per ticker for idx, cctx := range cctxList { @@ -618,7 +619,7 @@ func (oc *Orchestrator) ScheduleCctxSolana( return } // #nosec G701 positive - interval := uint64(observer.GetChainParams().OutboundScheduleInterval) + interval := uint64(observer.ChainParams().OutboundScheduleInterval) // schedule keysign for each pending cctx for _, cctx := range cctxList { @@ -666,28 +667,18 @@ func (oc *Orchestrator) ScheduleCctxSolana( // runObserverSignerSync runs a blocking ticker that observes chain changes from zetacore // and optionally (de)provisions respective observers and signers. func (oc *Orchestrator) runObserverSignerSync(ctx context.Context) error { - // sync observers and signers right away to speed up zetaclient startup - if err := oc.syncObserverSigner(ctx); err != nil { - oc.logger.Error().Err(err).Msg("runObserverSignerSync: syncObserverSigner failed for initial sync") - } - - // sync observer and signer every 10 blocks (approx. 1 minute) - const cadence = 10 * constant.ZetaBlockTime - - ticker := time.NewTicker(cadence) - defer ticker.Stop() + // every other block + const cadence = 2 * constant.ZetaBlockTime - for { - select { - case <-oc.stop: - oc.logger.Warn().Msg("runObserverSignerSync: stopped") - return nil - case <-ticker.C: - if err := oc.syncObserverSigner(ctx); err != nil { - oc.logger.Error().Err(err).Msg("runObserverSignerSync: syncObserverSigner failed") - } + task := func(ctx context.Context, _ *ticker.Ticker) error { + if err := oc.syncObserverSigner(ctx); err != nil { + oc.logger.Error().Err(err).Msg("syncObserverSigner failed") } + + return nil } + + return ticker.Run(ctx, cadence, task, ticker.WithLogger(oc.logger.Logger, "SyncObserverSigner")) } // syncs and provisions observers & signers. diff --git a/zetaclient/orchestrator/orchestrator_test.go b/zetaclient/orchestrator/orchestrator_test.go index 969dbbb393..2ab34b900e 100644 --- a/zetaclient/orchestrator/orchestrator_test.go +++ b/zetaclient/orchestrator/orchestrator_test.go @@ -196,7 +196,7 @@ func Test_GetUpdatedChainObserver(t *testing.T) { chainOb, err := orchestrator.resolveObserver(appContext, evmChain.ChainId) require.NoError(t, err) require.NotNil(t, chainOb) - require.True(t, observertypes.ChainParamsEqual(*evmChainParamsNew, chainOb.GetChainParams())) + require.True(t, observertypes.ChainParamsEqual(*evmChainParamsNew, chainOb.ChainParams())) }) t.Run("btc chain observer should not be found", func(t *testing.T) { @@ -244,7 +244,7 @@ func Test_GetUpdatedChainObserver(t *testing.T) { chainOb, err := orchestrator.resolveObserver(appContext, btcChain.ChainId) require.NoError(t, err) require.NotNil(t, chainOb) - require.True(t, observertypes.ChainParamsEqual(*btcChainParamsNew, chainOb.GetChainParams())) + require.True(t, observertypes.ChainParamsEqual(*btcChainParamsNew, chainOb.ChainParams())) }) t.Run("solana chain observer should not be found", func(t *testing.T) { orchestrator := mockOrchestrator( @@ -282,7 +282,7 @@ func Test_GetUpdatedChainObserver(t *testing.T) { chainOb, err := orchestrator.resolveObserver(appContext, solChain.ChainId) require.NoError(t, err) require.NotNil(t, chainOb) - require.True(t, observertypes.ChainParamsEqual(*solChainParamsNew, chainOb.GetChainParams())) + require.True(t, observertypes.ChainParamsEqual(*solChainParamsNew, chainOb.ChainParams())) }) } diff --git a/zetaclient/testutils/mocks/chain_clients.go b/zetaclient/testutils/mocks/chain_clients.go index 94f636bf4e..aa5e36889b 100644 --- a/zetaclient/testutils/mocks/chain_clients.go +++ b/zetaclient/testutils/mocks/chain_clients.go @@ -15,12 +15,12 @@ var _ interfaces.ChainObserver = (*EVMObserver)(nil) // EVMObserver is a mock of evm chain observer for testing type EVMObserver struct { - ChainParams observertypes.ChainParams + chainParams observertypes.ChainParams } func NewEVMObserver(chainParams *observertypes.ChainParams) *EVMObserver { return &EVMObserver{ - ChainParams: *chainParams, + chainParams: *chainParams, } } @@ -35,11 +35,11 @@ func (ob *EVMObserver) VoteOutboundIfConfirmed( } func (ob *EVMObserver) SetChainParams(chainParams observertypes.ChainParams) { - ob.ChainParams = chainParams + ob.chainParams = chainParams } -func (ob *EVMObserver) GetChainParams() observertypes.ChainParams { - return ob.ChainParams +func (ob *EVMObserver) ChainParams() observertypes.ChainParams { + return ob.chainParams } func (ob *EVMObserver) GetTxID(_ uint64) string { @@ -57,12 +57,12 @@ var _ interfaces.ChainObserver = (*BTCObserver)(nil) // BTCObserver is a mock of btc chain observer for testing type BTCObserver struct { - ChainParams observertypes.ChainParams + chainParams observertypes.ChainParams } func NewBTCObserver(chainParams *observertypes.ChainParams) *BTCObserver { return &BTCObserver{ - ChainParams: *chainParams, + chainParams: *chainParams, } } @@ -78,11 +78,11 @@ func (ob *BTCObserver) VoteOutboundIfConfirmed( } func (ob *BTCObserver) SetChainParams(chainParams observertypes.ChainParams) { - ob.ChainParams = chainParams + ob.chainParams = chainParams } -func (ob *BTCObserver) GetChainParams() observertypes.ChainParams { - return ob.ChainParams +func (ob *BTCObserver) ChainParams() observertypes.ChainParams { + return ob.chainParams } func (ob *BTCObserver) GetTxID(_ uint64) string { @@ -98,12 +98,12 @@ var _ interfaces.ChainObserver = (*SolanaObserver)(nil) // SolanaObserver is a mock of solana chain observer for testing type SolanaObserver struct { - ChainParams observertypes.ChainParams + chainParams observertypes.ChainParams } func NewSolanaObserver(chainParams *observertypes.ChainParams) *SolanaObserver { return &SolanaObserver{ - ChainParams: *chainParams, + chainParams: *chainParams, } } @@ -119,11 +119,11 @@ func (ob *SolanaObserver) VoteOutboundIfConfirmed( } func (ob *SolanaObserver) SetChainParams(chainParams observertypes.ChainParams) { - ob.ChainParams = chainParams + ob.chainParams = chainParams } -func (ob *SolanaObserver) GetChainParams() observertypes.ChainParams { - return ob.ChainParams +func (ob *SolanaObserver) ChainParams() observertypes.ChainParams { + return ob.chainParams } func (ob *SolanaObserver) GetTxID(_ uint64) string { diff --git a/zetaclient/testutils/mocks/ton_liteclient.go b/zetaclient/testutils/mocks/ton_liteclient.go new file mode 100644 index 0000000000..f11ccaf24c --- /dev/null +++ b/zetaclient/testutils/mocks/ton_liteclient.go @@ -0,0 +1,127 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + tlb "github.com/tonkeeper/tongo/tlb" + + ton "github.com/tonkeeper/tongo/ton" +) + +// LiteClient is an autogenerated mock type for the LiteClient type +type LiteClient struct { + mock.Mock +} + +// GetBlockHeader provides a mock function with given fields: ctx, blockID, mode +func (_m *LiteClient) GetBlockHeader(ctx context.Context, blockID ton.BlockIDExt, mode uint32) (tlb.BlockInfo, error) { + ret := _m.Called(ctx, blockID, mode) + + if len(ret) == 0 { + panic("no return value specified for GetBlockHeader") + } + + var r0 tlb.BlockInfo + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ton.BlockIDExt, uint32) (tlb.BlockInfo, error)); ok { + return rf(ctx, blockID, mode) + } + if rf, ok := ret.Get(0).(func(context.Context, ton.BlockIDExt, uint32) tlb.BlockInfo); ok { + r0 = rf(ctx, blockID, mode) + } else { + r0 = ret.Get(0).(tlb.BlockInfo) + } + + if rf, ok := ret.Get(1).(func(context.Context, ton.BlockIDExt, uint32) error); ok { + r1 = rf(ctx, blockID, mode) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetFirstTransaction provides a mock function with given fields: ctx, id +func (_m *LiteClient) GetFirstTransaction(ctx context.Context, id ton.AccountID) (*ton.Transaction, int, error) { + ret := _m.Called(ctx, id) + + if len(ret) == 0 { + panic("no return value specified for GetFirstTransaction") + } + + var r0 *ton.Transaction + var r1 int + var r2 error + if rf, ok := ret.Get(0).(func(context.Context, ton.AccountID) (*ton.Transaction, int, error)); ok { + return rf(ctx, id) + } + if rf, ok := ret.Get(0).(func(context.Context, ton.AccountID) *ton.Transaction); ok { + r0 = rf(ctx, id) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*ton.Transaction) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ton.AccountID) int); ok { + r1 = rf(ctx, id) + } else { + r1 = ret.Get(1).(int) + } + + if rf, ok := ret.Get(2).(func(context.Context, ton.AccountID) error); ok { + r2 = rf(ctx, id) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// GetTransactionsSince provides a mock function with given fields: ctx, acc, lt, bits +func (_m *LiteClient) GetTransactionsSince(ctx context.Context, acc ton.AccountID, lt uint64, bits ton.Bits256) ([]ton.Transaction, error) { + ret := _m.Called(ctx, acc, lt, bits) + + if len(ret) == 0 { + panic("no return value specified for GetTransactionsSince") + } + + var r0 []ton.Transaction + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ton.AccountID, uint64, ton.Bits256) ([]ton.Transaction, error)); ok { + return rf(ctx, acc, lt, bits) + } + if rf, ok := ret.Get(0).(func(context.Context, ton.AccountID, uint64, ton.Bits256) []ton.Transaction); ok { + r0 = rf(ctx, acc, lt, bits) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]ton.Transaction) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ton.AccountID, uint64, ton.Bits256) error); ok { + r1 = rf(ctx, acc, lt, bits) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// NewLiteClient creates a new instance of LiteClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewLiteClient(t interface { + mock.TestingT + Cleanup(func()) +}) *LiteClient { + mock := &LiteClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/zetaclient/testutils/testrpc/rpc.go b/zetaclient/testutils/testrpc/rpc.go index f444631813..12f368fb3f 100644 --- a/zetaclient/testutils/testrpc/rpc.go +++ b/zetaclient/testutils/testrpc/rpc.go @@ -59,7 +59,7 @@ func (s *Server) httpHandler(w http.ResponseWriter, r *http.Request) { // Decode request raw, err := io.ReadAll(r.Body) require.NoError(s.t, err) - require.NoError(s.t, json.Unmarshal(raw, &req), "unable to unmarshal request") + require.NoError(s.t, json.Unmarshal(raw, &req), "unable to unmarshal request for %s", s.name) // Process request res := s.rpcHandler(req) From 81fc485d78617b29f9676b6b53529411e5824769 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Thu, 10 Oct 2024 01:36:29 -0700 Subject: [PATCH 18/36] fix(e2e): tolerate revert message in both error and status message (#2983) --- e2e/e2etests/test_eth_deposit_call.go | 7 ++++++- e2e/e2etests/test_solana_deposit_refund.go | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/e2e/e2etests/test_eth_deposit_call.go b/e2e/e2etests/test_eth_deposit_call.go index 46805f9f81..9484888cf3 100644 --- a/e2e/e2etests/test_eth_deposit_call.go +++ b/e2e/e2etests/test_eth_deposit_call.go @@ -88,5 +88,10 @@ func TestEtherDepositAndCall(r *runner.E2ERunner, args []string) { r.Logger.Info("Cross-chain call to reverter reverted") // Check the error carries the revert executed. - require.Contains(r, cctx.CctxStatus.ErrorMessage, "revert executed") + // tolerate the error in both the ErrorMessage field and the StatusMessage field + if cctx.CctxStatus.ErrorMessage != "" { + require.Contains(r, cctx.CctxStatus.ErrorMessage, "revert executed") + } else { + require.Contains(r, cctx.CctxStatus.StatusMessage, utils.ErrHashRevertFoo) + } } diff --git a/e2e/e2etests/test_solana_deposit_refund.go b/e2e/e2etests/test_solana_deposit_refund.go index 3176edee78..0a62b70ac6 100644 --- a/e2e/e2etests/test_solana_deposit_refund.go +++ b/e2e/e2etests/test_solana_deposit_refund.go @@ -32,5 +32,10 @@ func TestSolanaDepositAndCallRefund(r *runner.E2ERunner, args []string) { utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_Reverted) // Check the error carries the revert executed. - require.Contains(r, cctx.CctxStatus.ErrorMessage, "revert executed") + // tolerate the error in both the ErrorMessage field and the StatusMessage field + if cctx.CctxStatus.ErrorMessage != "" { + require.Contains(r, cctx.CctxStatus.ErrorMessage, "revert executed") + } else { + require.Contains(r, cctx.CctxStatus.StatusMessage, utils.ErrHashRevertFoo) + } } From cb74b251552bc4415b85fb021bd336c281cd83bf Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Thu, 10 Oct 2024 11:06:44 -0700 Subject: [PATCH 19/36] chore: use prebuilt bitcoin-node-sidecar (#2989) --- contrib/localnet/bitcoin-sidecar/Dockerfile | 14 -- .../localnet/bitcoin-sidecar/js/package.json | 23 --- .../localnet/bitcoin-sidecar/js/src/client.ts | 183 ------------------ .../localnet/bitcoin-sidecar/js/src/index.ts | 38 ---- .../localnet/bitcoin-sidecar/js/src/script.ts | 52 ----- .../bitcoin-sidecar/js/src/tsconfig.json | 11 -- .../localnet/bitcoin-sidecar/js/src/util.ts | 1 - contrib/localnet/docker-compose.yml | 3 +- 8 files changed, 1 insertion(+), 324 deletions(-) delete mode 100644 contrib/localnet/bitcoin-sidecar/Dockerfile delete mode 100644 contrib/localnet/bitcoin-sidecar/js/package.json delete mode 100644 contrib/localnet/bitcoin-sidecar/js/src/client.ts delete mode 100644 contrib/localnet/bitcoin-sidecar/js/src/index.ts delete mode 100644 contrib/localnet/bitcoin-sidecar/js/src/script.ts delete mode 100644 contrib/localnet/bitcoin-sidecar/js/src/tsconfig.json delete mode 100644 contrib/localnet/bitcoin-sidecar/js/src/util.ts diff --git a/contrib/localnet/bitcoin-sidecar/Dockerfile b/contrib/localnet/bitcoin-sidecar/Dockerfile deleted file mode 100644 index aef54cf56d..0000000000 --- a/contrib/localnet/bitcoin-sidecar/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM node:18.20.4 as builder - -WORKDIR /home/zeta/node - -COPY bitcoin-sidecar/js/* . - -RUN npm install && npm install typescript -g && tsc - -FROM node:alpine - -COPY --from=builder /home/zeta/node/dist ./dist -COPY --from=builder /home/zeta/node/node_modules ./node_modules - -CMD ["node", "dist/index.js"] \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/package.json b/contrib/localnet/bitcoin-sidecar/js/package.json deleted file mode 100644 index 1a4dd4b90a..0000000000 --- a/contrib/localnet/bitcoin-sidecar/js/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "zeta-btc-client", - "version": "0.0.1", - "description": "The Zetachain BTC client", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "bip32": "^4.0.0", - "bitcoinjs-lib": "^6.1.6", - "ecpair": "^2.1.0", - "express": "^4.19.2", - "randombytes": "^2.1.0", - "tiny-secp256k1": "^2.2.3" - }, - "devDependencies": { - "@types/node": "^20.14.11", - "typescript": "^5.5.3" - } -} \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/client.ts b/contrib/localnet/bitcoin-sidecar/js/src/client.ts deleted file mode 100644 index 678b90f6da..0000000000 --- a/contrib/localnet/bitcoin-sidecar/js/src/client.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { initEccLib, payments, Psbt } from "bitcoinjs-lib"; -import { bitcoin, Network, regtest } from "bitcoinjs-lib/src/networks"; -import BIP32Factory, { BIP32Interface } from 'bip32'; -import * as ecc from 'tiny-secp256k1'; -import randomBytes from "randombytes"; -import { ScriptBuilder } from "./script"; -import { Taptree } from "bitcoinjs-lib/src/types"; -import { toXOnly } from "./util"; - -const LEAF_VERSION_TAPSCRIPT = 0xc0; - -initEccLib(ecc); -const bip32 = BIP32Factory(ecc); -const rng = randomBytes; - -/// The evm address type, a 20 bytes hex string -export type Address = String; -export type BtcAddress = String; - -/// The BTC transaction hash returned -export type BtcTxnHash = String; -export interface BtcInput { - txn: BtcTxnHash, - idx: number, -} - -/** - * The example client for interacting with ZetaChain in BTC. There are currently two ways - * of calling a smart contract on ZetaChain from BTC: - * - * - Using OP_RETURN - * - Using Witness - * - * The method used is now based on the data size. Within 80 bytes, `OP_RETURN` is used, else - * the data is written to Witness. - * - * This class handles only the case where data is more than 80 bytes. - */ -export class ZetaBtcClient { - /** The BTC network interracting with */ - readonly network: Network; - - private reveal: RevealTxnBuilder | null; - - private constructor(network: Network) { - this.network = network; - } - - public static regtest(): ZetaBtcClient { - return new ZetaBtcClient(regtest); - } - - public static mainnet(): ZetaBtcClient { - return new ZetaBtcClient(bitcoin); - } - - /** - * Call a target address and passing the data call. - * - * @param address The target zetachain evm address - * @param calldata The calldata that will be invoked on Zetachain - */ - public call( - address: Address, - calldata: Buffer, - ): Address { - if (calldata.length <= 80) { - throw Error("Use op return instead"); - } - - if (address.startsWith("0x")) { - address = address.substring(2); - } - - return this.callWithWitness(Buffer.concat([Buffer.from(address, "hex"), calldata])); - } - - private callWithWitness( - data: Buffer, - ): Address { - const internalKey = bip32.fromSeed(rng(64), this.network); - - const leafScript = this.genLeafScript(internalKey.publicKey, data); - - const scriptTree: Taptree = { output: leafScript }; - - const { address: commitAddress } = payments.p2tr({ - internalPubkey: toXOnly(internalKey.publicKey), - scriptTree, - network: this.network, - }); - - this.reveal = new RevealTxnBuilder(internalKey, leafScript, this.network); - - return commitAddress; - } - - public buildRevealTxn(to: string, commitTxn: BtcInput, commitAmount: number, feeRate: number): Buffer { - if (this.reveal === null) { - throw new Error("commit txn not built yet"); - } - - this.reveal.with_commit_tx(to, commitTxn, commitAmount, feeRate); - return this.reveal.dump(); - } - - private genLeafScript(publicKey: Buffer, data: Buffer,): Buffer { - const builder = ScriptBuilder.new(publicKey); - builder.pushData(data); - return builder.build(); - } -} - -class RevealTxnBuilder { - private psbt: Psbt; - private key: BIP32Interface; - private leafScript: Buffer; - private network: Network - - constructor(key: BIP32Interface, leafScript: Buffer, network: Network) { - this.psbt = new Psbt({ network });; - this.key = key; - this.leafScript = leafScript; - this.network = network; - } - - public with_commit_tx(to: string, commitTxn: BtcInput, commitAmount: number, feeRate: number): RevealTxnBuilder { - const scriptTree: Taptree = { output: this.leafScript }; - - const { output, witness } = payments.p2tr({ - internalPubkey: toXOnly(this.key.publicKey), - scriptTree, - redeem: { - output: this.leafScript, - redeemVersion: LEAF_VERSION_TAPSCRIPT, - }, - network: this.network, - }); - - this.psbt.addInput({ - hash: commitTxn.txn.toString(), - index: commitTxn.idx, - witnessUtxo: { value: commitAmount, script: output! }, - tapLeafScript: [ - { - leafVersion: LEAF_VERSION_TAPSCRIPT, - script: this.leafScript, - controlBlock: witness![witness!.length - 1], - }, - ], - }); - - this.psbt.addOutput({ - value: commitAmount - this.estimateFee(to, commitAmount, feeRate), - address: to, - }); - - this.psbt.signAllInputs(this.key); - this.psbt.finalizeAllInputs(); - - return this; - } - - public dump(): Buffer { - return this.psbt.extractTransaction(true).toBuffer(); - } - - private estimateFee(to: string, amount: number, feeRate: number): number { - const cloned = this.psbt.clone(); - - cloned.addOutput({ - value: amount, - address: to, - }); - - // should have a way to avoid signing but just providing mocked signautre - cloned.signAllInputs(this.key); - cloned.finalizeAllInputs(); - - const size = cloned.extractTransaction().virtualSize(); - return size * feeRate; - } -} \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/index.ts b/contrib/localnet/bitcoin-sidecar/js/src/index.ts deleted file mode 100644 index 5164a6f148..0000000000 --- a/contrib/localnet/bitcoin-sidecar/js/src/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { ZetaBtcClient } from "./client"; -import express, { Request, Response } from 'express'; - -const app = express(); -const PORT = process.env.PORT || 3000; -let zetaClient = ZetaBtcClient.regtest(); - -app.use(express.json()); - -// Middleware to parse URL-encoded bodies -app.use(express.urlencoded({ extended: true })); - -// Route to handle JSON POST requests -app.post('/commit', (req: Request, res: Response) => { - const memo: string = req.body.memo; - const address = zetaClient.call("", Buffer.from(memo, "hex")); - res.json({ address }); -}); - -// Route to handle URL-encoded POST requests -app.post('/reveal', (req: Request, res: Response) => { - const { txn, idx, amount, feeRate, to } = req.body; - console.log(txn, idx, amount, feeRate); - - const rawHex = zetaClient.buildRevealTxn(to,{ txn, idx }, Number(amount), feeRate).toString("hex"); - zetaClient = ZetaBtcClient.regtest(); - res.json({ rawHex }); -}); - -// Start the server -app.listen(PORT, () => { - console.log(`Server is running on http://localhost:${PORT}`); -}); - -/** - * curl --request POST --header "Content-Type: application/json" --data '{"memo":"72f080c854647755d0d9e6f6821f6931f855b9acffd53d87433395672756d58822fd143360762109ab898626556b1c3b8d3096d2361f1297df4a41c1b429471a9aa2fc9be5f27c13b3863d6ac269e4b587d8389f8fd9649859935b0d48dea88cdb40f20c"}' http://localhost:3000/commit - * curl --request POST --header "Content-Type: application/json" --data '{"txn": "7a57f987a3cb605896a5909d9ef2bf7afbf0c78f21e4118b85d00d9e4cce0c2c", "idx": 0, "amount": 1000, "feeRate": 10}' http://localhost:3000/reveal - */ \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/script.ts b/contrib/localnet/bitcoin-sidecar/js/src/script.ts deleted file mode 100644 index f282e39f01..0000000000 --- a/contrib/localnet/bitcoin-sidecar/js/src/script.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { opcodes, script, Stack } from "bitcoinjs-lib"; -import { toXOnly } from "./util"; - -const MAX_SCRIPT_ELEMENT_SIZE = 520; - -/** The tapscript builder for zetaclient spending script */ -export class ScriptBuilder { - private script: Stack; - - private constructor(initialScript: Stack) { - this.script = initialScript; - } - - public static new(publicKey: Buffer): ScriptBuilder { - const stack = [ - toXOnly(publicKey), - opcodes.OP_CHECKSIG, - ]; - return new ScriptBuilder(stack); - } - - public pushData(data: Buffer) { - if (data.length <= 80) { - throw new Error("data length should be more than 80 bytes"); - } - - this.script.push( - opcodes.OP_FALSE, - opcodes.OP_IF - ); - - const chunks = chunkBuffer(data, MAX_SCRIPT_ELEMENT_SIZE); - for (const chunk of chunks) { - this.script.push(chunk); - } - - this.script.push(opcodes.OP_ENDIF); - } - - public build(): Buffer { - return script.compile(this.script); - } -} - -function chunkBuffer(buffer: Buffer, chunkSize: number): Buffer[] { - const chunks = []; - for (let i = 0; i < buffer.length; i += chunkSize) { - const chunk = buffer.slice(i, i + chunkSize); - chunks.push(chunk); - } - return chunks; -} \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/tsconfig.json b/contrib/localnet/bitcoin-sidecar/js/src/tsconfig.json deleted file mode 100644 index 4033670b3d..0000000000 --- a/contrib/localnet/bitcoin-sidecar/js/src/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "esModuleInterop": true, - "target": "es6", - "moduleResolution": "node", - "sourceMap": true, - "outDir": "dist" - }, - "lib": ["es2015"] -} \ No newline at end of file diff --git a/contrib/localnet/bitcoin-sidecar/js/src/util.ts b/contrib/localnet/bitcoin-sidecar/js/src/util.ts deleted file mode 100644 index 87c4d36d0f..0000000000 --- a/contrib/localnet/bitcoin-sidecar/js/src/util.ts +++ /dev/null @@ -1 +0,0 @@ -export const toXOnly = pubKey => (pubKey.length === 32 ? pubKey : pubKey.slice(1, 33)); \ No newline at end of file diff --git a/contrib/localnet/docker-compose.yml b/contrib/localnet/docker-compose.yml index 7044390647..363f5e1f6d 100644 --- a/contrib/localnet/docker-compose.yml +++ b/contrib/localnet/docker-compose.yml @@ -228,8 +228,7 @@ services: -txindex=1 bitcoin-node-sidecar: - build: - dockerfile: ./bitcoin-sidecar/Dockerfile + image: ghcr.io/zeta-chain/node-localnet-bitcoin-sidecar:e0205d7 container_name: bitcoin-node-sidecar hostname: bitcoin-node-sidecar networks: From a36bc0a11d021df9ec7b823936679e25f6cb5717 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Thu, 10 Oct 2024 11:57:27 -0700 Subject: [PATCH 20/36] chore: upgrade cosmos-sdk to v0.47.14 (#2980) * chore: upgrade cosmos-sdk to v0.47.14 * update slices.SortFunc usage * use merged ethermint version --- go.mod | 74 ++++++++++---------- go.sum | 136 +++++++++++++++++++++++------------- zetaclient/context/chain.go | 5 +- 3 files changed, 131 insertions(+), 84 deletions(-) diff --git a/go.mod b/go.mod index 7625fc2047..eb87031b7e 100644 --- a/go.mod +++ b/go.mod @@ -16,20 +16,20 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 github.com/cockroachdb/errors v1.11.1 github.com/coinbase/rosetta-sdk-go v0.7.9 - github.com/cometbft/cometbft v0.37.4 + github.com/cometbft/cometbft v0.37.5 github.com/cometbft/cometbft-db v0.12.0 github.com/cosmos/btcutil v1.0.5 - github.com/cosmos/cosmos-sdk v0.47.10 - github.com/cosmos/gogoproto v1.4.10 + github.com/cosmos/cosmos-sdk v0.47.14 + github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/ibc-go/v7 v7.4.0 - github.com/davecgh/go-spew v1.1.1 + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/emicklei/proto v1.11.1 github.com/ethereum/go-ethereum v1.10.26 - github.com/fatih/color v1.13.0 + github.com/fatih/color v1.14.1 github.com/frumioj/crypto11 v1.2.5-0.20210823151709-946ce662cc0e github.com/gagliardetto/solana-go v1.10.0 github.com/golang/mock v1.6.0 - github.com/golang/protobuf v1.5.3 + github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 @@ -49,26 +49,26 @@ require ( github.com/prometheus/client_golang v1.14.0 github.com/rakyll/statik v0.1.7 github.com/rs/cors v1.8.3 - github.com/rs/zerolog v1.32.0 + github.com/rs/zerolog v1.33.0 github.com/samber/lo v1.46.0 github.com/spf13/afero v1.11.0 - github.com/spf13/cast v1.5.1 + github.com/spf13/cast v1.6.0 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.16.0 + github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 - github.com/zeta-chain/ethermint v0.0.0-20240927155358-f34e2a4a86f1 + github.com/zeta-chain/ethermint v0.0.0-20241010181243-044e22bdb7e7 github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20240924201108-3a274ce7bad0 gitlab.com/thorchain/tss/go-tss v1.6.5 go.nhat.io/grpcmock v0.25.0 golang.org/x/crypto v0.23.0 - golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/net v0.25.0 golang.org/x/sync v0.7.0 - google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 - google.golang.org/grpc v1.60.1 - google.golang.org/protobuf v1.32.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 + google.golang.org/grpc v1.62.1 + google.golang.org/protobuf v1.33.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -77,15 +77,15 @@ require ( ) require ( - cloud.google.com/go v0.111.0 // indirect + cloud.google.com/go v0.112.0 // indirect cloud.google.com/go/compute v1.23.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.5 // indirect - cloud.google.com/go/storage v1.35.1 // indirect + cloud.google.com/go/storage v1.36.0 // indirect cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect - cosmossdk.io/log v1.3.1 // indirect + cosmossdk.io/log v1.4.1 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect @@ -116,7 +116,7 @@ require ( github.com/confio/ics23/go v0.9.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.4 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.1 // indirect @@ -140,9 +140,9 @@ require ( github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/edsrzf/mmap-go v1.0.0 // indirect github.com/elastic/gosigar v0.14.2 // indirect - github.com/felixge/httpsnoop v1.0.2 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect github.com/flynn/noise v1.0.0 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gagliardetto/binary v0.8.0 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect @@ -150,7 +150,7 @@ require ( github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect @@ -159,7 +159,7 @@ require ( github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang/glog v1.1.2 // indirect + github.com/golang/glog v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect @@ -202,7 +202,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -258,9 +258,9 @@ require ( github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/otiai10/primes v0.0.0-20180210170552-f6d2a1ba97c4 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect @@ -275,11 +275,10 @@ require ( github.com/sergi/go-diff v1.3.1 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/subosito/gotenv v1.4.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/swaggest/assertjson v1.9.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/btcd v0.1.1 // indirect @@ -304,9 +303,9 @@ require ( go.nhat.io/matcher/v2 v2.0.0 // indirect go.nhat.io/wait v0.1.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.19.0 // indirect + go.opentelemetry.io/otel v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/dig v1.17.0 // indirect go.uber.org/fx v1.19.2 // indirect @@ -314,17 +313,17 @@ require ( go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sys v0.20.0 // indirect + golang.org/x/oauth2 v0.16.0 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/term v0.20.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gonum.org/v1/gonum v0.13.0 // indirect - google.golang.org/api v0.152.0 // indirect + google.golang.org/api v0.155.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 // indirect + google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect lukechampine.com/blake3 v1.2.1 // indirect @@ -342,7 +341,12 @@ require ( require ( github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20220328075252-7dd334e3daae // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/snksoft/crc v1.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect ) replace ( diff --git a/go.sum b/go.sum index dd2ce7f425..14bfa8eb35 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,9 @@ cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5x cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk= cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM= cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= -cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -1057,8 +1058,8 @@ cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= -cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= -cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= +cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= @@ -1213,8 +1214,9 @@ cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vM cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= -cosmossdk.io/log v1.3.1 h1:UZx8nWIkfbbNEWusZqzAx3ZGvu54TZacWib3EzUYmGI= cosmossdk.io/log v1.3.1/go.mod h1:2/dIomt8mKdk6vl3OWJcPk2be3pGOS8OQaLUM/3/tCM= +cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= +cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= cosmossdk.io/math v1.0.0-beta.3/go.mod h1:3LYasri3Zna4XpbrTNdKsWmD5fHHkaNAod/mNT9XdE4= cosmossdk.io/math v1.0.0-beta.4/go.mod h1:An0MllWJY6PxibUpnwGk8jOm+a/qIxlKmL5Zyp9NnaM= cosmossdk.io/math v1.0.0-beta.6/go.mod h1:gUVtWwIzfSXqcOT+lBVz2jyjfua8DoBdzRsIyaUAT/8= @@ -1363,8 +1365,9 @@ github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOp github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= @@ -1695,6 +1698,8 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230428030218-4003588d1b74/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= +github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= 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/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= @@ -1733,8 +1738,9 @@ github.com/coinbase/rosetta-sdk-go v0.7.9 h1:lqllBjMnazTjIqYrOGv8h8jxjg9+hJazIGZ github.com/coinbase/rosetta-sdk-go v0.7.9/go.mod h1:0/knutI7XGVqXmmH4OQD8OckFrbQ8yMsUZTG7FXCR2M= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= github.com/cometbft/cometbft v0.34.27-alpha.1/go.mod h1:hct3hasQ2hIF3HoD7foVw4RaqTNSSeJ/lgcrVK6uDvs= -github.com/cometbft/cometbft v0.37.4 h1:xyvvEqlyfK8MgNIIKVJaMsuIp03wxOcFmVkT26+Ikpg= github.com/cometbft/cometbft v0.37.4/go.mod h1:Cmg5Hp4sNpapm7j+x0xRyt2g0juQfmB752ous+pA0G8= +github.com/cometbft/cometbft v0.37.5 h1:/U/TlgMh4NdnXNo+YU9T2NMCWyhXNDF34Mx582jlvq0= +github.com/cometbft/cometbft v0.37.5/go.mod h1:QC+mU0lBhKn8r9qvmnq53Dmf3DWBt4VtkcKw2C81wxY= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/cometbft/cometbft-db v0.12.0 h1:v77/z0VyfSU7k682IzZeZPFZrQAKiQwkqGN0QzAjMi0= github.com/cometbft/cometbft-db v0.12.0/go.mod h1:aX2NbCrjNVd2ZajYxt1BsiFf/Z+TQ2MN0VxdicheYuw= @@ -1891,12 +1897,14 @@ github.com/cosmos/cosmos-db v0.0.0-20221226095112-f3c38ecb5e32/go.mod h1:kwMlEC4 github.com/cosmos/cosmos-proto v1.0.0-alpha7/go.mod h1:dosO4pSAbJF8zWCzCoTWP7nNsjcvSUBQmniFxDg5daw= github.com/cosmos/cosmos-proto v1.0.0-alpha8/go.mod h1:6/p+Bc4O8JKeZqe0VqUGTX31eoYqemTT4C1hLCWsO7I= github.com/cosmos/cosmos-proto v1.0.0-beta.1/go.mod h1:8k2GNZghi5sDRFw/scPL8gMSowT1vDA+5ouxL8GjaUE= -github.com/cosmos/cosmos-proto v1.0.0-beta.4 h1:aEL7tU/rLOmxZQ9z4i7mzxcLbSCY48OdY7lIWTLG7oU= github.com/cosmos/cosmos-proto v1.0.0-beta.4/go.mod h1:oeB+FyVzG3XrQJbJng0EnV8Vljfk9XvTIpGILNU/9Co= +github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= +github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20221207001918-ed5124f932fd/go.mod h1:dmCp0cYz6/S5KWKJ9QzePRwWNEbcSu+jbBTRgnzPnPo= github.com/cosmos/cosmos-sdk v0.47.0-rc2.0.20230220103612-f094a0c33410/go.mod h1:SNeHakoKi9YlfhI53+ijEZZIHp90NrB1By4NgWN0KZ0= -github.com/cosmos/cosmos-sdk v0.47.10 h1:Wxf5yEN3jZbG4fftxAMKB6rpd8ME0mxuCVihpz65dt0= github.com/cosmos/cosmos-sdk v0.47.10/go.mod h1:UWpgWkhcsBIATS68uUC0del7IiBN4hPv/vqg8Zz23uw= +github.com/cosmos/cosmos-sdk v0.47.14 h1:vD9JyIdlbVaXMOE/BLamViQvylfUq0E0FpqdPVv/fWw= +github.com/cosmos/cosmos-sdk v0.47.14/go.mod h1:GrDj/zd9Tiuy8ZpG9PbUbhghCVU7lwyH0GS7CpxHpyM= github.com/cosmos/cosmos-sdk/db v1.0.0-beta.1.0.20220726092710-f848e4300a8a/go.mod h1:c8IO23vgNxueCCJlSI9awQtcxsvc+buzaeThB85qfBU= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 h1:iKclrn3YEOwk4jQHT2ulgzuXyxmzmPczUalMwW4XH9k= github.com/cosmos/cosmos-sdk/ics23/go v0.8.0/go.mod h1:2a4dBq88TUoqoWAU5eu0lGvpFP3wWDPgdHPargtyw30= @@ -1909,8 +1917,9 @@ github.com/cosmos/gogoproto v1.4.1/go.mod h1:Ac9lzL4vFpBMcptJROQ6dQ4M3pOEK5Z/l0Q github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU= github.com/cosmos/gogoproto v1.4.4/go.mod h1:/yl6/nLwsZcZ2JY3OrqjRqvqCG9InUMcXRfRjQiF9DU= -github.com/cosmos/gogoproto v1.4.10 h1:QH/yT8X+c0F4ZDacDv3z+xE3WU1P1Z3wQoLMBRJoKuI= github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= +github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= +github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cosmos/iavl v0.19.4/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/iavl v0.20.0-alpha4/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= @@ -1963,8 +1972,9 @@ github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= @@ -2108,6 +2118,8 @@ github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6Ni github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= @@ -2125,13 +2137,15 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= 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/firefart/nonamedreturns v1.0.1/go.mod h1:D3dpIBojGGNh5UfElmwPu73SwDCm+VKhHYqwlNOk2uQ= github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= @@ -2155,16 +2169,17 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2 github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +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/frumioj/crypto11 v1.2.5-0.20210823151709-946ce662cc0e h1:HRagc2sBsKLDvVVXQMaCEU8ueRFAl3txucwykhQPbGc= github.com/frumioj/crypto11 v1.2.5-0.20210823151709-946ce662cc0e/go.mod h1:/1u7qgWwAI7wja4BdNu5Vd5gqMtmtoiACHlhl46uY1E= 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.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +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/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= github.com/fzipp/gocyclo v0.5.1/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= @@ -2255,8 +2270,9 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= @@ -2381,8 +2397,9 @@ github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgR github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= +github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= +github.com/golang/glog v1.2.0/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-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -2421,8 +2438,9 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -2993,8 +3011,9 @@ github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrD github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= @@ -3555,8 +3574,8 @@ github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZO github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -3593,8 +3612,9 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ 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 v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -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/pointlander/compress v1.1.1-0.20190518213731-ff44bd196cc3/go.mod h1:q5NXNGzqj5uPnVuhGkZfmgHqNUhf15VLi6L9kW0VEc0= github.com/pointlander/jetset v1.0.1-0.20190518214125-eee7eff80bd4/go.mod h1:RdR1j20Aj5pB6+fw6Y9Ur7lMHpegTEjY1vc19hEZL40= github.com/pointlander/peg v1.0.1/go.mod h1:5hsGDQR2oZI4QoWz0/Kdg3VSVEC31iJw/b7WjqCBGRI= @@ -3735,8 +3755,9 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= -github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= +github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= @@ -3758,6 +3779,10 @@ github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43 github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sagikazarmark/crypt v0.8.0/go.mod h1:TmKwZAo97S4Fy4sfMH/HX/cQP5D+ijra2NyLpNNmttY= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +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/samber/lo v1.46.0 h1:w8G+oaCPgz1PoCJztqymCFaKwXt+5cCXn51uPxExFfQ= github.com/samber/lo v1.46.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -3845,6 +3870,8 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak= github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= @@ -3863,8 +3890,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -3880,7 +3907,6 @@ github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUq github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= 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 v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -3899,8 +3925,8 @@ github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUs github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= -github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= -github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= 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.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= @@ -3951,8 +3977,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= -github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/supranational/blst v0.3.8-0.20220526154634-513d2456b344/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= @@ -4172,8 +4198,8 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPS github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -github.com/zeta-chain/ethermint v0.0.0-20240927155358-f34e2a4a86f1 h1:o0Sh6Y2PKcG634hWqRWmWqBteSuoQUDxIR04OX9Llr8= -github.com/zeta-chain/ethermint v0.0.0-20240927155358-f34e2a4a86f1/go.mod h1:NeQEwcKBpKAUxIsii2F+jfyOD94jN/3fzPMv/1kVF9M= +github.com/zeta-chain/ethermint v0.0.0-20241010181243-044e22bdb7e7 h1:eW5aAW9Ag4GDMa7qzsQm6EWC6SENQUokHUpCdS+WSSg= +github.com/zeta-chain/ethermint v0.0.0-20241010181243-044e22bdb7e7/go.mod h1:bY9wUmkSjTJ65U7LF3e9Pc2737NqxCXGN+b/U2Rm5rU= github.com/zeta-chain/go-ethereum v1.10.26-spc h1:NvY4rR9yw52wfxWt7YoFsWbaIwVMyOtTsWKqGAXk+sE= github.com/zeta-chain/go-ethereum v1.10.26-spc/go.mod h1:/6CsT5Ceen2WPLI/oCA3xMcZ5sWMF/D46SjM/ayY0Oo= github.com/zeta-chain/go-libp2p v0.0.0-20240710192637-567fbaacc2b4 h1:FmO3HfVdZ7LzxBUfg6sVzV7ilKElQU2DZm8PxJ7KcYI= @@ -4260,17 +4286,22 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.2 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0/go.mod h1:LsankqVDx4W+RhZNA5uWarULII/MBhF5qwCYxTuyXjs= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.33.0/go.mod h1:y/SlJpJQPd2UzfBCj0E9Flk9FDCtTyqUmaCB41qFrWI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.3/go.mod h1:Dts42MGkzZne2yCru741+bFiTMWkIj/LLRizad7b9tw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.29.0/go.mod h1:vHItvsnJtp7ES++nFLLFBzUWny7fJQSvTlxFcqQGUr4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.29.0/go.mod h1:tLYsuf2v8fZreBVwp9gVMhefZlLFZaUiNVSq8QxXRII= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk= go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4= go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk= -go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/jaeger v1.4.1/go.mod h1:ZW7vkOu9nC1CxsD8bHNHCia5JUbwP39vxgd1q4Z5rCI= go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= @@ -4285,14 +4316,16 @@ go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/on go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g= go.opentelemetry.io/otel/metric v0.32.3/go.mod h1:pgiGmKohxHyTPHGOff+vrtIH39/R9fiO/WoenUQ3kcc= -go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= go.opentelemetry.io/otel/sdk v1.4.1/go.mod h1:NBwHDgDIBYjwK2WNu1OPgsIc2IJzmBXNnvIJxJc8BpE= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= @@ -4301,8 +4334,9 @@ go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+ go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc= go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U= -go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= go.opentelemetry.io/proto/otlp v0.12.0/go.mod h1:TsIjwGWIx5VFYv9KGVlOpxoBl5Dy+63SUguV7GGvlSQ= @@ -4452,8 +4486,9 @@ golang.org/x/exp v0.0.0-20221019170559-20944726eadf/go.mod h1:cyybsKvd6eL0RnXn6p golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -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/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20220613132600-b0d781184e0d/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= @@ -4672,8 +4707,8 @@ golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 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= @@ -4905,8 +4940,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.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-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -5226,8 +5261,8 @@ google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvy google.golang.org/api v0.128.0/go.mod h1:Y611qgqaE92On/7g65MQgxYul3c0rEB894kniWLY750= google.golang.org/api v0.139.0/go.mod h1:CVagp6Eekz9CjGZ718Z+sloknzkDJE7Vc1Ckj9+viBk= google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= -google.golang.org/api v0.152.0 h1:t0r1vPnfMc260S2Ci+en7kfCZaLOPs5KI0sVV/6jZrY= -google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= +google.golang.org/api v0.155.0 h1:vBmGhCYs0djJttDNynWo44zosHlPvHmA0XiN2zP2DtA= +google.golang.org/api v0.155.0/go.mod h1:GI5qK5f40kCpHfPn6+YzGAByIKWv8ujFnmoWm7Igduk= 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.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -5428,8 +5463,9 @@ google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJ google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto v0.0.0-20231120223509-83a465c0220f/go.mod h1:nWSwAFPb+qfNJXsoeO3Io7zf4tMSfN8EA8RlDA04GhY= google.golang.org/genproto v0.0.0-20231211222908-989df2bf70f3/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ= +google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= @@ -5448,8 +5484,9 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go. google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= -google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 h1:s1w3X6gQxwrLEpxnLd/qXTVLgQE2yXwaOaoa6IlY/+o= google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 h1:Lj5rbfG876hIAYFjqiJnPHfhXbv+nzTWfm04Fg/XSVU= +google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230807174057-1744710a1577/go.mod h1:NjCQG/D8JandXxM57PZbAJL1DCNL6EypA0vPPwfsc7c= google.golang.org/genproto/googleapis/bytestream v0.0.0-20231030173426-d783a09b4405/go.mod h1:GRUCuLdzVqZte8+Dl/D4N25yLzcGqqWaYkeVOwulFqw= @@ -5473,8 +5510,9 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= google.golang.org/genproto/googleapis/rpc v0.0.0-20231211222908-989df2bf70f3/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0/go.mod h1:FUoWkonphQm3RhTS+kOEhF8h0iDpm4tdXolVCeZ9KKA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4= google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 h1:AjyfHzEPEFp/NpvfN5g+KDla3EMojjhRVZc1i7cj+oM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -5539,8 +5577,9 @@ google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSs google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= +google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= 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= @@ -5565,8 +5604,9 @@ google.golang.org/protobuf v1.29.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 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= diff --git a/zetaclient/context/chain.go b/zetaclient/context/chain.go index 6d05d97371..4f35953ce0 100644 --- a/zetaclient/context/chain.go +++ b/zetaclient/context/chain.go @@ -1,6 +1,7 @@ package context import ( + "cmp" "fmt" "sync" @@ -65,7 +66,9 @@ func (cr *ChainRegistry) Get(chainID int64) (Chain, error) { func (cr *ChainRegistry) All() []Chain { items := maps.Values(cr.chains) - slices.SortFunc(items, func(a, b Chain) bool { return a.ID() < b.ID() }) + slices.SortFunc(items, func(a, b Chain) int { + return cmp.Compare(a.ID(), b.ID()) + }) return items } From 95186e0b1a03dcd07ce5ecf36a4a8d890e19d641 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Fri, 11 Oct 2024 10:37:35 +0200 Subject: [PATCH 21/36] docs: move invalid v20 breaking changes (#2986) --- docs/releases/v20_breaking_changes.md | 9 --------- docs/releases/v21_breaking_changes.md | 9 ++++++++- 2 files changed, 8 insertions(+), 10 deletions(-) delete mode 100644 docs/releases/v20_breaking_changes.md diff --git a/docs/releases/v20_breaking_changes.md b/docs/releases/v20_breaking_changes.md deleted file mode 100644 index 1519ccf8a6..0000000000 --- a/docs/releases/v20_breaking_changes.md +++ /dev/null @@ -1,9 +0,0 @@ - -# V20 Breaking Changes - -### Emissions factors deprecated - -* `EmissionsFactors` have been deprecated and removed from the `emissions` module. - - This results in the removal of the query `/zeta-chain/emissions/get_emissions_factors`. - - The fixed block reward amount can now be queried via `/zeta-chain/emissions/params`. This is constant for every block and does not depend on any factors. - diff --git a/docs/releases/v21_breaking_changes.md b/docs/releases/v21_breaking_changes.md index df82831bad..818258fdf3 100644 --- a/docs/releases/v21_breaking_changes.md +++ b/docs/releases/v21_breaking_changes.md @@ -8,4 +8,11 @@ * If the chain already exists, the details will be updated. * If the chain does not exist, it will be added to the list of chains and saved to the store. * A new transaction type `RemoveChainInfo` has also been added to remove a chain from the list of chains. - * It accepts the chain-id of the chain to be removed as a parameter. \ No newline at end of file + * It accepts the chain-id of the chain to be removed as a parameter. + +### Emissions factors deprecated + +* `EmissionsFactors` have been deprecated and removed from the `emissions` module. + - This results in the removal of the query `/zeta-chain/emissions/get_emissions_factors`. + - The fixed block reward amount can now be queried via `/zeta-chain/emissions/params`. This is constant for every block and does not depend on any factors. + From 404bd9625da63d958daa185839fc2fe5d1d93475 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Fri, 11 Oct 2024 10:19:32 -0700 Subject: [PATCH 22/36] refactor: configure solana chain during e2e setup (#2990) * refactor: configure solana chain during setup * add sol back to app_test.go --- cmd/zetae2e/local/local.go | 2 +- e2e/e2etests/test_solana_withdraw.go | 7 ++- e2e/runner/setup_solana.go | 70 +++++++++++++++++++++++++++- e2e/runner/solana.go | 4 +- x/observer/genesis.go | 3 -- x/observer/genesis_test.go | 6 --- x/observer/types/chain_params.go | 21 --------- zetaclient/context/app_test.go | 4 +- 8 files changed, 78 insertions(+), 39 deletions(-) diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 23a7f6b866..588a74e367 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -226,7 +226,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { deployerRunner.ERC20CustodyAddr = deployerRunner.ERC20CustodyV2Addr if testSolana { - deployerRunner.SetSolanaContracts(conf.AdditionalAccounts.UserSolana.SolanaPrivateKey.String()) + deployerRunner.SetupSolana(conf.AdditionalAccounts.UserSolana.SolanaPrivateKey.String()) } noError(deployerRunner.FundEmissionsPool()) diff --git a/e2e/e2etests/test_solana_withdraw.go b/e2e/e2etests/test_solana_withdraw.go index 9ff5114c34..c7f6ccc58b 100644 --- a/e2e/e2etests/test_solana_withdraw.go +++ b/e2e/e2etests/test_solana_withdraw.go @@ -13,19 +13,22 @@ import ( func TestSolanaWithdraw(r *runner.E2ERunner, args []string) { require.Len(r, args, 1) + withdrawAmount := parseBigInt(r, args[0]) + // get ERC20 SOL balance before withdraw balanceBefore, err := r.SOLZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress()) require.NoError(r, err) r.Logger.Info("runner balance of SOL before withdraw: %d", balanceBefore) + require.Equal(r, 1, balanceBefore.Cmp(withdrawAmount), "Insufficient balance for withdrawal") + // parse withdraw amount (in lamports), approve amount is 1 SOL approvedAmount := new(big.Int).SetUint64(solana.LAMPORTS_PER_SOL) - withdrawAmount := parseBigInt(r, args[0]) require.Equal( r, -1, withdrawAmount.Cmp(approvedAmount), - "Withdrawal amount must be less than the approved amount (1e9).", + "Withdrawal amount must be less than the approved amount (1e9)", ) // load deployer private key diff --git a/e2e/runner/setup_solana.go b/e2e/runner/setup_solana.go index 8f209dd23e..17bf3149dd 100644 --- a/e2e/runner/setup_solana.go +++ b/e2e/runner/setup_solana.go @@ -1,14 +1,20 @@ package runner import ( + "time" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" "github.com/near/borsh-go" + "github.com/pkg/errors" "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/e2e/utils" "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/pkg/constant" solanacontracts "github.com/zeta-chain/node/pkg/contracts/solana" + observertypes "github.com/zeta-chain/node/x/observer/types" ) // SetupSolanaAccount imports the deployer's private key @@ -20,8 +26,8 @@ func (r *E2ERunner) SetupSolanaAccount() { r.Logger.Info("SolanaDeployerAddress: %s", r.SolanaDeployerAddress) } -// SetSolanaContracts set Solana contracts -func (r *E2ERunner) SetSolanaContracts(deployerPrivateKey string) { +// SetupSolana sets Solana contracts and params +func (r *E2ERunner) SetupSolana(deployerPrivateKey string) { r.Logger.Print("⚙️ initializing gateway program on Solana") // set Solana contracts @@ -78,4 +84,64 @@ func (r *E2ERunner) SetSolanaContracts(deployerPrivateKey string) { balance, err := r.SolanaClient.GetBalance(r.Ctx, pdaComputed, rpc.CommitmentConfirmed) require.NoError(r, err) r.Logger.Info("initial PDA balance: %d lamports", balance.Value) + + err = r.ensureSolanaChainParams() + require.NoError(r, err) +} + +func (r *E2ERunner) ensureSolanaChainParams() error { + if r.ZetaTxServer == nil { + return errors.New("ZetaTxServer is not initialized") + } + + creator := r.ZetaTxServer.MustGetAccountAddressFromName(utils.OperationalPolicyName) + + chainID := chains.SolanaLocalnet.ChainId + + chainParams := &observertypes.ChainParams{ + ChainId: chainID, + ConfirmationCount: 32, + ZetaTokenContractAddress: constant.EVMZeroAddress, + ConnectorContractAddress: constant.EVMZeroAddress, + Erc20CustodyContractAddress: constant.EVMZeroAddress, + GasPriceTicker: 5, + WatchUtxoTicker: 0, + InboundTicker: 2, + OutboundTicker: 2, + OutboundScheduleInterval: 2, + OutboundScheduleLookahead: 5, + BallotThreshold: observertypes.DefaultBallotThreshold, + MinObserverDelegation: observertypes.DefaultMinObserverDelegation, + IsSupported: true, + GatewayAddress: solanacontracts.SolanaGatewayProgramID, + } + + updateMsg := observertypes.NewMsgUpdateChainParams(creator, chainParams) + + if _, err := r.ZetaTxServer.BroadcastTx(utils.OperationalPolicyName, updateMsg); err != nil { + return errors.Wrap(err, "unable to broadcast solana chain params tx") + } + + resetMsg := observertypes.NewMsgResetChainNonces(creator, chainID, 0, 0) + if _, err := r.ZetaTxServer.BroadcastTx(utils.OperationalPolicyName, resetMsg); err != nil { + return errors.Wrap(err, "unable to broadcast solana chain nonce reset tx") + } + + r.Logger.Print("⚙️ voted for adding solana chain params (localnet). Waiting for confirmation") + + query := &observertypes.QueryGetChainParamsForChainRequest{ChainId: chainID} + + const duration = 2 * time.Second + + for i := 0; i < 10; i++ { + _, err := r.ObserverClient.GetChainParamsForChain(r.Ctx, query) + if err == nil { + r.Logger.Print("⚙️ solana chain params are set") + return nil + } + + time.Sleep(duration) + } + + return errors.New("unable to set Solana chain params") } diff --git a/e2e/runner/solana.go b/e2e/runner/solana.go index 8ff67b9d72..4d5e6a9b9d 100644 --- a/e2e/runner/solana.go +++ b/e2e/runner/solana.go @@ -153,7 +153,7 @@ func (r *E2ERunner) WithdrawSOLZRC20( tx, err := r.SOLZRC20.Approve(r.ZEVMAuth, r.SOLZRC20Addr, approveAmount) require.NoError(r, err) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - utils.RequireTxSuccessful(r, receipt) + utils.RequireTxSuccessful(r, receipt, "approve") // withdraw tx, err = r.SOLZRC20.Withdraw(r.ZEVMAuth, []byte(to.String()), amount) @@ -162,7 +162,7 @@ func (r *E2ERunner) WithdrawSOLZRC20( // wait for tx receipt receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - utils.RequireTxSuccessful(r, receipt) + utils.RequireTxSuccessful(r, receipt, "withdraw") r.Logger.Info("Receipt txhash %s status %d", receipt.TxHash, receipt.Status) // wait for the cctx to be mined diff --git a/x/observer/genesis.go b/x/observer/genesis.go index 46ed737b6f..12a92887c2 100644 --- a/x/observer/genesis.go +++ b/x/observer/genesis.go @@ -26,15 +26,12 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) btcChainParams.IsSupported = true goerliChainParams := types.GetDefaultGoerliLocalnetChainParams() goerliChainParams.IsSupported = true - solanaChainParams := types.GetDefaultSolanaLocalnetChainParams() - solanaChainParams.IsSupported = true zetaPrivnetChainParams := types.GetDefaultZetaPrivnetChainParams() zetaPrivnetChainParams.IsSupported = true k.SetChainParamsList(ctx, types.ChainParamsList{ ChainParams: []*types.ChainParams{ btcChainParams, goerliChainParams, - solanaChainParams, zetaPrivnetChainParams, }, }) diff --git a/x/observer/genesis_test.go b/x/observer/genesis_test.go index 096dc0db43..13f9a54008 100644 --- a/x/observer/genesis_test.go +++ b/x/observer/genesis_test.go @@ -68,15 +68,12 @@ func TestGenesis(t *testing.T) { btcChainParams.IsSupported = true goerliChainParams := types.GetDefaultGoerliLocalnetChainParams() goerliChainParams.IsSupported = true - solanaChainParams := types.GetDefaultSolanaLocalnetChainParams() - solanaChainParams.IsSupported = true zetaPrivnetChainParams := types.GetDefaultZetaPrivnetChainParams() zetaPrivnetChainParams.IsSupported = true localnetChainParams := types.ChainParamsList{ ChainParams: []*types.ChainParams{ btcChainParams, goerliChainParams, - solanaChainParams, zetaPrivnetChainParams, }, } @@ -107,15 +104,12 @@ func TestGenesis(t *testing.T) { btcChainParams.IsSupported = true goerliChainParams := types.GetDefaultGoerliLocalnetChainParams() goerliChainParams.IsSupported = true - solanaChainParams := types.GetDefaultSolanaLocalnetChainParams() - solanaChainParams.IsSupported = true zetaPrivnetChainParams := types.GetDefaultZetaPrivnetChainParams() zetaPrivnetChainParams.IsSupported = true localnetChainParams := types.ChainParamsList{ ChainParams: []*types.ChainParams{ btcChainParams, goerliChainParams, - solanaChainParams, zetaPrivnetChainParams, }, } diff --git a/x/observer/types/chain_params.go b/x/observer/types/chain_params.go index d9d1cc2294..b1a5335e58 100644 --- a/x/observer/types/chain_params.go +++ b/x/observer/types/chain_params.go @@ -11,7 +11,6 @@ import ( "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/constant" - solanacontracts "github.com/zeta-chain/node/pkg/contracts/solana" ) var ( @@ -148,7 +147,6 @@ func GetDefaultChainParams() ChainParamsList { GetDefaultMumbaiTestnetChainParams(), GetDefaultBtcTestnetChainParams(), GetDefaultBtcRegtestChainParams(), - GetDefaultSolanaLocalnetChainParams(), GetDefaultGoerliLocalnetChainParams(), }, } @@ -299,25 +297,6 @@ func GetDefaultBtcRegtestChainParams() *ChainParams { IsSupported: false, } } -func GetDefaultSolanaLocalnetChainParams() *ChainParams { - return &ChainParams{ - ChainId: chains.SolanaLocalnet.ChainId, - ConfirmationCount: 32, - ZetaTokenContractAddress: constant.EVMZeroAddress, - ConnectorContractAddress: constant.EVMZeroAddress, - Erc20CustodyContractAddress: constant.EVMZeroAddress, - GasPriceTicker: 5, - WatchUtxoTicker: 0, - InboundTicker: 2, - OutboundTicker: 2, - OutboundScheduleInterval: 2, - OutboundScheduleLookahead: 5, - BallotThreshold: DefaultBallotThreshold, - MinObserverDelegation: DefaultMinObserverDelegation, - IsSupported: false, - GatewayAddress: solanacontracts.SolanaGatewayProgramID, - } -} func GetDefaultGoerliLocalnetChainParams() *ChainParams { return &ChainParams{ ChainId: chains.GoerliLocalnet.ChainId, diff --git a/zetaclient/context/app_test.go b/zetaclient/context/app_test.go index 7439aebc44..2297a3cdec 100644 --- a/zetaclient/context/app_test.go +++ b/zetaclient/context/app_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/testutil/sample" "github.com/zeta-chain/node/x/observer/types" "github.com/zeta-chain/node/zetaclient/config" "golang.org/x/exp/maps" @@ -38,8 +39,7 @@ func TestAppContext(t *testing.T) { btcParams := types.GetDefaultBtcMainnetChainParams() btcParams.IsSupported = true - solParams := types.GetDefaultSolanaLocalnetChainParams() - solParams.IsSupported = true + solParams := sample.ChainParamsSupported(chains.SolanaLocalnet.ChainId) fancyL2 := chains.Chain{ ChainId: 123, From cb9f34854b1effa2da165837e94bbe0aff716af9 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Mon, 14 Oct 2024 10:02:48 +0200 Subject: [PATCH 23/36] fix(emissions): add nil checks for reward distributions (#2999) * add nil check in beginBlocker * add nil check in params * variable renaming * fix imports * fix test --- app/app.go | 2 +- testutil/keeper/keeper.go | 2 +- x/emissions/abci.go | 29 ++- x/emissions/abci_test.go | 235 ++++++++++++------ x/emissions/keeper/params_test.go | 6 +- x/emissions/module.go | 2 +- x/emissions/types/keys.go | 4 +- .../types/message_update_params_test.go | 2 +- x/emissions/types/params.go | 22 +- x/emissions/types/params_test.go | 4 +- 10 files changed, 209 insertions(+), 99 deletions(-) diff --git a/app/app.go b/app/app.go index 4fe5595199..897cf305fe 100644 --- a/app/app.go +++ b/app/app.go @@ -224,7 +224,7 @@ var ( fungibletypes.ModuleName: {authtypes.Minter, authtypes.Burner}, emissionstypes.ModuleName: nil, emissionstypes.UndistributedObserverRewardsPool: nil, - emissionstypes.UndistributedTssRewardsPool: nil, + emissionstypes.UndistributedTSSRewardsPool: nil, } // module accounts that are NOT allowed to receive tokens diff --git a/testutil/keeper/keeper.go b/testutil/keeper/keeper.go index 0582c4232f..ed3a107dac 100644 --- a/testutil/keeper/keeper.go +++ b/testutil/keeper/keeper.go @@ -136,7 +136,7 @@ var moduleAccountPerms = map[string][]string{ fungibletypes.ModuleName: {authtypes.Minter, authtypes.Burner}, emissionstypes.ModuleName: {authtypes.Minter}, emissionstypes.UndistributedObserverRewardsPool: nil, - emissionstypes.UndistributedTssRewardsPool: nil, + emissionstypes.UndistributedTSSRewardsPool: nil, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, ibccrosschaintypes.ModuleName: nil, } diff --git a/x/emissions/abci.go b/x/emissions/abci.go index b4b75562ff..c1924ff2e2 100644 --- a/x/emissions/abci.go +++ b/x/emissions/abci.go @@ -15,6 +15,15 @@ import ( func BeginBlocker(ctx sdk.Context, keeper keeper.Keeper) { emissionPoolBalance := keeper.GetReservesFactor(ctx) + // reduce frequency of log messages + logEach10Blocks := func(message string) { + if ctx.BlockHeight()%10 == 0 { + ctx.Logger().Info(message) + } else { + ctx.Logger().Debug(message) + } + } + // Get the block rewards from the params params, found := keeper.GetParams(ctx) if !found { @@ -22,9 +31,17 @@ func BeginBlocker(ctx sdk.Context, keeper keeper.Keeper) { return } blockRewards := params.BlockRewardAmount + + // skip if block rewards are nil or not positive + if blockRewards.IsNil() || !blockRewards.IsPositive() { + logEach10Blocks("Block rewards are nil or not positive") + return + } + if blockRewards.GT(emissionPoolBalance) { - ctx.Logger(). - Info(fmt.Sprintf("Block rewards %s are greater than emission pool balance %s", blockRewards.String(), emissionPoolBalance.String())) + logEach10Blocks(fmt.Sprintf("Block rewards %s are greater than emission pool balance %s", + blockRewards.String(), emissionPoolBalance.String()), + ) return } @@ -44,7 +61,7 @@ func BeginBlocker(ctx sdk.Context, keeper keeper.Keeper) { ctx.Logger().Error(fmt.Sprintf("Error while distributing observer rewards %s", err)) return } - err = DistributeTssRewards(tmpCtx, tssSignerRewards, keeper.GetBankKeeper()) + err = DistributeTSSRewards(tmpCtx, tssSignerRewards, keeper.GetBankKeeper()) if err != nil { ctx.Logger().Error(fmt.Sprintf("Error while distributing tss signer rewards %s", err)) return @@ -166,9 +183,9 @@ func DistributeObserverRewards( return nil } -// DistributeTssRewards trasferes the allocated rewards to the Undistributed Tss Rewards Pool. +// DistributeTSSRewards trasferes the allocated rewards to the Undistributed Tss Rewards Pool. // This is done so that the reserves factor is properly calculated in the next block -func DistributeTssRewards(ctx sdk.Context, amount sdk.Int, bankKeeper types.BankKeeper) error { +func DistributeTSSRewards(ctx sdk.Context, amount sdk.Int, bankKeeper types.BankKeeper) error { coin := sdk.NewCoins(sdk.NewCoin(config.BaseDenom, amount)) - return bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, types.UndistributedTssRewardsPool, coin) + return bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, types.UndistributedTSSRewardsPool, coin) } diff --git a/x/emissions/abci_test.go b/x/emissions/abci_test.go index 26420231fd..681a8b1247 100644 --- a/x/emissions/abci_test.go +++ b/x/emissions/abci_test.go @@ -13,9 +13,10 @@ import ( "github.com/zeta-chain/node/pkg/sdkconfig" keepertest "github.com/zeta-chain/node/testutil/keeper" "github.com/zeta-chain/node/testutil/sample" - emissionsModule "github.com/zeta-chain/node/x/emissions" + "github.com/zeta-chain/node/x/emissions" + emissionskeeper "github.com/zeta-chain/node/x/emissions/keeper" emissionstypes "github.com/zeta-chain/node/x/emissions/types" - observerTypes "github.com/zeta-chain/node/x/observer/types" + observertypes "github.com/zeta-chain/node/x/observer/types" ) func TestBeginBlocker(t *testing.T) { @@ -35,14 +36,14 @@ func TestBeginBlocker(t *testing.T) { zk.ObserverKeeper.SetBallot(ctx, &ballot) ballotIdentifiers = append(ballotIdentifiers, ballot.BallotIdentifier) } - zk.ObserverKeeper.SetBallotList(ctx, &observerTypes.BallotListForHeight{ + zk.ObserverKeeper.SetBallotList(ctx, &observertypes.BallotListForHeight{ Height: 0, BallotsIndexList: ballotIdentifiers, }) //Act for i := 0; i < 100; i++ { - emissionsModule.BeginBlocker(ctx, *k) + emissions.BeginBlocker(ctx, *k) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) } @@ -64,12 +65,12 @@ func TestBeginBlocker(t *testing.T) { zk.ObserverKeeper.SetBallot(ctx, &ballot) ballotIdentifiers = append(ballotIdentifiers, ballot.BallotIdentifier) } - zk.ObserverKeeper.SetBallotList(ctx, &observerTypes.BallotListForHeight{ + zk.ObserverKeeper.SetBallotList(ctx, &observertypes.BallotListForHeight{ Height: 0, BallotsIndexList: ballotIdentifiers, }) for i := 0; i < 100; i++ { - emissionsModule.BeginBlocker(ctx, *k) + emissions.BeginBlocker(ctx, *k) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) } for _, observer := range observerSet.ObserverList { @@ -82,7 +83,7 @@ func TestBeginBlocker(t *testing.T) { k, ctx, sk, _ := keepertest.EmissionsKeeper(t) feeCollectorAddress := sk.AuthKeeper.GetModuleAccount(ctx, types.FeeCollectorName).GetAddress() for i := 0; i < 100; i++ { - emissionsModule.BeginBlocker(ctx, *k) + emissions.BeginBlocker(ctx, *k) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) } require.True(t, sk.BankKeeper.GetBalance(ctx, feeCollectorAddress, config.BaseDenom).Amount.IsZero()) @@ -99,13 +100,13 @@ func TestBeginBlocker(t *testing.T) { ) require.NoError(t, err) // Setup module accounts for emission pools except for observer pool , so that the observer distribution fails - _ = sk.AuthKeeper.GetModuleAccount(ctx, emissionstypes.UndistributedTssRewardsPool).GetAddress() + _ = sk.AuthKeeper.GetModuleAccount(ctx, emissionstypes.UndistributedTSSRewardsPool).GetAddress() feeCollectorAddress := sk.AuthKeeper.GetModuleAccount(ctx, types.FeeCollectorName).GetAddress() _ = sk.AuthKeeper.GetModuleAccount(ctx, emissionstypes.ModuleName).GetAddress() for i := 0; i < 100; i++ { // produce a block - emissionsModule.BeginBlocker(ctx, *k) + emissions.BeginBlocker(ctx, *k) ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) } require.True(t, sk.BankKeeper.GetBalance(ctx, feeCollectorAddress, config.BaseDenom).Amount.IsZero()) @@ -138,7 +139,7 @@ func TestBeginBlocker(t *testing.T) { bankMock.On("SendCoinsFromModuleToModule", mock.Anything, emissionstypes.ModuleName, k.GetFeeCollector(), mock.Anything). Return(emissionstypes.ErrUnableToWithdrawEmissions).Once() - emissionsModule.BeginBlocker(ctx, *k) + emissions.BeginBlocker(ctx, *k) bankMock.AssertNumberOfCalls(t, "SendCoinsFromModuleToModule", 1) }) @@ -165,7 +166,7 @@ func TestBeginBlocker(t *testing.T) { bankMock.On("SendCoinsFromModuleToModule", mock.Anything, emissionstypes.ModuleName, emissionstypes.UndistributedObserverRewardsPool, mock.Anything). Return(emissionstypes.ErrUnableToWithdrawEmissions).Once() - emissionsModule.BeginBlocker(ctx, *k) + emissions.BeginBlocker(ctx, *k) bankMock.AssertNumberOfCalls(t, "SendCoinsFromModuleToModule", 2) }) @@ -196,9 +197,9 @@ func TestBeginBlocker(t *testing.T) { // fail third distribution bankMock.On("SendCoinsFromModuleToModule", - mock.Anything, emissionstypes.ModuleName, emissionstypes.UndistributedTssRewardsPool, mock.Anything). + mock.Anything, emissionstypes.ModuleName, emissionstypes.UndistributedTSSRewardsPool, mock.Anything). Return(emissionstypes.ErrUnableToWithdrawEmissions).Once() - emissionsModule.BeginBlocker(ctx, *k) + emissions.BeginBlocker(ctx, *k) bankMock.AssertNumberOfCalls(t, "SendCoinsFromModuleToModule", 3) }) @@ -216,7 +217,7 @@ func TestBeginBlocker(t *testing.T) { zk.ObserverKeeper.SetBallot(ctx, &ballot) ballotIdentifiers = append(ballotIdentifiers, ballot.BallotIdentifier) } - zk.ObserverKeeper.SetBallotList(ctx, &observerTypes.BallotListForHeight{ + zk.ObserverKeeper.SetBallotList(ctx, &observertypes.BallotListForHeight{ Height: 0, BallotsIndexList: ballotIdentifiers, }) @@ -232,7 +233,7 @@ func TestBeginBlocker(t *testing.T) { // Setup module accounts for emission pools undistributedObserverPoolAddress := sk.AuthKeeper.GetModuleAccount(ctx, emissionstypes.UndistributedObserverRewardsPool). GetAddress() - undistributedTssPoolAddress := sk.AuthKeeper.GetModuleAccount(ctx, emissionstypes.UndistributedTssRewardsPool). + undistributedTssPoolAddress := sk.AuthKeeper.GetModuleAccount(ctx, emissionstypes.UndistributedTSSRewardsPool). GetAddress() feeCollecterAddress := sk.AuthKeeper.GetModuleAccount(ctx, types.FeeCollectorName).GetAddress() emissionPool := sk.AuthKeeper.GetModuleAccount(ctx, emissionstypes.ModuleName).GetAddress() @@ -251,7 +252,7 @@ func TestBeginBlocker(t *testing.T) { for i := 0; i < numberOfTestBlocks; i++ { emissionPoolBeforeBlockDistribution := sk.BankKeeper.GetBalance(ctx, emissionPool, config.BaseDenom).Amount // produce a block - emissionsModule.BeginBlocker(ctx, *k) + emissions.BeginBlocker(ctx, *k) // require distribution amount emissionPoolBalanceAfterBlockDistribution := sk.BankKeeper.GetBalance( @@ -313,27 +314,29 @@ func TestBeginBlocker(t *testing.T) { func TestDistributeObserverRewards(t *testing.T) { sdkconfig.SetDefault(false) - k, ctx, _, _ := keepertest.EmissionsKeeper(t) observerSet := sample.ObserverSet(4) tt := []struct { - name string - votes [][]observerTypes.VoteType - totalRewardsForBlock sdkmath.Int - expectedRewards map[string]int64 - ballotStatus observerTypes.BallotStatus - slashAmount sdkmath.Int + name string + votes [][]observertypes.VoteType + observerStartingEmissions sdkmath.Int + totalRewardsForBlock sdkmath.Int + expectedRewards map[string]int64 + ballotStatus observertypes.BallotStatus + slashAmount sdkmath.Int + rewardsPerBlock sdkmath.LegacyDec }{ { name: "all observers rewarded correctly", - votes: [][]observerTypes.VoteType{ + votes: [][]observertypes.VoteType{ { - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, }, }, + observerStartingEmissions: sdkmath.NewInt(100), // total reward units would be 4 as all votes match the ballot status totalRewardsForBlock: sdkmath.NewInt(100), expectedRewards: map[string]int64{ @@ -342,19 +345,21 @@ func TestDistributeObserverRewards(t *testing.T) { observerSet.ObserverList[2]: 125, observerSet.ObserverList[3]: 125, }, - ballotStatus: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - slashAmount: sdkmath.NewInt(25), + ballotStatus: observertypes.BallotStatus_BallotFinalized_SuccessObservation, + slashAmount: sdkmath.NewInt(25), + rewardsPerBlock: emissionstypes.BlockReward, }, { name: "one observer slashed", - votes: [][]observerTypes.VoteType{ + votes: [][]observertypes.VoteType{ { - observerTypes.VoteType_FailureObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, + observertypes.VoteType_FailureObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, }, }, + observerStartingEmissions: sdkmath.NewInt(100), // total reward units would be 3 as 3 votes match the ballot status totalRewardsForBlock: sdkmath.NewInt(75), expectedRewards: map[string]int64{ @@ -363,19 +368,21 @@ func TestDistributeObserverRewards(t *testing.T) { observerSet.ObserverList[2]: 125, observerSet.ObserverList[3]: 125, }, - ballotStatus: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - slashAmount: sdkmath.NewInt(25), + ballotStatus: observertypes.BallotStatus_BallotFinalized_SuccessObservation, + slashAmount: sdkmath.NewInt(25), + rewardsPerBlock: emissionstypes.BlockReward, }, { name: "all observer slashed", - votes: [][]observerTypes.VoteType{ + votes: [][]observertypes.VoteType{ { - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, }, }, + observerStartingEmissions: sdkmath.NewInt(100), // total reward units would be 0 as no votes match the ballot status totalRewardsForBlock: sdkmath.NewInt(100), expectedRewards: map[string]int64{ @@ -384,19 +391,21 @@ func TestDistributeObserverRewards(t *testing.T) { observerSet.ObserverList[2]: 75, observerSet.ObserverList[3]: 75, }, - ballotStatus: observerTypes.BallotStatus_BallotFinalized_FailureObservation, - slashAmount: sdkmath.NewInt(25), + ballotStatus: observertypes.BallotStatus_BallotFinalized_FailureObservation, + slashAmount: sdkmath.NewInt(25), + rewardsPerBlock: emissionstypes.BlockReward, }, { name: "slashed to zero if slash amount is greater than available emissions", - votes: [][]observerTypes.VoteType{ + votes: [][]observertypes.VoteType{ { - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, }, }, + observerStartingEmissions: sdkmath.NewInt(100), // total reward units would be 0 as no votes match the ballot status totalRewardsForBlock: sdkmath.NewInt(100), expectedRewards: map[string]int64{ @@ -405,25 +414,27 @@ func TestDistributeObserverRewards(t *testing.T) { observerSet.ObserverList[2]: 0, observerSet.ObserverList[3]: 0, }, - ballotStatus: observerTypes.BallotStatus_BallotFinalized_FailureObservation, - slashAmount: sdkmath.NewInt(2500), + ballotStatus: observertypes.BallotStatus_BallotFinalized_FailureObservation, + slashAmount: sdkmath.NewInt(2500), + rewardsPerBlock: emissionstypes.BlockReward, }, { name: "withdraw able emissions unchanged if rewards and slashes are equal", - votes: [][]observerTypes.VoteType{ + votes: [][]observertypes.VoteType{ { - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, }, { - observerTypes.VoteType_FailureObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, - observerTypes.VoteType_SuccessObservation, + observertypes.VoteType_FailureObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, }, }, + observerStartingEmissions: sdkmath.NewInt(100), // total reward units would be 7 as 7 votes match the ballot status, including both ballots totalRewardsForBlock: sdkmath.NewInt(70), expectedRewards: map[string]int64{ @@ -432,19 +443,82 @@ func TestDistributeObserverRewards(t *testing.T) { observerSet.ObserverList[2]: 120, observerSet.ObserverList[3]: 120, }, - ballotStatus: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, + ballotStatus: observertypes.BallotStatus_BallotFinalized_SuccessObservation, + slashAmount: sdkmath.NewInt(25), + rewardsPerBlock: emissionstypes.BlockReward, + }, + { + name: "no rewards if block reward is nil", + votes: [][]observertypes.VoteType{ + { + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + }, + }, + observerStartingEmissions: sdkmath.NewInt(0), + // total reward units would be 4 as all votes match the ballot status + totalRewardsForBlock: sdkmath.NewInt(0), + expectedRewards: map[string]int64{ + observerSet.ObserverList[0]: 0, + observerSet.ObserverList[1]: 0, + observerSet.ObserverList[2]: 0, + observerSet.ObserverList[3]: 0, + }, + ballotStatus: observertypes.BallotStatus_BallotFinalized_SuccessObservation, slashAmount: sdkmath.NewInt(25), + //rewardsPerBlock: nil, + }, + { + name: "no rewards if block reward is negative", + votes: [][]observertypes.VoteType{ + { + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + }, + }, + observerStartingEmissions: sdkmath.NewInt(0), + // total reward units would be 4 as all votes match the ballot status + totalRewardsForBlock: sdkmath.NewInt(0), + expectedRewards: map[string]int64{ + observerSet.ObserverList[0]: 0, + observerSet.ObserverList[1]: 0, + observerSet.ObserverList[2]: 0, + observerSet.ObserverList[3]: 0, + }, + ballotStatus: observertypes.BallotStatus_BallotFinalized_SuccessObservation, + slashAmount: sdkmath.NewInt(25), + rewardsPerBlock: sdk.NewDec(1).NegMut(), + }, + { + name: "no rewards if block reward is zero", + votes: [][]observertypes.VoteType{ + { + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + observertypes.VoteType_SuccessObservation, + }, + }, + observerStartingEmissions: sdkmath.NewInt(0), + // total reward units would be 4 as all votes match the ballot status + totalRewardsForBlock: sdkmath.NewInt(0), + expectedRewards: map[string]int64{ + observerSet.ObserverList[0]: 0, + observerSet.ObserverList[1]: 0, + observerSet.ObserverList[2]: 0, + observerSet.ObserverList[3]: 0, + }, + ballotStatus: observertypes.BallotStatus_BallotFinalized_SuccessObservation, + slashAmount: sdkmath.NewInt(25), + rewardsPerBlock: sdk.ZeroDec(), }, } for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { - for _, observer := range observerSet.ObserverList { - k.SetWithdrawableEmission(ctx, emissionstypes.WithdrawableEmissions{ - Address: observer, - Amount: sdkmath.NewInt(100), - }) - } - // Keeper initialization k, ctx, sk, zk := keepertest.EmissionsKeeper(t) zk.ObserverKeeper.SetObserverSet(ctx, observerSet) @@ -457,24 +531,24 @@ func TestDistributeObserverRewards(t *testing.T) { err := sk.BankKeeper.MintCoins(ctx, emissionstypes.ModuleName, totalRewardCoins) require.NoError(t, err) - // Set starting emission for all observers to 100 so that we can calculate the rewards and slashes + // Set starting emission for all observers to a specified value so that we can calculate the rewards and slashes for _, observer := range observerSet.ObserverList { k.SetWithdrawableEmission(ctx, emissionstypes.WithdrawableEmissions{ Address: observer, - Amount: sdkmath.NewInt(100), + Amount: tc.observerStartingEmissions, }) } // Set the params params := emissionstypes.DefaultParams() params.ObserverSlashAmount = tc.slashAmount - err = k.SetParams(ctx, params) - require.NoError(t, err) + params.BlockRewardAmount = tc.rewardsPerBlock + setEmissionsParams(t, ctx, *k, params) // Set the ballot list ballotIdentifiers := []string{} for i, votes := range tc.votes { - ballot := observerTypes.Ballot{ + ballot := observertypes.Ballot{ BallotIdentifier: "ballot" + string(rune(i)), BallotStatus: tc.ballotStatus, VoterList: observerSet.ObserverList, @@ -483,14 +557,14 @@ func TestDistributeObserverRewards(t *testing.T) { zk.ObserverKeeper.SetBallot(ctx, &ballot) ballotIdentifiers = append(ballotIdentifiers, ballot.BallotIdentifier) } - zk.ObserverKeeper.SetBallotList(ctx, &observerTypes.BallotListForHeight{ + zk.ObserverKeeper.SetBallotList(ctx, &observertypes.BallotListForHeight{ Height: 0, BallotsIndexList: ballotIdentifiers, }) ctx = ctx.WithBlockHeight(100) // Distribute the rewards and check if the rewards are distributed correctly - err = emissionsModule.DistributeObserverRewards(ctx, tc.totalRewardsForBlock, *k, params) + err = emissions.DistributeObserverRewards(ctx, tc.totalRewardsForBlock, *k, params) require.NoError(t, err) for i, observer := range observerSet.ObserverList { @@ -507,3 +581,14 @@ func TestDistributeObserverRewards(t *testing.T) { }) } } + +// setEmissionsParams sets the emissions params in the store without validation +func setEmissionsParams(t *testing.T, ctx sdk.Context, k emissionskeeper.Keeper, params emissionstypes.Params) { + store := ctx.KVStore(k.GetStoreKey()) + bz, err := k.GetCodec().Marshal(¶ms) + if err != nil { + require.NoError(t, err) + } + + store.Set(emissionstypes.KeyPrefix(emissionstypes.ParamsKey), bz) +} diff --git a/x/emissions/keeper/params_test.go b/x/emissions/keeper/params_test.go index 72c752c3ad..41800829fe 100644 --- a/x/emissions/keeper/params_test.go +++ b/x/emissions/keeper/params_test.go @@ -38,7 +38,7 @@ func TestKeeper_GetParams(t *testing.T) { BallotMaturityBlocks: int64(emissionstypes.BallotMaturityBlocks), BlockRewardAmount: emissionstypes.BlockReward, }, - constainsErr: "slash amount cannot be less than 0", + constainsErr: "slash amount must not be negative", }, { name: "validator emission percentage too high", @@ -122,7 +122,7 @@ func TestKeeper_GetParams(t *testing.T) { BallotMaturityBlocks: -100, BlockRewardAmount: emissionstypes.BlockReward, }, - constainsErr: "ballot maturity types must be gte 0", + constainsErr: "ballot maturity types must not be negative", }, { name: "block reward amount too low", @@ -134,7 +134,7 @@ func TestKeeper_GetParams(t *testing.T) { BallotMaturityBlocks: int64(emissionstypes.BallotMaturityBlocks), BlockRewardAmount: sdkmath.LegacyMustNewDecFromStr("-10.00"), }, - constainsErr: "block reward amount cannot be less than 0", + constainsErr: "block reward amount must not be negative", }, } for _, tt := range tests { diff --git a/x/emissions/module.go b/x/emissions/module.go index 08676efb54..b445cf3d44 100644 --- a/x/emissions/module.go +++ b/x/emissions/module.go @@ -150,7 +150,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.Ra InitGenesis(ctx, am.keeper, genState) am.keeper.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) - am.keeper.GetAuthKeeper().GetModuleAccount(ctx, types.UndistributedTssRewardsPool) + am.keeper.GetAuthKeeper().GetModuleAccount(ctx, types.UndistributedTSSRewardsPool) am.keeper.GetAuthKeeper().GetModuleAccount(ctx, types.UndistributedObserverRewardsPool) return []abci.ValidatorUpdate{} diff --git a/x/emissions/types/keys.go b/x/emissions/types/keys.go index 0c71be1284..b800b1a529 100644 --- a/x/emissions/types/keys.go +++ b/x/emissions/types/keys.go @@ -10,7 +10,7 @@ const ( // ModuleName defines the module name ModuleName = "emissions" UndistributedObserverRewardsPool = ModuleName + "Observers" - UndistributedTssRewardsPool = ModuleName + "Tss" + UndistributedTSSRewardsPool = ModuleName + "Tss" // StoreKey defines the primary module store key StoreKey = ModuleName @@ -42,7 +42,7 @@ const ( var ( EmissionsModuleAddress = authtypes.NewModuleAddress(ModuleName) UndistributedObserverRewardsPoolAddress = authtypes.NewModuleAddress(UndistributedObserverRewardsPool) - UndistributedTssRewardsPoolAddress = authtypes.NewModuleAddress(UndistributedTssRewardsPool) + UndistributedTssRewardsPoolAddress = authtypes.NewModuleAddress(UndistributedTSSRewardsPool) // BlockReward is an initial block reward amount when emissions module was initialized. // The current value can be obtained from by querying the params BlockReward = sdk.MustNewDecFromStr("9620949074074074074.074070733466756687") diff --git a/x/emissions/types/message_update_params_test.go b/x/emissions/types/message_update_params_test.go index cf02f19000..c5722a19f2 100644 --- a/x/emissions/types/message_update_params_test.go +++ b/x/emissions/types/message_update_params_test.go @@ -29,7 +29,7 @@ func TestMsgUpdateParams_ValidateBasic(t *testing.T) { Params: params, } err := msg.ValidateBasic() - require.ErrorContains(t, err, "block reward amount cannot be less than 0") + require.ErrorContains(t, err, "block reward amount must not be negative") }) t.Run("valid", func(t *testing.T) { diff --git a/x/emissions/types/params.go b/x/emissions/types/params.go index 715c615b9d..582de6ffd4 100644 --- a/x/emissions/types/params.go +++ b/x/emissions/types/params.go @@ -63,7 +63,7 @@ func validateValidatorEmissionPercentage(i interface{}) error { if dec.GT(sdk.OneDec()) { return fmt.Errorf("validator emission percentage cannot be more than 100 percent") } - if dec.LT(sdk.ZeroDec()) { + if dec.IsNegative() { return fmt.Errorf("validator emission percentage cannot be less than 0 percent") } return nil @@ -78,7 +78,7 @@ func validateObserverEmissionPercentage(i interface{}) error { if dec.GT(sdk.OneDec()) { return fmt.Errorf("observer emission percentage cannot be more than 100 percent") } - if dec.LT(sdk.ZeroDec()) { + if dec.IsNegative() { return fmt.Errorf("observer emission percentage cannot be less than 0 percent") } return nil @@ -93,7 +93,7 @@ func validateTssEmissionPercentage(i interface{}) error { if dec.GT(sdk.OneDec()) { return fmt.Errorf("tss emission percentage cannot be more than 100 percent") } - if dec.LT(sdk.ZeroDec()) { + if dec.IsNegative() { return fmt.Errorf("tss emission percentage cannot be less than 0 percent") } return nil @@ -104,8 +104,11 @@ func validateObserverSlashAmount(i interface{}) error { if !ok { return fmt.Errorf("invalid parameter type: %T", i) } - if v.LT(sdk.ZeroInt()) { - return fmt.Errorf("slash amount cannot be less than 0") + if v.IsNil() { + return fmt.Errorf("observer slash amount cannot be nil") + } + if v.IsNegative() { + return fmt.Errorf("slash amount must not be negative") } return nil } @@ -117,7 +120,7 @@ func validateBallotMaturityBlocks(i interface{}) error { } if v < 0 { - return fmt.Errorf("ballot maturity types must be gte 0") + return fmt.Errorf("ballot maturity types must not be negative") } return nil @@ -128,8 +131,11 @@ func validateBlockRewardsAmount(i interface{}) error { if !ok { return fmt.Errorf("invalid parameter type: %T", i) } - if v.LT(sdkmath.LegacyZeroDec()) { - return fmt.Errorf("block reward amount cannot be less than 0") + if v.IsNil() { + return fmt.Errorf("block reward amount cannot be nil") + } + if v.IsNegative() { + return fmt.Errorf("block reward amount must not be negative") } return nil } diff --git a/x/emissions/types/params_test.go b/x/emissions/types/params_test.go index 6a8e90a98b..5facd08f9f 100644 --- a/x/emissions/types/params_test.go +++ b/x/emissions/types/params_test.go @@ -56,6 +56,7 @@ func TestValidateObserverSlashAmount(t *testing.T) { require.Error(t, validateObserverSlashAmount(10)) require.Error(t, validateObserverSlashAmount("10")) require.Error(t, validateObserverSlashAmount(sdkmath.NewInt(-10))) // Less than 0 + require.Error(t, validateObserverSlashAmount(nil)) require.NoError(t, validateObserverSlashAmount(sdkmath.NewInt(10))) } @@ -69,6 +70,7 @@ func TestValidateBlockRewardAmount(t *testing.T) { require.Error(t, validateBlockRewardsAmount("0.50")) require.Error(t, validateBlockRewardsAmount("-0.50")) require.Error(t, validateBlockRewardsAmount(sdkmath.LegacyMustNewDecFromStr("-0.50"))) + require.Error(t, validateBlockRewardsAmount(nil)) require.NoError(t, validateBlockRewardsAmount(sdkmath.LegacyMustNewDecFromStr("0.50"))) require.NoError(t, validateBlockRewardsAmount(sdkmath.LegacyZeroDec())) require.NoError(t, validateBlockRewardsAmount(BlockReward)) @@ -113,7 +115,7 @@ func TestValidate(t *testing.T) { t.Run("should error for negative block reward amount", func(t *testing.T) { params := NewParams() params.BlockRewardAmount = sdkmath.LegacyMustNewDecFromStr("-1.30") - require.ErrorContains(t, params.Validate(), "block reward amount cannot be less than 0") + require.ErrorContains(t, params.Validate(), "block reward amount must not be negative") }) } func TestParamsString(t *testing.T) { From 902554eabe927f54c7d0c92ab0c2c8e8616dc186 Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Mon, 14 Oct 2024 14:55:15 +0200 Subject: [PATCH 24/36] refactor(precompile): do not execute write functions on staticcall (#3001) * refactor(staking): do not execute write functions on staticcall * use require --------- Co-authored-by: lumtis --- precompiles/bank/bank.go | 4 +-- precompiles/bank/method_test.go | 8 +++--- precompiles/staking/staking.go | 20 +++++++++++++- precompiles/types/errors.go | 8 ++++++ precompiles/types/errors_test.go | 46 +++++++++++++------------------- 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index 436364dfa6..51a559edd3 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -136,8 +136,8 @@ func (c *Contract) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]byt // Deposit and Withdraw methods are both not allowed in read-only mode. case DepositMethodName, WithdrawMethodName: if readOnly { - return nil, ptypes.ErrUnexpected{ - Got: "method not allowed in read-only mode: " + method.Name, + return nil, ptypes.ErrWriteMethod{ + Method: method.Name, } } diff --git a/precompiles/bank/method_test.go b/precompiles/bank/method_test.go index 912c41b40c..107439c576 100644 --- a/precompiles/bank/method_test.go +++ b/precompiles/bank/method_test.go @@ -46,8 +46,8 @@ func Test_Methods(t *testing.T) { success, err := ts.bankContract.Run(ts.mockEVM, ts.mockVMContract, true) require.ErrorIs( t, - ptypes.ErrUnexpected{ - Got: "method not allowed in read-only mode: deposit", + ptypes.ErrWriteMethod{ + Method: "deposit", }, err) require.Empty(t, success) @@ -73,8 +73,8 @@ func Test_Methods(t *testing.T) { success, err := ts.bankContract.Run(ts.mockEVM, ts.mockVMContract, true) require.ErrorIs( t, - ptypes.ErrUnexpected{ - Got: "method not allowed in read-only mode: withdraw", + ptypes.ErrWriteMethod{ + Method: "withdraw", }, err) require.Empty(t, success) diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index 7ef467b039..f3a01a541e 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -380,7 +380,7 @@ func (c *Contract) MoveStake( // Run is the entrypoint of the precompiled contract, it switches over the input method, // and execute them accordingly. -func (c *Contract) Run(evm *vm.EVM, contract *vm.Contract, _ bool) ([]byte, error) { +func (c *Contract) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]byte, error) { method, err := ABI.MethodById(contract.Input[:4]) if err != nil { return nil, err @@ -415,6 +415,12 @@ func (c *Contract) Run(evm *vm.EVM, contract *vm.Contract, _ bool) ([]byte, erro } return res, nil case StakeMethodName: + if readOnly { + return nil, ptypes.ErrWriteMethod{ + Method: method.Name, + } + } + var res []byte execErr := stateDB.ExecuteNativeAction(contract.Address(), nil, func(ctx sdk.Context) error { res, err = c.Stake(ctx, evm, contract, method, args) @@ -425,6 +431,12 @@ func (c *Contract) Run(evm *vm.EVM, contract *vm.Contract, _ bool) ([]byte, erro } return res, nil case UnstakeMethodName: + if readOnly { + return nil, ptypes.ErrWriteMethod{ + Method: method.Name, + } + } + var res []byte execErr := stateDB.ExecuteNativeAction(contract.Address(), nil, func(ctx sdk.Context) error { res, err = c.Unstake(ctx, evm, contract, method, args) @@ -435,6 +447,12 @@ func (c *Contract) Run(evm *vm.EVM, contract *vm.Contract, _ bool) ([]byte, erro } return res, nil case MoveStakeMethodName: + if readOnly { + return nil, ptypes.ErrWriteMethod{ + Method: method.Name, + } + } + var res []byte execErr := stateDB.ExecuteNativeAction(contract.Address(), nil, func(ctx sdk.Context) error { res, err = c.MoveStake(ctx, evm, contract, method, args) diff --git a/precompiles/types/errors.go b/precompiles/types/errors.go index 03e397fa14..a624ab27af 100644 --- a/precompiles/types/errors.go +++ b/precompiles/types/errors.go @@ -94,6 +94,14 @@ func (e ErrInvalidMethod) Error() string { return fmt.Sprintf("invalid method: %s", e.Method) } +type ErrWriteMethod struct { + Method string +} + +func (e ErrWriteMethod) Error() string { + return fmt.Sprintf("method not allowed in read-only mode: %s", e.Method) +} + type ErrUnexpected struct { When string Got string diff --git a/precompiles/types/errors_test.go b/precompiles/types/errors_test.go index c80647a08d..d432aa901c 100644 --- a/precompiles/types/errors_test.go +++ b/precompiles/types/errors_test.go @@ -13,9 +13,7 @@ func Test_ErrInvalidAddr(t *testing.T) { } got := e.Error() expect := "invalid address foo, reason: bar" - if got != expect { - t.Errorf("Expected %v, got %v", expect, got) - } + require.Equal(t, expect, got) require.ErrorIs(t, ErrInvalidAddr{"foo", "bar"}, e) } @@ -26,9 +24,7 @@ func Test_ErrInvalidNumberOfArgs(t *testing.T) { } got := e.Error() expect := "invalid number of arguments; expected 2; got: 1" - if got != expect { - t.Errorf("Expected %v, got %v", expect, got) - } + require.Equal(t, expect, got) require.ErrorIs(t, ErrInvalidNumberOfArgs{1, 2}, e) } @@ -38,9 +34,7 @@ func Test_ErrInvalidArgument(t *testing.T) { } got := e.Error() expect := "invalid argument: foo" - if got != expect { - t.Errorf("Expected %v, got %v", expect, got) - } + require.Equal(t, expect, got) require.ErrorIs(t, ErrInvalidArgument{"foo"}, e) } @@ -50,9 +44,7 @@ func Test_ErrInvalidMethod(t *testing.T) { } got := e.Error() expect := "invalid method: foo" - if got != expect { - t.Errorf("Expected %v, got %v", expect, got) - } + require.Equal(t, expect, got) require.ErrorIs(t, ErrInvalidMethod{"foo"}, e) } @@ -65,9 +57,7 @@ func Test_ErrInvalidCoin(t *testing.T) { } got := e.Error() expect := "invalid coin: denom: foo, is negative: true, is nil: false, is empty: false" - if got != expect { - t.Errorf("Expected %v, got %v", expect, got) - } + require.Equal(t, expect, got) require.ErrorIs(t, ErrInvalidCoin{"foo", true, false, false}, e) } @@ -77,9 +67,7 @@ func Test_ErrInvalidAmount(t *testing.T) { } got := e.Error() expect := "invalid token amount: foo" - if got != expect { - t.Errorf("Expected %v, got %v", expect, got) - } + require.Equal(t, expect, got) require.ErrorIs(t, ErrInvalidAmount{"foo"}, e) } @@ -90,9 +78,7 @@ func Test_ErrUnexpected(t *testing.T) { } got := e.Error() expect := "unexpected error in foo: bar" - if got != expect { - t.Errorf("Expected %v, got %v", expect, got) - } + require.Equal(t, expect, got) require.ErrorIs(t, ErrUnexpected{"foo", "bar"}, e) } @@ -103,9 +89,7 @@ func Test_ErrInsufficientBalance(t *testing.T) { } got := e.Error() expect := "insufficient balance: requested foo, current bar" - if got != expect { - t.Errorf("Expected %v, got %v", expect, got) - } + require.Equal(t, expect, got) require.ErrorIs(t, ErrInsufficientBalance{"foo", "bar"}, e) } @@ -116,8 +100,16 @@ func Test_ErrInvalidToken(t *testing.T) { } got := e.Error() expect := "invalid token foo: bar" - if got != expect { - t.Errorf("Expected %v, got %v", expect, got) - } + require.Equal(t, expect, got) require.ErrorIs(t, ErrInvalidToken{"foo", "bar"}, e) } + +func Test_ErrWriteMethod(t *testing.T) { + e := ErrWriteMethod{ + Method: "foo", + } + got := e.Error() + expect := "method not allowed in read-only mode: foo" + require.Equal(t, expect, got) + require.ErrorIs(t, ErrWriteMethod{"foo"}, e) +} From 09e8c3a120c1e1de53e3bbf00d1c028f0a45c99d Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Mon, 14 Oct 2024 11:34:28 -0700 Subject: [PATCH 25/36] fix!: tolerate v2 contracts in tss migration tests (#3002) * fix!: tolerate v2 contracts in tss migration tests * fix upgrade tests --------- Co-authored-by: skosito --- e2e/runner/admin_evm.go | 5 +++-- e2e/utils/require.go | 20 ++++++++++++++++---- go.mod | 2 +- go.sum | 4 ++-- pkg/contracts/testdappv2/TestDAppV2.abi | 4 ++-- pkg/contracts/testdappv2/TestDAppV2.bin | 2 +- pkg/contracts/testdappv2/TestDAppV2.go | 18 +++++++++--------- pkg/contracts/testdappv2/TestDAppV2.json | 6 +++--- pkg/contracts/testdappv2/TestDAppV2.sol | 2 +- x/fungible/keeper/v2_evm.go | 4 ++-- zetaclient/chains/evm/signer/v2_sign.go | 4 ++-- 11 files changed, 42 insertions(+), 29 deletions(-) diff --git a/e2e/runner/admin_evm.go b/e2e/runner/admin_evm.go index a373f2325a..1cd0c29db8 100644 --- a/e2e/runner/admin_evm.go +++ b/e2e/runner/admin_evm.go @@ -26,13 +26,14 @@ func (r *E2ERunner) UpdateTssAddressForConnector() { func (r *E2ERunner) UpdateTssAddressForErc20custody() { require.NoError(r, r.SetTSSAddresses()) - tx, err := r.ERC20Custody.UpdateTSSAddress(r.EVMAuth, r.TSSAddress) + tx, err := r.ERC20CustodyV2.UpdateTSSAddress(r.EVMAuth, r.TSSAddress) require.NoError(r, err) r.Logger.Info(fmt.Sprintf("TSS ERC20 Address Update Tx: %s", tx.Hash().String())) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) utils.RequireTxSuccessful(r, receipt) - tssAddressOnCustody, err := r.ERC20Custody.TSSAddress(&bind.CallOpts{Context: r.Ctx}) + // we have to reference ERC20CustodyV2 since it's `TssAddress` on v2 and `TSSAddress` on v1 + tssAddressOnCustody, err := r.ERC20CustodyV2.TssAddress(&bind.CallOpts{Context: r.Ctx}) require.NoError(r, err) require.Equal(r, r.TSSAddress, tssAddressOnCustody) } diff --git a/e2e/utils/require.go b/e2e/utils/require.go index e610219e15..3dedb7dd26 100644 --- a/e2e/utils/require.go +++ b/e2e/utils/require.go @@ -25,15 +25,27 @@ func RequireCCTXStatus( // RequireTxSuccessful checks if the receipt status is successful. // Currently, it accepts eth receipt, but we can make this more generic by using type assertion. func RequireTxSuccessful(t require.TestingT, receipt *ethtypes.Receipt, msgAndArgs ...any) { - msg := "receipt status is not successful" - require.Equal(t, ethtypes.ReceiptStatusSuccessful, receipt.Status, msg+errSuffix(msgAndArgs...)) + msg := "receipt status is not successful: %s" + require.Equal( + t, + ethtypes.ReceiptStatusSuccessful, + receipt.Status, + msg+errSuffix(msgAndArgs...), + receipt.TxHash.String(), + ) } // RequiredTxFailed checks if the receipt status is failed. // Currently, it accepts eth receipt, but we can make this more generic by using type assertion. func RequiredTxFailed(t require.TestingT, receipt *ethtypes.Receipt, msgAndArgs ...any) { - msg := "receipt status is not successful" - require.Equal(t, ethtypes.ReceiptStatusFailed, receipt.Status, msg+errSuffix(msgAndArgs...)) + msg := "receipt status is not successful: %s" + require.Equal( + t, + ethtypes.ReceiptStatusFailed, + receipt.Status, + msg+errSuffix(msgAndArgs...), + receipt.TxHash.String(), + ) } func errSuffix(msgAndArgs ...any) string { diff --git a/go.mod b/go.mod index eb87031b7e..23dae42fae 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/zeta-chain/ethermint v0.0.0-20241010181243-044e22bdb7e7 github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 - github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20240924201108-3a274ce7bad0 + github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241009160411-475acfac26ef gitlab.com/thorchain/tss/go-tss v1.6.5 go.nhat.io/grpcmock v0.25.0 golang.org/x/crypto v0.23.0 diff --git a/go.sum b/go.sum index 14bfa8eb35..f5be31056c 100644 --- a/go.sum +++ b/go.sum @@ -4208,8 +4208,8 @@ github.com/zeta-chain/go-tss v0.0.0-20240916173049-89fee4b0ae7f h1:XqUvw9a3EnDa2 github.com/zeta-chain/go-tss v0.0.0-20240916173049-89fee4b0ae7f/go.mod h1:B1FDE6kHs8hozKSX1/iXgCdvlFbS6+FeAupoBHDK0Cc= github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 h1:vck/FcIIpFOvpBUm0NO17jbEtmSz/W/a5Y4jRuSJl6I= github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138/go.mod h1:U494OsZTWsU75hqoriZgMdSsgSGP1mUL1jX+wN/Aez8= -github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20240924201108-3a274ce7bad0 h1:GbfO2dyjSAWqBH0xDIttwPB2fE5A+zw0UUbEoW3S3wU= -github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20240924201108-3a274ce7bad0/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w= +github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241009160411-475acfac26ef h1:tfF31iib7rTeBLGrvWMbW2HM6omkzPDjsX8QM2VY6a4= +github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241009160411-475acfac26ef/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w= github.com/zeta-chain/tss-lib v0.0.0-20240916163010-2e6b438bd901 h1:9whtN5fjYHfk4yXIuAsYP2EHxImwDWDVUOnZJ2pfL3w= github.com/zeta-chain/tss-lib v0.0.0-20240916163010-2e6b438bd901/go.mod h1:d2iTC62s9JwKiCMPhcDDXbIZmuzAyJ4lwso0H5QyRbk= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= diff --git a/pkg/contracts/testdappv2/TestDAppV2.abi b/pkg/contracts/testdappv2/TestDAppV2.abi index cbfdc1bfca..95618cf9db 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.abi +++ b/pkg/contracts/testdappv2/TestDAppV2.abi @@ -215,9 +215,9 @@ "type": "address" }, { - "internalType": "uint64", + "internalType": "uint256", "name": "amount", - "type": "uint64" + "type": "uint256" }, { "internalType": "bytes", diff --git a/pkg/contracts/testdappv2/TestDAppV2.bin b/pkg/contracts/testdappv2/TestDAppV2.bin index 0a7fe69007..1c087ef1b5 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.bin +++ b/pkg/contracts/testdappv2/TestDAppV2.bin @@ -1 +1 @@ -608060405234801561001057600080fd5b5061150a806100206000396000f3fe6080604052600436106100c65760003560e01c8063a799911f1161007f578063de43156e11610059578063de43156e14610267578063e2842ed714610290578063f592cbfb146102cd578063f936ae851461030a576100cd565b8063a799911f146101f9578063c234fecf14610215578063c7a339a91461023e576100cd565b806336e980a0146100d25780634297a263146100fb57806359f4a777146101385780635ac1e07014610163578063676cc0541461018c5780639291fe26146101bc576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610de7565b610347565b005b34801561010757600080fd5b50610122600480360381019061011d9190610d02565b610371565b60405161012f9190611173565b60405180910390f35b34801561014457600080fd5b5061014d610389565b60405161015a91906110c4565b60405180910390f35b34801561016f57600080fd5b5061018a60048036038101906101859190610e90565b6103ad565b005b6101a660048036038101906101a19190610e30565b6104e7565b6040516101b39190611131565b60405180910390f35b3480156101c857600080fd5b506101e360048036038101906101de9190610de7565b61069c565b6040516101f09190611173565b60405180910390f35b610213600480360381019061020e9190610de7565b6106df565b005b34801561022157600080fd5b5061023c60048036038101906102379190610ca8565b610708565b005b34801561024a57600080fd5b5061026560048036038101906102609190610d78565b61074b565b005b34801561027357600080fd5b5061028e60048036038101906102899190610ed9565b61080e565b005b34801561029c57600080fd5b506102b760048036038101906102b29190610d02565b610907565b6040516102c49190611116565b60405180910390f35b3480156102d957600080fd5b506102f460048036038101906102ef9190610de7565b610927565b6040516103019190611116565b60405180910390f35b34801561031657600080fd5b50610331600480360381019061032c9190610d2f565b610977565b60405161033e91906110c4565b60405180910390f35b610350816109c0565b1561035a57600080fd5b61036381610a16565b61036e816000610a6a565b50565b60036020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6104088180606001906103c0919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61046581806060019061041b919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000610a6a565b8060000160208101906104789190610ca8565b600282806060019061048a919061118e565b60405161049892919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160208101906105339190610ca8565b73ffffffffffffffffffffffffffffffffffffffff1614610589576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161058090611153565b60405180910390fd5b6105d683838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61062483838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505034610a6a565b8360000160208101906106379190610ca8565b6002848460405161064992919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060036000836040516020016106b39190611098565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6106e8816109c0565b156106f257600080fd5b6106fb81610a16565b6107058134610a6a565b50565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610754816109c0565b1561075e57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b815260040161079b939291906110df565b602060405180830381600087803b1580156107b557600080fd5b505af11580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610cd5565b6107f657600080fd5b6107ff81610a16565b6108098183610a6a565b505050565b61085b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506109c0565b1561086557600080fd5b6108b282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61090082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a6a565b5050505050565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600160008360405160200161093e9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6002818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040516020016109d1906110af565b60405160208183030381529060405280519060200120826040516020016109f89190611098565b60405160208183030381529060405280519060200120149050919050565b600180600083604051602001610a2c9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806003600084604051602001610a809190611098565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000610abf610aba84611216565b6111f1565b905082815260208101848484011115610adb57610ada6113ef565b5b610ae684828561132a565b509392505050565b6000610b01610afc84611247565b6111f1565b905082815260208101848484011115610b1d57610b1c6113ef565b5b610b2884828561132a565b509392505050565b600081359050610b3f81611461565b92915050565b600081519050610b5481611478565b92915050565b600081359050610b698161148f565b92915050565b60008083601f840112610b8557610b846113d1565b5b8235905067ffffffffffffffff811115610ba257610ba16113cc565b5b602083019150836001820283011115610bbe57610bbd6113e5565b5b9250929050565b600082601f830112610bda57610bd96113d1565b5b8135610bea848260208601610aac565b91505092915050565b600081359050610c02816114a6565b92915050565b600082601f830112610c1d57610c1c6113d1565b5b8135610c2d848260208601610aee565b91505092915050565b600060208284031215610c4c57610c4b6113db565b5b81905092915050565b600060808284031215610c6b57610c6a6113db565b5b81905092915050565b600060608284031215610c8a57610c896113db565b5b81905092915050565b600081359050610ca2816114bd565b92915050565b600060208284031215610cbe57610cbd6113f9565b5b6000610ccc84828501610b30565b91505092915050565b600060208284031215610ceb57610cea6113f9565b5b6000610cf984828501610b45565b91505092915050565b600060208284031215610d1857610d176113f9565b5b6000610d2684828501610b5a565b91505092915050565b600060208284031215610d4557610d446113f9565b5b600082013567ffffffffffffffff811115610d6357610d626113f4565b5b610d6f84828501610bc5565b91505092915050565b600080600060608486031215610d9157610d906113f9565b5b6000610d9f86828701610bf3565b9350506020610db086828701610c93565b925050604084013567ffffffffffffffff811115610dd157610dd06113f4565b5b610ddd86828701610c08565b9150509250925092565b600060208284031215610dfd57610dfc6113f9565b5b600082013567ffffffffffffffff811115610e1b57610e1a6113f4565b5b610e2784828501610c08565b91505092915050565b600080600060408486031215610e4957610e486113f9565b5b6000610e5786828701610c36565b935050602084013567ffffffffffffffff811115610e7857610e776113f4565b5b610e8486828701610b6f565b92509250509250925092565b600060208284031215610ea657610ea56113f9565b5b600082013567ffffffffffffffff811115610ec457610ec36113f4565b5b610ed084828501610c55565b91505092915050565b600080600080600060808688031215610ef557610ef46113f9565b5b600086013567ffffffffffffffff811115610f1357610f126113f4565b5b610f1f88828901610c74565b9550506020610f3088828901610b30565b9450506040610f4188828901610c93565b935050606086013567ffffffffffffffff811115610f6257610f616113f4565b5b610f6e88828901610b6f565b92509250509295509295909350565b610f86816112c6565b82525050565b610f95816112d8565b82525050565b6000610fa7838561129f565b9350610fb483858461132a565b82840190509392505050565b6000610fcb82611278565b610fd5818561128e565b9350610fe5818560208601611339565b610fee816113fe565b840191505092915050565b600061100482611283565b61100e81856112bb565b935061101e818560208601611339565b80840191505092915050565b60006110376016836112aa565b91506110428261140f565b602082019050919050565b600061105a6006836112bb565b915061106582611438565b600682019050919050565b61107981611320565b82525050565b600061108c828486610f9b565b91508190509392505050565b60006110a48284610ff9565b915081905092915050565b60006110ba8261104d565b9150819050919050565b60006020820190506110d96000830184610f7d565b92915050565b60006060820190506110f46000830186610f7d565b6111016020830185610f7d565b61110e6040830184611070565b949350505050565b600060208201905061112b6000830184610f8c565b92915050565b6000602082019050818103600083015261114b8184610fc0565b905092915050565b6000602082019050818103600083015261116c8161102a565b9050919050565b60006020820190506111886000830184611070565b92915050565b600080833560016020038436030381126111ab576111aa6113e0565b5b80840192508235915067ffffffffffffffff8211156111cd576111cc6113d6565b5b6020830192506001820236038313156111e9576111e86113ea565b5b509250929050565b60006111fb61120c565b9050611207828261136c565b919050565b6000604051905090565b600067ffffffffffffffff8211156112315761123061139d565b5b61123a826113fe565b9050602081019050919050565b600067ffffffffffffffff8211156112625761126161139d565b5b61126b826113fe565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006112d182611300565b9050919050565b60008115159050919050565b6000819050919050565b60006112f9826112c6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561135757808201518184015260208101905061133c565b83811115611366576000848401525b50505050565b611375826113fe565b810181811067ffffffffffffffff821117156113945761139361139d565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f756e61757468656e746963617465642073656e64657200000000000000000000600082015250565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61146a816112c6565b811461147557600080fd5b50565b611481816112d8565b811461148c57600080fd5b50565b611498816112e4565b81146114a357600080fd5b50565b6114af816112ee565b81146114ba57600080fd5b50565b6114c681611320565b81146114d157600080fd5b5056fea2646970667358221220e090c5cd81361f8bba5d13d4fb801ab148714dad774e12a4acf812e341dc93c564736f6c63430008070033 +608060405234801561001057600080fd5b5061150a806100206000396000f3fe6080604052600436106100c65760003560e01c8063c234fecf1161007f578063de43156e11610059578063de43156e14610267578063e2842ed714610290578063f592cbfb146102cd578063f936ae851461030a576100cd565b8063c234fecf146101ec578063c7a339a914610215578063c9028a361461023e576100cd565b806336e980a0146100d25780634297a263146100fb57806359f4a77714610138578063676cc054146101635780639291fe2614610193578063a799911f146101d0576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610de7565b610347565b005b34801561010757600080fd5b50610122600480360381019061011d9190610d02565b610371565b60405161012f9190611173565b60405180910390f35b34801561014457600080fd5b5061014d610389565b60405161015a91906110c4565b60405180910390f35b61017d60048036038101906101789190610e30565b6103ad565b60405161018a9190611131565b60405180910390f35b34801561019f57600080fd5b506101ba60048036038101906101b59190610de7565b610562565b6040516101c79190611173565b60405180910390f35b6101ea60048036038101906101e59190610de7565b6105a5565b005b3480156101f857600080fd5b50610213600480360381019061020e9190610ca8565b6105ce565b005b34801561022157600080fd5b5061023c60048036038101906102379190610d78565b610611565b005b34801561024a57600080fd5b5061026560048036038101906102609190610e90565b6106d4565b005b34801561027357600080fd5b5061028e60048036038101906102899190610ed9565b61080e565b005b34801561029c57600080fd5b506102b760048036038101906102b29190610d02565b610907565b6040516102c49190611116565b60405180910390f35b3480156102d957600080fd5b506102f460048036038101906102ef9190610de7565b610927565b6040516103019190611116565b60405180910390f35b34801561031657600080fd5b50610331600480360381019061032c9190610d2f565b610977565b60405161033e91906110c4565b60405180910390f35b610350816109c0565b1561035a57600080fd5b61036381610a16565b61036e816000610a6a565b50565b60036020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160208101906103f99190610ca8565b73ffffffffffffffffffffffffffffffffffffffff161461044f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044690611153565b60405180910390fd5b61049c83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b6104ea83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505034610a6a565b8360000160208101906104fd9190610ca8565b6002848460405161050f92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060036000836040516020016105799190611098565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105ae816109c0565b156105b857600080fd5b6105c181610a16565b6105cb8134610a6a565b50565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61061a816109c0565b1561062457600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b8152600401610661939291906110df565b602060405180830381600087803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190610cd5565b6106bc57600080fd5b6106c581610a16565b6106cf8183610a6a565b505050565b61072f8180606001906106e7919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61078c818060600190610742919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000610a6a565b80600001602081019061079f9190610ca8565b60028280606001906107b1919061118e565b6040516107bf92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61085b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506109c0565b1561086557600080fd5b6108b282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61090082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a6a565b5050505050565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600160008360405160200161093e9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6002818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040516020016109d1906110af565b60405160208183030381529060405280519060200120826040516020016109f89190611098565b60405160208183030381529060405280519060200120149050919050565b600180600083604051602001610a2c9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806003600084604051602001610a809190611098565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000610abf610aba84611216565b6111f1565b905082815260208101848484011115610adb57610ada6113ef565b5b610ae684828561132a565b509392505050565b6000610b01610afc84611247565b6111f1565b905082815260208101848484011115610b1d57610b1c6113ef565b5b610b2884828561132a565b509392505050565b600081359050610b3f81611461565b92915050565b600081519050610b5481611478565b92915050565b600081359050610b698161148f565b92915050565b60008083601f840112610b8557610b846113d1565b5b8235905067ffffffffffffffff811115610ba257610ba16113cc565b5b602083019150836001820283011115610bbe57610bbd6113e5565b5b9250929050565b600082601f830112610bda57610bd96113d1565b5b8135610bea848260208601610aac565b91505092915050565b600081359050610c02816114a6565b92915050565b600082601f830112610c1d57610c1c6113d1565b5b8135610c2d848260208601610aee565b91505092915050565b600060208284031215610c4c57610c4b6113db565b5b81905092915050565b600060808284031215610c6b57610c6a6113db565b5b81905092915050565b600060608284031215610c8a57610c896113db565b5b81905092915050565b600081359050610ca2816114bd565b92915050565b600060208284031215610cbe57610cbd6113f9565b5b6000610ccc84828501610b30565b91505092915050565b600060208284031215610ceb57610cea6113f9565b5b6000610cf984828501610b45565b91505092915050565b600060208284031215610d1857610d176113f9565b5b6000610d2684828501610b5a565b91505092915050565b600060208284031215610d4557610d446113f9565b5b600082013567ffffffffffffffff811115610d6357610d626113f4565b5b610d6f84828501610bc5565b91505092915050565b600080600060608486031215610d9157610d906113f9565b5b6000610d9f86828701610bf3565b9350506020610db086828701610c93565b925050604084013567ffffffffffffffff811115610dd157610dd06113f4565b5b610ddd86828701610c08565b9150509250925092565b600060208284031215610dfd57610dfc6113f9565b5b600082013567ffffffffffffffff811115610e1b57610e1a6113f4565b5b610e2784828501610c08565b91505092915050565b600080600060408486031215610e4957610e486113f9565b5b6000610e5786828701610c36565b935050602084013567ffffffffffffffff811115610e7857610e776113f4565b5b610e8486828701610b6f565b92509250509250925092565b600060208284031215610ea657610ea56113f9565b5b600082013567ffffffffffffffff811115610ec457610ec36113f4565b5b610ed084828501610c55565b91505092915050565b600080600080600060808688031215610ef557610ef46113f9565b5b600086013567ffffffffffffffff811115610f1357610f126113f4565b5b610f1f88828901610c74565b9550506020610f3088828901610b30565b9450506040610f4188828901610c93565b935050606086013567ffffffffffffffff811115610f6257610f616113f4565b5b610f6e88828901610b6f565b92509250509295509295909350565b610f86816112c6565b82525050565b610f95816112d8565b82525050565b6000610fa7838561129f565b9350610fb483858461132a565b82840190509392505050565b6000610fcb82611278565b610fd5818561128e565b9350610fe5818560208601611339565b610fee816113fe565b840191505092915050565b600061100482611283565b61100e81856112bb565b935061101e818560208601611339565b80840191505092915050565b60006110376016836112aa565b91506110428261140f565b602082019050919050565b600061105a6006836112bb565b915061106582611438565b600682019050919050565b61107981611320565b82525050565b600061108c828486610f9b565b91508190509392505050565b60006110a48284610ff9565b915081905092915050565b60006110ba8261104d565b9150819050919050565b60006020820190506110d96000830184610f7d565b92915050565b60006060820190506110f46000830186610f7d565b6111016020830185610f7d565b61110e6040830184611070565b949350505050565b600060208201905061112b6000830184610f8c565b92915050565b6000602082019050818103600083015261114b8184610fc0565b905092915050565b6000602082019050818103600083015261116c8161102a565b9050919050565b60006020820190506111886000830184611070565b92915050565b600080833560016020038436030381126111ab576111aa6113e0565b5b80840192508235915067ffffffffffffffff8211156111cd576111cc6113d6565b5b6020830192506001820236038313156111e9576111e86113ea565b5b509250929050565b60006111fb61120c565b9050611207828261136c565b919050565b6000604051905090565b600067ffffffffffffffff8211156112315761123061139d565b5b61123a826113fe565b9050602081019050919050565b600067ffffffffffffffff8211156112625761126161139d565b5b61126b826113fe565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006112d182611300565b9050919050565b60008115159050919050565b6000819050919050565b60006112f9826112c6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561135757808201518184015260208101905061133c565b83811115611366576000848401525b50505050565b611375826113fe565b810181811067ffffffffffffffff821117156113945761139361139d565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f756e61757468656e746963617465642073656e64657200000000000000000000600082015250565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61146a816112c6565b811461147557600080fd5b50565b611481816112d8565b811461148c57600080fd5b50565b611498816112e4565b81146114a357600080fd5b50565b6114af816112ee565b81146114ba57600080fd5b50565b6114c681611320565b81146114d157600080fd5b5056fea2646970667358221220da9e50cb7b79ace99166ed06c9234f984bc9599fca79796389af6656411f73f964736f6c63430008070033 diff --git a/pkg/contracts/testdappv2/TestDAppV2.go b/pkg/contracts/testdappv2/TestDAppV2.go index 50e4bbcecb..5c32fe96f8 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.go +++ b/pkg/contracts/testdappv2/TestDAppV2.go @@ -38,7 +38,7 @@ type TestDAppV2MessageContext struct { type TestDAppV2RevertContext struct { Sender common.Address Asset common.Address - Amount uint64 + Amount *big.Int RevertMessage []byte } @@ -51,8 +51,8 @@ type TestDAppV2zContext struct { // TestDAppV2MetaData contains all meta data concerning the TestDAppV2 contract. var TestDAppV2MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"amountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"calledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"erc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"erc20Call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"expectedOnCallSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"gasCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getAmountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getCalledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"internalType\":\"structTestDAppV2.MessageContext\",\"name\":\"messageContext\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"origin\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainID\",\"type\":\"uint256\"}],\"internalType\":\"structTestDAppV2.zContext\",\"name\":\"_context\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_zrc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCrossChainCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"amount\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"revertMessage\",\"type\":\"bytes\"}],\"internalType\":\"structTestDAppV2.RevertContext\",\"name\":\"revertContext\",\"type\":\"tuple\"}],\"name\":\"onRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"senderWithMessage\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_expectedOnCallSender\",\"type\":\"address\"}],\"name\":\"setExpectedOnCallSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"simpleCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x608060405234801561001057600080fd5b5061150a806100206000396000f3fe6080604052600436106100c65760003560e01c8063a799911f1161007f578063de43156e11610059578063de43156e14610267578063e2842ed714610290578063f592cbfb146102cd578063f936ae851461030a576100cd565b8063a799911f146101f9578063c234fecf14610215578063c7a339a91461023e576100cd565b806336e980a0146100d25780634297a263146100fb57806359f4a777146101385780635ac1e07014610163578063676cc0541461018c5780639291fe26146101bc576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610de7565b610347565b005b34801561010757600080fd5b50610122600480360381019061011d9190610d02565b610371565b60405161012f9190611173565b60405180910390f35b34801561014457600080fd5b5061014d610389565b60405161015a91906110c4565b60405180910390f35b34801561016f57600080fd5b5061018a60048036038101906101859190610e90565b6103ad565b005b6101a660048036038101906101a19190610e30565b6104e7565b6040516101b39190611131565b60405180910390f35b3480156101c857600080fd5b506101e360048036038101906101de9190610de7565b61069c565b6040516101f09190611173565b60405180910390f35b610213600480360381019061020e9190610de7565b6106df565b005b34801561022157600080fd5b5061023c60048036038101906102379190610ca8565b610708565b005b34801561024a57600080fd5b5061026560048036038101906102609190610d78565b61074b565b005b34801561027357600080fd5b5061028e60048036038101906102899190610ed9565b61080e565b005b34801561029c57600080fd5b506102b760048036038101906102b29190610d02565b610907565b6040516102c49190611116565b60405180910390f35b3480156102d957600080fd5b506102f460048036038101906102ef9190610de7565b610927565b6040516103019190611116565b60405180910390f35b34801561031657600080fd5b50610331600480360381019061032c9190610d2f565b610977565b60405161033e91906110c4565b60405180910390f35b610350816109c0565b1561035a57600080fd5b61036381610a16565b61036e816000610a6a565b50565b60036020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6104088180606001906103c0919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61046581806060019061041b919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000610a6a565b8060000160208101906104789190610ca8565b600282806060019061048a919061118e565b60405161049892919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160208101906105339190610ca8565b73ffffffffffffffffffffffffffffffffffffffff1614610589576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161058090611153565b60405180910390fd5b6105d683838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61062483838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505034610a6a565b8360000160208101906106379190610ca8565b6002848460405161064992919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060036000836040516020016106b39190611098565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6106e8816109c0565b156106f257600080fd5b6106fb81610a16565b6107058134610a6a565b50565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610754816109c0565b1561075e57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b815260040161079b939291906110df565b602060405180830381600087803b1580156107b557600080fd5b505af11580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610cd5565b6107f657600080fd5b6107ff81610a16565b6108098183610a6a565b505050565b61085b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506109c0565b1561086557600080fd5b6108b282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61090082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a6a565b5050505050565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600160008360405160200161093e9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6002818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040516020016109d1906110af565b60405160208183030381529060405280519060200120826040516020016109f89190611098565b60405160208183030381529060405280519060200120149050919050565b600180600083604051602001610a2c9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806003600084604051602001610a809190611098565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000610abf610aba84611216565b6111f1565b905082815260208101848484011115610adb57610ada6113ef565b5b610ae684828561132a565b509392505050565b6000610b01610afc84611247565b6111f1565b905082815260208101848484011115610b1d57610b1c6113ef565b5b610b2884828561132a565b509392505050565b600081359050610b3f81611461565b92915050565b600081519050610b5481611478565b92915050565b600081359050610b698161148f565b92915050565b60008083601f840112610b8557610b846113d1565b5b8235905067ffffffffffffffff811115610ba257610ba16113cc565b5b602083019150836001820283011115610bbe57610bbd6113e5565b5b9250929050565b600082601f830112610bda57610bd96113d1565b5b8135610bea848260208601610aac565b91505092915050565b600081359050610c02816114a6565b92915050565b600082601f830112610c1d57610c1c6113d1565b5b8135610c2d848260208601610aee565b91505092915050565b600060208284031215610c4c57610c4b6113db565b5b81905092915050565b600060808284031215610c6b57610c6a6113db565b5b81905092915050565b600060608284031215610c8a57610c896113db565b5b81905092915050565b600081359050610ca2816114bd565b92915050565b600060208284031215610cbe57610cbd6113f9565b5b6000610ccc84828501610b30565b91505092915050565b600060208284031215610ceb57610cea6113f9565b5b6000610cf984828501610b45565b91505092915050565b600060208284031215610d1857610d176113f9565b5b6000610d2684828501610b5a565b91505092915050565b600060208284031215610d4557610d446113f9565b5b600082013567ffffffffffffffff811115610d6357610d626113f4565b5b610d6f84828501610bc5565b91505092915050565b600080600060608486031215610d9157610d906113f9565b5b6000610d9f86828701610bf3565b9350506020610db086828701610c93565b925050604084013567ffffffffffffffff811115610dd157610dd06113f4565b5b610ddd86828701610c08565b9150509250925092565b600060208284031215610dfd57610dfc6113f9565b5b600082013567ffffffffffffffff811115610e1b57610e1a6113f4565b5b610e2784828501610c08565b91505092915050565b600080600060408486031215610e4957610e486113f9565b5b6000610e5786828701610c36565b935050602084013567ffffffffffffffff811115610e7857610e776113f4565b5b610e8486828701610b6f565b92509250509250925092565b600060208284031215610ea657610ea56113f9565b5b600082013567ffffffffffffffff811115610ec457610ec36113f4565b5b610ed084828501610c55565b91505092915050565b600080600080600060808688031215610ef557610ef46113f9565b5b600086013567ffffffffffffffff811115610f1357610f126113f4565b5b610f1f88828901610c74565b9550506020610f3088828901610b30565b9450506040610f4188828901610c93565b935050606086013567ffffffffffffffff811115610f6257610f616113f4565b5b610f6e88828901610b6f565b92509250509295509295909350565b610f86816112c6565b82525050565b610f95816112d8565b82525050565b6000610fa7838561129f565b9350610fb483858461132a565b82840190509392505050565b6000610fcb82611278565b610fd5818561128e565b9350610fe5818560208601611339565b610fee816113fe565b840191505092915050565b600061100482611283565b61100e81856112bb565b935061101e818560208601611339565b80840191505092915050565b60006110376016836112aa565b91506110428261140f565b602082019050919050565b600061105a6006836112bb565b915061106582611438565b600682019050919050565b61107981611320565b82525050565b600061108c828486610f9b565b91508190509392505050565b60006110a48284610ff9565b915081905092915050565b60006110ba8261104d565b9150819050919050565b60006020820190506110d96000830184610f7d565b92915050565b60006060820190506110f46000830186610f7d565b6111016020830185610f7d565b61110e6040830184611070565b949350505050565b600060208201905061112b6000830184610f8c565b92915050565b6000602082019050818103600083015261114b8184610fc0565b905092915050565b6000602082019050818103600083015261116c8161102a565b9050919050565b60006020820190506111886000830184611070565b92915050565b600080833560016020038436030381126111ab576111aa6113e0565b5b80840192508235915067ffffffffffffffff8211156111cd576111cc6113d6565b5b6020830192506001820236038313156111e9576111e86113ea565b5b509250929050565b60006111fb61120c565b9050611207828261136c565b919050565b6000604051905090565b600067ffffffffffffffff8211156112315761123061139d565b5b61123a826113fe565b9050602081019050919050565b600067ffffffffffffffff8211156112625761126161139d565b5b61126b826113fe565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006112d182611300565b9050919050565b60008115159050919050565b6000819050919050565b60006112f9826112c6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561135757808201518184015260208101905061133c565b83811115611366576000848401525b50505050565b611375826113fe565b810181811067ffffffffffffffff821117156113945761139361139d565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f756e61757468656e746963617465642073656e64657200000000000000000000600082015250565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61146a816112c6565b811461147557600080fd5b50565b611481816112d8565b811461148c57600080fd5b50565b611498816112e4565b81146114a357600080fd5b50565b6114af816112ee565b81146114ba57600080fd5b50565b6114c681611320565b81146114d157600080fd5b5056fea2646970667358221220e090c5cd81361f8bba5d13d4fb801ab148714dad774e12a4acf812e341dc93c564736f6c63430008070033", + ABI: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"amountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"calledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"erc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"erc20Call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"expectedOnCallSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"gasCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getAmountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getCalledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"internalType\":\"structTestDAppV2.MessageContext\",\"name\":\"messageContext\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"origin\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainID\",\"type\":\"uint256\"}],\"internalType\":\"structTestDAppV2.zContext\",\"name\":\"_context\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_zrc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCrossChainCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"revertMessage\",\"type\":\"bytes\"}],\"internalType\":\"structTestDAppV2.RevertContext\",\"name\":\"revertContext\",\"type\":\"tuple\"}],\"name\":\"onRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"senderWithMessage\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_expectedOnCallSender\",\"type\":\"address\"}],\"name\":\"setExpectedOnCallSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"simpleCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x608060405234801561001057600080fd5b5061150a806100206000396000f3fe6080604052600436106100c65760003560e01c8063c234fecf1161007f578063de43156e11610059578063de43156e14610267578063e2842ed714610290578063f592cbfb146102cd578063f936ae851461030a576100cd565b8063c234fecf146101ec578063c7a339a914610215578063c9028a361461023e576100cd565b806336e980a0146100d25780634297a263146100fb57806359f4a77714610138578063676cc054146101635780639291fe2614610193578063a799911f146101d0576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610de7565b610347565b005b34801561010757600080fd5b50610122600480360381019061011d9190610d02565b610371565b60405161012f9190611173565b60405180910390f35b34801561014457600080fd5b5061014d610389565b60405161015a91906110c4565b60405180910390f35b61017d60048036038101906101789190610e30565b6103ad565b60405161018a9190611131565b60405180910390f35b34801561019f57600080fd5b506101ba60048036038101906101b59190610de7565b610562565b6040516101c79190611173565b60405180910390f35b6101ea60048036038101906101e59190610de7565b6105a5565b005b3480156101f857600080fd5b50610213600480360381019061020e9190610ca8565b6105ce565b005b34801561022157600080fd5b5061023c60048036038101906102379190610d78565b610611565b005b34801561024a57600080fd5b5061026560048036038101906102609190610e90565b6106d4565b005b34801561027357600080fd5b5061028e60048036038101906102899190610ed9565b61080e565b005b34801561029c57600080fd5b506102b760048036038101906102b29190610d02565b610907565b6040516102c49190611116565b60405180910390f35b3480156102d957600080fd5b506102f460048036038101906102ef9190610de7565b610927565b6040516103019190611116565b60405180910390f35b34801561031657600080fd5b50610331600480360381019061032c9190610d2f565b610977565b60405161033e91906110c4565b60405180910390f35b610350816109c0565b1561035a57600080fd5b61036381610a16565b61036e816000610a6a565b50565b60036020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160208101906103f99190610ca8565b73ffffffffffffffffffffffffffffffffffffffff161461044f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044690611153565b60405180910390fd5b61049c83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b6104ea83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505034610a6a565b8360000160208101906104fd9190610ca8565b6002848460405161050f92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060036000836040516020016105799190611098565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105ae816109c0565b156105b857600080fd5b6105c181610a16565b6105cb8134610a6a565b50565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61061a816109c0565b1561062457600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b8152600401610661939291906110df565b602060405180830381600087803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190610cd5565b6106bc57600080fd5b6106c581610a16565b6106cf8183610a6a565b505050565b61072f8180606001906106e7919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61078c818060600190610742919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000610a6a565b80600001602081019061079f9190610ca8565b60028280606001906107b1919061118e565b6040516107bf92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61085b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506109c0565b1561086557600080fd5b6108b282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61090082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a6a565b5050505050565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600160008360405160200161093e9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6002818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040516020016109d1906110af565b60405160208183030381529060405280519060200120826040516020016109f89190611098565b60405160208183030381529060405280519060200120149050919050565b600180600083604051602001610a2c9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806003600084604051602001610a809190611098565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000610abf610aba84611216565b6111f1565b905082815260208101848484011115610adb57610ada6113ef565b5b610ae684828561132a565b509392505050565b6000610b01610afc84611247565b6111f1565b905082815260208101848484011115610b1d57610b1c6113ef565b5b610b2884828561132a565b509392505050565b600081359050610b3f81611461565b92915050565b600081519050610b5481611478565b92915050565b600081359050610b698161148f565b92915050565b60008083601f840112610b8557610b846113d1565b5b8235905067ffffffffffffffff811115610ba257610ba16113cc565b5b602083019150836001820283011115610bbe57610bbd6113e5565b5b9250929050565b600082601f830112610bda57610bd96113d1565b5b8135610bea848260208601610aac565b91505092915050565b600081359050610c02816114a6565b92915050565b600082601f830112610c1d57610c1c6113d1565b5b8135610c2d848260208601610aee565b91505092915050565b600060208284031215610c4c57610c4b6113db565b5b81905092915050565b600060808284031215610c6b57610c6a6113db565b5b81905092915050565b600060608284031215610c8a57610c896113db565b5b81905092915050565b600081359050610ca2816114bd565b92915050565b600060208284031215610cbe57610cbd6113f9565b5b6000610ccc84828501610b30565b91505092915050565b600060208284031215610ceb57610cea6113f9565b5b6000610cf984828501610b45565b91505092915050565b600060208284031215610d1857610d176113f9565b5b6000610d2684828501610b5a565b91505092915050565b600060208284031215610d4557610d446113f9565b5b600082013567ffffffffffffffff811115610d6357610d626113f4565b5b610d6f84828501610bc5565b91505092915050565b600080600060608486031215610d9157610d906113f9565b5b6000610d9f86828701610bf3565b9350506020610db086828701610c93565b925050604084013567ffffffffffffffff811115610dd157610dd06113f4565b5b610ddd86828701610c08565b9150509250925092565b600060208284031215610dfd57610dfc6113f9565b5b600082013567ffffffffffffffff811115610e1b57610e1a6113f4565b5b610e2784828501610c08565b91505092915050565b600080600060408486031215610e4957610e486113f9565b5b6000610e5786828701610c36565b935050602084013567ffffffffffffffff811115610e7857610e776113f4565b5b610e8486828701610b6f565b92509250509250925092565b600060208284031215610ea657610ea56113f9565b5b600082013567ffffffffffffffff811115610ec457610ec36113f4565b5b610ed084828501610c55565b91505092915050565b600080600080600060808688031215610ef557610ef46113f9565b5b600086013567ffffffffffffffff811115610f1357610f126113f4565b5b610f1f88828901610c74565b9550506020610f3088828901610b30565b9450506040610f4188828901610c93565b935050606086013567ffffffffffffffff811115610f6257610f616113f4565b5b610f6e88828901610b6f565b92509250509295509295909350565b610f86816112c6565b82525050565b610f95816112d8565b82525050565b6000610fa7838561129f565b9350610fb483858461132a565b82840190509392505050565b6000610fcb82611278565b610fd5818561128e565b9350610fe5818560208601611339565b610fee816113fe565b840191505092915050565b600061100482611283565b61100e81856112bb565b935061101e818560208601611339565b80840191505092915050565b60006110376016836112aa565b91506110428261140f565b602082019050919050565b600061105a6006836112bb565b915061106582611438565b600682019050919050565b61107981611320565b82525050565b600061108c828486610f9b565b91508190509392505050565b60006110a48284610ff9565b915081905092915050565b60006110ba8261104d565b9150819050919050565b60006020820190506110d96000830184610f7d565b92915050565b60006060820190506110f46000830186610f7d565b6111016020830185610f7d565b61110e6040830184611070565b949350505050565b600060208201905061112b6000830184610f8c565b92915050565b6000602082019050818103600083015261114b8184610fc0565b905092915050565b6000602082019050818103600083015261116c8161102a565b9050919050565b60006020820190506111886000830184611070565b92915050565b600080833560016020038436030381126111ab576111aa6113e0565b5b80840192508235915067ffffffffffffffff8211156111cd576111cc6113d6565b5b6020830192506001820236038313156111e9576111e86113ea565b5b509250929050565b60006111fb61120c565b9050611207828261136c565b919050565b6000604051905090565b600067ffffffffffffffff8211156112315761123061139d565b5b61123a826113fe565b9050602081019050919050565b600067ffffffffffffffff8211156112625761126161139d565b5b61126b826113fe565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006112d182611300565b9050919050565b60008115159050919050565b6000819050919050565b60006112f9826112c6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561135757808201518184015260208101905061133c565b83811115611366576000848401525b50505050565b611375826113fe565b810181811067ffffffffffffffff821117156113945761139361139d565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f756e61757468656e746963617465642073656e64657200000000000000000000600082015250565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61146a816112c6565b811461147557600080fd5b50565b611481816112d8565b811461148c57600080fd5b50565b611498816112e4565b81146114a357600080fd5b50565b6114af816112ee565b81146114ba57600080fd5b50565b6114c681611320565b81146114d157600080fd5b5056fea2646970667358221220da9e50cb7b79ace99166ed06c9234f984bc9599fca79796389af6656411f73f964736f6c63430008070033", } // TestDAppV2ABI is the input ABI used to generate the binding from. @@ -492,23 +492,23 @@ func (_TestDAppV2 *TestDAppV2TransactorSession) OnCrossChainCall(_context TestDA return _TestDAppV2.Contract.OnCrossChainCall(&_TestDAppV2.TransactOpts, _context, _zrc20, amount, message) } -// OnRevert is a paid mutator transaction binding the contract method 0x5ac1e070. +// OnRevert is a paid mutator transaction binding the contract method 0xc9028a36. // -// Solidity: function onRevert((address,address,uint64,bytes) revertContext) returns() +// Solidity: function onRevert((address,address,uint256,bytes) revertContext) returns() func (_TestDAppV2 *TestDAppV2Transactor) OnRevert(opts *bind.TransactOpts, revertContext TestDAppV2RevertContext) (*types.Transaction, error) { return _TestDAppV2.contract.Transact(opts, "onRevert", revertContext) } -// OnRevert is a paid mutator transaction binding the contract method 0x5ac1e070. +// OnRevert is a paid mutator transaction binding the contract method 0xc9028a36. // -// Solidity: function onRevert((address,address,uint64,bytes) revertContext) returns() +// Solidity: function onRevert((address,address,uint256,bytes) revertContext) returns() func (_TestDAppV2 *TestDAppV2Session) OnRevert(revertContext TestDAppV2RevertContext) (*types.Transaction, error) { return _TestDAppV2.Contract.OnRevert(&_TestDAppV2.TransactOpts, revertContext) } -// OnRevert is a paid mutator transaction binding the contract method 0x5ac1e070. +// OnRevert is a paid mutator transaction binding the contract method 0xc9028a36. // -// Solidity: function onRevert((address,address,uint64,bytes) revertContext) returns() +// Solidity: function onRevert((address,address,uint256,bytes) revertContext) returns() func (_TestDAppV2 *TestDAppV2TransactorSession) OnRevert(revertContext TestDAppV2RevertContext) (*types.Transaction, error) { return _TestDAppV2.Contract.OnRevert(&_TestDAppV2.TransactOpts, revertContext) } diff --git a/pkg/contracts/testdappv2/TestDAppV2.json b/pkg/contracts/testdappv2/TestDAppV2.json index 3117879927..632521fa63 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.json +++ b/pkg/contracts/testdappv2/TestDAppV2.json @@ -216,9 +216,9 @@ "type": "address" }, { - "internalType": "uint64", + "internalType": "uint256", "name": "amount", - "type": "uint64" + "type": "uint256" }, { "internalType": "bytes", @@ -286,5 +286,5 @@ "type": "receive" } ], - "bin": "608060405234801561001057600080fd5b5061150a806100206000396000f3fe6080604052600436106100c65760003560e01c8063a799911f1161007f578063de43156e11610059578063de43156e14610267578063e2842ed714610290578063f592cbfb146102cd578063f936ae851461030a576100cd565b8063a799911f146101f9578063c234fecf14610215578063c7a339a91461023e576100cd565b806336e980a0146100d25780634297a263146100fb57806359f4a777146101385780635ac1e07014610163578063676cc0541461018c5780639291fe26146101bc576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610de7565b610347565b005b34801561010757600080fd5b50610122600480360381019061011d9190610d02565b610371565b60405161012f9190611173565b60405180910390f35b34801561014457600080fd5b5061014d610389565b60405161015a91906110c4565b60405180910390f35b34801561016f57600080fd5b5061018a60048036038101906101859190610e90565b6103ad565b005b6101a660048036038101906101a19190610e30565b6104e7565b6040516101b39190611131565b60405180910390f35b3480156101c857600080fd5b506101e360048036038101906101de9190610de7565b61069c565b6040516101f09190611173565b60405180910390f35b610213600480360381019061020e9190610de7565b6106df565b005b34801561022157600080fd5b5061023c60048036038101906102379190610ca8565b610708565b005b34801561024a57600080fd5b5061026560048036038101906102609190610d78565b61074b565b005b34801561027357600080fd5b5061028e60048036038101906102899190610ed9565b61080e565b005b34801561029c57600080fd5b506102b760048036038101906102b29190610d02565b610907565b6040516102c49190611116565b60405180910390f35b3480156102d957600080fd5b506102f460048036038101906102ef9190610de7565b610927565b6040516103019190611116565b60405180910390f35b34801561031657600080fd5b50610331600480360381019061032c9190610d2f565b610977565b60405161033e91906110c4565b60405180910390f35b610350816109c0565b1561035a57600080fd5b61036381610a16565b61036e816000610a6a565b50565b60036020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6104088180606001906103c0919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61046581806060019061041b919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000610a6a565b8060000160208101906104789190610ca8565b600282806060019061048a919061118e565b60405161049892919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160208101906105339190610ca8565b73ffffffffffffffffffffffffffffffffffffffff1614610589576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161058090611153565b60405180910390fd5b6105d683838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61062483838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505034610a6a565b8360000160208101906106379190610ca8565b6002848460405161064992919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060036000836040516020016106b39190611098565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6106e8816109c0565b156106f257600080fd5b6106fb81610a16565b6107058134610a6a565b50565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610754816109c0565b1561075e57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b815260040161079b939291906110df565b602060405180830381600087803b1580156107b557600080fd5b505af11580156107c9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107ed9190610cd5565b6107f657600080fd5b6107ff81610a16565b6108098183610a6a565b505050565b61085b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506109c0565b1561086557600080fd5b6108b282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61090082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a6a565b5050505050565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600160008360405160200161093e9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6002818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040516020016109d1906110af565b60405160208183030381529060405280519060200120826040516020016109f89190611098565b60405160208183030381529060405280519060200120149050919050565b600180600083604051602001610a2c9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806003600084604051602001610a809190611098565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000610abf610aba84611216565b6111f1565b905082815260208101848484011115610adb57610ada6113ef565b5b610ae684828561132a565b509392505050565b6000610b01610afc84611247565b6111f1565b905082815260208101848484011115610b1d57610b1c6113ef565b5b610b2884828561132a565b509392505050565b600081359050610b3f81611461565b92915050565b600081519050610b5481611478565b92915050565b600081359050610b698161148f565b92915050565b60008083601f840112610b8557610b846113d1565b5b8235905067ffffffffffffffff811115610ba257610ba16113cc565b5b602083019150836001820283011115610bbe57610bbd6113e5565b5b9250929050565b600082601f830112610bda57610bd96113d1565b5b8135610bea848260208601610aac565b91505092915050565b600081359050610c02816114a6565b92915050565b600082601f830112610c1d57610c1c6113d1565b5b8135610c2d848260208601610aee565b91505092915050565b600060208284031215610c4c57610c4b6113db565b5b81905092915050565b600060808284031215610c6b57610c6a6113db565b5b81905092915050565b600060608284031215610c8a57610c896113db565b5b81905092915050565b600081359050610ca2816114bd565b92915050565b600060208284031215610cbe57610cbd6113f9565b5b6000610ccc84828501610b30565b91505092915050565b600060208284031215610ceb57610cea6113f9565b5b6000610cf984828501610b45565b91505092915050565b600060208284031215610d1857610d176113f9565b5b6000610d2684828501610b5a565b91505092915050565b600060208284031215610d4557610d446113f9565b5b600082013567ffffffffffffffff811115610d6357610d626113f4565b5b610d6f84828501610bc5565b91505092915050565b600080600060608486031215610d9157610d906113f9565b5b6000610d9f86828701610bf3565b9350506020610db086828701610c93565b925050604084013567ffffffffffffffff811115610dd157610dd06113f4565b5b610ddd86828701610c08565b9150509250925092565b600060208284031215610dfd57610dfc6113f9565b5b600082013567ffffffffffffffff811115610e1b57610e1a6113f4565b5b610e2784828501610c08565b91505092915050565b600080600060408486031215610e4957610e486113f9565b5b6000610e5786828701610c36565b935050602084013567ffffffffffffffff811115610e7857610e776113f4565b5b610e8486828701610b6f565b92509250509250925092565b600060208284031215610ea657610ea56113f9565b5b600082013567ffffffffffffffff811115610ec457610ec36113f4565b5b610ed084828501610c55565b91505092915050565b600080600080600060808688031215610ef557610ef46113f9565b5b600086013567ffffffffffffffff811115610f1357610f126113f4565b5b610f1f88828901610c74565b9550506020610f3088828901610b30565b9450506040610f4188828901610c93565b935050606086013567ffffffffffffffff811115610f6257610f616113f4565b5b610f6e88828901610b6f565b92509250509295509295909350565b610f86816112c6565b82525050565b610f95816112d8565b82525050565b6000610fa7838561129f565b9350610fb483858461132a565b82840190509392505050565b6000610fcb82611278565b610fd5818561128e565b9350610fe5818560208601611339565b610fee816113fe565b840191505092915050565b600061100482611283565b61100e81856112bb565b935061101e818560208601611339565b80840191505092915050565b60006110376016836112aa565b91506110428261140f565b602082019050919050565b600061105a6006836112bb565b915061106582611438565b600682019050919050565b61107981611320565b82525050565b600061108c828486610f9b565b91508190509392505050565b60006110a48284610ff9565b915081905092915050565b60006110ba8261104d565b9150819050919050565b60006020820190506110d96000830184610f7d565b92915050565b60006060820190506110f46000830186610f7d565b6111016020830185610f7d565b61110e6040830184611070565b949350505050565b600060208201905061112b6000830184610f8c565b92915050565b6000602082019050818103600083015261114b8184610fc0565b905092915050565b6000602082019050818103600083015261116c8161102a565b9050919050565b60006020820190506111886000830184611070565b92915050565b600080833560016020038436030381126111ab576111aa6113e0565b5b80840192508235915067ffffffffffffffff8211156111cd576111cc6113d6565b5b6020830192506001820236038313156111e9576111e86113ea565b5b509250929050565b60006111fb61120c565b9050611207828261136c565b919050565b6000604051905090565b600067ffffffffffffffff8211156112315761123061139d565b5b61123a826113fe565b9050602081019050919050565b600067ffffffffffffffff8211156112625761126161139d565b5b61126b826113fe565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006112d182611300565b9050919050565b60008115159050919050565b6000819050919050565b60006112f9826112c6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561135757808201518184015260208101905061133c565b83811115611366576000848401525b50505050565b611375826113fe565b810181811067ffffffffffffffff821117156113945761139361139d565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f756e61757468656e746963617465642073656e64657200000000000000000000600082015250565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61146a816112c6565b811461147557600080fd5b50565b611481816112d8565b811461148c57600080fd5b50565b611498816112e4565b81146114a357600080fd5b50565b6114af816112ee565b81146114ba57600080fd5b50565b6114c681611320565b81146114d157600080fd5b5056fea2646970667358221220e090c5cd81361f8bba5d13d4fb801ab148714dad774e12a4acf812e341dc93c564736f6c63430008070033" + "bin": "608060405234801561001057600080fd5b5061150a806100206000396000f3fe6080604052600436106100c65760003560e01c8063c234fecf1161007f578063de43156e11610059578063de43156e14610267578063e2842ed714610290578063f592cbfb146102cd578063f936ae851461030a576100cd565b8063c234fecf146101ec578063c7a339a914610215578063c9028a361461023e576100cd565b806336e980a0146100d25780634297a263146100fb57806359f4a77714610138578063676cc054146101635780639291fe2614610193578063a799911f146101d0576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610de7565b610347565b005b34801561010757600080fd5b50610122600480360381019061011d9190610d02565b610371565b60405161012f9190611173565b60405180910390f35b34801561014457600080fd5b5061014d610389565b60405161015a91906110c4565b60405180910390f35b61017d60048036038101906101789190610e30565b6103ad565b60405161018a9190611131565b60405180910390f35b34801561019f57600080fd5b506101ba60048036038101906101b59190610de7565b610562565b6040516101c79190611173565b60405180910390f35b6101ea60048036038101906101e59190610de7565b6105a5565b005b3480156101f857600080fd5b50610213600480360381019061020e9190610ca8565b6105ce565b005b34801561022157600080fd5b5061023c60048036038101906102379190610d78565b610611565b005b34801561024a57600080fd5b5061026560048036038101906102609190610e90565b6106d4565b005b34801561027357600080fd5b5061028e60048036038101906102899190610ed9565b61080e565b005b34801561029c57600080fd5b506102b760048036038101906102b29190610d02565b610907565b6040516102c49190611116565b60405180910390f35b3480156102d957600080fd5b506102f460048036038101906102ef9190610de7565b610927565b6040516103019190611116565b60405180910390f35b34801561031657600080fd5b50610331600480360381019061032c9190610d2f565b610977565b60405161033e91906110c4565b60405180910390f35b610350816109c0565b1561035a57600080fd5b61036381610a16565b61036e816000610a6a565b50565b60036020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160208101906103f99190610ca8565b73ffffffffffffffffffffffffffffffffffffffff161461044f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044690611153565b60405180910390fd5b61049c83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b6104ea83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505034610a6a565b8360000160208101906104fd9190610ca8565b6002848460405161050f92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060036000836040516020016105799190611098565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105ae816109c0565b156105b857600080fd5b6105c181610a16565b6105cb8134610a6a565b50565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61061a816109c0565b1561062457600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b8152600401610661939291906110df565b602060405180830381600087803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190610cd5565b6106bc57600080fd5b6106c581610a16565b6106cf8183610a6a565b505050565b61072f8180606001906106e7919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61078c818060600190610742919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000610a6a565b80600001602081019061079f9190610ca8565b60028280606001906107b1919061118e565b6040516107bf92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61085b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506109c0565b1561086557600080fd5b6108b282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61090082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a6a565b5050505050565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600160008360405160200161093e9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6002818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040516020016109d1906110af565b60405160208183030381529060405280519060200120826040516020016109f89190611098565b60405160208183030381529060405280519060200120149050919050565b600180600083604051602001610a2c9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806003600084604051602001610a809190611098565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000610abf610aba84611216565b6111f1565b905082815260208101848484011115610adb57610ada6113ef565b5b610ae684828561132a565b509392505050565b6000610b01610afc84611247565b6111f1565b905082815260208101848484011115610b1d57610b1c6113ef565b5b610b2884828561132a565b509392505050565b600081359050610b3f81611461565b92915050565b600081519050610b5481611478565b92915050565b600081359050610b698161148f565b92915050565b60008083601f840112610b8557610b846113d1565b5b8235905067ffffffffffffffff811115610ba257610ba16113cc565b5b602083019150836001820283011115610bbe57610bbd6113e5565b5b9250929050565b600082601f830112610bda57610bd96113d1565b5b8135610bea848260208601610aac565b91505092915050565b600081359050610c02816114a6565b92915050565b600082601f830112610c1d57610c1c6113d1565b5b8135610c2d848260208601610aee565b91505092915050565b600060208284031215610c4c57610c4b6113db565b5b81905092915050565b600060808284031215610c6b57610c6a6113db565b5b81905092915050565b600060608284031215610c8a57610c896113db565b5b81905092915050565b600081359050610ca2816114bd565b92915050565b600060208284031215610cbe57610cbd6113f9565b5b6000610ccc84828501610b30565b91505092915050565b600060208284031215610ceb57610cea6113f9565b5b6000610cf984828501610b45565b91505092915050565b600060208284031215610d1857610d176113f9565b5b6000610d2684828501610b5a565b91505092915050565b600060208284031215610d4557610d446113f9565b5b600082013567ffffffffffffffff811115610d6357610d626113f4565b5b610d6f84828501610bc5565b91505092915050565b600080600060608486031215610d9157610d906113f9565b5b6000610d9f86828701610bf3565b9350506020610db086828701610c93565b925050604084013567ffffffffffffffff811115610dd157610dd06113f4565b5b610ddd86828701610c08565b9150509250925092565b600060208284031215610dfd57610dfc6113f9565b5b600082013567ffffffffffffffff811115610e1b57610e1a6113f4565b5b610e2784828501610c08565b91505092915050565b600080600060408486031215610e4957610e486113f9565b5b6000610e5786828701610c36565b935050602084013567ffffffffffffffff811115610e7857610e776113f4565b5b610e8486828701610b6f565b92509250509250925092565b600060208284031215610ea657610ea56113f9565b5b600082013567ffffffffffffffff811115610ec457610ec36113f4565b5b610ed084828501610c55565b91505092915050565b600080600080600060808688031215610ef557610ef46113f9565b5b600086013567ffffffffffffffff811115610f1357610f126113f4565b5b610f1f88828901610c74565b9550506020610f3088828901610b30565b9450506040610f4188828901610c93565b935050606086013567ffffffffffffffff811115610f6257610f616113f4565b5b610f6e88828901610b6f565b92509250509295509295909350565b610f86816112c6565b82525050565b610f95816112d8565b82525050565b6000610fa7838561129f565b9350610fb483858461132a565b82840190509392505050565b6000610fcb82611278565b610fd5818561128e565b9350610fe5818560208601611339565b610fee816113fe565b840191505092915050565b600061100482611283565b61100e81856112bb565b935061101e818560208601611339565b80840191505092915050565b60006110376016836112aa565b91506110428261140f565b602082019050919050565b600061105a6006836112bb565b915061106582611438565b600682019050919050565b61107981611320565b82525050565b600061108c828486610f9b565b91508190509392505050565b60006110a48284610ff9565b915081905092915050565b60006110ba8261104d565b9150819050919050565b60006020820190506110d96000830184610f7d565b92915050565b60006060820190506110f46000830186610f7d565b6111016020830185610f7d565b61110e6040830184611070565b949350505050565b600060208201905061112b6000830184610f8c565b92915050565b6000602082019050818103600083015261114b8184610fc0565b905092915050565b6000602082019050818103600083015261116c8161102a565b9050919050565b60006020820190506111886000830184611070565b92915050565b600080833560016020038436030381126111ab576111aa6113e0565b5b80840192508235915067ffffffffffffffff8211156111cd576111cc6113d6565b5b6020830192506001820236038313156111e9576111e86113ea565b5b509250929050565b60006111fb61120c565b9050611207828261136c565b919050565b6000604051905090565b600067ffffffffffffffff8211156112315761123061139d565b5b61123a826113fe565b9050602081019050919050565b600067ffffffffffffffff8211156112625761126161139d565b5b61126b826113fe565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006112d182611300565b9050919050565b60008115159050919050565b6000819050919050565b60006112f9826112c6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561135757808201518184015260208101905061133c565b83811115611366576000848401525b50505050565b611375826113fe565b810181811067ffffffffffffffff821117156113945761139361139d565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f756e61757468656e746963617465642073656e64657200000000000000000000600082015250565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61146a816112c6565b811461147557600080fd5b50565b611481816112d8565b811461148c57600080fd5b50565b611498816112e4565b81146114a357600080fd5b50565b6114af816112ee565b81146114ba57600080fd5b50565b6114c681611320565b81146114d157600080fd5b5056fea2646970667358221220da9e50cb7b79ace99166ed06c9234f984bc9599fca79796389af6656411f73f964736f6c63430008070033" } diff --git a/pkg/contracts/testdappv2/TestDAppV2.sol b/pkg/contracts/testdappv2/TestDAppV2.sol index 5f301a08cf..7919d13b5d 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.sol +++ b/pkg/contracts/testdappv2/TestDAppV2.sol @@ -20,7 +20,7 @@ contract TestDAppV2 { struct RevertContext { address sender; address asset; - uint64 amount; + uint256 amount; bytes revertMessage; } diff --git a/x/fungible/keeper/v2_evm.go b/x/fungible/keeper/v2_evm.go index 4f76606151..b2b76dc428 100644 --- a/x/fungible/keeper/v2_evm.go +++ b/x/fungible/keeper/v2_evm.go @@ -187,7 +187,7 @@ func (k Keeper) CallExecuteRevert( revert.RevertContext{ Sender: common.HexToAddress(inboundSender), Asset: zrc20, - Amount: amount.Uint64(), + Amount: amount, RevertMessage: message, }, ) @@ -241,7 +241,7 @@ func (k Keeper) CallDepositAndRevert( revert.RevertContext{ Sender: common.HexToAddress(inboundSender), Asset: zrc20, - Amount: amount.Uint64(), + Amount: amount, RevertMessage: message, }, ) diff --git a/zetaclient/chains/evm/signer/v2_sign.go b/zetaclient/chains/evm/signer/v2_sign.go index 510c0e2a4d..3a00a86c48 100644 --- a/zetaclient/chains/evm/signer/v2_sign.go +++ b/zetaclient/chains/evm/signer/v2_sign.go @@ -81,7 +81,7 @@ func (signer *Signer) signGatewayExecuteRevert( revert.RevertContext{ Sender: common.HexToAddress(inboundSender), Asset: txData.asset, - Amount: txData.amount.Uint64(), + Amount: txData.amount, RevertMessage: txData.revertOptions.RevertMessage, }, ) @@ -201,7 +201,7 @@ func (signer *Signer) signERC20CustodyWithdrawRevert( revert.RevertContext{ Sender: common.HexToAddress(inboundSender), Asset: txData.asset, - Amount: txData.amount.Uint64(), + Amount: txData.amount, RevertMessage: txData.revertOptions.RevertMessage, }, ) From 2146e4f1a2e007d788dfae018af15e52d8e658ee Mon Sep 17 00:00:00 2001 From: skosito Date: Tue, 15 Oct 2024 16:41:36 +0100 Subject: [PATCH 26/36] fix: fix admin e2e tests and bump protocol contracts (#3006) * bump protocol contracts * fix build and e2e tests * upgrade custody in upgrade tests * PR comments * fmt --- cmd/zetae2e/local/local.go | 12 +++--- .../localnet/orchestrator/start-zetae2e.sh | 4 +- e2e/runner/v2_setup_evm.go | 41 +++++++++++++------ e2e/runner/{v2_gateway.go => v2_upgrade.go} | 27 ++++++++++-- go.mod | 2 +- go.sum | 4 +- 6 files changed, 63 insertions(+), 27 deletions(-) rename e2e/runner/{v2_gateway.go => v2_upgrade.go} (62%) diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 588a74e367..2d404ba391 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -46,7 +46,7 @@ const ( flagTestV2Migration = "test-v2-migration" flagSkipTrackerCheck = "skip-tracker-check" flagSkipPrecompiles = "skip-precompiles" - flagUpgradeGateways = "upgrade-gateways" + flagUpgradeContracts = "upgrade-contracts" ) var ( @@ -84,7 +84,8 @@ func NewLocalCmd() *cobra.Command { cmd.Flags().Bool(flagTestV2Migration, false, "set to true to run tests for v2 contracts migration test") cmd.Flags().Bool(flagSkipTrackerCheck, false, "set to true to skip tracker check at the end of the tests") cmd.Flags().Bool(flagSkipPrecompiles, false, "set to true to skip stateful precompiled contracts test") - cmd.Flags().Bool(flagUpgradeGateways, false, "set to true to upgrade gateways during setup for ZEVM and EVM") + cmd.Flags(). + Bool(flagUpgradeContracts, false, "set to true to upgrade Gateways and ERC20Custody contracts during setup for ZEVM and EVM") return cmd } @@ -114,7 +115,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { testV2 = must(cmd.Flags().GetBool(flagTestV2)) testV2Migration = must(cmd.Flags().GetBool(flagTestV2Migration)) skipPrecompiles = must(cmd.Flags().GetBool(flagSkipPrecompiles)) - upgradeGateways = must(cmd.Flags().GetBool(flagUpgradeGateways)) + upgradeContracts = must(cmd.Flags().GetBool(flagUpgradeContracts)) ) logger := runner.NewLogger(verbose, color.FgWhite, "setup") @@ -413,9 +414,8 @@ func localE2ETest(cmd *cobra.Command, _ []string) { eg.Go(tonTestRoutine(conf, deployerRunner, verbose, tonTests...)) } - // upgrade gateways - if upgradeGateways { - deployerRunner.UpgradeGateways() + if upgradeContracts { + deployerRunner.UpgradeGatewaysAndERC20Custody() } if testV2 || testV2Migration { diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index e7374216f3..33f0d4e956 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -258,9 +258,9 @@ if [ "$LOCALNET_MODE" == "upgrade" ]; then # When the upgrade height is greater than 100 for upgrade test, the Bitcoin tests have been run once, therefore the Bitcoin wallet is already set up # Use light flag to skip advanced tests if [ "$UPGRADE_HEIGHT" -lt 100 ]; then - zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --light --test-v2 --upgrade-gateways ${COMMON_ARGS} + zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --light --test-v2 --upgrade-contracts ${COMMON_ARGS} else - zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --skip-bitcoin-setup --light --test-v2 --upgrade-gateways ${COMMON_ARGS} + zetae2e local $E2E_ARGS --skip-setup --config "$deployed_config_path" --skip-bitcoin-setup --light --test-v2 --upgrade-contracts ${COMMON_ARGS} fi ZETAE2E_EXIT_CODE=$? diff --git a/e2e/runner/v2_setup_evm.go b/e2e/runner/v2_setup_evm.go index 37f6423f29..5b8e686d9b 100644 --- a/e2e/runner/v2_setup_evm.go +++ b/e2e/runner/v2_setup_evm.go @@ -48,8 +48,8 @@ func (r *E2ERunner) SetupEVMV2() { initializerData, err := gatewayEVMABI.Pack("initialize", r.TSSAddress, r.ZetaEthAddr, r.Account.EVMAddress()) require.NoError(r, err) - // Deploy the proxy contract - proxyAddress, txProxy, _, err := erc1967proxy.DeployERC1967Proxy( + // Deploy gateway proxy contract + gatewayProxyAddress, gatewayProxyTx, _, err := erc1967proxy.DeployERC1967Proxy( r.EVMAuth, r.EVMClient, gatewayEVMAddr, @@ -57,33 +57,47 @@ func (r *E2ERunner) SetupEVMV2() { ) require.NoError(r, err) - r.GatewayEVMAddr = proxyAddress - r.GatewayEVM, err = gatewayevm.NewGatewayEVM(proxyAddress, r.EVMClient) + r.GatewayEVMAddr = gatewayProxyAddress + r.GatewayEVM, err = gatewayevm.NewGatewayEVM(gatewayProxyAddress, r.EVMClient) require.NoError(r, err) r.Logger.Info("Gateway EVM contract address: %s, tx hash: %s", gatewayEVMAddr.Hex(), txGateway.Hash().Hex()) + // Deploy erc20custody proxy contract r.Logger.Info("Deploying ERC20Custody contract") - erc20CustodyNewAddr, txCustody, erc20CustodyNew, err := erc20custodyv2.DeployERC20Custody( + erc20CustodyAddr, txCustody, _, err := erc20custodyv2.DeployERC20Custody(r.EVMAuth, r.EVMClient) + require.NoError(r, err) + + ensureTxReceipt(txCustody, "ERC20Custody deployment failed") + + erc20CustodyABI, err := erc20custodyv2.ERC20CustodyMetaData.GetAbi() + require.NoError(r, err) + + // Encode the initializer data + initializerData, err = erc20CustodyABI.Pack("initialize", r.GatewayEVMAddr, r.TSSAddress, r.Account.EVMAddress()) + require.NoError(r, err) + + // Deploy erc20custody proxy contract + erc20CustodyProxyAddress, erc20ProxyTx, _, err := erc1967proxy.DeployERC1967Proxy( r.EVMAuth, r.EVMClient, - r.GatewayEVMAddr, - r.TSSAddress, - r.Account.EVMAddress(), + erc20CustodyAddr, + initializerData, ) require.NoError(r, err) - r.ERC20CustodyV2Addr = erc20CustodyNewAddr - r.ERC20CustodyV2 = erc20CustodyNew + r.ERC20CustodyV2Addr = erc20CustodyProxyAddress + r.ERC20CustodyV2, err = erc20custodyv2.NewERC20Custody(erc20CustodyProxyAddress, r.EVMClient) + require.NoError(r, err) r.Logger.Info( "ERC20CustodyV2 contract address: %s, tx hash: %s", - erc20CustodyNewAddr.Hex(), + erc20CustodyAddr.Hex(), txCustody.Hash().Hex(), ) ensureTxReceipt(txCustody, "ERC20CustodyV2 deployment failed") // set custody contract in gateway - txSetCustody, err := r.GatewayEVM.SetCustody(r.EVMAuth, erc20CustodyNewAddr) + txSetCustody, err := r.GatewayEVM.SetCustody(r.EVMAuth, erc20CustodyProxyAddress) require.NoError(r, err) // deploy test dapp v2 @@ -96,7 +110,8 @@ func (r *E2ERunner) SetupEVMV2() { // check contract deployment receipt ensureTxReceipt(txDonation, "EVM donation tx failed") - ensureTxReceipt(txProxy, "Gateway proxy deployment failed") + ensureTxReceipt(gatewayProxyTx, "Gateway proxy deployment failed") + ensureTxReceipt(erc20ProxyTx, "ERC20Custody proxy deployment failed") ensureTxReceipt(txSetCustody, "Set custody in Gateway failed") ensureTxReceipt(txTestDAppV2, "TestDAppV2 deployment failed") diff --git a/e2e/runner/v2_gateway.go b/e2e/runner/v2_upgrade.go similarity index 62% rename from e2e/runner/v2_gateway.go rename to e2e/runner/v2_upgrade.go index 2bede9e3fe..eb5af7f860 100644 --- a/e2e/runner/v2_gateway.go +++ b/e2e/runner/v2_upgrade.go @@ -3,17 +3,19 @@ package runner import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/v2/pkg/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol" "github.com/zeta-chain/node/e2e/utils" ) -// UpgradeGateways upgrades the GatewayEVM and GatewayZEVM contracts -// It deploy new gateway contract implementation with the current imported artifacts and upgrade the gateway contract -func (r *E2ERunner) UpgradeGateways() { +// UpgradeGatewaysAndERC20Custody upgrades gateways and ERC20Custody contracts +// It deploys new contract implementation with the current imported artifacts and upgrades the contract +func (r *E2ERunner) UpgradeGatewaysAndERC20Custody() { r.UpgradeGatewayZEVM() r.UpgradeGatewayEVM() + r.UpgradeERC20Custody() } // UpgradeGatewayZEVM upgrades the GatewayZEVM contract @@ -53,3 +55,22 @@ func (r *E2ERunner) UpgradeGatewayEVM() { require.NoError(r, err) ensureTxReceipt(txUpgrade, "GatewayEVM upgrade failed") } + +// UpgradeERC20CustodyZEVM upgrades the ERC20Custody contract +func (r *E2ERunner) UpgradeERC20Custody() { + ensureTxReceipt := func(tx *ethtypes.Transaction, failMessage string) { + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) + r.requireTxSuccessful(receipt, failMessage+" tx hash: "+tx.Hash().Hex()) + } + + r.Logger.Info("Upgrading ERC20Custody contract") + // Deploy the new erc20Custody contract implementation + newImplementationAddress, txDeploy, _, err := erc20custody.DeployERC20Custody(r.EVMAuth, r.EVMClient) + require.NoError(r, err) + ensureTxReceipt(txDeploy, "New ERC20Custody implementation deployment failed") + + // Upgrade + txUpgrade, err := r.ERC20CustodyV2.UpgradeToAndCall(r.EVMAuth, newImplementationAddress, []byte{}) + require.NoError(r, err) + ensureTxReceipt(txUpgrade, "ERC20Custody upgrade failed") +} diff --git a/go.mod b/go.mod index 23dae42fae..cb746a49bf 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/zeta-chain/ethermint v0.0.0-20241010181243-044e22bdb7e7 github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 - github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241009160411-475acfac26ef + github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241014093550-f7f6d9fd971a gitlab.com/thorchain/tss/go-tss v1.6.5 go.nhat.io/grpcmock v0.25.0 golang.org/x/crypto v0.23.0 diff --git a/go.sum b/go.sum index f5be31056c..8842365a96 100644 --- a/go.sum +++ b/go.sum @@ -4208,8 +4208,8 @@ github.com/zeta-chain/go-tss v0.0.0-20240916173049-89fee4b0ae7f h1:XqUvw9a3EnDa2 github.com/zeta-chain/go-tss v0.0.0-20240916173049-89fee4b0ae7f/go.mod h1:B1FDE6kHs8hozKSX1/iXgCdvlFbS6+FeAupoBHDK0Cc= github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 h1:vck/FcIIpFOvpBUm0NO17jbEtmSz/W/a5Y4jRuSJl6I= github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138/go.mod h1:U494OsZTWsU75hqoriZgMdSsgSGP1mUL1jX+wN/Aez8= -github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241009160411-475acfac26ef h1:tfF31iib7rTeBLGrvWMbW2HM6omkzPDjsX8QM2VY6a4= -github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241009160411-475acfac26ef/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w= +github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241014093550-f7f6d9fd971a h1:xsup+oupCrBtZT/jEaBGcL3k6KUlXWR7iXw/3RHBIpU= +github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241014093550-f7f6d9fd971a/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w= github.com/zeta-chain/tss-lib v0.0.0-20240916163010-2e6b438bd901 h1:9whtN5fjYHfk4yXIuAsYP2EHxImwDWDVUOnZJ2pfL3w= github.com/zeta-chain/tss-lib v0.0.0-20240916163010-2e6b438bd901/go.mod h1:d2iTC62s9JwKiCMPhcDDXbIZmuzAyJ4lwso0H5QyRbk= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= From ae6ab23ac732a5b0cfd92e4637f8ceb0441bfc1e Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 15 Oct 2024 19:41:00 +0200 Subject: [PATCH 27/36] fix: add legacy messages back to codec (#2909) * add supply field back * legacy messages * add to codec * add message definition * changelog * add MsgGasPriceVoter * add new message to codec * comments --- changelog.md | 1 + docs/spec/crosschain/messages.md | 1 + .../zetacore/crosschain/legacy_msgs.proto | 102 + proto/zetachain/zetacore/crosschain/tx.proto | 2 +- .../zetachain/zetacore/crosschain/index.d.ts | 1 + .../zetacore/crosschain/legacy_msgs_pb.d.ts | 389 +++ .../zetachain/zetacore/crosschain/tx_pb.d.ts | 6 + x/crosschain/types/codec.go | 16 + x/crosschain/types/legacy_msgs.go | 181 + x/crosschain/types/legacy_msgs.pb.go | 3002 +++++++++++++++++ x/crosschain/types/tx.pb.go | 281 +- 11 files changed, 3867 insertions(+), 115 deletions(-) create mode 100644 proto/zetachain/zetacore/crosschain/legacy_msgs.proto create mode 100644 typescript/zetachain/zetacore/crosschain/legacy_msgs_pb.d.ts create mode 100644 x/crosschain/types/legacy_msgs.go create mode 100644 x/crosschain/types/legacy_msgs.pb.go diff --git a/changelog.md b/changelog.md index e25f46e129..8bfbae13f7 100644 --- a/changelog.md +++ b/changelog.md @@ -50,6 +50,7 @@ * [2842](https://github.com/zeta-chain/node/pull/2842) - fix: move interval assignment out of cctx loop in EVM outbound tx scheduler * [2853](https://github.com/zeta-chain/node/pull/2853) - calling precompile through sc with sc state update * [2925](https://github.com/zeta-chain/node/pull/2925) - add recover to init chainer to diplay informative message when starting a node from block 1 +* [2909](https://github.com/zeta-chain/node/pull/2909) - add legacy messages back to codec for querier backward compatibility ## v20.0.0 diff --git a/docs/spec/crosschain/messages.md b/docs/spec/crosschain/messages.md index c369443d27..b12149de9e 100644 --- a/docs/spec/crosschain/messages.md +++ b/docs/spec/crosschain/messages.md @@ -63,6 +63,7 @@ message MsgVoteGasPrice { uint64 price = 3; uint64 priority_fee = 6; uint64 block_number = 4; + string supply = 5; } ``` diff --git a/proto/zetachain/zetacore/crosschain/legacy_msgs.proto b/proto/zetachain/zetacore/crosschain/legacy_msgs.proto new file mode 100644 index 0000000000..452ce0d94d --- /dev/null +++ b/proto/zetachain/zetacore/crosschain/legacy_msgs.proto @@ -0,0 +1,102 @@ +syntax = "proto3"; +package zetachain.zetacore.crosschain; + +import "gogoproto/gogo.proto"; +import "zetachain/zetacore/pkg/chains/chains.proto"; +import "zetachain/zetacore/pkg/coin/coin.proto"; +import "zetachain/zetacore/pkg/proofs/proofs.proto"; +import "zetachain/zetacore/crosschain/rate_limiter_flags.proto"; +import "zetachain/zetacore/crosschain/cross_chain_tx.proto"; + +option go_package = "github.com/zeta-chain/node/x/crosschain/types"; + +// legacy MsgAddOutboundTracker +// defined to keep codec compatibility +message MsgAddToOutTxTracker { + string creator = 1; + int64 chain_id = 2; + uint64 nonce = 3; + string tx_hash = 4; + pkg.proofs.Proof proof = 5; + string block_hash = 6; + int64 tx_index = 7; +} + +// legacy MsgAddInboundTracker +// defined to keep codec compatibility +message MsgAddToInTxTracker { + string creator = 1; + int64 chain_id = 2; + string tx_hash = 3; + pkg.coin.CoinType coin_type = 4; + pkg.proofs.Proof proof = 5; + string block_hash = 6; + int64 tx_index = 7; +} + +// legacy MsgRemoveOutboundTracker +// defined to keep codec compatibility +message MsgRemoveFromOutTxTracker { + string creator = 1; + int64 chain_id = 2; + uint64 nonce = 3; +} + +// legacy MsgVoteOutbound +// defined to keep codec compatibility +message MsgVoteOnObservedOutboundTx { + string creator = 1; + string cctx_hash = 2; + string observed_outTx_hash = 3; + uint64 observed_outTx_blockHeight = 4; + uint64 observed_outTx_gas_used = 10; + string observed_outTx_effective_gas_price = 11 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + uint64 observed_outTx_effective_gas_limit = 12; + string value_received = 5 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"value_received\"" + ]; + pkg.chains.ReceiveStatus status = 6; + int64 outTx_chain = 7; + uint64 outTx_tss_nonce = 8; + pkg.coin.CoinType coin_type = 9; +} + +// legacy MsgVoteInbound +// defined to keep codec compatibility +message MsgVoteOnObservedInboundTx { + string creator = 1; + string sender = 2; + int64 sender_chain_id = 3; + string receiver = 4; + int64 receiver_chain = 5; + // string zeta_burnt = 6; + string amount = 6 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", + (gogoproto.nullable) = false + ]; + // string mMint = 7; + string message = 8; + string in_tx_hash = 9; + uint64 in_block_height = 10; + uint64 gas_limit = 11; + pkg.coin.CoinType coin_type = 12; + string tx_origin = 13; + string asset = 14; + // event index of the sent asset in the observed tx + uint64 event_index = 15; +} + +// legacy MsgVoteGasPrice +// defined to keep codec compatibility +message MsgGasPriceVoter { + string creator = 1; + int64 chain_id = 2; + uint64 price = 3; + uint64 block_number = 4; + string supply = 5; +} diff --git a/proto/zetachain/zetacore/crosschain/tx.proto b/proto/zetachain/zetacore/crosschain/tx.proto index 59a449ddfc..9499a7c25c 100644 --- a/proto/zetachain/zetacore/crosschain/tx.proto +++ b/proto/zetachain/zetacore/crosschain/tx.proto @@ -119,7 +119,7 @@ message MsgVoteGasPrice { uint64 block_number = 4; - reserved 5; // deprecated `string supply` + string supply = 5 [ deprecated = true ]; } message MsgVoteGasPriceResponse {} diff --git a/typescript/zetachain/zetacore/crosschain/index.d.ts b/typescript/zetachain/zetacore/crosschain/index.d.ts index d5819411ec..8f9ae8e678 100644 --- a/typescript/zetachain/zetacore/crosschain/index.d.ts +++ b/typescript/zetachain/zetacore/crosschain/index.d.ts @@ -5,6 +5,7 @@ export * from "./genesis_pb"; export * from "./inbound_hash_to_cctx_pb"; export * from "./inbound_tracker_pb"; export * from "./last_block_height_pb"; +export * from "./legacy_msgs_pb"; export * from "./outbound_tracker_pb"; export * from "./query_pb"; export * from "./rate_limiter_flags_pb"; diff --git a/typescript/zetachain/zetacore/crosschain/legacy_msgs_pb.d.ts b/typescript/zetachain/zetacore/crosschain/legacy_msgs_pb.d.ts new file mode 100644 index 0000000000..fe99443d97 --- /dev/null +++ b/typescript/zetachain/zetacore/crosschain/legacy_msgs_pb.d.ts @@ -0,0 +1,389 @@ +// @generated by protoc-gen-es v1.3.0 with parameter "target=dts" +// @generated from file zetachain/zetacore/crosschain/legacy_msgs.proto (package zetachain.zetacore.crosschain, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; +import { Message, proto3 } from "@bufbuild/protobuf"; +import type { Proof } from "../pkg/proofs/proofs_pb.js"; +import type { CoinType } from "../pkg/coin/coin_pb.js"; +import type { ReceiveStatus } from "../pkg/chains/chains_pb.js"; + +/** + * legacy MsgAddOutboundTracker + * defined to keep codec compatibility + * + * @generated from message zetachain.zetacore.crosschain.MsgAddToOutTxTracker + */ +export declare class MsgAddToOutTxTracker extends Message { + /** + * @generated from field: string creator = 1; + */ + creator: string; + + /** + * @generated from field: int64 chain_id = 2; + */ + chainId: bigint; + + /** + * @generated from field: uint64 nonce = 3; + */ + nonce: bigint; + + /** + * @generated from field: string tx_hash = 4; + */ + txHash: string; + + /** + * @generated from field: zetachain.zetacore.pkg.proofs.Proof proof = 5; + */ + proof?: Proof; + + /** + * @generated from field: string block_hash = 6; + */ + blockHash: string; + + /** + * @generated from field: int64 tx_index = 7; + */ + txIndex: bigint; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.MsgAddToOutTxTracker"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): MsgAddToOutTxTracker; + + static fromJson(jsonValue: JsonValue, options?: Partial): MsgAddToOutTxTracker; + + static fromJsonString(jsonString: string, options?: Partial): MsgAddToOutTxTracker; + + static equals(a: MsgAddToOutTxTracker | PlainMessage | undefined, b: MsgAddToOutTxTracker | PlainMessage | undefined): boolean; +} + +/** + * legacy MsgAddInboundTracker + * defined to keep codec compatibility + * + * @generated from message zetachain.zetacore.crosschain.MsgAddToInTxTracker + */ +export declare class MsgAddToInTxTracker extends Message { + /** + * @generated from field: string creator = 1; + */ + creator: string; + + /** + * @generated from field: int64 chain_id = 2; + */ + chainId: bigint; + + /** + * @generated from field: string tx_hash = 3; + */ + txHash: string; + + /** + * @generated from field: zetachain.zetacore.pkg.coin.CoinType coin_type = 4; + */ + coinType: CoinType; + + /** + * @generated from field: zetachain.zetacore.pkg.proofs.Proof proof = 5; + */ + proof?: Proof; + + /** + * @generated from field: string block_hash = 6; + */ + blockHash: string; + + /** + * @generated from field: int64 tx_index = 7; + */ + txIndex: bigint; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.MsgAddToInTxTracker"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): MsgAddToInTxTracker; + + static fromJson(jsonValue: JsonValue, options?: Partial): MsgAddToInTxTracker; + + static fromJsonString(jsonString: string, options?: Partial): MsgAddToInTxTracker; + + static equals(a: MsgAddToInTxTracker | PlainMessage | undefined, b: MsgAddToInTxTracker | PlainMessage | undefined): boolean; +} + +/** + * legacy MsgRemoveOutboundTracker + * defined to keep codec compatibility + * + * @generated from message zetachain.zetacore.crosschain.MsgRemoveFromOutTxTracker + */ +export declare class MsgRemoveFromOutTxTracker extends Message { + /** + * @generated from field: string creator = 1; + */ + creator: string; + + /** + * @generated from field: int64 chain_id = 2; + */ + chainId: bigint; + + /** + * @generated from field: uint64 nonce = 3; + */ + nonce: bigint; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.MsgRemoveFromOutTxTracker"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): MsgRemoveFromOutTxTracker; + + static fromJson(jsonValue: JsonValue, options?: Partial): MsgRemoveFromOutTxTracker; + + static fromJsonString(jsonString: string, options?: Partial): MsgRemoveFromOutTxTracker; + + static equals(a: MsgRemoveFromOutTxTracker | PlainMessage | undefined, b: MsgRemoveFromOutTxTracker | PlainMessage | undefined): boolean; +} + +/** + * legacy MsgVoteOutbound + * defined to keep codec compatibility + * + * @generated from message zetachain.zetacore.crosschain.MsgVoteOnObservedOutboundTx + */ +export declare class MsgVoteOnObservedOutboundTx extends Message { + /** + * @generated from field: string creator = 1; + */ + creator: string; + + /** + * @generated from field: string cctx_hash = 2; + */ + cctxHash: string; + + /** + * @generated from field: string observed_outTx_hash = 3; + */ + observedOutTxHash: string; + + /** + * @generated from field: uint64 observed_outTx_blockHeight = 4; + */ + observedOutTxBlockHeight: bigint; + + /** + * @generated from field: uint64 observed_outTx_gas_used = 10; + */ + observedOutTxGasUsed: bigint; + + /** + * @generated from field: string observed_outTx_effective_gas_price = 11; + */ + observedOutTxEffectiveGasPrice: string; + + /** + * @generated from field: uint64 observed_outTx_effective_gas_limit = 12; + */ + observedOutTxEffectiveGasLimit: bigint; + + /** + * @generated from field: string value_received = 5; + */ + valueReceived: string; + + /** + * @generated from field: zetachain.zetacore.pkg.chains.ReceiveStatus status = 6; + */ + status: ReceiveStatus; + + /** + * @generated from field: int64 outTx_chain = 7; + */ + outTxChain: bigint; + + /** + * @generated from field: uint64 outTx_tss_nonce = 8; + */ + outTxTssNonce: bigint; + + /** + * @generated from field: zetachain.zetacore.pkg.coin.CoinType coin_type = 9; + */ + coinType: CoinType; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.MsgVoteOnObservedOutboundTx"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): MsgVoteOnObservedOutboundTx; + + static fromJson(jsonValue: JsonValue, options?: Partial): MsgVoteOnObservedOutboundTx; + + static fromJsonString(jsonString: string, options?: Partial): MsgVoteOnObservedOutboundTx; + + static equals(a: MsgVoteOnObservedOutboundTx | PlainMessage | undefined, b: MsgVoteOnObservedOutboundTx | PlainMessage | undefined): boolean; +} + +/** + * legacy MsgVoteInbound + * defined to keep codec compatibility + * + * @generated from message zetachain.zetacore.crosschain.MsgVoteOnObservedInboundTx + */ +export declare class MsgVoteOnObservedInboundTx extends Message { + /** + * @generated from field: string creator = 1; + */ + creator: string; + + /** + * @generated from field: string sender = 2; + */ + sender: string; + + /** + * @generated from field: int64 sender_chain_id = 3; + */ + senderChainId: bigint; + + /** + * @generated from field: string receiver = 4; + */ + receiver: string; + + /** + * @generated from field: int64 receiver_chain = 5; + */ + receiverChain: bigint; + + /** + * string zeta_burnt = 6; + * + * @generated from field: string amount = 6; + */ + amount: string; + + /** + * string mMint = 7; + * + * @generated from field: string message = 8; + */ + message: string; + + /** + * @generated from field: string in_tx_hash = 9; + */ + inTxHash: string; + + /** + * @generated from field: uint64 in_block_height = 10; + */ + inBlockHeight: bigint; + + /** + * @generated from field: uint64 gas_limit = 11; + */ + gasLimit: bigint; + + /** + * @generated from field: zetachain.zetacore.pkg.coin.CoinType coin_type = 12; + */ + coinType: CoinType; + + /** + * @generated from field: string tx_origin = 13; + */ + txOrigin: string; + + /** + * @generated from field: string asset = 14; + */ + asset: string; + + /** + * event index of the sent asset in the observed tx + * + * @generated from field: uint64 event_index = 15; + */ + eventIndex: bigint; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.MsgVoteOnObservedInboundTx"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): MsgVoteOnObservedInboundTx; + + static fromJson(jsonValue: JsonValue, options?: Partial): MsgVoteOnObservedInboundTx; + + static fromJsonString(jsonString: string, options?: Partial): MsgVoteOnObservedInboundTx; + + static equals(a: MsgVoteOnObservedInboundTx | PlainMessage | undefined, b: MsgVoteOnObservedInboundTx | PlainMessage | undefined): boolean; +} + +/** + * legacy MsgVoteGasPrice + * defined to keep codec compatibility + * + * @generated from message zetachain.zetacore.crosschain.MsgGasPriceVoter + */ +export declare class MsgGasPriceVoter extends Message { + /** + * @generated from field: string creator = 1; + */ + creator: string; + + /** + * @generated from field: int64 chain_id = 2; + */ + chainId: bigint; + + /** + * @generated from field: uint64 price = 3; + */ + price: bigint; + + /** + * @generated from field: uint64 block_number = 4; + */ + blockNumber: bigint; + + /** + * @generated from field: string supply = 5; + */ + supply: string; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.MsgGasPriceVoter"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): MsgGasPriceVoter; + + static fromJson(jsonValue: JsonValue, options?: Partial): MsgGasPriceVoter; + + static fromJsonString(jsonString: string, options?: Partial): MsgGasPriceVoter; + + static equals(a: MsgGasPriceVoter | PlainMessage | undefined, b: MsgGasPriceVoter | PlainMessage | undefined): boolean; +} + diff --git a/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts b/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts index 751371fa03..caee83f0cc 100644 --- a/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts +++ b/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts @@ -430,6 +430,12 @@ export declare class MsgVoteGasPrice extends Message { */ blockNumber: bigint; + /** + * @generated from field: string supply = 5 [deprecated = true]; + * @deprecated + */ + supply: string; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/x/crosschain/types/codec.go b/x/crosschain/types/codec.go index f45f745f5f..b93795aa3a 100644 --- a/x/crosschain/types/codec.go +++ b/x/crosschain/types/codec.go @@ -19,6 +19,14 @@ func RegisterCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgUpdateTssAddress{}, "crosschain/UpdateTssAddress", nil) cdc.RegisterConcrete(&MsgAbortStuckCCTX{}, "crosschain/AbortStuckCCTX", nil) cdc.RegisterConcrete(&MsgUpdateRateLimiterFlags{}, "crosschain/UpdateRateLimiterFlags", nil) + + // legacy messages defined for backward compatibility + cdc.RegisterConcrete(&MsgAddToInTxTracker{}, "crosschain/AddToInTxTracker", nil) + cdc.RegisterConcrete(&MsgAddToOutTxTracker{}, "crosschain/AddToOutTxTracker", nil) + cdc.RegisterConcrete(&MsgRemoveFromOutTxTracker{}, "crosschain/RemoveFromOutTxTracker", nil) + cdc.RegisterConcrete(&MsgVoteOnObservedOutboundTx{}, "crosschain/VoteOnObservedOutboundTx", nil) + cdc.RegisterConcrete(&MsgVoteOnObservedInboundTx{}, "crosschain/VoteOnObservedInboundTx", nil) + cdc.RegisterConcrete(&MsgGasPriceVoter{}, "crosschain/GasPriceVoter", nil) } func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { @@ -34,6 +42,14 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { &MsgUpdateTssAddress{}, &MsgAbortStuckCCTX{}, &MsgUpdateRateLimiterFlags{}, + + // legacy messages defined for backward compatibility + &MsgAddToInTxTracker{}, + &MsgAddToOutTxTracker{}, + &MsgRemoveFromOutTxTracker{}, + &MsgVoteOnObservedOutboundTx{}, + &MsgVoteOnObservedInboundTx{}, + &MsgGasPriceVoter{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) diff --git a/x/crosschain/types/legacy_msgs.go b/x/crosschain/types/legacy_msgs.go new file mode 100644 index 0000000000..8b29ae9507 --- /dev/null +++ b/x/crosschain/types/legacy_msgs.go @@ -0,0 +1,181 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/zeta-chain/node/pkg/authz" +) + +// MsgVoteOnObservedInboundTx + +var _ sdk.Msg = &MsgVoteOnObservedInboundTx{} + +func (msg *MsgVoteOnObservedInboundTx) Route() string { + return RouterKey +} + +func (msg *MsgVoteOnObservedInboundTx) Type() string { + return authz.InboundVoter.String() +} + +func (msg *MsgVoteOnObservedInboundTx) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgVoteOnObservedInboundTx) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgVoteOnObservedInboundTx) ValidateBasic() error { + return nil +} + +// MsgVoteOnObservedOutboundTx + +var _ sdk.Msg = &MsgVoteOnObservedOutboundTx{} + +func (msg *MsgVoteOnObservedOutboundTx) Route() string { + return RouterKey +} + +func (msg *MsgVoteOnObservedOutboundTx) Type() string { + return authz.OutboundVoter.String() +} + +func (msg *MsgVoteOnObservedOutboundTx) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgVoteOnObservedOutboundTx) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgVoteOnObservedOutboundTx) ValidateBasic() error { + return nil +} + +// MsgAddToInTxTracker + +var _ sdk.Msg = &MsgAddToInTxTracker{} + +func (msg *MsgAddToInTxTracker) Route() string { + return RouterKey +} + +func (msg *MsgAddToInTxTracker) Type() string { + return "AddToInTxTracker" +} + +func (msg *MsgAddToInTxTracker) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgAddToInTxTracker) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgAddToInTxTracker) ValidateBasic() error { + return nil +} + +// MsgAddToOutTxTracker + +var _ sdk.Msg = &MsgAddToOutTxTracker{} + +func (msg *MsgAddToOutTxTracker) Route() string { + return RouterKey +} + +func (msg *MsgAddToOutTxTracker) Type() string { + return "AddToOutTxTracker" +} + +func (msg *MsgAddToOutTxTracker) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgAddToOutTxTracker) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgAddToOutTxTracker) ValidateBasic() error { + return nil +} + +// MsgRemoveFromOutTxTracker + +var _ sdk.Msg = &MsgRemoveFromOutTxTracker{} + +func (msg *MsgRemoveFromOutTxTracker) Route() string { + return RouterKey +} + +func (msg *MsgRemoveFromOutTxTracker) Type() string { + return "RemoveFromOutTxTracker" +} + +func (msg *MsgRemoveFromOutTxTracker) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgRemoveFromOutTxTracker) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgRemoveFromOutTxTracker) ValidateBasic() error { + return nil +} + +// MsgGasPriceVoter + +var _ sdk.Msg = &MsgGasPriceVoter{} + +func (msg *MsgGasPriceVoter) Route() string { + return RouterKey +} + +func (msg *MsgGasPriceVoter) Type() string { + return "GasPriceVoter" +} + +func (msg *MsgGasPriceVoter) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func (msg *MsgGasPriceVoter) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgGasPriceVoter) ValidateBasic() error { + return nil +} diff --git a/x/crosschain/types/legacy_msgs.pb.go b/x/crosschain/types/legacy_msgs.pb.go new file mode 100644 index 0000000000..e5a6e67355 --- /dev/null +++ b/x/crosschain/types/legacy_msgs.pb.go @@ -0,0 +1,3002 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: zetachain/zetacore/crosschain/legacy_msgs.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + chains "github.com/zeta-chain/node/pkg/chains" + coin "github.com/zeta-chain/node/pkg/coin" + proofs "github.com/zeta-chain/node/pkg/proofs" + 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 + +// legacy MsgAddOutboundTracker +// defined to keep codec compatibility +type MsgAddToOutTxTracker struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + ChainId int64 `protobuf:"varint,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Nonce uint64 `protobuf:"varint,3,opt,name=nonce,proto3" json:"nonce,omitempty"` + TxHash string `protobuf:"bytes,4,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` + Proof *proofs.Proof `protobuf:"bytes,5,opt,name=proof,proto3" json:"proof,omitempty"` + BlockHash string `protobuf:"bytes,6,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"` + TxIndex int64 `protobuf:"varint,7,opt,name=tx_index,json=txIndex,proto3" json:"tx_index,omitempty"` +} + +func (m *MsgAddToOutTxTracker) Reset() { *m = MsgAddToOutTxTracker{} } +func (m *MsgAddToOutTxTracker) String() string { return proto.CompactTextString(m) } +func (*MsgAddToOutTxTracker) ProtoMessage() {} +func (*MsgAddToOutTxTracker) Descriptor() ([]byte, []int) { + return fileDescriptor_246a7cc819884e07, []int{0} +} +func (m *MsgAddToOutTxTracker) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddToOutTxTracker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddToOutTxTracker.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 *MsgAddToOutTxTracker) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddToOutTxTracker.Merge(m, src) +} +func (m *MsgAddToOutTxTracker) XXX_Size() int { + return m.Size() +} +func (m *MsgAddToOutTxTracker) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddToOutTxTracker.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddToOutTxTracker proto.InternalMessageInfo + +func (m *MsgAddToOutTxTracker) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgAddToOutTxTracker) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *MsgAddToOutTxTracker) GetNonce() uint64 { + if m != nil { + return m.Nonce + } + return 0 +} + +func (m *MsgAddToOutTxTracker) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +func (m *MsgAddToOutTxTracker) GetProof() *proofs.Proof { + if m != nil { + return m.Proof + } + return nil +} + +func (m *MsgAddToOutTxTracker) GetBlockHash() string { + if m != nil { + return m.BlockHash + } + return "" +} + +func (m *MsgAddToOutTxTracker) GetTxIndex() int64 { + if m != nil { + return m.TxIndex + } + return 0 +} + +// legacy MsgAddInboundTracker +// defined to keep codec compatibility +type MsgAddToInTxTracker struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + ChainId int64 `protobuf:"varint,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + TxHash string `protobuf:"bytes,3,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` + CoinType coin.CoinType `protobuf:"varint,4,opt,name=coin_type,json=coinType,proto3,enum=zetachain.zetacore.pkg.coin.CoinType" json:"coin_type,omitempty"` + Proof *proofs.Proof `protobuf:"bytes,5,opt,name=proof,proto3" json:"proof,omitempty"` + BlockHash string `protobuf:"bytes,6,opt,name=block_hash,json=blockHash,proto3" json:"block_hash,omitempty"` + TxIndex int64 `protobuf:"varint,7,opt,name=tx_index,json=txIndex,proto3" json:"tx_index,omitempty"` +} + +func (m *MsgAddToInTxTracker) Reset() { *m = MsgAddToInTxTracker{} } +func (m *MsgAddToInTxTracker) String() string { return proto.CompactTextString(m) } +func (*MsgAddToInTxTracker) ProtoMessage() {} +func (*MsgAddToInTxTracker) Descriptor() ([]byte, []int) { + return fileDescriptor_246a7cc819884e07, []int{1} +} +func (m *MsgAddToInTxTracker) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddToInTxTracker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddToInTxTracker.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 *MsgAddToInTxTracker) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddToInTxTracker.Merge(m, src) +} +func (m *MsgAddToInTxTracker) XXX_Size() int { + return m.Size() +} +func (m *MsgAddToInTxTracker) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddToInTxTracker.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddToInTxTracker proto.InternalMessageInfo + +func (m *MsgAddToInTxTracker) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgAddToInTxTracker) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *MsgAddToInTxTracker) GetTxHash() string { + if m != nil { + return m.TxHash + } + return "" +} + +func (m *MsgAddToInTxTracker) GetCoinType() coin.CoinType { + if m != nil { + return m.CoinType + } + return coin.CoinType_Zeta +} + +func (m *MsgAddToInTxTracker) GetProof() *proofs.Proof { + if m != nil { + return m.Proof + } + return nil +} + +func (m *MsgAddToInTxTracker) GetBlockHash() string { + if m != nil { + return m.BlockHash + } + return "" +} + +func (m *MsgAddToInTxTracker) GetTxIndex() int64 { + if m != nil { + return m.TxIndex + } + return 0 +} + +// legacy MsgRemoveOutboundTracker +// defined to keep codec compatibility +type MsgRemoveFromOutTxTracker struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + ChainId int64 `protobuf:"varint,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Nonce uint64 `protobuf:"varint,3,opt,name=nonce,proto3" json:"nonce,omitempty"` +} + +func (m *MsgRemoveFromOutTxTracker) Reset() { *m = MsgRemoveFromOutTxTracker{} } +func (m *MsgRemoveFromOutTxTracker) String() string { return proto.CompactTextString(m) } +func (*MsgRemoveFromOutTxTracker) ProtoMessage() {} +func (*MsgRemoveFromOutTxTracker) Descriptor() ([]byte, []int) { + return fileDescriptor_246a7cc819884e07, []int{2} +} +func (m *MsgRemoveFromOutTxTracker) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRemoveFromOutTxTracker) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRemoveFromOutTxTracker.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 *MsgRemoveFromOutTxTracker) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRemoveFromOutTxTracker.Merge(m, src) +} +func (m *MsgRemoveFromOutTxTracker) XXX_Size() int { + return m.Size() +} +func (m *MsgRemoveFromOutTxTracker) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRemoveFromOutTxTracker.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRemoveFromOutTxTracker proto.InternalMessageInfo + +func (m *MsgRemoveFromOutTxTracker) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgRemoveFromOutTxTracker) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *MsgRemoveFromOutTxTracker) GetNonce() uint64 { + if m != nil { + return m.Nonce + } + return 0 +} + +// legacy MsgVoteOutbound +// defined to keep codec compatibility +type MsgVoteOnObservedOutboundTx struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + CctxHash string `protobuf:"bytes,2,opt,name=cctx_hash,json=cctxHash,proto3" json:"cctx_hash,omitempty"` + ObservedOutTxHash string `protobuf:"bytes,3,opt,name=observed_outTx_hash,json=observedOutTxHash,proto3" json:"observed_outTx_hash,omitempty"` + ObservedOutTxBlockHeight uint64 `protobuf:"varint,4,opt,name=observed_outTx_blockHeight,json=observedOutTxBlockHeight,proto3" json:"observed_outTx_blockHeight,omitempty"` + ObservedOutTxGasUsed uint64 `protobuf:"varint,10,opt,name=observed_outTx_gas_used,json=observedOutTxGasUsed,proto3" json:"observed_outTx_gas_used,omitempty"` + ObservedOutTxEffectiveGasPrice github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,11,opt,name=observed_outTx_effective_gas_price,json=observedOutTxEffectiveGasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"observed_outTx_effective_gas_price"` + ObservedOutTxEffectiveGasLimit uint64 `protobuf:"varint,12,opt,name=observed_outTx_effective_gas_limit,json=observedOutTxEffectiveGasLimit,proto3" json:"observed_outTx_effective_gas_limit,omitempty"` + ValueReceived github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,5,opt,name=value_received,json=valueReceived,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"value_received" yaml:"value_received"` + Status chains.ReceiveStatus `protobuf:"varint,6,opt,name=status,proto3,enum=zetachain.zetacore.pkg.chains.ReceiveStatus" json:"status,omitempty"` + OutTxChain int64 `protobuf:"varint,7,opt,name=outTx_chain,json=outTxChain,proto3" json:"outTx_chain,omitempty"` + OutTxTssNonce uint64 `protobuf:"varint,8,opt,name=outTx_tss_nonce,json=outTxTssNonce,proto3" json:"outTx_tss_nonce,omitempty"` + CoinType coin.CoinType `protobuf:"varint,9,opt,name=coin_type,json=coinType,proto3,enum=zetachain.zetacore.pkg.coin.CoinType" json:"coin_type,omitempty"` +} + +func (m *MsgVoteOnObservedOutboundTx) Reset() { *m = MsgVoteOnObservedOutboundTx{} } +func (m *MsgVoteOnObservedOutboundTx) String() string { return proto.CompactTextString(m) } +func (*MsgVoteOnObservedOutboundTx) ProtoMessage() {} +func (*MsgVoteOnObservedOutboundTx) Descriptor() ([]byte, []int) { + return fileDescriptor_246a7cc819884e07, []int{3} +} +func (m *MsgVoteOnObservedOutboundTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgVoteOnObservedOutboundTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgVoteOnObservedOutboundTx.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 *MsgVoteOnObservedOutboundTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgVoteOnObservedOutboundTx.Merge(m, src) +} +func (m *MsgVoteOnObservedOutboundTx) XXX_Size() int { + return m.Size() +} +func (m *MsgVoteOnObservedOutboundTx) XXX_DiscardUnknown() { + xxx_messageInfo_MsgVoteOnObservedOutboundTx.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgVoteOnObservedOutboundTx proto.InternalMessageInfo + +func (m *MsgVoteOnObservedOutboundTx) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgVoteOnObservedOutboundTx) GetCctxHash() string { + if m != nil { + return m.CctxHash + } + return "" +} + +func (m *MsgVoteOnObservedOutboundTx) GetObservedOutTxHash() string { + if m != nil { + return m.ObservedOutTxHash + } + return "" +} + +func (m *MsgVoteOnObservedOutboundTx) GetObservedOutTxBlockHeight() uint64 { + if m != nil { + return m.ObservedOutTxBlockHeight + } + return 0 +} + +func (m *MsgVoteOnObservedOutboundTx) GetObservedOutTxGasUsed() uint64 { + if m != nil { + return m.ObservedOutTxGasUsed + } + return 0 +} + +func (m *MsgVoteOnObservedOutboundTx) GetObservedOutTxEffectiveGasLimit() uint64 { + if m != nil { + return m.ObservedOutTxEffectiveGasLimit + } + return 0 +} + +func (m *MsgVoteOnObservedOutboundTx) GetStatus() chains.ReceiveStatus { + if m != nil { + return m.Status + } + return chains.ReceiveStatus_created +} + +func (m *MsgVoteOnObservedOutboundTx) GetOutTxChain() int64 { + if m != nil { + return m.OutTxChain + } + return 0 +} + +func (m *MsgVoteOnObservedOutboundTx) GetOutTxTssNonce() uint64 { + if m != nil { + return m.OutTxTssNonce + } + return 0 +} + +func (m *MsgVoteOnObservedOutboundTx) GetCoinType() coin.CoinType { + if m != nil { + return m.CoinType + } + return coin.CoinType_Zeta +} + +// legacy MsgVoteInbound +// defined to keep codec compatibility +type MsgVoteOnObservedInboundTx struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + Sender string `protobuf:"bytes,2,opt,name=sender,proto3" json:"sender,omitempty"` + SenderChainId int64 `protobuf:"varint,3,opt,name=sender_chain_id,json=senderChainId,proto3" json:"sender_chain_id,omitempty"` + Receiver string `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"` + ReceiverChain int64 `protobuf:"varint,5,opt,name=receiver_chain,json=receiverChain,proto3" json:"receiver_chain,omitempty"` + // string zeta_burnt = 6; + Amount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,6,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"amount"` + // string mMint = 7; + Message string `protobuf:"bytes,8,opt,name=message,proto3" json:"message,omitempty"` + InTxHash string `protobuf:"bytes,9,opt,name=in_tx_hash,json=inTxHash,proto3" json:"in_tx_hash,omitempty"` + InBlockHeight uint64 `protobuf:"varint,10,opt,name=in_block_height,json=inBlockHeight,proto3" json:"in_block_height,omitempty"` + GasLimit uint64 `protobuf:"varint,11,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` + CoinType coin.CoinType `protobuf:"varint,12,opt,name=coin_type,json=coinType,proto3,enum=zetachain.zetacore.pkg.coin.CoinType" json:"coin_type,omitempty"` + TxOrigin string `protobuf:"bytes,13,opt,name=tx_origin,json=txOrigin,proto3" json:"tx_origin,omitempty"` + Asset string `protobuf:"bytes,14,opt,name=asset,proto3" json:"asset,omitempty"` + // event index of the sent asset in the observed tx + EventIndex uint64 `protobuf:"varint,15,opt,name=event_index,json=eventIndex,proto3" json:"event_index,omitempty"` +} + +func (m *MsgVoteOnObservedInboundTx) Reset() { *m = MsgVoteOnObservedInboundTx{} } +func (m *MsgVoteOnObservedInboundTx) String() string { return proto.CompactTextString(m) } +func (*MsgVoteOnObservedInboundTx) ProtoMessage() {} +func (*MsgVoteOnObservedInboundTx) Descriptor() ([]byte, []int) { + return fileDescriptor_246a7cc819884e07, []int{4} +} +func (m *MsgVoteOnObservedInboundTx) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgVoteOnObservedInboundTx) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgVoteOnObservedInboundTx.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 *MsgVoteOnObservedInboundTx) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgVoteOnObservedInboundTx.Merge(m, src) +} +func (m *MsgVoteOnObservedInboundTx) XXX_Size() int { + return m.Size() +} +func (m *MsgVoteOnObservedInboundTx) XXX_DiscardUnknown() { + xxx_messageInfo_MsgVoteOnObservedInboundTx.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgVoteOnObservedInboundTx proto.InternalMessageInfo + +func (m *MsgVoteOnObservedInboundTx) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgVoteOnObservedInboundTx) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgVoteOnObservedInboundTx) GetSenderChainId() int64 { + if m != nil { + return m.SenderChainId + } + return 0 +} + +func (m *MsgVoteOnObservedInboundTx) GetReceiver() string { + if m != nil { + return m.Receiver + } + return "" +} + +func (m *MsgVoteOnObservedInboundTx) GetReceiverChain() int64 { + if m != nil { + return m.ReceiverChain + } + return 0 +} + +func (m *MsgVoteOnObservedInboundTx) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func (m *MsgVoteOnObservedInboundTx) GetInTxHash() string { + if m != nil { + return m.InTxHash + } + return "" +} + +func (m *MsgVoteOnObservedInboundTx) GetInBlockHeight() uint64 { + if m != nil { + return m.InBlockHeight + } + return 0 +} + +func (m *MsgVoteOnObservedInboundTx) GetGasLimit() uint64 { + if m != nil { + return m.GasLimit + } + return 0 +} + +func (m *MsgVoteOnObservedInboundTx) GetCoinType() coin.CoinType { + if m != nil { + return m.CoinType + } + return coin.CoinType_Zeta +} + +func (m *MsgVoteOnObservedInboundTx) GetTxOrigin() string { + if m != nil { + return m.TxOrigin + } + return "" +} + +func (m *MsgVoteOnObservedInboundTx) GetAsset() string { + if m != nil { + return m.Asset + } + return "" +} + +func (m *MsgVoteOnObservedInboundTx) GetEventIndex() uint64 { + if m != nil { + return m.EventIndex + } + return 0 +} + +// legacy MsgVoteGasPrice +// defined to keep codec compatibility +type MsgGasPriceVoter struct { + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + ChainId int64 `protobuf:"varint,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Price uint64 `protobuf:"varint,3,opt,name=price,proto3" json:"price,omitempty"` + BlockNumber uint64 `protobuf:"varint,4,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Supply string `protobuf:"bytes,5,opt,name=supply,proto3" json:"supply,omitempty"` +} + +func (m *MsgGasPriceVoter) Reset() { *m = MsgGasPriceVoter{} } +func (m *MsgGasPriceVoter) String() string { return proto.CompactTextString(m) } +func (*MsgGasPriceVoter) ProtoMessage() {} +func (*MsgGasPriceVoter) Descriptor() ([]byte, []int) { + return fileDescriptor_246a7cc819884e07, []int{5} +} +func (m *MsgGasPriceVoter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgGasPriceVoter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgGasPriceVoter.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 *MsgGasPriceVoter) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgGasPriceVoter.Merge(m, src) +} +func (m *MsgGasPriceVoter) XXX_Size() int { + return m.Size() +} +func (m *MsgGasPriceVoter) XXX_DiscardUnknown() { + xxx_messageInfo_MsgGasPriceVoter.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgGasPriceVoter proto.InternalMessageInfo + +func (m *MsgGasPriceVoter) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgGasPriceVoter) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *MsgGasPriceVoter) GetPrice() uint64 { + if m != nil { + return m.Price + } + return 0 +} + +func (m *MsgGasPriceVoter) GetBlockNumber() uint64 { + if m != nil { + return m.BlockNumber + } + return 0 +} + +func (m *MsgGasPriceVoter) GetSupply() string { + if m != nil { + return m.Supply + } + return "" +} + +func init() { + proto.RegisterType((*MsgAddToOutTxTracker)(nil), "zetachain.zetacore.crosschain.MsgAddToOutTxTracker") + proto.RegisterType((*MsgAddToInTxTracker)(nil), "zetachain.zetacore.crosschain.MsgAddToInTxTracker") + proto.RegisterType((*MsgRemoveFromOutTxTracker)(nil), "zetachain.zetacore.crosschain.MsgRemoveFromOutTxTracker") + proto.RegisterType((*MsgVoteOnObservedOutboundTx)(nil), "zetachain.zetacore.crosschain.MsgVoteOnObservedOutboundTx") + proto.RegisterType((*MsgVoteOnObservedInboundTx)(nil), "zetachain.zetacore.crosschain.MsgVoteOnObservedInboundTx") + proto.RegisterType((*MsgGasPriceVoter)(nil), "zetachain.zetacore.crosschain.MsgGasPriceVoter") +} + +func init() { + proto.RegisterFile("zetachain/zetacore/crosschain/legacy_msgs.proto", fileDescriptor_246a7cc819884e07) +} + +var fileDescriptor_246a7cc819884e07 = []byte{ + // 979 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x56, 0x4f, 0x6f, 0xe3, 0x44, + 0x14, 0xaf, 0xdb, 0x34, 0x8d, 0x5f, 0x9a, 0x14, 0xbc, 0x85, 0x75, 0x53, 0x36, 0x2d, 0x11, 0x5b, + 0x2a, 0x44, 0x13, 0xa9, 0x08, 0x0e, 0x2b, 0x2e, 0xa4, 0x40, 0x37, 0x88, 0x6e, 0x56, 0x26, 0xcb, + 0x81, 0x8b, 0xe5, 0xd8, 0x13, 0x67, 0x94, 0x78, 0x26, 0xf2, 0x8c, 0x23, 0x67, 0xef, 0xdc, 0xb9, + 0xc1, 0x85, 0xef, 0xb3, 0xc7, 0x3d, 0x22, 0x0e, 0x15, 0x6a, 0xbf, 0x00, 0xe2, 0x13, 0x20, 0xbf, + 0x19, 0xb7, 0x49, 0xe9, 0x1f, 0x28, 0x42, 0x5c, 0xe2, 0x79, 0xcf, 0xef, 0xf7, 0xe6, 0xfd, 0xfb, + 0xbd, 0x18, 0x5a, 0x2f, 0x89, 0xf4, 0xfc, 0xa1, 0x47, 0x99, 0x3a, 0xf1, 0x98, 0xb4, 0xfc, 0x98, + 0x0b, 0xa1, 0x74, 0x63, 0x12, 0x7a, 0xfe, 0xcc, 0x8d, 0x44, 0x28, 0x9a, 0x93, 0x98, 0x4b, 0x6e, + 0x3d, 0xba, 0x00, 0x34, 0x73, 0x40, 0xf3, 0x12, 0x50, 0xdb, 0x0c, 0x79, 0xc8, 0xd1, 0xb2, 0x95, + 0x9d, 0x14, 0xa8, 0xf6, 0xc1, 0x35, 0xb7, 0x4c, 0x46, 0x61, 0x0b, 0x55, 0x42, 0x3f, 0xb4, 0xed, + 0xde, 0x4d, 0xb6, 0x9c, 0x32, 0xfc, 0xb9, 0xc3, 0xe7, 0x24, 0xe6, 0x7c, 0x20, 0xf4, 0x43, 0xdb, + 0x7e, 0x72, 0x7b, 0x96, 0xb1, 0x27, 0x89, 0x3b, 0xa6, 0x11, 0x95, 0x24, 0x76, 0x07, 0x63, 0x2f, + 0x4f, 0xb6, 0x76, 0x78, 0x3b, 0x0e, 0x8f, 0x2e, 0x9e, 0x5d, 0x99, 0x2a, 0x4c, 0xe3, 0x77, 0x03, + 0x36, 0x4f, 0x44, 0xf8, 0x59, 0x10, 0xf4, 0x78, 0x37, 0x91, 0xbd, 0xb4, 0x17, 0x7b, 0xfe, 0x88, + 0xc4, 0x96, 0x0d, 0x6b, 0x7e, 0x4c, 0x3c, 0xc9, 0x63, 0xdb, 0xd8, 0x35, 0xf6, 0x4d, 0x27, 0x17, + 0xad, 0x2d, 0x28, 0x29, 0x27, 0x34, 0xb0, 0x97, 0x77, 0x8d, 0xfd, 0x15, 0x67, 0x0d, 0xe5, 0x4e, + 0x60, 0x6d, 0xc2, 0x2a, 0xe3, 0xcc, 0x27, 0xf6, 0xca, 0xae, 0xb1, 0x5f, 0x70, 0x94, 0x60, 0x3d, + 0x84, 0x35, 0x99, 0xba, 0x43, 0x4f, 0x0c, 0xed, 0x02, 0xba, 0x2a, 0xca, 0xf4, 0xa9, 0x27, 0x86, + 0xd6, 0x13, 0x58, 0xc5, 0xc4, 0xed, 0xd5, 0x5d, 0x63, 0xbf, 0x7c, 0xf8, 0x5e, 0xf3, 0x9a, 0x6e, + 0x4d, 0x46, 0x61, 0x53, 0x57, 0xe7, 0x79, 0xf6, 0x70, 0x14, 0xc4, 0x7a, 0x04, 0xd0, 0x1f, 0x73, + 0x7f, 0xa4, 0xfc, 0x16, 0xd1, 0xaf, 0x89, 0x1a, 0x74, 0xbd, 0x05, 0x25, 0x99, 0xba, 0x94, 0x05, + 0x24, 0xb5, 0xd7, 0x54, 0x90, 0x32, 0xed, 0x64, 0x62, 0xe3, 0xe7, 0x65, 0x78, 0x90, 0xa7, 0xdc, + 0x61, 0xff, 0x32, 0xe3, 0xb9, 0xdc, 0x56, 0x16, 0x72, 0x6b, 0x83, 0x99, 0xb5, 0xdf, 0x95, 0xb3, + 0x09, 0xc1, 0xb4, 0xab, 0x87, 0x8f, 0x6f, 0xca, 0x0f, 0xe7, 0xe4, 0x88, 0x53, 0xd6, 0x9b, 0x4d, + 0x88, 0x53, 0xf2, 0xf5, 0xe9, 0x7f, 0xaa, 0xcf, 0x00, 0xb6, 0x4e, 0x44, 0xe8, 0x90, 0x88, 0x4f, + 0xc9, 0x97, 0x31, 0x8f, 0xfe, 0xa3, 0xb1, 0x68, 0x7c, 0x5f, 0x84, 0xed, 0x13, 0x11, 0x7e, 0xcb, + 0x25, 0xe9, 0xb2, 0x6e, 0x5f, 0x90, 0x78, 0x4a, 0x82, 0x6e, 0x22, 0xfb, 0x3c, 0x61, 0x41, 0x2f, + 0xbd, 0xe5, 0xaa, 0x6d, 0x30, 0x7d, 0x3f, 0x2f, 0xfb, 0x32, 0xbe, 0x2b, 0x65, 0x0a, 0xcc, 0xac, + 0x09, 0x0f, 0xb8, 0x76, 0xe6, 0xf2, 0x2c, 0xf4, 0xf9, 0xee, 0xbc, 0xc9, 0x2f, 0xef, 0xe9, 0x29, + 0xfb, 0x4f, 0xa1, 0x76, 0xc5, 0x5e, 0x55, 0x89, 0xd0, 0x70, 0x28, 0xb1, 0x73, 0x05, 0xc7, 0x5e, + 0x80, 0xb5, 0x2f, 0xdf, 0x5b, 0x1f, 0xc3, 0xc3, 0x2b, 0xe8, 0xd0, 0x13, 0x6e, 0x22, 0x48, 0x60, + 0x03, 0x42, 0x37, 0x17, 0xa0, 0xc7, 0x9e, 0x78, 0x21, 0x48, 0x60, 0xbd, 0x84, 0xc6, 0x15, 0x18, + 0x19, 0x0c, 0x88, 0x2f, 0xe9, 0x94, 0xa0, 0x83, 0x49, 0x4c, 0x7d, 0x62, 0x97, 0xb3, 0x98, 0xdb, + 0xcd, 0x57, 0xa7, 0x3b, 0x4b, 0xbf, 0x9e, 0xee, 0xec, 0x85, 0x54, 0x0e, 0x93, 0x7e, 0xd3, 0xe7, + 0x51, 0xcb, 0xe7, 0x22, 0xe2, 0x42, 0x3f, 0x0e, 0x44, 0x30, 0x6a, 0x65, 0x73, 0x26, 0x9a, 0x1d, + 0x26, 0x9d, 0xfa, 0xc2, 0x8d, 0x5f, 0xe4, 0x7e, 0x8f, 0x3d, 0xf1, 0x3c, 0xf3, 0x6a, 0x7d, 0x75, + 0xc7, 0xdd, 0xb8, 0x5a, 0xec, 0x75, 0x8c, 0xfe, 0x66, 0x5f, 0x5f, 0x67, 0x56, 0x16, 0x87, 0xea, + 0xd4, 0x1b, 0x27, 0xc4, 0x8d, 0x89, 0x4f, 0xe8, 0x94, 0x04, 0x38, 0xaa, 0x66, 0xfb, 0xa9, 0x8e, + 0xf9, 0xfd, 0xbf, 0x11, 0xf3, 0x0b, 0xca, 0xe4, 0x1f, 0xa7, 0x3b, 0x6f, 0xcd, 0xbc, 0x68, 0xfc, + 0xa4, 0xb1, 0xe8, 0xae, 0xe1, 0x54, 0x50, 0xe1, 0x68, 0xd9, 0xfa, 0x1c, 0x8a, 0x42, 0x7a, 0x32, + 0x11, 0x38, 0xd2, 0xd5, 0xc3, 0x0f, 0x6f, 0xe4, 0x94, 0xda, 0xd2, 0x1a, 0xf8, 0x0d, 0x62, 0x1c, + 0x8d, 0xb5, 0x76, 0xa0, 0xac, 0x32, 0x47, 0x2b, 0x4d, 0x00, 0x40, 0xd5, 0x51, 0xa6, 0xb1, 0xf6, + 0x60, 0x43, 0x19, 0x48, 0x21, 0x5c, 0x35, 0xbb, 0x25, 0x2c, 0x48, 0x05, 0xd5, 0x3d, 0x21, 0x9e, + 0xe1, 0x6a, 0x5b, 0x60, 0xb9, 0x79, 0x2f, 0x96, 0x37, 0x7e, 0x2c, 0x40, 0xed, 0x2f, 0x3c, 0xe8, + 0xb0, 0xbb, 0x69, 0xf0, 0x36, 0x14, 0x05, 0x61, 0x01, 0x89, 0x35, 0x07, 0xb4, 0x94, 0x05, 0xaf, + 0x4e, 0xee, 0x05, 0x21, 0x57, 0x30, 0xc3, 0x8a, 0x52, 0x1f, 0x69, 0x5a, 0xd6, 0xa0, 0xa4, 0xeb, + 0x1c, 0xeb, 0xc5, 0x7c, 0x21, 0x5b, 0x8f, 0xa1, 0x9a, 0x9f, 0x75, 0x91, 0x56, 0x95, 0x8b, 0x5c, + 0xab, 0xea, 0x74, 0x0c, 0x45, 0x2f, 0xe2, 0x09, 0x93, 0x6a, 0xc3, 0xb4, 0x5b, 0xff, 0xb0, 0xef, + 0x8e, 0x86, 0x67, 0x59, 0x46, 0x44, 0x08, 0x2f, 0x54, 0x85, 0x36, 0x9d, 0x5c, 0xb4, 0xde, 0x01, + 0xc0, 0x3f, 0x2c, 0x45, 0x63, 0x53, 0xc5, 0x49, 0x99, 0x66, 0xef, 0x1e, 0x6c, 0x50, 0xe6, 0xea, + 0x4d, 0xa7, 0x28, 0xab, 0x78, 0x57, 0xa1, 0x6c, 0x9e, 0xa7, 0xdb, 0x60, 0x5e, 0xce, 0x76, 0x19, + 0x2d, 0x4a, 0x61, 0x3e, 0xc5, 0x0b, 0x5d, 0x5c, 0xbf, 0xdf, 0xae, 0xde, 0x06, 0x53, 0xa6, 0x2e, + 0x8f, 0x69, 0x48, 0x99, 0x5d, 0x51, 0x51, 0xca, 0xb4, 0x8b, 0x72, 0xb6, 0x00, 0x3d, 0x21, 0x88, + 0xb4, 0xab, 0xf8, 0x42, 0x09, 0xd9, 0x14, 0x92, 0x29, 0x61, 0x52, 0xaf, 0xe1, 0x0d, 0x8c, 0x0a, + 0x50, 0xa5, 0x36, 0xf1, 0x4f, 0x06, 0xbc, 0x71, 0x22, 0xc2, 0x9c, 0xb9, 0xd9, 0x84, 0xdc, 0x7f, + 0x03, 0xab, 0x95, 0xa2, 0x37, 0x30, 0x0a, 0xd6, 0xbb, 0xb0, 0xae, 0x2a, 0xc7, 0x92, 0xa8, 0xaf, + 0x87, 0xa0, 0xe0, 0x94, 0x51, 0xf7, 0x0c, 0x55, 0x38, 0x63, 0xc9, 0x64, 0x32, 0x9e, 0x29, 0x62, + 0x3b, 0x5a, 0x6a, 0x1f, 0xbf, 0x3a, 0xab, 0x1b, 0xaf, 0xcf, 0xea, 0xc6, 0x6f, 0x67, 0x75, 0xe3, + 0x87, 0xf3, 0xfa, 0xd2, 0xeb, 0xf3, 0xfa, 0xd2, 0x2f, 0xe7, 0xf5, 0xa5, 0xef, 0x0e, 0xe6, 0x5a, + 0x9f, 0x55, 0xee, 0x40, 0x7d, 0x7d, 0x30, 0x1e, 0x90, 0x56, 0x3a, 0xff, 0x3d, 0x82, 0x53, 0xd0, + 0x2f, 0xe2, 0x77, 0xc8, 0x47, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x59, 0xa5, 0x4e, 0x23, 0xdb, + 0x09, 0x00, 0x00, +} + +func (m *MsgAddToOutTxTracker) 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 *MsgAddToOutTxTracker) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAddToOutTxTracker) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TxIndex != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.TxIndex)) + i-- + dAtA[i] = 0x38 + } + if len(m.BlockHash) > 0 { + i -= len(m.BlockHash) + copy(dAtA[i:], m.BlockHash) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.BlockHash))) + i-- + dAtA[i] = 0x32 + } + if m.Proof != nil { + { + size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLegacyMsgs(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0x22 + } + if m.Nonce != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x18 + } + if m.ChainId != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgAddToInTxTracker) 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 *MsgAddToInTxTracker) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAddToInTxTracker) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TxIndex != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.TxIndex)) + i-- + dAtA[i] = 0x38 + } + if len(m.BlockHash) > 0 { + i -= len(m.BlockHash) + copy(dAtA[i:], m.BlockHash) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.BlockHash))) + i-- + dAtA[i] = 0x32 + } + if m.Proof != nil { + { + size, err := m.Proof.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintLegacyMsgs(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if m.CoinType != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x20 + } + if len(m.TxHash) > 0 { + i -= len(m.TxHash) + copy(dAtA[i:], m.TxHash) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.TxHash))) + i-- + dAtA[i] = 0x1a + } + if m.ChainId != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRemoveFromOutTxTracker) 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 *MsgRemoveFromOutTxTracker) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRemoveFromOutTxTracker) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Nonce != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.Nonce)) + i-- + dAtA[i] = 0x18 + } + if m.ChainId != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgVoteOnObservedOutboundTx) 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 *MsgVoteOnObservedOutboundTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgVoteOnObservedOutboundTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ObservedOutTxEffectiveGasLimit != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.ObservedOutTxEffectiveGasLimit)) + i-- + dAtA[i] = 0x60 + } + { + size := m.ObservedOutTxEffectiveGasPrice.Size() + i -= size + if _, err := m.ObservedOutTxEffectiveGasPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintLegacyMsgs(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + if m.ObservedOutTxGasUsed != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.ObservedOutTxGasUsed)) + i-- + dAtA[i] = 0x50 + } + if m.CoinType != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x48 + } + if m.OutTxTssNonce != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.OutTxTssNonce)) + i-- + dAtA[i] = 0x40 + } + if m.OutTxChain != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.OutTxChain)) + i-- + dAtA[i] = 0x38 + } + if m.Status != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.Status)) + i-- + dAtA[i] = 0x30 + } + { + size := m.ValueReceived.Size() + i -= size + if _, err := m.ValueReceived.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintLegacyMsgs(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if m.ObservedOutTxBlockHeight != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.ObservedOutTxBlockHeight)) + i-- + dAtA[i] = 0x20 + } + if len(m.ObservedOutTxHash) > 0 { + i -= len(m.ObservedOutTxHash) + copy(dAtA[i:], m.ObservedOutTxHash) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.ObservedOutTxHash))) + i-- + dAtA[i] = 0x1a + } + if len(m.CctxHash) > 0 { + i -= len(m.CctxHash) + copy(dAtA[i:], m.CctxHash) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.CctxHash))) + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgVoteOnObservedInboundTx) 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 *MsgVoteOnObservedInboundTx) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgVoteOnObservedInboundTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.EventIndex != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.EventIndex)) + i-- + dAtA[i] = 0x78 + } + if len(m.Asset) > 0 { + i -= len(m.Asset) + copy(dAtA[i:], m.Asset) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Asset))) + i-- + dAtA[i] = 0x72 + } + if len(m.TxOrigin) > 0 { + i -= len(m.TxOrigin) + copy(dAtA[i:], m.TxOrigin) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.TxOrigin))) + i-- + dAtA[i] = 0x6a + } + if m.CoinType != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x60 + } + if m.GasLimit != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.GasLimit)) + i-- + dAtA[i] = 0x58 + } + if m.InBlockHeight != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.InBlockHeight)) + i-- + dAtA[i] = 0x50 + } + if len(m.InTxHash) > 0 { + i -= len(m.InTxHash) + copy(dAtA[i:], m.InTxHash) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.InTxHash))) + i-- + dAtA[i] = 0x4a + } + if len(m.Message) > 0 { + i -= len(m.Message) + copy(dAtA[i:], m.Message) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Message))) + i-- + dAtA[i] = 0x42 + } + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintLegacyMsgs(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if m.ReceiverChain != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.ReceiverChain)) + i-- + dAtA[i] = 0x28 + } + if len(m.Receiver) > 0 { + i -= len(m.Receiver) + copy(dAtA[i:], m.Receiver) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Receiver))) + i-- + dAtA[i] = 0x22 + } + if m.SenderChainId != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.SenderChainId)) + i-- + dAtA[i] = 0x18 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0x12 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgGasPriceVoter) 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 *MsgGasPriceVoter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgGasPriceVoter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Supply) > 0 { + i -= len(m.Supply) + copy(dAtA[i:], m.Supply) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Supply))) + i-- + dAtA[i] = 0x2a + } + if m.BlockNumber != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.BlockNumber)) + i-- + dAtA[i] = 0x20 + } + if m.Price != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.Price)) + i-- + dAtA[i] = 0x18 + } + if m.ChainId != 0 { + i = encodeVarintLegacyMsgs(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x10 + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintLegacyMsgs(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintLegacyMsgs(dAtA []byte, offset int, v uint64) int { + offset -= sovLegacyMsgs(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgAddToOutTxTracker) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.ChainId != 0 { + n += 1 + sovLegacyMsgs(uint64(m.ChainId)) + } + if m.Nonce != 0 { + n += 1 + sovLegacyMsgs(uint64(m.Nonce)) + } + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.Proof != nil { + l = m.Proof.Size() + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + l = len(m.BlockHash) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.TxIndex != 0 { + n += 1 + sovLegacyMsgs(uint64(m.TxIndex)) + } + return n +} + +func (m *MsgAddToInTxTracker) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.ChainId != 0 { + n += 1 + sovLegacyMsgs(uint64(m.ChainId)) + } + l = len(m.TxHash) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.CoinType != 0 { + n += 1 + sovLegacyMsgs(uint64(m.CoinType)) + } + if m.Proof != nil { + l = m.Proof.Size() + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + l = len(m.BlockHash) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.TxIndex != 0 { + n += 1 + sovLegacyMsgs(uint64(m.TxIndex)) + } + return n +} + +func (m *MsgRemoveFromOutTxTracker) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.ChainId != 0 { + n += 1 + sovLegacyMsgs(uint64(m.ChainId)) + } + if m.Nonce != 0 { + n += 1 + sovLegacyMsgs(uint64(m.Nonce)) + } + return n +} + +func (m *MsgVoteOnObservedOutboundTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + l = len(m.CctxHash) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + l = len(m.ObservedOutTxHash) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.ObservedOutTxBlockHeight != 0 { + n += 1 + sovLegacyMsgs(uint64(m.ObservedOutTxBlockHeight)) + } + l = m.ValueReceived.Size() + n += 1 + l + sovLegacyMsgs(uint64(l)) + if m.Status != 0 { + n += 1 + sovLegacyMsgs(uint64(m.Status)) + } + if m.OutTxChain != 0 { + n += 1 + sovLegacyMsgs(uint64(m.OutTxChain)) + } + if m.OutTxTssNonce != 0 { + n += 1 + sovLegacyMsgs(uint64(m.OutTxTssNonce)) + } + if m.CoinType != 0 { + n += 1 + sovLegacyMsgs(uint64(m.CoinType)) + } + if m.ObservedOutTxGasUsed != 0 { + n += 1 + sovLegacyMsgs(uint64(m.ObservedOutTxGasUsed)) + } + l = m.ObservedOutTxEffectiveGasPrice.Size() + n += 1 + l + sovLegacyMsgs(uint64(l)) + if m.ObservedOutTxEffectiveGasLimit != 0 { + n += 1 + sovLegacyMsgs(uint64(m.ObservedOutTxEffectiveGasLimit)) + } + return n +} + +func (m *MsgVoteOnObservedInboundTx) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.SenderChainId != 0 { + n += 1 + sovLegacyMsgs(uint64(m.SenderChainId)) + } + l = len(m.Receiver) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.ReceiverChain != 0 { + n += 1 + sovLegacyMsgs(uint64(m.ReceiverChain)) + } + l = m.Amount.Size() + n += 1 + l + sovLegacyMsgs(uint64(l)) + l = len(m.Message) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + l = len(m.InTxHash) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.InBlockHeight != 0 { + n += 1 + sovLegacyMsgs(uint64(m.InBlockHeight)) + } + if m.GasLimit != 0 { + n += 1 + sovLegacyMsgs(uint64(m.GasLimit)) + } + if m.CoinType != 0 { + n += 1 + sovLegacyMsgs(uint64(m.CoinType)) + } + l = len(m.TxOrigin) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + l = len(m.Asset) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.EventIndex != 0 { + n += 1 + sovLegacyMsgs(uint64(m.EventIndex)) + } + return n +} + +func (m *MsgGasPriceVoter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + if m.ChainId != 0 { + n += 1 + sovLegacyMsgs(uint64(m.ChainId)) + } + if m.Price != 0 { + n += 1 + sovLegacyMsgs(uint64(m.Price)) + } + if m.BlockNumber != 0 { + n += 1 + sovLegacyMsgs(uint64(m.BlockNumber)) + } + l = len(m.Supply) + if l > 0 { + n += 1 + l + sovLegacyMsgs(uint64(l)) + } + return n +} + +func sovLegacyMsgs(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozLegacyMsgs(x uint64) (n int) { + return sovLegacyMsgs(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgAddToOutTxTracker) 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 ErrIntOverflowLegacyMsgs + } + 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: MsgAddToOutTxTracker: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddToOutTxTracker: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Proof == nil { + m.Proof = &proofs.Proof{} + } + if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlockHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxIndex", wireType) + } + m.TxIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxIndex |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLegacyMsgs(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLegacyMsgs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAddToInTxTracker) 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 ErrIntOverflowLegacyMsgs + } + 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: MsgAddToInTxTracker: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddToInTxTracker: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= coin.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Proof", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Proof == nil { + m.Proof = &proofs.Proof{} + } + if err := m.Proof.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlockHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxIndex", wireType) + } + m.TxIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxIndex |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLegacyMsgs(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLegacyMsgs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRemoveFromOutTxTracker) 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 ErrIntOverflowLegacyMsgs + } + 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: MsgRemoveFromOutTxTracker: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRemoveFromOutTxTracker: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) + } + m.Nonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Nonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLegacyMsgs(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLegacyMsgs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgVoteOnObservedOutboundTx) 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 ErrIntOverflowLegacyMsgs + } + 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: MsgVoteOnObservedOutboundTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgVoteOnObservedOutboundTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CctxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CctxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ObservedOutTxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ObservedOutTxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ObservedOutTxBlockHeight", wireType) + } + m.ObservedOutTxBlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ObservedOutTxBlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValueReceived", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ValueReceived.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) + } + m.Status = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Status |= chains.ReceiveStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OutTxChain", wireType) + } + m.OutTxChain = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OutTxChain |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OutTxTssNonce", wireType) + } + m.OutTxTssNonce = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OutTxTssNonce |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= coin.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ObservedOutTxGasUsed", wireType) + } + m.ObservedOutTxGasUsed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ObservedOutTxGasUsed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ObservedOutTxEffectiveGasPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ObservedOutTxEffectiveGasPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ObservedOutTxEffectiveGasLimit", wireType) + } + m.ObservedOutTxEffectiveGasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ObservedOutTxEffectiveGasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLegacyMsgs(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLegacyMsgs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgVoteOnObservedInboundTx) 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 ErrIntOverflowLegacyMsgs + } + 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: MsgVoteOnObservedInboundTx: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgVoteOnObservedInboundTx: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + 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 ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SenderChainId", wireType) + } + m.SenderChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SenderChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + 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 ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ReceiverChain", wireType) + } + m.ReceiverChain = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ReceiverChain |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Message = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InTxHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.InTxHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InBlockHeight", wireType) + } + m.InBlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InBlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType) + } + m.GasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= coin.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxOrigin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxOrigin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Asset = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EventIndex", wireType) + } + m.EventIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EventIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipLegacyMsgs(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLegacyMsgs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgGasPriceVoter) 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 ErrIntOverflowLegacyMsgs + } + 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: MsgGasPriceVoter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgGasPriceVoter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) + } + m.Price = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Price |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockNumber", wireType) + } + m.BlockNumber = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockNumber |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Supply", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowLegacyMsgs + } + 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 ErrInvalidLengthLegacyMsgs + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthLegacyMsgs + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Supply = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipLegacyMsgs(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthLegacyMsgs + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipLegacyMsgs(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, ErrIntOverflowLegacyMsgs + } + 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, ErrIntOverflowLegacyMsgs + } + 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, ErrIntOverflowLegacyMsgs + } + 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, ErrInvalidLengthLegacyMsgs + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupLegacyMsgs + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthLegacyMsgs + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthLegacyMsgs = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowLegacyMsgs = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupLegacyMsgs = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/crosschain/types/tx.pb.go b/x/crosschain/types/tx.pb.go index 7496f74404..ad8b7cbd9d 100644 --- a/x/crosschain/types/tx.pb.go +++ b/x/crosschain/types/tx.pb.go @@ -719,6 +719,7 @@ type MsgVoteGasPrice struct { Price uint64 `protobuf:"varint,3,opt,name=price,proto3" json:"price,omitempty"` PriorityFee uint64 `protobuf:"varint,6,opt,name=priority_fee,json=priorityFee,proto3" json:"priority_fee,omitempty"` BlockNumber uint64 `protobuf:"varint,4,opt,name=block_number,json=blockNumber,proto3" json:"block_number,omitempty"` + Supply string `protobuf:"bytes,5,opt,name=supply,proto3" json:"supply,omitempty"` // Deprecated: Do not use. } func (m *MsgVoteGasPrice) Reset() { *m = MsgVoteGasPrice{} } @@ -789,6 +790,14 @@ func (m *MsgVoteGasPrice) GetBlockNumber() uint64 { return 0 } +// Deprecated: Do not use. +func (m *MsgVoteGasPrice) GetSupply() string { + if m != nil { + return m.Supply + } + return "" +} + type MsgVoteGasPriceResponse struct { } @@ -1715,120 +1724,121 @@ func init() { } var fileDescriptor_15f0860550897740 = []byte{ - // 1807 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x4f, 0x6f, 0x23, 0x49, - 0x15, 0x4f, 0x6f, 0x1c, 0xc7, 0x7e, 0x4e, 0x9c, 0xa4, 0x37, 0x93, 0x38, 0x9d, 0x8d, 0x93, 0xf1, - 0x30, 0x21, 0x5a, 0x4d, 0xec, 0xe0, 0x59, 0x86, 0x25, 0x8b, 0x58, 0x26, 0xde, 0x9d, 0x6c, 0xd0, - 0x78, 0x26, 0xea, 0xcd, 0x2c, 0x7f, 0x2e, 0xad, 0x76, 0x77, 0xa5, 0xd3, 0x8a, 0xdd, 0x65, 0x75, - 0x95, 0xbd, 0xce, 0x08, 0x09, 0x84, 0x84, 0xc4, 0x11, 0x10, 0xa7, 0x3d, 0x70, 0x43, 0x82, 0x6f, - 0xc0, 0x47, 0xd8, 0xe3, 0x88, 0x13, 0xe2, 0x30, 0x42, 0x33, 0x5f, 0x00, 0xb8, 0x72, 0x41, 0xfd, - 0xaa, 0xba, 0x63, 0xb7, 0xff, 0xc6, 0x11, 0xe2, 0x92, 0xee, 0x7a, 0xfd, 0x7e, 0xef, 0x5f, 0xbd, - 0xaa, 0xf7, 0x9e, 0x03, 0xbb, 0x2f, 0x09, 0x37, 0xad, 0x0b, 0xd3, 0xf5, 0x4a, 0xf8, 0x46, 0x7d, - 0x52, 0xb2, 0x7c, 0xca, 0x98, 0xa0, 0xf1, 0x4e, 0xb1, 0xe9, 0x53, 0x4e, 0xd5, 0xad, 0x88, 0xaf, - 0x18, 0xf2, 0x15, 0xaf, 0xf9, 0xb4, 0x55, 0x87, 0x3a, 0x14, 0x39, 0x4b, 0xc1, 0x9b, 0x00, 0x69, - 0xef, 0x0f, 0x10, 0xde, 0xbc, 0x74, 0x4a, 0x48, 0x62, 0xf2, 0x21, 0x79, 0x77, 0x87, 0xf1, 0x52, - 0xd7, 0xc3, 0x3f, 0x63, 0x64, 0x36, 0x7d, 0x4a, 0xcf, 0x99, 0x7c, 0x48, 0xde, 0x47, 0xa3, 0x9d, - 0xf3, 0x4d, 0x4e, 0x8c, 0xba, 0xdb, 0x70, 0x39, 0xf1, 0x8d, 0xf3, 0xba, 0xe9, 0x84, 0xb8, 0xf2, - 0x68, 0x1c, 0xbe, 0x1a, 0xf8, 0x6e, 0x84, 0x01, 0x2a, 0xfc, 0x4e, 0x01, 0xb5, 0xca, 0x9c, 0xaa, - 0xeb, 0x04, 0x62, 0xcf, 0x18, 0x7b, 0xd2, 0xf2, 0x6c, 0xa6, 0xe6, 0x60, 0xde, 0xf2, 0x89, 0xc9, - 0xa9, 0x9f, 0x53, 0x76, 0x94, 0xbd, 0xb4, 0x1e, 0x2e, 0xd5, 0x0d, 0x48, 0x09, 0x11, 0xae, 0x9d, - 0x7b, 0x67, 0x47, 0xd9, 0x9b, 0xd5, 0xe7, 0x71, 0x7d, 0x62, 0xab, 0xc7, 0x90, 0x34, 0x1b, 0xb4, - 0xe5, 0xf1, 0xdc, 0x6c, 0x80, 0x39, 0x2a, 0x7d, 0xfd, 0x7a, 0x7b, 0xe6, 0xef, 0xaf, 0xb7, 0xbf, - 0xe9, 0xb8, 0xfc, 0xa2, 0x55, 0x2b, 0x5a, 0xb4, 0x51, 0xb2, 0x28, 0x6b, 0x50, 0x26, 0x1f, 0xfb, - 0xcc, 0xbe, 0x2c, 0xf1, 0xab, 0x26, 0x61, 0xc5, 0x17, 0xae, 0xc7, 0x75, 0x09, 0x2f, 0xbc, 0x07, - 0x5a, 0xbf, 0x4d, 0x3a, 0x61, 0x4d, 0xea, 0x31, 0x52, 0x78, 0x06, 0xef, 0x56, 0x99, 0xf3, 0xa2, - 0x69, 0x8b, 0x8f, 0x8f, 0x6d, 0xdb, 0x27, 0x6c, 0x94, 0xc9, 0x5b, 0x00, 0x9c, 0x31, 0xa3, 0xd9, - 0xaa, 0x5d, 0x92, 0x2b, 0x34, 0x3a, 0xad, 0xa7, 0x39, 0x63, 0xa7, 0x48, 0x28, 0x6c, 0xc1, 0xe6, - 0x00, 0x79, 0x91, 0xba, 0x3f, 0xbc, 0x03, 0xab, 0x55, 0xe6, 0x3c, 0xb6, 0xed, 0x13, 0xaf, 0x46, - 0x5b, 0x9e, 0x7d, 0xe6, 0x9b, 0xd6, 0x25, 0xf1, 0xa7, 0x8b, 0xd1, 0x3a, 0xcc, 0xf3, 0x8e, 0x71, - 0x61, 0xb2, 0x0b, 0x11, 0x24, 0x3d, 0xc9, 0x3b, 0x9f, 0x99, 0xec, 0x42, 0x3d, 0x82, 0x74, 0x90, - 0x2e, 0x46, 0x10, 0x8e, 0x5c, 0x62, 0x47, 0xd9, 0xcb, 0x96, 0xef, 0x17, 0x07, 0x64, 0x6f, 0xf3, - 0xd2, 0x29, 0x62, 0x5e, 0x55, 0xa8, 0xeb, 0x9d, 0x5d, 0x35, 0x89, 0x9e, 0xb2, 0xe4, 0x9b, 0x7a, - 0x08, 0x73, 0x98, 0x48, 0xb9, 0xb9, 0x1d, 0x65, 0x2f, 0x53, 0xfe, 0xc6, 0x30, 0xbc, 0xcc, 0xb6, - 0xd3, 0xe0, 0xa1, 0x0b, 0x48, 0x10, 0xa4, 0x5a, 0x9d, 0x5a, 0x97, 0xc2, 0xb6, 0xa4, 0x08, 0x12, - 0x52, 0xd0, 0xbc, 0x0d, 0x48, 0xf1, 0x8e, 0xe1, 0x7a, 0x36, 0xe9, 0xe4, 0xe6, 0x85, 0x4b, 0xbc, - 0x73, 0x12, 0x2c, 0x0b, 0x79, 0x78, 0x6f, 0x50, 0x7c, 0xa2, 0x00, 0xfe, 0x55, 0x81, 0x95, 0x2a, - 0x73, 0x7e, 0x74, 0xe1, 0x72, 0x52, 0x77, 0x19, 0xff, 0x54, 0xaf, 0x94, 0x0f, 0x46, 0x44, 0xef, - 0x1e, 0x2c, 0x12, 0xdf, 0x2a, 0x1f, 0x18, 0xa6, 0xd8, 0x09, 0xb9, 0x63, 0x0b, 0x48, 0x0c, 0x77, - 0xbb, 0x3b, 0xc4, 0xb3, 0xbd, 0x21, 0x56, 0x21, 0xe1, 0x99, 0x0d, 0x11, 0xc4, 0xb4, 0x8e, 0xef, - 0xea, 0x1a, 0x24, 0xd9, 0x55, 0xa3, 0x46, 0xeb, 0x18, 0x9a, 0xb4, 0x2e, 0x57, 0xaa, 0x06, 0x29, - 0x9b, 0x58, 0x6e, 0xc3, 0xac, 0x33, 0xf4, 0x79, 0x51, 0x8f, 0xd6, 0xea, 0x26, 0xa4, 0x1d, 0x93, - 0x89, 0x93, 0x26, 0x7d, 0x4e, 0x39, 0x26, 0x7b, 0x1a, 0xac, 0x0b, 0x06, 0x6c, 0xf4, 0xf9, 0x14, - 0x7a, 0x1c, 0x78, 0xf0, 0xb2, 0xc7, 0x03, 0xe1, 0xe1, 0xc2, 0xcb, 0x6e, 0x0f, 0xb6, 0x00, 0x2c, - 0x2b, 0x8a, 0xa9, 0xcc, 0xca, 0x80, 0x22, 0xa2, 0xfa, 0x2f, 0x05, 0xee, 0x88, 0xb0, 0x3e, 0x6f, - 0xf1, 0xdb, 0xe7, 0xdd, 0x2a, 0xcc, 0x79, 0xd4, 0xb3, 0x08, 0x06, 0x2b, 0xa1, 0x8b, 0x45, 0x77, - 0x36, 0x26, 0x7a, 0xb2, 0xf1, 0xff, 0x93, 0x49, 0xdf, 0x87, 0xad, 0x81, 0x2e, 0x47, 0x81, 0xdd, - 0x02, 0x70, 0x99, 0xe1, 0x93, 0x06, 0x6d, 0x13, 0x1b, 0xbd, 0x4f, 0xe9, 0x69, 0x97, 0xe9, 0x82, - 0x50, 0x20, 0x90, 0xab, 0x32, 0x47, 0xac, 0xfe, 0x77, 0x51, 0x2b, 0x14, 0x60, 0x67, 0x98, 0x9a, - 0x28, 0xe9, 0xff, 0xa4, 0xc0, 0x52, 0x95, 0x39, 0x5f, 0x50, 0x4e, 0x8e, 0x4d, 0x76, 0xea, 0xbb, - 0x16, 0x99, 0xda, 0x84, 0x66, 0x80, 0x0e, 0x4d, 0xc0, 0x85, 0x7a, 0x17, 0x16, 0x9a, 0xbe, 0x4b, - 0x7d, 0x97, 0x5f, 0x19, 0xe7, 0x84, 0x60, 0x94, 0x13, 0x7a, 0x26, 0xa4, 0x3d, 0x21, 0xc8, 0x22, - 0xb6, 0xc1, 0x6b, 0x35, 0x6a, 0xc4, 0xc7, 0x0d, 0x4e, 0xe8, 0x19, 0xa4, 0x3d, 0x43, 0xd2, 0x0f, - 0x13, 0xa9, 0xb9, 0xe5, 0x64, 0x61, 0x03, 0xd6, 0x63, 0x96, 0x46, 0x5e, 0xfc, 0x31, 0x19, 0x79, - 0x11, 0x3a, 0x3a, 0xc2, 0x8b, 0x4d, 0xc0, 0xfc, 0x15, 0xfb, 0x2e, 0x12, 0x3a, 0x15, 0x10, 0x70, - 0xdb, 0x3f, 0x80, 0x35, 0x5a, 0x63, 0xc4, 0x6f, 0x13, 0xdb, 0xa0, 0x52, 0x56, 0xf7, 0x3d, 0xb8, - 0x1a, 0x7e, 0x0d, 0x15, 0x21, 0xaa, 0x02, 0xf9, 0x7e, 0x94, 0xcc, 0x2e, 0xe2, 0x3a, 0x17, 0x5c, - 0xba, 0xb5, 0x19, 0x47, 0x1f, 0x61, 0xbe, 0x21, 0x8b, 0xfa, 0x11, 0x68, 0xfd, 0x42, 0x82, 0xa3, - 0xdd, 0x62, 0xc4, 0xce, 0x01, 0x0a, 0x58, 0x8f, 0x0b, 0x38, 0x36, 0xd9, 0x0b, 0x46, 0x6c, 0xf5, - 0x17, 0x0a, 0xdc, 0xef, 0x47, 0x93, 0xf3, 0x73, 0x62, 0x71, 0xb7, 0x4d, 0x50, 0x8e, 0xd8, 0xa0, - 0x0c, 0x16, 0xbd, 0xa2, 0x2c, 0x7a, 0xbb, 0x13, 0x14, 0xbd, 0x13, 0x8f, 0xeb, 0x77, 0xe3, 0x8a, - 0x3f, 0x0d, 0x45, 0x47, 0x79, 0x73, 0x3a, 0xde, 0x02, 0x71, 0x49, 0x2d, 0xa0, 0x2b, 0x23, 0x25, - 0xe2, 0xed, 0xa5, 0x52, 0xc8, 0xb6, 0xcd, 0x7a, 0x8b, 0x18, 0x3e, 0xb1, 0x88, 0x1b, 0x9c, 0x25, - 0xbc, 0x16, 0x8f, 0x3e, 0xbb, 0x61, 0xc5, 0xfe, 0xf7, 0xeb, 0xed, 0x3b, 0x57, 0x66, 0xa3, 0x7e, - 0x58, 0xe8, 0x15, 0x57, 0xd0, 0x17, 0x91, 0xa0, 0xcb, 0xb5, 0xfa, 0x09, 0x24, 0x19, 0x37, 0x79, - 0x4b, 0xdc, 0xb2, 0xd9, 0xf2, 0x83, 0xa1, 0xa5, 0x4d, 0x34, 0x57, 0x12, 0xf8, 0x39, 0x62, 0x74, - 0x89, 0x55, 0xef, 0x43, 0x36, 0xf2, 0x1f, 0x19, 0xe5, 0x05, 0xb2, 0x18, 0x52, 0x2b, 0x01, 0x51, - 0x7d, 0x00, 0x6a, 0xc4, 0x16, 0x14, 0x7e, 0x71, 0x84, 0x53, 0x18, 0x9c, 0xe5, 0xf0, 0xcb, 0x19, - 0x63, 0xcf, 0xf0, 0x0e, 0xec, 0x29, 0xbc, 0xe9, 0xa9, 0x0a, 0x6f, 0xd7, 0x11, 0x0a, 0x63, 0x1e, - 0x1d, 0xa1, 0xbf, 0x24, 0x21, 0x2b, 0xbf, 0xc9, 0xfa, 0x38, 0xe2, 0x04, 0x05, 0x65, 0x8a, 0x78, - 0x36, 0xf1, 0xe5, 0xf1, 0x91, 0x2b, 0x75, 0x17, 0x96, 0xc4, 0x9b, 0x11, 0x2b, 0x7a, 0x8b, 0x82, - 0x5c, 0x91, 0x97, 0x85, 0x06, 0x29, 0xb9, 0x05, 0xbe, 0xbc, 0xd0, 0xa3, 0x75, 0x10, 0xbc, 0xf0, - 0x5d, 0x06, 0x6f, 0x4e, 0x88, 0x08, 0xa9, 0x22, 0x78, 0xd7, 0x4d, 0x5c, 0xf2, 0x56, 0x4d, 0x5c, - 0xe0, 0x65, 0x83, 0x30, 0x66, 0x3a, 0x22, 0xf4, 0x69, 0x3d, 0x5c, 0x06, 0x37, 0x93, 0xeb, 0x75, - 0x5d, 0x00, 0x69, 0xfc, 0x9c, 0x91, 0x34, 0x3c, 0xf7, 0x07, 0xb0, 0x1a, 0xb2, 0xf4, 0x9c, 0x76, - 0x71, 0x58, 0x55, 0xf9, 0xad, 0xfb, 0x90, 0xf7, 0x54, 0xeb, 0x0c, 0xb2, 0x45, 0xd5, 0xba, 0x77, - 0x8f, 0x17, 0xa6, 0x6b, 0xae, 0x36, 0x21, 0xcd, 0x3b, 0x06, 0xf5, 0x5d, 0xc7, 0xf5, 0x72, 0x8b, - 0x22, 0xb8, 0xbc, 0xf3, 0x1c, 0xd7, 0xc1, 0x2d, 0x6d, 0x32, 0x46, 0x78, 0x2e, 0x8b, 0x1f, 0xc4, - 0x42, 0xdd, 0x86, 0x0c, 0x69, 0x13, 0x8f, 0xcb, 0x6a, 0xb7, 0x84, 0x56, 0x01, 0x92, 0xb0, 0xe0, - 0xa9, 0x3e, 0x6c, 0x60, 0x1b, 0x6e, 0xd1, 0xba, 0x61, 0x51, 0x8f, 0xfb, 0xa6, 0xc5, 0x8d, 0x36, - 0xf1, 0x99, 0x4b, 0xbd, 0xdc, 0x32, 0xda, 0xf9, 0xa8, 0x38, 0x72, 0x84, 0x09, 0x4a, 0x2f, 0xe2, - 0x2b, 0x12, 0xfe, 0x85, 0x40, 0xeb, 0xeb, 0xcd, 0xc1, 0x1f, 0xd4, 0x9f, 0x04, 0x79, 0xd0, 0x26, - 0x3e, 0x37, 0x68, 0x93, 0xbb, 0xd4, 0x63, 0xb9, 0x15, 0xac, 0xf1, 0x0f, 0xc6, 0x28, 0xd2, 0x11, - 0xf4, 0x5c, 0x60, 0x8e, 0x12, 0x41, 0x5a, 0x04, 0xb9, 0xd3, 0x45, 0x54, 0xab, 0xb0, 0x60, 0x99, - 0xf5, 0x7a, 0x24, 0x58, 0x45, 0xc1, 0xef, 0x8f, 0x11, 0x5c, 0x31, 0xeb, 0x75, 0x29, 0x41, 0xcf, - 0x58, 0xd7, 0x8b, 0x42, 0x0e, 0xd6, 0x7a, 0x4f, 0x4e, 0x74, 0xa8, 0x9e, 0x62, 0x47, 0xf9, 0xb8, - 0x46, 0x7d, 0xfe, 0x39, 0x6f, 0x59, 0x97, 0x95, 0xca, 0xd9, 0x8f, 0x47, 0x0f, 0x00, 0xa3, 0x5a, - 0xad, 0x4d, 0xec, 0xe5, 0x7a, 0xa5, 0x45, 0xaa, 0xda, 0xd8, 0xfd, 0xeb, 0xe4, 0xbc, 0xe5, 0xd9, - 0xc8, 0x42, 0xec, 0x5b, 0x69, 0x13, 0xe7, 0x30, 0x90, 0x16, 0x75, 0x87, 0xa2, 0x00, 0x2e, 0x0a, - 0xaa, 0x6c, 0x0f, 0x65, 0x57, 0xdd, 0xa7, 0x37, 0xb2, 0xeb, 0x2b, 0x05, 0xad, 0x16, 0x63, 0x8b, - 0x6e, 0x72, 0xf2, 0x54, 0x4c, 0x84, 0x4f, 0x82, 0x81, 0x70, 0x84, 0x75, 0x16, 0xa8, 0xfd, 0x03, - 0x24, 0x5a, 0x99, 0x29, 0x97, 0xc6, 0xa5, 0x40, 0x4c, 0x8d, 0xcc, 0x82, 0x65, 0x3f, 0x46, 0x2f, - 0xdc, 0x83, 0xbb, 0x43, 0x6d, 0x8b, 0x3c, 0xf8, 0xa7, 0x82, 0x83, 0x97, 0x1c, 0xf3, 0xb0, 0x83, - 0xae, 0xb4, 0x18, 0xa7, 0xf6, 0xd5, 0x2d, 0x66, 0xd0, 0x22, 0xbc, 0xeb, 0x91, 0x2f, 0x0d, 0x4b, - 0x08, 0x8a, 0x85, 0x78, 0xc5, 0x23, 0x5f, 0x4a, 0x15, 0x61, 0x17, 0xde, 0x37, 0x6c, 0x24, 0x06, - 0x0c, 0x1b, 0xd7, 0x77, 0xe2, 0xdc, 0xed, 0x06, 0xdb, 0x4f, 0xe0, 0xde, 0x08, 0x8f, 0xbb, 0xdb, - 0xdc, 0xae, 0x0c, 0x52, 0xe2, 0xf9, 0xda, 0xc0, 0xfe, 0x53, 0x44, 0xb7, 0x5b, 0xc8, 0xa9, 0xd9, - 0x62, 0xb2, 0x64, 0x4e, 0xdf, 0x6b, 0x06, 0x32, 0x30, 0x5c, 0x29, 0x5d, 0x2c, 0x0a, 0x27, 0xb0, - 0x37, 0x4e, 0xdd, 0x84, 0x96, 0x97, 0xff, 0x93, 0x85, 0xd9, 0x2a, 0x73, 0xd4, 0x5f, 0x2b, 0xa0, - 0x0e, 0x98, 0x6c, 0x3e, 0x18, 0x93, 0x7f, 0x03, 0x87, 0x03, 0xed, 0x7b, 0xd3, 0xa0, 0x22, 0x8b, - 0x7f, 0xa5, 0xc0, 0x4a, 0xff, 0x6c, 0xff, 0x70, 0x22, 0x99, 0xbd, 0x20, 0xed, 0xa3, 0x29, 0x40, - 0x91, 0x1d, 0xbf, 0x55, 0xe0, 0xce, 0xe0, 0xc9, 0xe5, 0x3b, 0xe3, 0xc5, 0x0e, 0x04, 0x6a, 0x1f, - 0x4f, 0x09, 0x8c, 0x6c, 0x6a, 0xc3, 0x42, 0xcf, 0x00, 0x53, 0x1c, 0x2f, 0xb0, 0x9b, 0x5f, 0x7b, - 0x74, 0x33, 0xfe, 0xb8, 0xde, 0x68, 0xe4, 0x98, 0x50, 0x6f, 0xc8, 0x3f, 0xa9, 0xde, 0x78, 0xaf, - 0xa6, 0x32, 0xc8, 0x74, 0xf7, 0x69, 0xfb, 0x93, 0x89, 0x91, 0xec, 0xda, 0xb7, 0x6f, 0xc4, 0x1e, - 0x29, 0xfd, 0x19, 0x64, 0x63, 0x3f, 0x8d, 0x1c, 0x8c, 0x17, 0xd4, 0x8b, 0xd0, 0x3e, 0xbc, 0x29, - 0x22, 0xd2, 0xfe, 0x4b, 0x05, 0x96, 0xfb, 0x7e, 0x4a, 0x2b, 0x8f, 0x17, 0x17, 0xc7, 0x68, 0x87, - 0x37, 0xc7, 0x44, 0x46, 0xfc, 0x1c, 0x96, 0xe2, 0x3f, 0x40, 0x7e, 0x6b, 0xbc, 0xb8, 0x18, 0x44, - 0xfb, 0xee, 0x8d, 0x21, 0xdd, 0x7b, 0x10, 0x6b, 0x26, 0x26, 0xd8, 0x83, 0x5e, 0xc4, 0x24, 0x7b, - 0x30, 0xb8, 0xc5, 0xc0, 0x2b, 0xa8, 0xbf, 0xc1, 0x78, 0x38, 0xc9, 0xe9, 0x8d, 0x81, 0x26, 0xb9, - 0x82, 0x86, 0xb6, 0x14, 0xea, 0xef, 0x15, 0x58, 0x1b, 0xd2, 0x4f, 0x7c, 0x38, 0xe9, 0xee, 0xc6, - 0x91, 0xda, 0x0f, 0xa6, 0x45, 0x46, 0x66, 0x7d, 0xa5, 0x40, 0x6e, 0x68, 0x93, 0x70, 0x38, 0xf1, - 0xa6, 0xf7, 0x61, 0xb5, 0xa3, 0xe9, 0xb1, 0x91, 0x71, 0x7f, 0x56, 0x60, 0x6b, 0x74, 0x25, 0xfe, - 0x78, 0xd2, 0x00, 0x0c, 0x11, 0xa0, 0x1d, 0xdf, 0x52, 0x40, 0x68, 0xeb, 0xd1, 0xf1, 0xd7, 0x6f, - 0xf2, 0xca, 0xab, 0x37, 0x79, 0xe5, 0x1f, 0x6f, 0xf2, 0xca, 0x6f, 0xde, 0xe6, 0x67, 0x5e, 0xbd, - 0xcd, 0xcf, 0xfc, 0xed, 0x6d, 0x7e, 0xe6, 0xa7, 0xfb, 0x5d, 0x8d, 0x4c, 0xa0, 0x62, 0x5f, 0xfc, - 0xc7, 0xc0, 0xa3, 0x36, 0x29, 0x75, 0x7a, 0xfe, 0xb1, 0x12, 0xf4, 0x34, 0xb5, 0x24, 0xce, 0x16, - 0x0f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x68, 0xfd, 0xc9, 0x86, 0x19, 0x00, 0x00, + // 1818 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x4f, 0x6f, 0xdb, 0xd8, + 0x11, 0x0f, 0x13, 0x59, 0x91, 0x46, 0xb6, 0x92, 0xbc, 0x75, 0x12, 0x9a, 0x5e, 0x2b, 0x8e, 0xd2, + 0xa4, 0xc6, 0x22, 0x91, 0x52, 0x65, 0x9b, 0x6e, 0xb3, 0x45, 0xb7, 0xb1, 0x76, 0xe3, 0x35, 0x10, + 0x25, 0x06, 0xd7, 0xd9, 0xfe, 0xb9, 0x10, 0x14, 0xf9, 0x4c, 0x13, 0x96, 0xf8, 0x04, 0xbe, 0x27, + 0xad, 0x14, 0x14, 0x68, 0x51, 0xa0, 0x40, 0x8f, 0x6d, 0xd1, 0xd3, 0x1e, 0x7a, 0xeb, 0xa1, 0xdf, + 0xa0, 0xa7, 0x9e, 0xf7, 0xb8, 0xe8, 0xa9, 0xe8, 0x21, 0x28, 0x92, 0x2f, 0xd0, 0xf6, 0xda, 0x4b, + 0xc1, 0x79, 0x8f, 0x8c, 0x44, 0xfd, 0xb5, 0x8c, 0x62, 0x2f, 0x26, 0xdf, 0x70, 0x7e, 0xf3, 0x66, + 0xe6, 0xcd, 0xbc, 0x99, 0x91, 0xe1, 0xce, 0x4b, 0x2a, 0x6c, 0xe7, 0xd8, 0xf6, 0x83, 0x2a, 0xbe, + 0xb1, 0x90, 0x56, 0x9d, 0x90, 0x71, 0x2e, 0x69, 0xa2, 0x5f, 0xe9, 0x84, 0x4c, 0x30, 0xb2, 0x95, + 0xf0, 0x55, 0x62, 0xbe, 0xca, 0x5b, 0x3e, 0x63, 0xdd, 0x63, 0x1e, 0x43, 0xce, 0x6a, 0xf4, 0x26, + 0x41, 0xc6, 0x7b, 0x13, 0x84, 0x77, 0x4e, 0xbc, 0x2a, 0x92, 0xb8, 0x7a, 0x28, 0xde, 0x3b, 0xd3, + 0x78, 0x99, 0x1f, 0xe0, 0x9f, 0x39, 0x32, 0x3b, 0x21, 0x63, 0x47, 0x5c, 0x3d, 0x14, 0xef, 0xc3, + 0xd9, 0xc6, 0x85, 0xb6, 0xa0, 0x56, 0xcb, 0x6f, 0xfb, 0x82, 0x86, 0xd6, 0x51, 0xcb, 0xf6, 0x62, + 0x5c, 0x6d, 0x36, 0x0e, 0x5f, 0x2d, 0x7c, 0xb7, 0x62, 0x07, 0x95, 0x7f, 0xaf, 0x01, 0x69, 0x70, + 0xaf, 0xe1, 0x7b, 0x91, 0xd8, 0x43, 0xce, 0x9f, 0x74, 0x03, 0x97, 0x13, 0x1d, 0x2e, 0x3a, 0x21, + 0xb5, 0x05, 0x0b, 0x75, 0x6d, 0x5b, 0xdb, 0xc9, 0x9b, 0xf1, 0x92, 0x6c, 0x40, 0x4e, 0x8a, 0xf0, + 0x5d, 0xfd, 0xfc, 0xb6, 0xb6, 0x73, 0xc1, 0xbc, 0x88, 0xeb, 0x7d, 0x97, 0xec, 0x41, 0xd6, 0x6e, + 0xb3, 0x6e, 0x20, 0xf4, 0x0b, 0x11, 0x66, 0xb7, 0xfa, 0xd5, 0xab, 0x1b, 0xe7, 0xfe, 0xf1, 0xea, + 0xc6, 0xb7, 0x3d, 0x5f, 0x1c, 0x77, 0x9b, 0x15, 0x87, 0xb5, 0xab, 0x0e, 0xe3, 0x6d, 0xc6, 0xd5, + 0xe3, 0x1e, 0x77, 0x4f, 0xaa, 0x62, 0xd0, 0xa1, 0xbc, 0xf2, 0xc2, 0x0f, 0x84, 0xa9, 0xe0, 0xe5, + 0x77, 0xc1, 0x18, 0xd7, 0xc9, 0xa4, 0xbc, 0xc3, 0x02, 0x4e, 0xcb, 0xcf, 0xe0, 0x9d, 0x06, 0xf7, + 0x5e, 0x74, 0x5c, 0xf9, 0xf1, 0xb1, 0xeb, 0x86, 0x94, 0xcf, 0x52, 0x79, 0x0b, 0x40, 0x70, 0x6e, + 0x75, 0xba, 0xcd, 0x13, 0x3a, 0x40, 0xa5, 0xf3, 0x66, 0x5e, 0x70, 0x7e, 0x80, 0x84, 0xf2, 0x16, + 0x6c, 0x4e, 0x90, 0x97, 0x6c, 0xf7, 0xc7, 0xf3, 0xb0, 0xde, 0xe0, 0xde, 0x63, 0xd7, 0xdd, 0x0f, + 0x9a, 0xac, 0x1b, 0xb8, 0x87, 0xa1, 0xed, 0x9c, 0xd0, 0x70, 0x39, 0x1f, 0x5d, 0x87, 0x8b, 0xa2, + 0x6f, 0x1d, 0xdb, 0xfc, 0x58, 0x3a, 0xc9, 0xcc, 0x8a, 0xfe, 0xa7, 0x36, 0x3f, 0x26, 0xbb, 0x90, + 0x8f, 0xc2, 0xc5, 0x8a, 0xdc, 0xa1, 0x67, 0xb6, 0xb5, 0x9d, 0x62, 0xed, 0x76, 0x65, 0x42, 0xf4, + 0x76, 0x4e, 0xbc, 0x0a, 0xc6, 0x55, 0x9d, 0xf9, 0xc1, 0xe1, 0xa0, 0x43, 0xcd, 0x9c, 0xa3, 0xde, + 0xc8, 0x23, 0x58, 0xc1, 0x40, 0xd2, 0x57, 0xb6, 0xb5, 0x9d, 0x42, 0xed, 0x5b, 0xd3, 0xf0, 0x2a, + 0xda, 0x0e, 0xa2, 0x87, 0x29, 0x21, 0x91, 0x93, 0x9a, 0x2d, 0xe6, 0x9c, 0x48, 0xdd, 0xb2, 0xd2, + 0x49, 0x48, 0x41, 0xf5, 0x36, 0x20, 0x27, 0xfa, 0x96, 0x1f, 0xb8, 0xb4, 0xaf, 0x5f, 0x94, 0x26, + 0x89, 0xfe, 0x7e, 0xb4, 0x2c, 0x97, 0xe0, 0xdd, 0x49, 0xfe, 0x49, 0x1c, 0xf8, 0x37, 0x0d, 0xae, + 0x34, 0xb8, 0xf7, 0xe3, 0x63, 0x5f, 0xd0, 0x96, 0xcf, 0xc5, 0x27, 0x66, 0xbd, 0x76, 0x7f, 0x86, + 0xf7, 0x6e, 0xc1, 0x1a, 0x0d, 0x9d, 0xda, 0x7d, 0xcb, 0x96, 0x27, 0xa1, 0x4e, 0x6c, 0x15, 0x89, + 0xf1, 0x69, 0x0f, 0xbb, 0xf8, 0xc2, 0xa8, 0x8b, 0x09, 0x64, 0x02, 0xbb, 0x2d, 0x9d, 0x98, 0x37, + 0xf1, 0x9d, 0x5c, 0x83, 0x2c, 0x1f, 0xb4, 0x9b, 0xac, 0x85, 0xae, 0xc9, 0x9b, 0x6a, 0x45, 0x0c, + 0xc8, 0xb9, 0xd4, 0xf1, 0xdb, 0x76, 0x8b, 0xa3, 0xcd, 0x6b, 0x66, 0xb2, 0x26, 0x9b, 0x90, 0xf7, + 0x6c, 0x2e, 0x33, 0x4d, 0xd9, 0x9c, 0xf3, 0x6c, 0xfe, 0x34, 0x5a, 0x97, 0x2d, 0xd8, 0x18, 0xb3, + 0x29, 0xb6, 0x38, 0xb2, 0xe0, 0xe5, 0x88, 0x05, 0xd2, 0xc2, 0xd5, 0x97, 0xc3, 0x16, 0x6c, 0x01, + 0x38, 0x4e, 0xe2, 0x53, 0x15, 0x95, 0x11, 0x45, 0x7a, 0xf5, 0xdf, 0x1a, 0x5c, 0x95, 0x6e, 0x7d, + 0xde, 0x15, 0x67, 0x8f, 0xbb, 0x75, 0x58, 0x09, 0x58, 0xe0, 0x50, 0x74, 0x56, 0xc6, 0x94, 0x8b, + 0xe1, 0x68, 0xcc, 0x8c, 0x44, 0xe3, 0x37, 0x13, 0x49, 0x3f, 0x84, 0xad, 0x89, 0x26, 0x27, 0x8e, + 0xdd, 0x02, 0xf0, 0xb9, 0x15, 0xd2, 0x36, 0xeb, 0x51, 0x17, 0xad, 0xcf, 0x99, 0x79, 0x9f, 0x9b, + 0x92, 0x50, 0xa6, 0xa0, 0x37, 0xb8, 0x27, 0x57, 0xff, 0x3f, 0xaf, 0x95, 0xcb, 0xb0, 0x3d, 0x6d, + 0x9b, 0x24, 0xe8, 0xff, 0xaa, 0xc1, 0xa5, 0x06, 0xf7, 0x3e, 0x67, 0x82, 0xee, 0xd9, 0xfc, 0x20, + 0xf4, 0x1d, 0xba, 0xb4, 0x0a, 0x9d, 0x08, 0x1d, 0xab, 0x80, 0x0b, 0x72, 0x13, 0x56, 0x3b, 0xa1, + 0xcf, 0x42, 0x5f, 0x0c, 0xac, 0x23, 0x4a, 0xd1, 0xcb, 0x19, 0xb3, 0x10, 0xd3, 0x9e, 0x50, 0x64, + 0x91, 0xc7, 0x10, 0x74, 0xdb, 0x4d, 0x1a, 0xe2, 0x01, 0x67, 0xcc, 0x02, 0xd2, 0x9e, 0x21, 0x89, + 0x18, 0x90, 0xe5, 0xdd, 0x4e, 0xa7, 0x35, 0x90, 0x59, 0xb1, 0x7b, 0x5e, 0xd7, 0x4c, 0x45, 0x29, + 0x6f, 0xc0, 0xf5, 0x94, 0xfe, 0x89, 0x6d, 0x7f, 0xca, 0x26, 0xb6, 0xc5, 0xe6, 0xcf, 0xb0, 0x6d, + 0x13, 0x30, 0xaa, 0x65, 0x34, 0xc8, 0x30, 0xcf, 0x45, 0x04, 0x0c, 0x86, 0xf7, 0xe1, 0x1a, 0x6b, + 0x72, 0x1a, 0xf6, 0xa8, 0x6b, 0x31, 0x25, 0x6b, 0xf8, 0x76, 0x5c, 0x8f, 0xbf, 0xc6, 0x1b, 0x21, + 0xaa, 0x0e, 0xa5, 0x71, 0x94, 0x8a, 0x39, 0xea, 0x7b, 0xc7, 0x42, 0x19, 0xbb, 0x99, 0x46, 0xef, + 0x62, 0x14, 0x22, 0x0b, 0xf9, 0x10, 0x8c, 0x71, 0x21, 0x51, 0xc2, 0x77, 0x39, 0x75, 0x75, 0x40, + 0x01, 0xd7, 0xd3, 0x02, 0xf6, 0x6c, 0xfe, 0x82, 0x53, 0x97, 0xfc, 0x52, 0x83, 0xdb, 0xe3, 0x68, + 0x7a, 0x74, 0x44, 0x1d, 0xe1, 0xf7, 0x28, 0xca, 0x91, 0xc7, 0x56, 0x40, 0xcf, 0x56, 0x54, 0x29, + 0xbc, 0xb3, 0x40, 0x29, 0xdc, 0x0f, 0x84, 0x79, 0x33, 0xbd, 0xf1, 0x27, 0xb1, 0xe8, 0x24, 0x9a, + 0x0e, 0xe6, 0x6b, 0x20, 0xaf, 0xae, 0x55, 0x34, 0x65, 0xa6, 0x44, 0xbc, 0xd3, 0x08, 0x83, 0x62, + 0xcf, 0x6e, 0x75, 0xa9, 0x15, 0x52, 0x87, 0xfa, 0x51, 0x86, 0xc9, 0xb0, 0xf8, 0xf4, 0x94, 0x75, + 0xfc, 0x3f, 0xaf, 0x6e, 0x5c, 0x1d, 0xd8, 0xed, 0xd6, 0xa3, 0xf2, 0xa8, 0xb8, 0xb2, 0xb9, 0x86, + 0x04, 0x53, 0xad, 0xc9, 0xc7, 0x90, 0xe5, 0xc2, 0x16, 0x5d, 0x79, 0xf7, 0x16, 0x6b, 0x77, 0xa7, + 0x16, 0x3c, 0xd9, 0x72, 0x29, 0xe0, 0x67, 0x88, 0x31, 0x15, 0x96, 0xdc, 0x86, 0x62, 0x62, 0x3f, + 0x32, 0xaa, 0x6b, 0x65, 0x2d, 0xa6, 0xd6, 0x23, 0x22, 0xb9, 0x0b, 0x24, 0x61, 0x8b, 0xda, 0x01, + 0x99, 0xd8, 0x39, 0x74, 0xce, 0xe5, 0xf8, 0xcb, 0x21, 0xe7, 0xcf, 0xf0, 0x66, 0x1c, 0x29, 0xc7, + 0xf9, 0xa5, 0xca, 0xf1, 0x50, 0x0a, 0xc5, 0x3e, 0x4f, 0x52, 0xe8, 0x2f, 0x59, 0x28, 0xaa, 0x6f, + 0xaa, 0x6a, 0xce, 0xc8, 0xa0, 0xa8, 0x78, 0xd1, 0xc0, 0xa5, 0xa1, 0x4a, 0x1f, 0xb5, 0x22, 0x77, + 0xe0, 0x92, 0x7c, 0xb3, 0x52, 0xa5, 0x70, 0x4d, 0x92, 0xeb, 0xea, 0x0a, 0x31, 0x20, 0xa7, 0x8e, + 0x20, 0x54, 0xd7, 0x7c, 0xb2, 0x8e, 0x9c, 0x17, 0xbf, 0x2b, 0xe7, 0xad, 0x48, 0x11, 0x31, 0x55, + 0x3a, 0xef, 0x6d, 0x6b, 0x97, 0x3d, 0x53, 0x6b, 0x17, 0x59, 0xd9, 0xa6, 0x9c, 0xdb, 0x9e, 0x74, + 0x7d, 0xde, 0x8c, 0x97, 0xd1, 0x7d, 0xe5, 0x07, 0x43, 0x17, 0x40, 0x1e, 0x3f, 0x17, 0x14, 0x0d, + 0xf3, 0xfe, 0x3e, 0xac, 0xc7, 0x2c, 0x23, 0xd9, 0x2e, 0x93, 0x95, 0xa8, 0x6f, 0xc3, 0x49, 0x3e, + 0x52, 0xc3, 0x0b, 0xc8, 0x96, 0xd4, 0xf0, 0xd1, 0x33, 0x5e, 0x5d, 0xae, 0xe5, 0xda, 0x84, 0xbc, + 0xe8, 0x5b, 0x2c, 0xf4, 0x3d, 0x3f, 0xd0, 0xd7, 0xa4, 0x73, 0x45, 0xff, 0x39, 0xae, 0xa3, 0xbb, + 0xdb, 0xe6, 0x9c, 0x0a, 0xbd, 0x88, 0x1f, 0xe4, 0x82, 0xdc, 0x80, 0x02, 0xed, 0xd1, 0x40, 0xa8, + 0x1a, 0x78, 0x09, 0xb5, 0x02, 0x24, 0x61, 0x19, 0x24, 0x21, 0x6c, 0x60, 0x73, 0xee, 0xb0, 0x96, + 0xe5, 0xb0, 0x40, 0x84, 0xb6, 0x23, 0xac, 0x1e, 0x0d, 0xb9, 0xcf, 0x02, 0xfd, 0x32, 0xea, 0xf9, + 0xb0, 0x32, 0x73, 0xb0, 0x89, 0x0a, 0x32, 0xe2, 0xeb, 0x0a, 0xfe, 0xb9, 0x44, 0x9b, 0xd7, 0x3b, + 0x93, 0x3f, 0x90, 0x9f, 0x46, 0x71, 0xd0, 0xa3, 0xa1, 0xb0, 0x58, 0x47, 0xf8, 0x2c, 0xe0, 0xfa, + 0x15, 0xac, 0xfc, 0x77, 0xe7, 0x6c, 0x64, 0x22, 0xe8, 0xb9, 0xc4, 0xec, 0x66, 0xa2, 0xb0, 0x88, + 0x62, 0x67, 0x88, 0x48, 0x1a, 0xb0, 0xea, 0xd8, 0xad, 0x56, 0x22, 0x98, 0xa0, 0xe0, 0xf7, 0xe6, + 0x08, 0xae, 0xdb, 0xad, 0x96, 0x92, 0x60, 0x16, 0x9c, 0xb7, 0x8b, 0xb2, 0x0e, 0xd7, 0x46, 0x33, + 0x27, 0x49, 0xaa, 0xa7, 0xd8, 0x67, 0x3e, 0x6e, 0xb2, 0x50, 0x7c, 0x26, 0xba, 0xce, 0x49, 0xbd, + 0x7e, 0xf8, 0x93, 0xd9, 0x63, 0xc1, 0xac, 0x06, 0x6c, 0x13, 0x3b, 0xbc, 0x51, 0x69, 0xc9, 0x56, + 0x3d, 0x9c, 0x09, 0x4c, 0x7a, 0xd4, 0x0d, 0x5c, 0x64, 0xa1, 0xee, 0x99, 0x76, 0x93, 0x79, 0x18, + 0x49, 0x4b, 0x7a, 0x46, 0x59, 0x00, 0xd7, 0x24, 0x55, 0x35, 0x8d, 0xaa, 0xd7, 0x1e, 0xdb, 0x37, + 0xd1, 0xeb, 0x4b, 0x0d, 0xb5, 0x96, 0xc3, 0x8c, 0x69, 0x0b, 0xfa, 0x54, 0xce, 0x89, 0x4f, 0xa2, + 0x31, 0x71, 0x86, 0x76, 0x0e, 0x90, 0xf1, 0xb1, 0x12, 0xb5, 0x2c, 0xd4, 0xaa, 0xf3, 0x42, 0x20, + 0xb5, 0x8d, 0x8a, 0x82, 0xcb, 0x61, 0x8a, 0x5e, 0xbe, 0x05, 0x37, 0xa7, 0xea, 0x96, 0x58, 0xf0, + 0x2f, 0x0d, 0xc7, 0x31, 0x35, 0xfc, 0x61, 0x5f, 0x5d, 0xef, 0x72, 0xc1, 0xdc, 0xc1, 0x19, 0x26, + 0xd3, 0x0a, 0xbc, 0x13, 0xd0, 0x2f, 0x2c, 0x47, 0x0a, 0x4a, 0xb9, 0xf8, 0x4a, 0x40, 0xbf, 0x50, + 0x5b, 0xc4, 0xbd, 0xf9, 0xd8, 0x08, 0x92, 0x99, 0x30, 0x82, 0xbc, 0xbd, 0x13, 0x57, 0xce, 0x36, + 0xee, 0x7e, 0x0c, 0xb7, 0x66, 0x58, 0x3c, 0xdc, 0xfc, 0x0e, 0x45, 0x90, 0x96, 0x8e, 0xd7, 0x36, + 0x76, 0xa5, 0xd2, 0xbb, 0xc3, 0x42, 0x0e, 0xec, 0x2e, 0x57, 0x25, 0x73, 0xf9, 0x0e, 0x34, 0x92, + 0x81, 0xee, 0xca, 0x99, 0x72, 0x51, 0xde, 0x87, 0x9d, 0x79, 0xdb, 0x2d, 0xa8, 0x79, 0xed, 0xbf, + 0x45, 0xb8, 0xd0, 0xe0, 0x1e, 0xf9, 0x8d, 0x06, 0x64, 0xc2, 0xbc, 0xf3, 0xfe, 0x9c, 0xf8, 0x9b, + 0x38, 0x32, 0x18, 0x3f, 0x58, 0x06, 0x95, 0x68, 0xfc, 0x6b, 0x0d, 0xae, 0x8c, 0x4f, 0xfc, 0x0f, + 0x16, 0x92, 0x39, 0x0a, 0x32, 0x3e, 0x5c, 0x02, 0x94, 0xe8, 0xf1, 0x3b, 0x0d, 0xae, 0x4e, 0x9e, + 0x67, 0xbe, 0x37, 0x5f, 0xec, 0x44, 0xa0, 0xf1, 0xd1, 0x92, 0xc0, 0x44, 0xa7, 0x1e, 0xac, 0x8e, + 0x8c, 0x35, 0x95, 0xf9, 0x02, 0x87, 0xf9, 0x8d, 0x87, 0xa7, 0xe3, 0x4f, 0xef, 0x9b, 0x8c, 0x1c, + 0x0b, 0xee, 0x1b, 0xf3, 0x2f, 0xba, 0x6f, 0xba, 0x57, 0x23, 0x1c, 0x0a, 0xc3, 0x7d, 0xda, 0xbd, + 0xc5, 0xc4, 0x28, 0x76, 0xe3, 0xbb, 0xa7, 0x62, 0x4f, 0x36, 0xfd, 0x39, 0x14, 0x53, 0x3f, 0x98, + 0xdc, 0x9f, 0x2f, 0x68, 0x14, 0x61, 0x7c, 0x70, 0x5a, 0x44, 0xb2, 0xfb, 0xaf, 0x34, 0xb8, 0x3c, + 0xf6, 0x03, 0x5b, 0x6d, 0xbe, 0xb8, 0x34, 0xc6, 0x78, 0x74, 0x7a, 0x4c, 0xa2, 0xc4, 0x2f, 0xe0, + 0x52, 0xfa, 0x67, 0xc9, 0xef, 0xcc, 0x17, 0x97, 0x82, 0x18, 0xdf, 0x3f, 0x35, 0x64, 0xf8, 0x0c, + 0x52, 0xcd, 0xc4, 0x02, 0x67, 0x30, 0x8a, 0x58, 0xe4, 0x0c, 0x26, 0xb7, 0x18, 0x78, 0x05, 0x8d, + 0x37, 0x18, 0x0f, 0x16, 0xc9, 0xde, 0x14, 0x68, 0x91, 0x2b, 0x68, 0x6a, 0x4b, 0x41, 0xfe, 0xa0, + 0xc1, 0xb5, 0x29, 0xfd, 0xc4, 0x07, 0x8b, 0x9e, 0x6e, 0x1a, 0x69, 0xfc, 0x68, 0x59, 0x64, 0xa2, + 0xd6, 0x97, 0x1a, 0xe8, 0x53, 0x9b, 0x84, 0x47, 0x0b, 0x1f, 0xfa, 0x18, 0xd6, 0xd8, 0x5d, 0x1e, + 0x9b, 0x28, 0xf7, 0x67, 0x0d, 0xb6, 0x66, 0x57, 0xe2, 0x8f, 0x16, 0x75, 0xc0, 0x14, 0x01, 0xc6, + 0xde, 0x19, 0x05, 0xc4, 0xba, 0xee, 0xee, 0x7d, 0xf5, 0xba, 0xa4, 0x7d, 0xfd, 0xba, 0xa4, 0xfd, + 0xf3, 0x75, 0x49, 0xfb, 0xed, 0x9b, 0xd2, 0xb9, 0xaf, 0xdf, 0x94, 0xce, 0xfd, 0xfd, 0x4d, 0xe9, + 0xdc, 0xcf, 0xee, 0x0d, 0x35, 0x32, 0xd1, 0x16, 0xf7, 0xe4, 0xff, 0x11, 0x02, 0xe6, 0xd2, 0x6a, + 0x7f, 0xe4, 0xdf, 0x2d, 0x51, 0x4f, 0xd3, 0xcc, 0xe2, 0x6c, 0xf1, 0xe0, 0x7f, 0x01, 0x00, 0x00, + 0xff, 0xff, 0x45, 0x32, 0x2c, 0x14, 0x9c, 0x19, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2896,6 +2906,13 @@ func (m *MsgVoteGasPrice) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x30 } + if len(m.Supply) > 0 { + i -= len(m.Supply) + copy(dAtA[i:], m.Supply) + i = encodeVarintTx(dAtA, i, uint64(len(m.Supply))) + i-- + dAtA[i] = 0x2a + } if m.BlockNumber != 0 { i = encodeVarintTx(dAtA, i, uint64(m.BlockNumber)) i-- @@ -3839,6 +3856,10 @@ func (m *MsgVoteGasPrice) Size() (n int) { if m.BlockNumber != 0 { n += 1 + sovTx(uint64(m.BlockNumber)) } + l = len(m.Supply) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } if m.PriorityFee != 0 { n += 1 + sovTx(uint64(m.PriorityFee)) } @@ -5725,6 +5746,38 @@ func (m *MsgVoteGasPrice) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Supply", 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.Supply = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex case 6: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field PriorityFee", wireType) From 7b2bbe763d7a180befc8254b0cf3142e8c1b5d60 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Wed, 16 Oct 2024 17:43:57 +0200 Subject: [PATCH 28/36] docs: update readme with new protocol contract directories (#3011) --- readme.md | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index 61f04f632f..6995b2c6a3 100644 --- a/readme.md +++ b/readme.md @@ -19,12 +19,22 @@ modular framework for building blockchain and [Ethermint](https://github.com/zeta-chain/ethermint), a module that implements EVM-compatibility (ZetaChain fork). -- [zeta-node](https://github.com/zeta-chain/zeta-node) (this repository) - contains the source code for the ZetaChain node (`zetacored`) and the - ZetaChain client (`zetaclientd`). -- [protocol-contracts](https://github.com/zeta-chain/protocol-contracts) - contains the source code for the Solidity smart contracts that implement the - core functionality of ZetaChain. +This repository contains the core components: + +* [Blockchain Modules (ZetaCore)](x): +This section contains the core logic of the ZetaChain blockchain, built using Cosmos SDK modules. These modules are responsible for managing the state, state transitions, and overall functionality of the ZetaChain network. +* [ZetaClient](zetaclient): +The ZetaClient is a specialized client designed to act as an observer and signer for the ZetaChain network. It is responsible for communicating with the blockchain, relaying messages, and performing signature tasks to ensure the network operates cross-chain transactions. + +### Protocol Contracts + +In addition to the blockchain codebase, ZetaChain’s architecture includes a set of protocol contracts that serve as an interface for developers to interact with the blockchain. These smart contracts are deployed across various blockchain networks. The smart contract source code is maintained in separate repositories, depending on the network they are deployed on: + +* [ZetaChain EVM and EVM connected chains](https://github.com/zeta-chain/protocol-contracts) +* [Solana connected chains (SVM)](https://github.com/zeta-chain/protocol-contracts-solana) +* [TON connected chains (TVM)](https://github.com/zeta-chain/protocol-contracts-ton) + +These repositories contain the necessary code and tools to deploy, interact with, and extend the functionality of ZetaChain’s cross-chain protocol on each respective blockchain network. ## Building the `zetacored`/`zetaclientd` binaries From 250b90e43993ceb8eecbdd02c909dbb7638de6a7 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:14:20 -0500 Subject: [PATCH 29/36] feat: standard non-evm inbound memo (#2987) * initiated memo package * add unit tests against memo fields version 0 * added memo unit tests * use separate file for memo header; add more unit tests * a few renaming and wrapped err message * add extra good-to-have check for memo fields validation * add changelog entry * fix nosec error * add two more unit tests for missed lines * remove redundant dependency github.com/test-go/testify v1.1.4 * enhance codec error message * a few renaming and move test constant to testutil pkg * corrected typo and improved unit tests * fix build * make receiver address optional * move bits.go to bits folder; type defines for OpCode and EncodingFormat; add more func descriptions * move legacy Bitcoin memo decoding to memo package * move sample functions ABIPack, CompactPack into memo pkg self; remove sample package reference from memo to minimize dependency * fix unit test compile error --- changelog.md | 1 + pkg/chains/conversion.go | 25 -- pkg/chains/utils_test.go | 37 -- pkg/math/bits/bits.go | 56 +++ pkg/math/bits/bits_test.go | 171 ++++++++ pkg/memo/arg.go | 52 +++ pkg/memo/arg_test.go | 70 +++ pkg/memo/codec.go | 64 +++ pkg/memo/codec_abi.go | 94 ++++ pkg/memo/codec_abi_test.go | 345 +++++++++++++++ pkg/memo/codec_compact.go | 265 +++++++++++ pkg/memo/codec_compact_test.go | 413 ++++++++++++++++++ pkg/memo/codec_test.go | 92 ++++ pkg/memo/fields.go | 16 + pkg/memo/fields_v0.go | 208 +++++++++ pkg/memo/fields_v0_test.go | 388 ++++++++++++++++ pkg/memo/header.go | 139 ++++++ pkg/memo/header_test.go | 167 +++++++ pkg/memo/memo.go | 98 +++++ pkg/memo/memo_test.go | 306 +++++++++++++ x/crosschain/keeper/evm_deposit.go | 3 +- zetaclient/chains/bitcoin/observer/inbound.go | 4 +- zetaclient/chains/evm/observer/inbound.go | 6 +- zetaclient/compliance/compliance.go | 4 +- 24 files changed, 2954 insertions(+), 70 deletions(-) create mode 100644 pkg/math/bits/bits.go create mode 100644 pkg/math/bits/bits_test.go create mode 100644 pkg/memo/arg.go create mode 100644 pkg/memo/arg_test.go create mode 100644 pkg/memo/codec.go create mode 100644 pkg/memo/codec_abi.go create mode 100644 pkg/memo/codec_abi_test.go create mode 100644 pkg/memo/codec_compact.go create mode 100644 pkg/memo/codec_compact_test.go create mode 100644 pkg/memo/codec_test.go create mode 100644 pkg/memo/fields.go create mode 100644 pkg/memo/fields_v0.go create mode 100644 pkg/memo/fields_v0_test.go create mode 100644 pkg/memo/header.go create mode 100644 pkg/memo/header_test.go create mode 100644 pkg/memo/memo.go create mode 100644 pkg/memo/memo_test.go diff --git a/changelog.md b/changelog.md index 8bfbae13f7..3f8206a9f1 100644 --- a/changelog.md +++ b/changelog.md @@ -18,6 +18,7 @@ * [2919](https://github.com/zeta-chain/node/pull/2919) - add inbound sender to revert context * [2957](https://github.com/zeta-chain/node/pull/2957) - enable Bitcoin inscription support on testnet * [2896](https://github.com/zeta-chain/node/pull/2896) - add TON inbound observation +* [2987](https://github.com/zeta-chain/node/pull/2987) - add non-EVM standard inbound memo package ### Refactor diff --git a/pkg/chains/conversion.go b/pkg/chains/conversion.go index 3200b76693..5d03b77007 100644 --- a/pkg/chains/conversion.go +++ b/pkg/chains/conversion.go @@ -1,10 +1,8 @@ package chains import ( - "encoding/hex" "fmt" - "cosmossdk.io/errors" "github.com/btcsuite/btcd/chaincfg/chainhash" ethcommon "github.com/ethereum/go-ethereum/common" ) @@ -28,26 +26,3 @@ func StringToHash(chainID int64, hash string, additionalChains []Chain) ([]byte, } return nil, fmt.Errorf("cannot convert hash to bytes for chain %d", chainID) } - -// ParseAddressAndData parses the message string into an address and data -// message is hex encoded byte array -// [ contractAddress calldata ] -// [ 20B, variable] -func ParseAddressAndData(message string) (ethcommon.Address, []byte, error) { - if len(message) == 0 { - return ethcommon.Address{}, nil, nil - } - - data, err := hex.DecodeString(message) - if err != nil { - return ethcommon.Address{}, nil, errors.Wrap(err, "message should be a hex encoded string") - } - - if len(data) < 20 { - return ethcommon.Address{}, data, nil - } - - address := ethcommon.BytesToAddress(data[:20]) - data = data[20:] - return address, data, nil -} diff --git a/pkg/chains/utils_test.go b/pkg/chains/utils_test.go index 915fa2b8ca..7552e10967 100644 --- a/pkg/chains/utils_test.go +++ b/pkg/chains/utils_test.go @@ -1,7 +1,6 @@ package chains import ( - "encoding/hex" "testing" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -66,39 +65,3 @@ func TestStringToHash(t *testing.T) { }) } } - -func TestParseAddressAndData(t *testing.T) { - expectedShortMsgResult, err := hex.DecodeString("1a2b3c4d5e6f708192a3b4c5d6e7f808") - require.NoError(t, err) - tests := []struct { - name string - message string - expectAddr ethcommon.Address - expectData []byte - wantErr bool - }{ - { - "valid msg", - "95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5", - ethcommon.HexToAddress("95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5"), - []byte{}, - false, - }, - {"empty msg", "", ethcommon.Address{}, nil, false}, - {"invalid hex", "invalidHex", ethcommon.Address{}, nil, true}, - {"short msg", "1a2b3c4d5e6f708192a3b4c5d6e7f808", ethcommon.Address{}, expectedShortMsgResult, false}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - addr, data, err := ParseAddressAndData(tt.message) - if tt.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - require.Equal(t, tt.expectAddr, addr) - require.Equal(t, tt.expectData, data) - } - }) - } -} diff --git a/pkg/math/bits/bits.go b/pkg/math/bits/bits.go new file mode 100644 index 0000000000..a7a7865793 --- /dev/null +++ b/pkg/math/bits/bits.go @@ -0,0 +1,56 @@ +package math + +import ( + "math/bits" +) + +// SetBit sets the bit at the given position (0-7) in the byte to 1 +func SetBit(b *byte, position uint8) { + if position > 7 { + return + } + + // Example: given b = 0b00000000 and position = 3 + // step-1: shift value 1 to left by 3 times: 1 << 3 = 0b00001000 + // step-2: make an OR operation with original byte to set the bit: 0b00000000 | 0b00001000 = 0b00001000 + *b |= 1 << position +} + +// IsBitSet returns true if the bit at the given position (0-7) is set in the byte, false otherwise +func IsBitSet(b byte, position uint8) bool { + if position > 7 { + return false + } + bitMask := byte(1 << position) + return b&bitMask != 0 +} + +// GetBits extracts the value of bits for a given mask +// +// Example: given b = 0b11011001 and mask = 0b11100000, the function returns 0b110 +func GetBits(b byte, mask byte) byte { + extracted := b & mask + + // get the number of trailing zero bits + trailingZeros := bits.TrailingZeros8(mask) + + // remove trailing zeros + return extracted >> trailingZeros +} + +// SetBits sets the value to the bits specified in the mask +// +// Example: given b = 0b00100001 and mask = 0b11100000, and value = 0b110, the function returns 0b11000001 +func SetBits(b byte, mask byte, value byte) byte { + // get the number of trailing zero bits in the mask + trailingZeros := bits.TrailingZeros8(mask) + + // shift the value left by the number of trailing zeros + valueShifted := value << trailingZeros + + // clear the bits in 'b' that correspond to the mask + bCleared := b &^ mask + + // Set the bits by ORing the cleared 'b' with the shifted value + return bCleared | valueShifted +} diff --git a/pkg/math/bits/bits_test.go b/pkg/math/bits/bits_test.go new file mode 100644 index 0000000000..65632d0a24 --- /dev/null +++ b/pkg/math/bits/bits_test.go @@ -0,0 +1,171 @@ +package math_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + zetabits "github.com/zeta-chain/node/pkg/math/bits" +) + +func TestSetBit(t *testing.T) { + tests := []struct { + name string + initial byte + position uint8 + expected byte + }{ + { + name: "set bit at position 0", + initial: 0b00001000, + position: 0, + expected: 0b00001001, + }, + { + name: "set bit at position 7", + initial: 0b00001000, + position: 7, + expected: 0b10001000, + }, + { + name: "out of range bit position (no effect)", + initial: 0b00000000, + position: 8, // Out of range + expected: 0b00000000, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b := tt.initial + zetabits.SetBit(&b, tt.position) + require.Equal(t, tt.expected, b) + }) + } +} + +func TestIsBitSet(t *testing.T) { + tests := []struct { + name string + b byte + position uint8 + expected bool + }{ + { + name: "bit 0 set", + b: 0b00000001, + position: 0, + expected: true, + }, + { + name: "bit 7 set", + b: 0b10000000, + position: 7, + expected: true, + }, + { + name: "bit 2 not set", + b: 0b00000001, + position: 2, + expected: false, + }, + { + name: "bit out of range", + b: 0b00000001, + position: 8, // Position out of range + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := zetabits.IsBitSet(tt.b, tt.position) + require.Equal(t, tt.expected, result) + }) + } +} + +func TestGetBits(t *testing.T) { + tests := []struct { + name string + b byte + mask byte + expected byte + }{ + { + name: "extract upper 3 bits", + b: 0b11011001, + mask: 0b11100000, + expected: 0b110, + }, + { + name: "extract middle 3 bits", + b: 0b11011001, + mask: 0b00011100, + expected: 0b110, + }, + { + name: "extract lower 3 bits", + b: 0b11011001, + mask: 0b00000111, + expected: 0b001, + }, + { + name: "extract no bits", + b: 0b11011001, + mask: 0b00000000, + expected: 0b000, + }, + { + name: "extract all bits", + b: 0b11111111, + mask: 0b11111111, + expected: 0b11111111, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := zetabits.GetBits(tt.b, tt.mask) + require.Equal(t, tt.expected, result) + }) + } +} + +func TestSetBits(t *testing.T) { + tests := []struct { + name string + b byte + mask byte + value byte + expected byte + }{ + { + name: "set upper 3 bits", + b: 0b00100001, + mask: 0b11100000, + value: 0b110, + expected: 0b11000001, + }, + { + name: "set middle 3 bits", + b: 0b00100001, + mask: 0b00011100, + value: 0b101, + expected: 0b00110101, + }, + { + name: "set lower 3 bits", + b: 0b11111100, + mask: 0b00000111, + value: 0b101, + expected: 0b11111101, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := zetabits.SetBits(tt.b, tt.mask, tt.value) + require.Equal(t, tt.expected, result) + }) + } +} diff --git a/pkg/memo/arg.go b/pkg/memo/arg.go new file mode 100644 index 0000000000..e29615f562 --- /dev/null +++ b/pkg/memo/arg.go @@ -0,0 +1,52 @@ +package memo + +// ArgType is the enum for types supported by the codec +type ArgType string + +// Define all the types supported by the codec +const ( + ArgTypeBytes ArgType = "bytes" + ArgTypeString ArgType = "string" + ArgTypeAddress ArgType = "address" +) + +// CodecArg represents a codec argument +type CodecArg struct { + Name string + Type ArgType + Arg interface{} +} + +// NewArg create a new codec argument +func NewArg(name string, argType ArgType, arg interface{}) CodecArg { + return CodecArg{ + Name: name, + Type: argType, + Arg: arg, + } +} + +// ArgReceiver wraps the receiver address in a CodecArg +func ArgReceiver(arg interface{}) CodecArg { + return NewArg("receiver", ArgTypeAddress, arg) +} + +// ArgPayload wraps the payload in a CodecArg +func ArgPayload(arg interface{}) CodecArg { + return NewArg("payload", ArgTypeBytes, arg) +} + +// ArgRevertAddress wraps the revert address in a CodecArg +func ArgRevertAddress(arg interface{}) CodecArg { + return NewArg("revertAddress", ArgTypeString, arg) +} + +// ArgAbortAddress wraps the abort address in a CodecArg +func ArgAbortAddress(arg interface{}) CodecArg { + return NewArg("abortAddress", ArgTypeAddress, arg) +} + +// ArgRevertMessage wraps the revert message in a CodecArg +func ArgRevertMessage(arg interface{}) CodecArg { + return NewArg("revertMessage", ArgTypeBytes, arg) +} diff --git a/pkg/memo/arg_test.go b/pkg/memo/arg_test.go new file mode 100644 index 0000000000..ee9373e688 --- /dev/null +++ b/pkg/memo/arg_test.go @@ -0,0 +1,70 @@ +package memo_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/memo" +) + +func Test_NewArg(t *testing.T) { + argAddress := common.HexToAddress("0x0B85C56e5453e0f4273d1D1BF3091d43B08B38CE") + argString := "some other string argument" + argBytes := []byte("here is a bytes argument") + + tests := []struct { + name string + argType string + arg interface{} + }{ + { + name: "receiver", + argType: "address", + arg: &argAddress, + }, + { + name: "payload", + argType: "bytes", + arg: &argBytes, + }, + { + name: "revertAddress", + argType: "string", + arg: &argString, + }, + { + name: "abortAddress", + argType: "address", + arg: &argAddress, + }, + { + name: "revertMessage", + argType: "bytes", + arg: &argBytes, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + arg := memo.NewArg(tt.name, memo.ArgType(tt.argType), tt.arg) + + require.Equal(t, tt.name, arg.Name) + require.Equal(t, memo.ArgType(tt.argType), arg.Type) + require.Equal(t, tt.arg, arg.Arg) + + switch tt.name { + case "receiver": + require.Equal(t, arg, memo.ArgReceiver(&argAddress)) + case "payload": + require.Equal(t, arg, memo.ArgPayload(&argBytes)) + case "revertAddress": + require.Equal(t, arg, memo.ArgRevertAddress(&argString)) + case "abortAddress": + require.Equal(t, arg, memo.ArgAbortAddress(&argAddress)) + case "revertMessage": + require.Equal(t, arg, memo.ArgRevertMessage(&argBytes)) + } + }) + } +} diff --git a/pkg/memo/codec.go b/pkg/memo/codec.go new file mode 100644 index 0000000000..ea60fa24c1 --- /dev/null +++ b/pkg/memo/codec.go @@ -0,0 +1,64 @@ +package memo + +import ( + "fmt" +) + +type EncodingFormat uint8 + +// Enum for non-EVM chain memo encoding format (2 bits) +const ( + // EncodingFmtABI represents ABI encoding format + EncodingFmtABI EncodingFormat = 0b0000 + + // EncodingFmtCompactShort represents 'compact short' encoding format + EncodingFmtCompactShort EncodingFormat = 0b0001 + + // EncodingFmtCompactLong represents 'compact long' encoding format + EncodingFmtCompactLong EncodingFormat = 0b0010 + + // EncodingFmtInvalid represents invalid encoding format + EncodingFmtInvalid EncodingFormat = 0b0011 +) + +// Enum for length of bytes used to encode compact data +const ( + LenBytesShort = 1 + LenBytesLong = 2 +) + +// Codec is the interface for a codec +type Codec interface { + // AddArguments adds a list of arguments to the codec + AddArguments(args ...CodecArg) + + // PackArguments packs the arguments into the encoded data + PackArguments() ([]byte, error) + + // UnpackArguments unpacks the encoded data into the arguments + UnpackArguments(data []byte) error +} + +// GetLenBytes returns the number of bytes used to encode the length of the data +func GetLenBytes(encodingFmt EncodingFormat) (int, error) { + switch encodingFmt { + case EncodingFmtCompactShort: + return LenBytesShort, nil + case EncodingFmtCompactLong: + return LenBytesLong, nil + default: + return 0, fmt.Errorf("invalid compact encoding format %d", encodingFmt) + } +} + +// GetCodec returns the codec based on the encoding format +func GetCodec(encodingFmt EncodingFormat) (Codec, error) { + switch encodingFmt { + case EncodingFmtABI: + return NewCodecABI(), nil + case EncodingFmtCompactShort, EncodingFmtCompactLong: + return NewCodecCompact(encodingFmt) + default: + return nil, fmt.Errorf("invalid encoding format %d", encodingFmt) + } +} diff --git a/pkg/memo/codec_abi.go b/pkg/memo/codec_abi.go new file mode 100644 index 0000000000..708e1a6398 --- /dev/null +++ b/pkg/memo/codec_abi.go @@ -0,0 +1,94 @@ +package memo + +import ( + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/pkg/errors" +) + +const ( + // selectorLength is the length of the selector in bytes + selectorLength = 4 + + // codecMethod is the name of the codec method + codecMethod = "codec" + + // codecMethodABIString is the ABI string template for codec method + codecMethodABIString = `[{"name":"codec", "inputs":[%s], "outputs":[%s], "type":"function"}]` +) + +var _ Codec = (*CodecABI)(nil) + +// CodecABI is a coder/decoder for ABI encoded memo fields +type CodecABI struct { + // abiTypes contains the ABI types of the arguments + abiTypes []string + + // abiArgs contains the ABI arguments to be packed or unpacked into + abiArgs []interface{} +} + +// NewCodecABI creates a new ABI codec +func NewCodecABI() *CodecABI { + return &CodecABI{ + abiTypes: make([]string, 0), + abiArgs: make([]interface{}, 0), + } +} + +// AddArguments adds a list of arguments to the codec +func (c *CodecABI) AddArguments(args ...CodecArg) { + for _, arg := range args { + typeJSON := fmt.Sprintf(`{"type":"%s"}`, arg.Type) + c.abiTypes = append(c.abiTypes, typeJSON) + c.abiArgs = append(c.abiArgs, arg.Arg) + } +} + +// PackArguments packs the arguments into the ABI encoded data +func (c *CodecABI) PackArguments() ([]byte, error) { + // get parsed ABI based on the inputs + parsedABI, err := c.parsedABI() + if err != nil { + return nil, errors.Wrap(err, "failed to parse ABI string") + } + + // pack the arguments + data, err := parsedABI.Pack(codecMethod, c.abiArgs...) + if err != nil { + return nil, errors.Wrap(err, "failed to pack ABI arguments") + } + + // this never happens + if len(data) < selectorLength { + return nil, errors.New("packed data less than selector length") + } + + return data[selectorLength:], nil +} + +// UnpackArguments unpacks the ABI encoded data into the output arguments +func (c *CodecABI) UnpackArguments(data []byte) error { + // get parsed ABI based on the inputs + parsedABI, err := c.parsedABI() + if err != nil { + return errors.Wrap(err, "failed to parse ABI string") + } + + // unpack data into outputs + err = parsedABI.UnpackIntoInterface(&c.abiArgs, codecMethod, data) + if err != nil { + return errors.Wrap(err, "failed to unpack ABI encoded data") + } + + return nil +} + +// parsedABI builds a parsed ABI based on the inputs +func (c *CodecABI) parsedABI() (abi.ABI, error) { + typeList := strings.Join(c.abiTypes, ",") + abiString := fmt.Sprintf(codecMethodABIString, typeList, typeList) + return abi.JSON(strings.NewReader(abiString)) +} diff --git a/pkg/memo/codec_abi_test.go b/pkg/memo/codec_abi_test.go new file mode 100644 index 0000000000..c4a2e1decd --- /dev/null +++ b/pkg/memo/codec_abi_test.go @@ -0,0 +1,345 @@ +package memo_test + +import ( + "bytes" + "encoding/binary" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/memo" +) + +const ( + // abiAlignment is the number of bytes used to align the ABI encoded data + abiAlignment = 32 +) + +// ABIPack is a helper function that simulates the abi.Pack function. +// Note: all arguments are assumed to be <= 32 bytes for simplicity. +func ABIPack(t *testing.T, args ...memo.CodecArg) []byte { + packedData := make([]byte, 0) + + // data offset for 1st dynamic-length field + offset := abiAlignment * len(args) + + // 1. pack 32-byte offset for each dynamic-length field (bytes, string) + // 2. pack actual data for each fixed-length field (address) + for _, arg := range args { + switch arg.Type { + case memo.ArgTypeBytes: + // left-pad length as uint16 + buff := make([]byte, 2) + binary.BigEndian.PutUint16(buff, uint16(offset)) + offsetData := abiPad32(t, buff, true) + packedData = append(packedData, offsetData...) + + argLen := len(arg.Arg.([]byte)) + if argLen > 0 { + offset += abiAlignment * 2 // [length + data] + } else { + offset += abiAlignment // only [length] + } + + case memo.ArgTypeString: + // left-pad length as uint16 + buff := make([]byte, 2) + binary.BigEndian.PutUint16(buff, uint16(offset)) + offsetData := abiPad32(t, buff, true) + packedData = append(packedData, offsetData...) + + argLen := len([]byte(arg.Arg.(string))) + if argLen > 0 { + offset += abiAlignment * 2 // [length + data] + } else { + offset += abiAlignment // only [length] + } + + case memo.ArgTypeAddress: // left-pad for address + data := abiPad32(t, arg.Arg.(common.Address).Bytes(), true) + packedData = append(packedData, data...) + } + } + + // pack dynamic-length fields + dynamicData := abiPackDynamicData(t, args...) + packedData = append(packedData, dynamicData...) + + return packedData +} + +// abiPad32 is a helper function to pad a byte slice to 32 bytes +func abiPad32(t *testing.T, data []byte, left bool) []byte { + // nothing needs to be encoded, return empty bytes + if len(data) == 0 { + return []byte{} + } + + require.LessOrEqual(t, len(data), abiAlignment) + padded := make([]byte, 32) + + if left { + // left-pad the data for fixed-size types + copy(padded[32-len(data):], data) + } else { + // right-pad the data for dynamic types + copy(padded, data) + } + return padded +} + +// abiPackDynamicData is a helper function to pack dynamic-length data +func abiPackDynamicData(t *testing.T, args ...memo.CodecArg) []byte { + packedData := make([]byte, 0) + + // pack with ABI format: length + data + for _, arg := range args { + // get length + var length int + switch arg.Type { + case memo.ArgTypeBytes: + length = len(arg.Arg.([]byte)) + case memo.ArgTypeString: + length = len([]byte(arg.Arg.(string))) + default: + continue + } + + // append length in bytes + lengthData := abiPad32(t, []byte{byte(length)}, true) + packedData = append(packedData, lengthData...) + + // append actual data in bytes + switch arg.Type { + case memo.ArgTypeBytes: // right-pad for bytes + data := abiPad32(t, arg.Arg.([]byte), false) + packedData = append(packedData, data...) + case memo.ArgTypeString: // right-pad for string + data := abiPad32(t, []byte(arg.Arg.(string)), false) + packedData = append(packedData, data...) + } + } + + return packedData +} + +// newArgInstance creates a new instance of the given argument type +func newArgInstance(v interface{}) interface{} { + switch v.(type) { + case common.Address: + return new(common.Address) + case []byte: + return &[]byte{} + case string: + return new(string) + } + return nil +} + +// ensureArgEquality ensures the expected argument and actual value are equal +func ensureArgEquality(t *testing.T, expected, actual interface{}) { + switch v := expected.(type) { + case common.Address: + require.Equal(t, v.Hex(), actual.(*common.Address).Hex()) + case []byte: + require.True(t, bytes.Equal(v, *actual.(*[]byte))) + case string: + require.Equal(t, v, *actual.(*string)) + default: + require.FailNow(t, "unexpected argument type", "Type: %T", v) + } +} + +func Test_NewCodecABI(t *testing.T) { + c := memo.NewCodecABI() + require.NotNil(t, c) +} + +func Test_CodecABI_AddArguments(t *testing.T) { + codec := memo.NewCodecABI() + require.NotNil(t, codec) + + address := common.HexToAddress("0xEf221eC80f004E6A2ee4E5F5d800699c1C68cD6F") + codec.AddArguments(memo.ArgReceiver(&address)) + + // attempt to pack the arguments, result should not be nil + packedData, err := codec.PackArguments() + require.NoError(t, err) + require.True(t, len(packedData) > 0) +} + +func Test_CodecABI_PackArgument(t *testing.T) { + // create sample arguments + argAddress := common.HexToAddress("0xEf221eC80f004E6A2ee4E5F5d800699c1C68cD6F") + argBytes := []byte("some test bytes argument") + argString := "some test string argument" + + // test cases + tests := []struct { + name string + args []memo.CodecArg + errMsg string + }{ + { + name: "pack in the order of [address, bytes, string]", + args: []memo.CodecArg{ + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + memo.ArgRevertAddress(argString), + }, + }, + { + name: "pack in the order of [string, address, bytes]", + args: []memo.CodecArg{ + memo.ArgRevertAddress(argString), + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + }, + }, + { + name: "pack empty bytes array and string", + args: []memo.CodecArg{ + memo.ArgPayload([]byte{}), + memo.ArgRevertAddress(""), + }, + }, + { + name: "unable to parse unsupported ABI type", + args: []memo.CodecArg{ + memo.ArgReceiver(&argAddress), + memo.NewArg("payload", memo.ArgType("unknown"), nil), + }, + errMsg: "failed to parse ABI string", + }, + { + name: "packing should fail on argument type mismatch", + args: []memo.CodecArg{ + memo.ArgReceiver(argBytes), // expect address type, but passed bytes + }, + errMsg: "failed to pack ABI arguments", + }, + } + + // loop through each test case + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // create a new ABI codec and add arguments + codec := memo.NewCodecABI() + codec.AddArguments(tc.args...) + + // pack arguments into ABI-encoded packedData + packedData, err := codec.PackArguments() + if tc.errMsg != "" { + require.ErrorContains(t, err, tc.errMsg) + require.Nil(t, packedData) + return + } + require.NoError(t, err) + + // calc expected data for comparison + expectedData := ABIPack(t, tc.args...) + + // validate the packed data + require.True(t, bytes.Equal(expectedData, packedData), "ABI encoded data mismatch") + }) + } +} + +func Test_CodecABI_UnpackArguments(t *testing.T) { + // create sample arguments + argAddress := common.HexToAddress("0xEf221eC80f004E6A2ee4E5F5d800699c1C68cD6F") + argBytes := []byte("some test bytes argument") + argString := "some test string argument" + + // test cases + tests := []struct { + name string + data []byte + expected []memo.CodecArg + errMsg string + }{ + { + name: "unpack in the order of [address, bytes, string]", + data: ABIPack(t, + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + memo.ArgRevertAddress(argString)), + expected: []memo.CodecArg{ + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + memo.ArgRevertAddress(argString), + }, + }, + { + name: "unpack in the order of [string, address, bytes]", + data: ABIPack(t, + memo.ArgRevertAddress(argString), + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes)), + expected: []memo.CodecArg{ + memo.ArgRevertAddress(argString), + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + }, + }, + { + name: "unpack empty bytes array and string", + data: ABIPack(t, + memo.ArgPayload([]byte{}), + memo.ArgRevertAddress("")), + expected: []memo.CodecArg{ + memo.ArgPayload([]byte{}), + memo.ArgRevertAddress(""), + }, + }, + { + name: "unable to parse unsupported ABI type", + data: []byte{}, + expected: []memo.CodecArg{ + memo.ArgReceiver(argAddress), + memo.NewArg("payload", memo.ArgType("unknown"), nil), + }, + errMsg: "failed to parse ABI string", + }, + { + name: "unpacking should fail on argument type mismatch", + data: ABIPack(t, + memo.ArgReceiver(argAddress), + ), + expected: []memo.CodecArg{ + memo.ArgReceiver(argBytes), // expect address type, but passed bytes + }, + errMsg: "failed to unpack ABI encoded data", + }, + } + + // loop through each test case + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // create a new ABI codec + codec := memo.NewCodecABI() + + // add output arguments + output := make([]memo.CodecArg, len(tc.expected)) + for i, arg := range tc.expected { + output[i] = memo.NewArg(arg.Name, arg.Type, newArgInstance(arg.Arg)) + } + codec.AddArguments(output...) + + // unpack arguments from ABI-encoded data + err := codec.UnpackArguments(tc.data) + + // validate the error message + if tc.errMsg != "" { + require.ErrorContains(t, err, tc.errMsg) + return + } + + // validate the unpacked arguments values + require.NoError(t, err) + for i, arg := range tc.expected { + ensureArgEquality(t, arg.Arg, output[i].Arg) + } + }) + } +} diff --git a/pkg/memo/codec_compact.go b/pkg/memo/codec_compact.go new file mode 100644 index 0000000000..bcb49d3f92 --- /dev/null +++ b/pkg/memo/codec_compact.go @@ -0,0 +1,265 @@ +package memo + +import ( + "encoding/binary" + "fmt" + "math" + + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" +) + +var _ Codec = (*CodecCompact)(nil) + +// CodecCompact is a coder/decoder for compact encoded memo fields +// +// This encoding format concatenates the memo fields into a single byte array +// with zero padding to minimize the total size of the memo. +type CodecCompact struct { + // lenBytes is the number of bytes used to encode the length of the data + lenBytes int + + // args contains the list of arguments + args []CodecArg +} + +// NewCodecCompact creates a new compact codec +func NewCodecCompact(encodingFmt EncodingFormat) (*CodecCompact, error) { + lenBytes, err := GetLenBytes(encodingFmt) + if err != nil { + return nil, err + } + + return &CodecCompact{ + lenBytes: lenBytes, + args: make([]CodecArg, 0), + }, nil +} + +// AddArguments adds a list of arguments to the codec +func (c *CodecCompact) AddArguments(args ...CodecArg) { + c.args = append(c.args, args...) +} + +// PackArguments packs the arguments into the compact encoded data +func (c *CodecCompact) PackArguments() ([]byte, error) { + data := make([]byte, 0) + + // pack according to argument type + for _, arg := range c.args { + switch arg.Type { + case ArgTypeBytes: + dataBytes, err := c.packBytes(arg.Arg) + if err != nil { + return nil, errors.Wrapf(err, "failed to pack bytes argument: %s", arg.Name) + } + data = append(data, dataBytes...) + case ArgTypeAddress: + dataAddress, err := c.packAddress(arg.Arg) + if err != nil { + return nil, errors.Wrapf(err, "failed to pack address argument: %s", arg.Name) + } + data = append(data, dataAddress...) + case ArgTypeString: + dataString, err := c.packString(arg.Arg) + if err != nil { + return nil, errors.Wrapf(err, "failed to pack string argument: %s", arg.Name) + } + data = append(data, dataString...) + default: + return nil, fmt.Errorf("unsupported argument (%s) type: %s", arg.Name, arg.Type) + } + } + + return data, nil +} + +// UnpackArguments unpacks the compact encoded data into the output arguments +func (c *CodecCompact) UnpackArguments(data []byte) error { + // unpack according to argument type + offset := 0 + for _, arg := range c.args { + switch arg.Type { + case ArgTypeBytes: + bytesRead, err := c.unpackBytes(data[offset:], arg.Arg) + if err != nil { + return errors.Wrapf(err, "failed to unpack bytes argument: %s", arg.Name) + } + offset += bytesRead + case ArgTypeAddress: + bytesRead, err := c.unpackAddress(data[offset:], arg.Arg) + if err != nil { + return errors.Wrapf(err, "failed to unpack address argument: %s", arg.Name) + } + offset += bytesRead + case ArgTypeString: + bytesRead, err := c.unpackString(data[offset:], arg.Arg) + if err != nil { + return errors.Wrapf(err, "failed to unpack string argument: %s", arg.Name) + } + offset += bytesRead + default: + return fmt.Errorf("unsupported argument (%s) type: %s", arg.Name, arg.Type) + } + } + + // ensure all data is consumed + if offset != len(data) { + return fmt.Errorf("consumed bytes (%d) != total bytes (%d)", offset, len(data)) + } + + return nil +} + +// packLength packs the length of the data into the compact format +func (c *CodecCompact) packLength(length int) ([]byte, error) { + data := make([]byte, c.lenBytes) + + switch c.lenBytes { + case LenBytesShort: + if length > math.MaxUint8 { + return nil, fmt.Errorf("data length %d exceeds %d bytes", length, math.MaxUint8) + } + data[0] = uint8(length) + case LenBytesLong: + if length > math.MaxUint16 { + return nil, fmt.Errorf("data length %d exceeds %d bytes", length, math.MaxUint16) + } + // #nosec G115 range checked + binary.LittleEndian.PutUint16(data, uint16(length)) + } + return data, nil +} + +// packAddress packs argument of type 'address'. +func (c *CodecCompact) packAddress(arg interface{}) ([]byte, error) { + // type assertion + address, ok := arg.(common.Address) + if !ok { + return nil, fmt.Errorf("argument is not of type common.Address") + } + + return address.Bytes(), nil +} + +// packBytes packs argument of type 'bytes'. +func (c *CodecCompact) packBytes(arg interface{}) ([]byte, error) { + // type assertion + bytes, ok := arg.([]byte) + if !ok { + return nil, fmt.Errorf("argument is not of type []byte") + } + + // pack length of the data + data, err := c.packLength(len(bytes)) + if err != nil { + return nil, errors.Wrap(err, "failed to pack length of bytes") + } + + // append the data + data = append(data, bytes...) + return data, nil +} + +// packString packs argument of type 'string'. +func (c *CodecCompact) packString(arg interface{}) ([]byte, error) { + // type assertion + str, ok := arg.(string) + if !ok { + return nil, fmt.Errorf("argument is not of type string") + } + + // pack length of the data + data, err := c.packLength(len([]byte(str))) + if err != nil { + return nil, errors.Wrap(err, "failed to pack length of string") + } + + // append the string + data = append(data, []byte(str)...) + return data, nil +} + +// unpackLength returns the length of the data encoded in the compact format +func (c *CodecCompact) unpackLength(data []byte) (int, error) { + if len(data) < c.lenBytes { + return 0, fmt.Errorf("expected %d bytes to decode length, got %d", c.lenBytes, len(data)) + } + + // decode length of the data + length := 0 + switch c.lenBytes { + case LenBytesShort: + length = int(data[0]) + case LenBytesLong: + // convert little-endian bytes to integer + length = int(binary.LittleEndian.Uint16(data[:2])) + } + + // ensure remaining data is long enough + if len(data) < c.lenBytes+length { + return 0, fmt.Errorf("expected %d bytes, got %d", length, len(data)-c.lenBytes) + } + + return length, nil +} + +// unpackAddress unpacks argument of type 'address'. +func (c *CodecCompact) unpackAddress(data []byte, output interface{}) (int, error) { + // type assertion + pAddress, ok := output.(*common.Address) + if !ok { + return 0, fmt.Errorf("argument is not of type *common.Address") + } + + // ensure remaining data >= 20 bytes + if len(data) < common.AddressLength { + return 0, fmt.Errorf("expected address, got %d bytes", len(data)) + } + *pAddress = common.BytesToAddress((data[:20])) + + return common.AddressLength, nil +} + +// unpackBytes unpacks argument of type 'bytes' and returns the number of bytes read. +func (c *CodecCompact) unpackBytes(data []byte, output interface{}) (int, error) { + // type assertion + pSlice, ok := output.(*[]byte) + if !ok { + return 0, fmt.Errorf("argument is not of type *[]byte") + } + + // unpack length + dataLen, err := c.unpackLength(data) + if err != nil { + return 0, errors.Wrap(err, "failed to unpack length of bytes") + } + + // make a copy of the data + if dataLen > 0 { + *pSlice = make([]byte, dataLen) + copy(*pSlice, data[c.lenBytes:c.lenBytes+dataLen]) + } + + return c.lenBytes + dataLen, nil +} + +// unpackString unpacks argument of type 'string' and returns the number of bytes read. +func (c *CodecCompact) unpackString(data []byte, output interface{}) (int, error) { + // type assertion + pString, ok := output.(*string) + if !ok { + return 0, fmt.Errorf("argument is not of type *string") + } + + // unpack length + strLen, err := c.unpackLength(data) + if err != nil { + return 0, errors.Wrap(err, "failed to unpack length of string") + } + + // make a copy of the string + *pString = string(data[c.lenBytes : c.lenBytes+strLen]) + + return c.lenBytes + strLen, nil +} diff --git a/pkg/memo/codec_compact_test.go b/pkg/memo/codec_compact_test.go new file mode 100644 index 0000000000..328beeb7e4 --- /dev/null +++ b/pkg/memo/codec_compact_test.go @@ -0,0 +1,413 @@ +package memo_test + +import ( + "bytes" + "encoding/binary" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/memo" +) + +// CompactPack is a helper function to pack arguments into compact encoded data +// Note: all arguments are assumed to be <= 65535 bytes for simplicity. +func CompactPack(encodingFmt memo.EncodingFormat, args ...memo.CodecArg) []byte { + var ( + length int + packedData []byte + ) + + for _, arg := range args { + // get length of argument + switch arg.Type { + case memo.ArgTypeBytes: + length = len(arg.Arg.([]byte)) + case memo.ArgTypeString: + length = len([]byte(arg.Arg.(string))) + default: + // skip length for other types + length = -1 + } + + // append length in bytes + if length != -1 { + switch encodingFmt { + case memo.EncodingFmtCompactShort: + packedData = append(packedData, byte(length)) + case memo.EncodingFmtCompactLong: + buff := make([]byte, 2) + binary.LittleEndian.PutUint16(buff, uint16(length)) + packedData = append(packedData, buff...) + } + } + + // append actual data in bytes + switch arg.Type { + case memo.ArgTypeBytes: + packedData = append(packedData, arg.Arg.([]byte)...) + case memo.ArgTypeAddress: + packedData = append(packedData, arg.Arg.(common.Address).Bytes()...) + case memo.ArgTypeString: + packedData = append(packedData, []byte(arg.Arg.(string))...) + } + } + + return packedData +} + +func Test_NewCodecCompact(t *testing.T) { + tests := []struct { + name string + encodeFmt memo.EncodingFormat + fail bool + }{ + { + name: "create codec compact successfully", + encodeFmt: memo.EncodingFmtCompactShort, + }, + { + name: "create codec compact failed on invalid encoding format", + encodeFmt: 0b11, + fail: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + codec, err := memo.NewCodecCompact(tc.encodeFmt) + if tc.fail { + require.Error(t, err) + require.Nil(t, codec) + } else { + require.NoError(t, err) + require.NotNil(t, codec) + } + }) + } +} + +func Test_CodecCompact_AddArguments(t *testing.T) { + codec, err := memo.NewCodecCompact(memo.EncodingFmtCompactLong) + require.NoError(t, err) + require.NotNil(t, codec) + + address := common.HexToAddress("0x855EfD3C54F9Ed106C6c3FB343539c89Df042e0B") + codec.AddArguments(memo.ArgReceiver(address)) + + // attempt to pack the arguments, result should not be nil + packedData, err := codec.PackArguments() + require.NoError(t, err) + require.True(t, len(packedData) == common.AddressLength) +} + +func Test_CodecCompact_PackArguments(t *testing.T) { + // create sample arguments + argAddress := common.HexToAddress("0x855EfD3C54F9Ed106C6c3FB343539c89Df042e0B") + argBytes := []byte("here is a bytes argument") + argString := "some other string argument" + + // test cases + tests := []struct { + name string + encodeFmt memo.EncodingFormat + args []memo.CodecArg + expectedLen int + errMsg string + }{ + { + name: "pack arguments of [address, bytes, string] in compact-short format", + encodeFmt: memo.EncodingFmtCompactShort, + args: []memo.CodecArg{ + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + memo.ArgRevertAddress(argString), + }, + expectedLen: 20 + 1 + len(argBytes) + 1 + len([]byte(argString)), + }, + { + name: "pack arguments of [string, address, bytes] in compact-long format", + encodeFmt: memo.EncodingFmtCompactLong, + args: []memo.CodecArg{ + memo.ArgRevertAddress(argString), + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + }, + expectedLen: 2 + len([]byte(argString)) + 20 + 2 + len(argBytes), + }, + { + name: "pack long string (> 255 bytes) with compact-long format", + encodeFmt: memo.EncodingFmtCompactLong, + args: []memo.CodecArg{ + memo.ArgPayload([]byte(strings.Repeat("a", 256))), + }, + expectedLen: 2 + 256, + }, + { + name: "pack long string (> 255 bytes) with compact-short format should fail", + encodeFmt: memo.EncodingFmtCompactShort, + args: []memo.CodecArg{ + memo.ArgPayload([]byte(strings.Repeat("b", 256))), + }, + errMsg: "exceeds 255 bytes", + }, + { + name: "pack long string (> 65535 bytes) with compact-long format should fail", + encodeFmt: memo.EncodingFmtCompactLong, + args: []memo.CodecArg{ + memo.ArgPayload([]byte(strings.Repeat("c", 65536))), + }, + errMsg: "exceeds 65535 bytes", + }, + { + name: "pack empty byte array and string arguments", + encodeFmt: memo.EncodingFmtCompactShort, + args: []memo.CodecArg{ + memo.ArgPayload([]byte{}), + memo.ArgRevertAddress(""), + }, + expectedLen: 2, + }, + { + name: "failed to pack bytes argument if string is passed", + encodeFmt: memo.EncodingFmtCompactShort, + args: []memo.CodecArg{ + memo.ArgPayload(argString), // expect bytes type, but passed string + }, + errMsg: "argument is not of type []byte", + }, + { + name: "failed to pack address argument if bytes is passed", + encodeFmt: memo.EncodingFmtCompactShort, + args: []memo.CodecArg{ + memo.ArgReceiver(argBytes), // expect address type, but passed bytes + }, + errMsg: "argument is not of type common.Address", + }, + { + name: "failed to pack string argument if bytes is passed", + encodeFmt: memo.EncodingFmtCompactShort, + args: []memo.CodecArg{ + memo.ArgRevertAddress(argBytes), // expect string type, but passed bytes + }, + errMsg: "argument is not of type string", + }, + { + name: "failed to pack unsupported argument type", + encodeFmt: memo.EncodingFmtCompactShort, + args: []memo.CodecArg{ + memo.NewArg("receiver", memo.ArgType("unknown"), nil), + }, + errMsg: "unsupported argument (receiver) type", + }, + } + + // loop through each test case + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // create a new compact codec and add arguments + codec, err := memo.NewCodecCompact(tc.encodeFmt) + require.NoError(t, err) + codec.AddArguments(tc.args...) + + // pack arguments + packedData, err := codec.PackArguments() + + if tc.errMsg != "" { + require.ErrorContains(t, err, tc.errMsg) + require.Nil(t, packedData) + return + } + require.NoError(t, err) + require.Equal(t, tc.expectedLen, len(packedData)) + + // calc expected data for comparison + expectedData := CompactPack(tc.encodeFmt, tc.args...) + + // validate the packed data + require.True(t, bytes.Equal(expectedData, packedData), "compact encoded data mismatch") + }) + } +} + +func Test_CodecCompact_UnpackArguments(t *testing.T) { + // create sample arguments + argAddress := common.HexToAddress("0x855EfD3C54F9Ed106C6c3FB343539c89Df042e0B") + argBytes := []byte("some test bytes argument") + argString := "some other string argument" + + // test cases + tests := []struct { + name string + encodeFmt memo.EncodingFormat + data []byte + expected []memo.CodecArg + errMsg string + }{ + { + name: "unpack arguments of [address, bytes, string] in compact-short format", + encodeFmt: memo.EncodingFmtCompactShort, + data: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + memo.ArgRevertAddress(argString), + ), + expected: []memo.CodecArg{ + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + memo.ArgRevertAddress(argString), + }, + }, + { + name: "unpack arguments of [string, address, bytes] in compact-long format", + encodeFmt: memo.EncodingFmtCompactLong, + data: CompactPack( + memo.EncodingFmtCompactLong, + memo.ArgRevertAddress(argString), + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + ), + expected: []memo.CodecArg{ + memo.ArgRevertAddress(argString), + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + }, + }, + { + name: "unpack empty byte array and string argument", + encodeFmt: memo.EncodingFmtCompactShort, + data: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgPayload([]byte{}), + memo.ArgRevertAddress(""), + ), + expected: []memo.CodecArg{ + memo.ArgPayload([]byte{}), + memo.ArgRevertAddress(""), + }, + }, + { + name: "failed to unpack address if data length < 20 bytes", + encodeFmt: memo.EncodingFmtCompactShort, + data: []byte{0x01, 0x02, 0x03, 0x04, 0x05}, + expected: []memo.CodecArg{ + memo.ArgReceiver(argAddress), + }, + errMsg: "expected address, got 5 bytes", + }, + { + name: "failed to unpack string if data length < 1 byte", + encodeFmt: memo.EncodingFmtCompactShort, + data: []byte{}, + expected: []memo.CodecArg{ + memo.ArgRevertAddress(argString), + }, + errMsg: "expected 1 bytes to decode length", + }, + { + name: "failed to unpack string if actual data is less than decoded length", + encodeFmt: memo.EncodingFmtCompactShort, + data: []byte{0x05, 0x0a, 0x0b, 0x0c, 0x0d}, // length = 5, but only 4 bytes provided + expected: []memo.CodecArg{ + memo.ArgPayload(argBytes), + }, + errMsg: "expected 5 bytes, got 4", + }, + { + name: "failed to unpack bytes argument if string is passed", + encodeFmt: memo.EncodingFmtCompactShort, + data: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgPayload(argBytes), + ), + expected: []memo.CodecArg{ + memo.ArgPayload(argString), // expect bytes type, but passed string + }, + errMsg: "argument is not of type *[]byte", + }, + { + name: "failed to unpack address argument if bytes is passed", + encodeFmt: memo.EncodingFmtCompactShort, + data: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgReceiver(argAddress), + ), + expected: []memo.CodecArg{ + memo.ArgReceiver(argBytes), // expect address type, but passed bytes + }, + errMsg: "argument is not of type *common.Address", + }, + { + name: "failed to unpack string argument if address is passed", + encodeFmt: memo.EncodingFmtCompactShort, + data: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgRevertAddress(argString), + ), + expected: []memo.CodecArg{ + memo.ArgRevertAddress(argAddress), // expect string type, but passed address + }, + errMsg: "argument is not of type *string", + }, + { + name: "failed to unpack unsupported argument type", + encodeFmt: memo.EncodingFmtCompactShort, + data: []byte{}, + expected: []memo.CodecArg{ + memo.NewArg("payload", memo.ArgType("unknown"), nil), + }, + errMsg: "unsupported argument (payload) type", + }, + { + name: "unpacking should fail if not all data is consumed", + encodeFmt: memo.EncodingFmtCompactShort, + data: func() []byte { + data := CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + ) + // append 1 extra byte + return append(data, 0x00) + }(), + expected: []memo.CodecArg{ + memo.ArgReceiver(argAddress), + memo.ArgPayload(argBytes), + }, + errMsg: "consumed bytes (45) != total bytes (46)", + }, + } + + // loop through each test case + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // create a new compact codec and add arguments + codec, err := memo.NewCodecCompact(tc.encodeFmt) + require.NoError(t, err) + + // add output arguments + output := make([]memo.CodecArg, len(tc.expected)) + for i, arg := range tc.expected { + output[i] = memo.NewArg(arg.Name, arg.Type, newArgInstance(arg.Arg)) + } + codec.AddArguments(output...) + + // unpack arguments from compact-encoded data + err = codec.UnpackArguments(tc.data) + + // validate error message + if tc.errMsg != "" { + require.ErrorContains(t, err, tc.errMsg) + return + } + + // validate the unpacked arguments values + require.NoError(t, err) + for i, arg := range tc.expected { + ensureArgEquality(t, arg.Arg, output[i].Arg) + } + }) + } +} diff --git a/pkg/memo/codec_test.go b/pkg/memo/codec_test.go new file mode 100644 index 0000000000..aa27667967 --- /dev/null +++ b/pkg/memo/codec_test.go @@ -0,0 +1,92 @@ +package memo_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/memo" +) + +func Test_GetLenBytes(t *testing.T) { + // Define table-driven test cases + tests := []struct { + name string + encodeFmt memo.EncodingFormat + expectedLen int + expectErr bool + }{ + { + name: "compact short", + encodeFmt: memo.EncodingFmtCompactShort, + expectedLen: 1, + }, + { + name: "compact long", + encodeFmt: memo.EncodingFmtCompactLong, + expectedLen: 2, + }, + { + name: "non-compact encoding format", + encodeFmt: memo.EncodingFmtABI, + expectedLen: 0, + expectErr: true, + }, + } + + // Loop through each test case + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + length, err := memo.GetLenBytes(tc.encodeFmt) + + // Check if error is expected + if tc.expectErr { + require.Error(t, err) + require.Equal(t, 0, length) + } else { + require.NoError(t, err) + require.Equal(t, tc.expectedLen, length) + } + }) + } +} + +func Test_GetCodec(t *testing.T) { + // Define table-driven test cases + tests := []struct { + name string + encodeFmt memo.EncodingFormat + errMsg string + }{ + { + name: "should get ABI codec", + encodeFmt: memo.EncodingFmtABI, + }, + { + name: "should get compact codec", + encodeFmt: memo.EncodingFmtCompactShort, + }, + { + name: "should get compact codec", + encodeFmt: memo.EncodingFmtCompactLong, + }, + { + name: "should fail to get codec", + encodeFmt: 0b0011, + errMsg: "invalid encoding format", + }, + } + + // Loop through each test case + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + codec, err := memo.GetCodec(tc.encodeFmt) + if tc.errMsg != "" { + require.Error(t, err) + require.Nil(t, codec) + } else { + require.NoError(t, err) + require.NotNil(t, codec) + } + }) + } +} diff --git a/pkg/memo/fields.go b/pkg/memo/fields.go new file mode 100644 index 0000000000..fff853f955 --- /dev/null +++ b/pkg/memo/fields.go @@ -0,0 +1,16 @@ +package memo + +// Fields is the interface for memo fields +type Fields interface { + // Pack encodes the memo fields + Pack(opCode OpCode, encodingFmt EncodingFormat, dataFlags uint8) ([]byte, error) + + // Unpack decodes the memo fields + Unpack(opCode OpCode, encodingFmt EncodingFormat, dataFlags uint8, data []byte) error + + // Validate checks if the fields are valid + Validate(opCode OpCode, dataFlags uint8) error + + // DataFlags build the data flags for the fields + DataFlags() uint8 +} diff --git a/pkg/memo/fields_v0.go b/pkg/memo/fields_v0.go new file mode 100644 index 0000000000..a8f79d99ba --- /dev/null +++ b/pkg/memo/fields_v0.go @@ -0,0 +1,208 @@ +package memo + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + + "github.com/zeta-chain/node/pkg/crypto" + zetabits "github.com/zeta-chain/node/pkg/math/bits" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +// Enum of the bit position of each memo fields +const ( + bitPosReceiver uint8 = 0 // receiver + bitPosPayload uint8 = 1 // payload + bitPosRevertAddress uint8 = 2 // revertAddress + bitPosAbortAddress uint8 = 3 // abortAddress + bitPosRevertMessage uint8 = 4 // revertMessage +) + +const ( + // MaskFlagsReserved is the mask for reserved data flags + MaskFlagsReserved = 0b11100000 +) + +var _ Fields = (*FieldsV0)(nil) + +// FieldsV0 contains the data fields of the inbound memo V0 +type FieldsV0 struct { + // Receiver is the ZEVM receiver address + Receiver common.Address + + // Payload is the calldata passed to ZEVM contract call + Payload []byte + + // RevertOptions is the options for cctx revert handling + RevertOptions crosschaintypes.RevertOptions +} + +// Pack encodes the memo fields +func (f *FieldsV0) Pack(opCode OpCode, encodingFmt EncodingFormat, dataFlags uint8) ([]byte, error) { + // validate fields + err := f.Validate(opCode, dataFlags) + if err != nil { + return nil, err + } + + codec, err := GetCodec(encodingFmt) + if err != nil { + return nil, errors.Wrap(err, "unable to get codec") + } + + return f.packFields(codec, dataFlags) +} + +// Unpack decodes the memo fields +func (f *FieldsV0) Unpack(opCode OpCode, encodingFmt EncodingFormat, dataFlags uint8, data []byte) error { + codec, err := GetCodec(encodingFmt) + if err != nil { + return errors.Wrap(err, "unable to get codec") + } + + err = f.unpackFields(codec, dataFlags, data) + if err != nil { + return err + } + + return f.Validate(opCode, dataFlags) +} + +// Validate checks if the fields are valid +func (f *FieldsV0) Validate(opCode OpCode, dataFlags uint8) error { + // receiver address must be a valid address + if zetabits.IsBitSet(dataFlags, bitPosReceiver) && crypto.IsEmptyAddress(f.Receiver) { + return errors.New("receiver address is empty") + } + + // payload is not allowed for deposit operation + if opCode == OpCodeDeposit && len(f.Payload) > 0 { + return errors.New("payload is not allowed for deposit operation") + } + + // abort address must be a valid address + if zetabits.IsBitSet(dataFlags, bitPosAbortAddress) && !common.IsHexAddress(f.RevertOptions.AbortAddress) { + return errors.New("invalid abort address") + } + + // revert message is not allowed when CallOnRevert is false + // 1. it's a good-to-have check to make the fields semantically correct. + // 2. unpacking won't hit this error as the codec will catch it earlier. + if !f.RevertOptions.CallOnRevert && len(f.RevertOptions.RevertMessage) > 0 { + return errors.New("revert message is not allowed when CallOnRevert is false") + } + + return nil +} + +// DataFlags build the data flags from actual fields +func (f *FieldsV0) DataFlags() uint8 { + var dataFlags uint8 + + // set 'receiver' flag if provided + if !crypto.IsEmptyAddress(f.Receiver) { + zetabits.SetBit(&dataFlags, bitPosReceiver) + } + + // set 'payload' flag if provided + if len(f.Payload) > 0 { + zetabits.SetBit(&dataFlags, bitPosPayload) + } + + // set 'revertAddress' flag if provided + if f.RevertOptions.RevertAddress != "" { + zetabits.SetBit(&dataFlags, bitPosRevertAddress) + } + + // set 'abortAddress' flag if provided + if f.RevertOptions.AbortAddress != "" { + zetabits.SetBit(&dataFlags, bitPosAbortAddress) + } + + // set 'revertMessage' flag if provided + if f.RevertOptions.CallOnRevert { + zetabits.SetBit(&dataFlags, bitPosRevertMessage) + } + + return dataFlags +} + +// packFieldsV0 packs the memo fields for version 0 +func (f *FieldsV0) packFields(codec Codec, dataFlags uint8) ([]byte, error) { + // add 'receiver' argument optionally + if zetabits.IsBitSet(dataFlags, bitPosReceiver) { + codec.AddArguments(ArgReceiver(f.Receiver)) + } + + // add 'payload' argument optionally + if zetabits.IsBitSet(dataFlags, bitPosPayload) { + codec.AddArguments(ArgPayload(f.Payload)) + } + + // add 'revertAddress' argument optionally + if zetabits.IsBitSet(dataFlags, bitPosRevertAddress) { + codec.AddArguments(ArgRevertAddress(f.RevertOptions.RevertAddress)) + } + + // add 'abortAddress' argument optionally + abortAddress := common.HexToAddress(f.RevertOptions.AbortAddress) + if zetabits.IsBitSet(dataFlags, bitPosAbortAddress) { + codec.AddArguments(ArgAbortAddress(abortAddress)) + } + + // add 'revertMessage' argument optionally + if f.RevertOptions.CallOnRevert { + codec.AddArguments(ArgRevertMessage(f.RevertOptions.RevertMessage)) + } + + // pack the codec arguments into data + data, err := codec.PackArguments() + if err != nil { // never happens + return nil, errors.Wrap(err, "failed to pack arguments") + } + + return data, nil +} + +// unpackFields unpacks the memo fields for version 0 +func (f *FieldsV0) unpackFields(codec Codec, dataFlags byte, data []byte) error { + // add 'receiver' argument optionally + if zetabits.IsBitSet(dataFlags, bitPosReceiver) { + codec.AddArguments(ArgReceiver(&f.Receiver)) + } + + // add 'payload' argument optionally + if zetabits.IsBitSet(dataFlags, bitPosPayload) { + codec.AddArguments(ArgPayload(&f.Payload)) + } + + // add 'revertAddress' argument optionally + if zetabits.IsBitSet(dataFlags, bitPosRevertAddress) { + codec.AddArguments(ArgRevertAddress(&f.RevertOptions.RevertAddress)) + } + + // add 'abortAddress' argument optionally + var abortAddress common.Address + if zetabits.IsBitSet(dataFlags, bitPosAbortAddress) { + codec.AddArguments(ArgAbortAddress(&abortAddress)) + } + + // add 'revertMessage' argument optionally + f.RevertOptions.CallOnRevert = zetabits.IsBitSet(dataFlags, bitPosRevertMessage) + if f.RevertOptions.CallOnRevert { + codec.AddArguments(ArgRevertMessage(&f.RevertOptions.RevertMessage)) + } + + // unpack the data (after flags) into codec arguments + err := codec.UnpackArguments(data) + if err != nil { + return errors.Wrap(err, "failed to unpack arguments") + } + + // convert abort address to string + if !crypto.IsEmptyAddress(abortAddress) { + f.RevertOptions.AbortAddress = abortAddress.Hex() + } + + return nil +} diff --git a/pkg/memo/fields_v0_test.go b/pkg/memo/fields_v0_test.go new file mode 100644 index 0000000000..13742422c2 --- /dev/null +++ b/pkg/memo/fields_v0_test.go @@ -0,0 +1,388 @@ +package memo_test + +import ( + "bytes" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/memo" + "github.com/zeta-chain/node/testutil/sample" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +const ( + // flagsAllFieldsSet sets all fields: [receiver, payload, revert address, abort address, CallOnRevert] + flagsAllFieldsSet = 0b00011111 +) + +func Test_V0_Pack(t *testing.T) { + // create sample fields + fAddress := sample.EthAddress() + fBytes := []byte("here_s_some_bytes_field") + fString := "this_is_a_string_field" + + tests := []struct { + name string + opCode memo.OpCode + encodeFmt memo.EncodingFormat + dataFlags uint8 + fields memo.FieldsV0 + expectedFlags byte + expectedData []byte + errMsg string + }{ + { + name: "pack all fields with ABI encoding", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: memo.EncodingFmtABI, + dataFlags: flagsAllFieldsSet, // all fields are set + fields: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), // it's a ZEVM address + RevertMessage: fBytes, + }, + }, + expectedData: ABIPack(t, + memo.ArgReceiver(fAddress), + memo.ArgPayload(fBytes), + memo.ArgRevertAddress(fString), + memo.ArgAbortAddress(fAddress), + memo.ArgRevertMessage(fBytes)), + }, + { + name: "pack all fields with compact encoding", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: memo.EncodingFmtCompactShort, + dataFlags: flagsAllFieldsSet, // all fields are set + fields: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), // it's a ZEVM address + RevertMessage: fBytes, + }, + }, + expectedData: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgReceiver(fAddress), + memo.ArgPayload(fBytes), + memo.ArgRevertAddress(fString), + memo.ArgAbortAddress(fAddress), + memo.ArgRevertMessage(fBytes)), + }, + { + name: "fields validation failed due to empty receiver address", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: memo.EncodingFmtABI, + dataFlags: 0b00000001, // receiver flag is set + fields: memo.FieldsV0{ + Receiver: common.Address{}, + }, + errMsg: "receiver address is empty", + }, + { + name: "unable to get codec on invalid encoding format", + opCode: memo.OpCodeDepositAndCall, + fields: memo.FieldsV0{ + Receiver: fAddress, + }, + encodeFmt: 0x0F, + errMsg: "unable to get codec", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // pack the fields + data, err := tc.fields.Pack(tc.opCode, tc.encodeFmt, tc.dataFlags) + + // validate the error message + if tc.errMsg != "" { + require.ErrorContains(t, err, tc.errMsg) + require.Nil(t, data) + return + } + + // compare the fields + require.NoError(t, err) + require.True(t, bytes.Equal(tc.expectedData, data)) + }) + } +} + +func Test_V0_Unpack(t *testing.T) { + // create sample fields + fAddress := common.HexToAddress("0xA029D053E13223E2442E28be80b3CeDA27ecbE31") + fBytes := []byte("here_s_some_bytes_field") + fString := "this_is_a_string_field" + + tests := []struct { + name string + opCode memo.OpCode + encodeFmt memo.EncodingFormat + dataFlags byte + data []byte + expected memo.FieldsV0 + errMsg string + }{ + { + name: "unpack all fields with ABI encoding", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: memo.EncodingFmtABI, + dataFlags: flagsAllFieldsSet, // all fields are set + data: ABIPack(t, + memo.ArgReceiver(fAddress), + memo.ArgPayload(fBytes), + memo.ArgRevertAddress(fString), + memo.ArgAbortAddress(fAddress), + memo.ArgRevertMessage(fBytes)), + expected: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), + RevertMessage: fBytes, + }, + }, + }, + { + name: "unpack all fields with compact encoding", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: memo.EncodingFmtCompactShort, + dataFlags: flagsAllFieldsSet, // all fields are set + data: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgReceiver(fAddress), + memo.ArgPayload(fBytes), + memo.ArgRevertAddress(fString), + memo.ArgAbortAddress(fAddress), + memo.ArgRevertMessage(fBytes)), + expected: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), + RevertMessage: fBytes, + }, + }, + }, + { + name: "unpack empty ABI encoded payload if flag is set", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: memo.EncodingFmtABI, + dataFlags: 0b00000010, // payload flags are set + data: ABIPack(t, + memo.ArgPayload([]byte{})), // empty payload + expected: memo.FieldsV0{}, + }, + { + name: "unpack empty compact encoded payload if flag is set", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: memo.EncodingFmtCompactShort, + dataFlags: 0b00000010, // payload flag is set + data: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgPayload([]byte{})), // empty payload + expected: memo.FieldsV0{}, + }, + { + name: "unable to get codec on invalid encoding format", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: 0x0F, + dataFlags: 0b00000001, + data: []byte{}, + errMsg: "unable to get codec", + }, + { + name: "failed to unpack ABI encoded data with compact encoding format", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: memo.EncodingFmtCompactShort, + dataFlags: 0b00000011, // receiver and payload flags are set + data: ABIPack(t, + memo.ArgReceiver(fAddress), + memo.ArgPayload(fBytes)), + errMsg: "failed to unpack arguments", + }, + { + name: "fields validation failed due to empty receiver address", + opCode: memo.OpCodeDepositAndCall, + encodeFmt: memo.EncodingFmtABI, + dataFlags: 0b00000011, // receiver and payload flags are set + data: ABIPack(t, + memo.ArgReceiver(common.Address{}), + memo.ArgPayload(fBytes)), + errMsg: "receiver address is empty", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // unpack the fields + fields := memo.FieldsV0{} + err := fields.Unpack(tc.opCode, tc.encodeFmt, tc.dataFlags, tc.data) + + // validate the error message + if tc.errMsg != "" { + require.ErrorContains(t, err, tc.errMsg) + return + } + + // compare the fields + require.NoError(t, err) + require.Equal(t, tc.expected, fields) + }) + } +} + +func Test_V0_Validate(t *testing.T) { + // create sample fields + fAddress := common.HexToAddress("0xA029D053E13223E2442E28be80b3CeDA27ecbE31") + fBytes := []byte("here_s_some_bytes_field") + fString := "this_is_a_string_field" + + tests := []struct { + name string + opCode memo.OpCode + dataFlags uint8 + fields memo.FieldsV0 + errMsg string + }{ + { + name: "valid fields", + opCode: memo.OpCodeDepositAndCall, + dataFlags: flagsAllFieldsSet, // all fields are set + fields: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), + RevertMessage: fBytes, + }, + }, + }, + { + name: "invalid receiver address", + opCode: memo.OpCodeCall, + dataFlags: 0b00000001, // receiver flag is set + fields: memo.FieldsV0{ + Receiver: common.Address{}, // provide empty receiver address + }, + errMsg: "receiver address is empty", + }, + { + name: "payload is not allowed when opCode is deposit", + opCode: memo.OpCodeDeposit, + fields: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, // payload is mistakenly set + }, + errMsg: "payload is not allowed for deposit operation", + }, + { + name: "abort address is invalid", + opCode: memo.OpCodeDeposit, + dataFlags: 0b00001000, // abort address flag is set + fields: memo.FieldsV0{ + RevertOptions: crosschaintypes.RevertOptions{ + AbortAddress: "invalid abort address", + }, + }, + errMsg: "invalid abort address", + }, + { + name: "revert message is not allowed when CallOnRevert is false", + opCode: memo.OpCodeDeposit, + fields: memo.FieldsV0{ + Receiver: fAddress, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: false, // CallOnRevert is false + RevertMessage: []byte("revert message"), // revert message is mistakenly set + }, + }, + errMsg: "revert message is not allowed when CallOnRevert is false", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // validate the fields + err := tc.fields.Validate(tc.opCode, tc.dataFlags) + + // validate the error message + if tc.errMsg != "" { + require.ErrorContains(t, err, tc.errMsg) + return + } + require.NoError(t, err) + }) + } +} + +func Test_V0_DataFlags(t *testing.T) { + // create sample fields + fAddress := common.HexToAddress("0xA029D053E13223E2442E28be80b3CeDA27ecbE31") + fBytes := []byte("here_s_some_bytes_field") + fString := "this_is_a_string_field" + + tests := []struct { + name string + fields memo.FieldsV0 + expectedFlags uint8 + }{ + { + name: "all fields set", + fields: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), + RevertMessage: fBytes, + }, + }, + expectedFlags: flagsAllFieldsSet, + }, + { + name: "no fields set", + fields: memo.FieldsV0{}, + expectedFlags: 0b00000000, + }, + { + name: "a few fields set", + fields: memo.FieldsV0{ + Receiver: fAddress, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + RevertMessage: fBytes, + }, + }, + expectedFlags: 0b00010101, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // get the data flags + flags := tc.fields.DataFlags() + + // compare the flags + require.Equal(t, tc.expectedFlags, flags) + }) + } +} diff --git a/pkg/memo/header.go b/pkg/memo/header.go new file mode 100644 index 0000000000..5f9bcd1e14 --- /dev/null +++ b/pkg/memo/header.go @@ -0,0 +1,139 @@ +package memo + +import ( + "fmt" + + "github.com/pkg/errors" + + zetabits "github.com/zeta-chain/node/pkg/math/bits" +) + +type OpCode uint8 + +const ( + // Identifier is the ASCII code of 'Z' (0x5A) + Identifier byte = 0x5A + + // HeaderSize is the size of the memo header: [identifier + ctrlByte1+ ctrlByte2 + dataFlags] + HeaderSize = 4 + + // maskVersion is the mask for the version bits(upper 4 bits) + maskVersion byte = 0b11110000 + + // maskEncodingFormat is the mask for the encoding format bits(lower 4 bits) + maskEncodingFormat byte = 0b00001111 + + // maskOpCode is the mask for the operation code bits(upper 4 bits) + maskOpCode byte = 0b11110000 + + // maskCtrlReserved is the mask for reserved control bits (lower 4 bits) + maskCtrlReserved byte = 0b00001111 +) + +// Enum for non-EVM chain inbound operation code (4 bits) +const ( + OpCodeDeposit OpCode = 0b0000 // operation 'deposit' + OpCodeDepositAndCall OpCode = 0b0001 // operation 'deposit_and_call' + OpCodeCall OpCode = 0b0010 // operation 'call' + OpCodeInvalid OpCode = 0b0011 // invalid operation code +) + +// Header represent the memo header +type Header struct { + // Version is the memo Version + Version uint8 + + // EncodingFmt is the memo encoding format + EncodingFmt EncodingFormat + + // OpCode is the inbound operation code + OpCode OpCode + + // Reserved is the reserved control bits + Reserved uint8 + + // DataFlags is the data flags + DataFlags uint8 +} + +// EncodeToBytes encodes the memo header to raw bytes +func (h *Header) EncodeToBytes() ([]byte, error) { + // validate header + if err := h.Validate(); err != nil { + return nil, err + } + + // create buffer for the header + data := make([]byte, HeaderSize) + + // set byte-0 as memo identifier + data[0] = Identifier + + // set version #, encoding format + var ctrlByte1 byte + ctrlByte1 = zetabits.SetBits(ctrlByte1, maskVersion, h.Version) + ctrlByte1 = zetabits.SetBits(ctrlByte1, maskEncodingFormat, byte(h.EncodingFmt)) + data[1] = ctrlByte1 + + // set operation code, reserved bits + var ctrlByte2 byte + ctrlByte2 = zetabits.SetBits(ctrlByte2, maskOpCode, byte(h.OpCode)) + ctrlByte2 = zetabits.SetBits(ctrlByte2, maskCtrlReserved, h.Reserved) + data[2] = ctrlByte2 + + // set data flags + data[3] = h.DataFlags + + return data, nil +} + +// DecodeFromBytes decodes the memo header from the given data +func (h *Header) DecodeFromBytes(data []byte) error { + // memo data must be longer than the header size + if len(data) < HeaderSize { + return errors.New("memo is too short") + } + + // byte-0 is the memo identifier + if data[0] != Identifier { + return fmt.Errorf("invalid memo identifier: %d", data[0]) + } + + // extract version #, encoding format + ctrlByte1 := data[1] + h.Version = zetabits.GetBits(ctrlByte1, maskVersion) + h.EncodingFmt = EncodingFormat(zetabits.GetBits(ctrlByte1, maskEncodingFormat)) + + // extract operation code, reserved bits + ctrlByte2 := data[2] + h.OpCode = OpCode(zetabits.GetBits(ctrlByte2, maskOpCode)) + h.Reserved = zetabits.GetBits(ctrlByte2, maskCtrlReserved) + + // extract data flags + h.DataFlags = data[3] + + // validate header + return h.Validate() +} + +// Validate checks if the memo header is valid +func (h *Header) Validate() error { + if h.Version != 0 { + return fmt.Errorf("invalid memo version: %d", h.Version) + } + + if h.EncodingFmt >= EncodingFmtInvalid { + return fmt.Errorf("invalid encoding format: %d", h.EncodingFmt) + } + + if h.OpCode >= OpCodeInvalid { + return fmt.Errorf("invalid operation code: %d", h.OpCode) + } + + // reserved control bits must be zero + if h.Reserved != 0 { + return fmt.Errorf("reserved control bits are not zero: %d", h.Reserved) + } + + return nil +} diff --git a/pkg/memo/header_test.go b/pkg/memo/header_test.go new file mode 100644 index 0000000000..9d89e1f1d6 --- /dev/null +++ b/pkg/memo/header_test.go @@ -0,0 +1,167 @@ +package memo_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/memo" +) + +// MakeHead is a helper function to create a memo head +// Note: all arguments are assumed to be <= 0b1111 for simplicity. +func MakeHead(version, encodingFmt, opCode, reserved, flags uint8) []byte { + head := make([]byte, memo.HeaderSize) + head[0] = memo.Identifier + head[1] = version<<4 | encodingFmt + head[2] = opCode<<4 | reserved + head[3] = flags + return head +} + +func Test_Header_EncodeToBytes(t *testing.T) { + tests := []struct { + name string + header memo.Header + expected []byte + errMsg string + }{ + { + name: "it works", + header: memo.Header{ + Version: 0, + EncodingFmt: memo.EncodingFmtABI, + OpCode: memo.OpCodeCall, + DataFlags: 0b00011111, + }, + expected: []byte{memo.Identifier, 0b00000000, 0b00100000, 0b00011111}, + }, + { + name: "header validation failed", + header: memo.Header{ + Version: 1, // invalid version + }, + errMsg: "invalid memo version", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + header, err := tt.header.EncodeToBytes() + if tt.errMsg != "" { + require.ErrorContains(t, err, tt.errMsg) + require.Nil(t, header) + return + } + require.NoError(t, err) + require.Equal(t, tt.expected, header) + }) + } +} + +func Test_Header_DecodeFromBytes(t *testing.T) { + tests := []struct { + name string + data []byte + expected memo.Header + errMsg string + }{ + { + name: "it works", + data: append( + MakeHead(0, uint8(memo.EncodingFmtABI), uint8(memo.OpCodeCall), 0, 0), + []byte{0x01, 0x02}...), + expected: memo.Header{ + Version: 0, + EncodingFmt: memo.EncodingFmtABI, + OpCode: memo.OpCodeCall, + Reserved: 0, + }, + }, + { + name: "memo is too short", + data: []byte{0x01, 0x02, 0x03}, + errMsg: "memo is too short", + }, + { + name: "invalid memo identifier", + data: []byte{'M', 0x02, 0x03, 0x04, 0x05}, + errMsg: "invalid memo identifier", + }, + { + name: "header validation failed", + data: append( + MakeHead(0, uint8(memo.EncodingFmtInvalid), uint8(memo.OpCodeCall), 0, 0), + []byte{0x01, 0x02}...), // invalid encoding format + errMsg: "invalid encoding format", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + memo := &memo.Header{} + err := memo.DecodeFromBytes(tt.data) + if tt.errMsg != "" { + require.ErrorContains(t, err, tt.errMsg) + return + } + require.NoError(t, err) + require.Equal(t, tt.expected, *memo) + }) + } +} + +func Test_Header_Validate(t *testing.T) { + tests := []struct { + name string + header memo.Header + errMsg string + }{ + { + name: "valid header", + header: memo.Header{ + Version: 0, + EncodingFmt: memo.EncodingFmtCompactShort, + OpCode: memo.OpCodeDepositAndCall, + }, + }, + { + name: "invalid version", + header: memo.Header{ + Version: 1, + }, + errMsg: "invalid memo version", + }, + { + name: "invalid encoding format", + header: memo.Header{ + EncodingFmt: memo.EncodingFmtInvalid, + }, + errMsg: "invalid encoding format", + }, + { + name: "invalid operation code", + header: memo.Header{ + OpCode: memo.OpCodeInvalid, + }, + errMsg: "invalid operation code", + }, + { + name: "reserved field is not zero", + header: memo.Header{ + Reserved: 1, + }, + errMsg: "reserved control bits are not zero", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.header.Validate() + if tt.errMsg != "" { + require.ErrorContains(t, err, tt.errMsg) + return + } + require.NoError(t, err) + }) + } +} diff --git a/pkg/memo/memo.go b/pkg/memo/memo.go new file mode 100644 index 0000000000..30670952b0 --- /dev/null +++ b/pkg/memo/memo.go @@ -0,0 +1,98 @@ +package memo + +import ( + "encoding/hex" + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" +) + +// InboundMemo represents the inbound memo structure for non-EVM chains +type InboundMemo struct { + // Header contains the memo header + Header + + // FieldsV0 contains the memo fields V0 + // Note: add a FieldsV1 if breaking change is needed in the future + FieldsV0 +} + +// EncodeToBytes encodes a InboundMemo struct to raw bytes +// +// Note: +// - Any provided 'DataFlags' is ignored as they are calculated based on the fields set in the memo. +// - The 'RevertGasLimit' is not used for now for non-EVM chains. +func (m *InboundMemo) EncodeToBytes() ([]byte, error) { + // build fields flags + dataFlags := m.FieldsV0.DataFlags() + m.Header.DataFlags = dataFlags + + // encode head + head, err := m.Header.EncodeToBytes() + if err != nil { + return nil, errors.Wrap(err, "failed to encode memo header") + } + + // encode fields based on version + var data []byte + switch m.Version { + case 0: + data, err = m.FieldsV0.Pack(m.OpCode, m.EncodingFmt, dataFlags) + default: + return nil, fmt.Errorf("invalid memo version: %d", m.Version) + } + if err != nil { + return nil, errors.Wrapf(err, "failed to pack memo fields version: %d", m.Version) + } + + return append(head, data...), nil +} + +// DecodeFromBytes decodes a InboundMemo struct from raw bytes +// +// Returns an error if given data is not a valid memo +func DecodeFromBytes(data []byte) (*InboundMemo, error) { + memo := &InboundMemo{} + + // decode header + err := memo.Header.DecodeFromBytes(data) + if err != nil { + return nil, errors.Wrap(err, "failed to decode memo header") + } + + // decode fields based on version + switch memo.Version { + case 0: + err = memo.FieldsV0.Unpack(memo.OpCode, memo.EncodingFmt, memo.Header.DataFlags, data[HeaderSize:]) + default: + return nil, fmt.Errorf("invalid memo version: %d", memo.Version) + } + if err != nil { + return nil, errors.Wrapf(err, "failed to unpack memo fields version: %d", memo.Version) + } + + return memo, nil +} + +// DecodeLegacyMemoHex decodes hex encoded memo message into address and calldata +// +// The layout of legacy memo is: [20-byte address, variable calldata] +func DecodeLegacyMemoHex(message string) (common.Address, []byte, error) { + if len(message) == 0 { + return common.Address{}, nil, nil + } + + data, err := hex.DecodeString(message) + if err != nil { + return common.Address{}, nil, errors.Wrap(err, "message should be a hex encoded string") + } + + if len(data) < common.AddressLength { + return common.Address{}, data, nil + } + + address := common.BytesToAddress(data[:common.AddressLength]) + data = data[common.AddressLength:] + return address, data, nil +} diff --git a/pkg/memo/memo_test.go b/pkg/memo/memo_test.go new file mode 100644 index 0000000000..e6cb067793 --- /dev/null +++ b/pkg/memo/memo_test.go @@ -0,0 +1,306 @@ +package memo_test + +import ( + "encoding/hex" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/pkg/memo" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +func Test_Memo_EncodeToBytes(t *testing.T) { + // create sample fields + fAddress := common.HexToAddress("0xEA9808f0Ac504d1F521B5BbdfC33e6f1953757a7") + fBytes := []byte("here_s_some_bytes_field") + fString := "this_is_a_string_field" + + tests := []struct { + name string + memo *memo.InboundMemo + expectedHead []byte + expectedData []byte + errMsg string + }{ + { + name: "encode memo with ABI encoding", + memo: &memo.InboundMemo{ + Header: memo.Header{ + Version: 0, + EncodingFmt: memo.EncodingFmtABI, + OpCode: memo.OpCodeDepositAndCall, + }, + FieldsV0: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), // it's a ZEVM address + RevertMessage: fBytes, + }, + }, + }, + expectedHead: MakeHead( + 0, + uint8(memo.EncodingFmtABI), + uint8(memo.OpCodeDepositAndCall), + 0, + flagsAllFieldsSet, // all fields are set + ), + expectedData: ABIPack(t, + memo.ArgReceiver(fAddress), + memo.ArgPayload(fBytes), + memo.ArgRevertAddress(fString), + memo.ArgAbortAddress(fAddress), + memo.ArgRevertMessage(fBytes)), + }, + { + name: "encode memo with compact encoding", + memo: &memo.InboundMemo{ + Header: memo.Header{ + Version: 0, + EncodingFmt: memo.EncodingFmtCompactShort, + OpCode: memo.OpCodeDepositAndCall, + }, + FieldsV0: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), // it's a ZEVM address + RevertMessage: fBytes, + }, + }, + }, + expectedHead: MakeHead( + 0, + uint8(memo.EncodingFmtCompactShort), + uint8(memo.OpCodeDepositAndCall), + 0, + flagsAllFieldsSet, // all fields are set + ), + expectedData: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgReceiver(fAddress), + memo.ArgPayload(fBytes), + memo.ArgRevertAddress(fString), + memo.ArgAbortAddress(fAddress), + memo.ArgRevertMessage(fBytes)), + }, + { + name: "failed to encode memo header", + memo: &memo.InboundMemo{ + Header: memo.Header{ + OpCode: memo.OpCodeInvalid, // invalid operation code + }, + }, + errMsg: "failed to encode memo header", + }, + { + name: "failed to encode if version is invalid", + memo: &memo.InboundMemo{ + Header: memo.Header{ + Version: 1, + }, + }, + errMsg: "invalid memo version", + }, + { + name: "failed to pack memo fields", + memo: &memo.InboundMemo{ + Header: memo.Header{ + Version: 0, + EncodingFmt: memo.EncodingFmtABI, + OpCode: memo.OpCodeDeposit, + }, + FieldsV0: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, // payload is not allowed for deposit + }, + }, + errMsg: "failed to pack memo fields version: 0", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data, err := tt.memo.EncodeToBytes() + if tt.errMsg != "" { + require.ErrorContains(t, err, tt.errMsg) + require.Nil(t, data) + return + } + require.NoError(t, err) + require.Equal(t, append(tt.expectedHead, tt.expectedData...), data) + + // decode the memo and compare with the original + decodedMemo, err := memo.DecodeFromBytes(data) + require.NoError(t, err) + require.Equal(t, tt.memo, decodedMemo) + }) + } +} + +func Test_Memo_DecodeFromBytes(t *testing.T) { + // create sample fields + fAddress := common.HexToAddress("0xEA9808f0Ac504d1F521B5BbdfC33e6f1953757a7") + fBytes := []byte("here_s_some_bytes_field") + fString := "this_is_a_string_field" + + tests := []struct { + name string + head []byte + data []byte + expectedMemo memo.InboundMemo + errMsg string + }{ + { + name: "decode memo with ABI encoding", + head: MakeHead( + 0, + uint8(memo.EncodingFmtABI), + uint8(memo.OpCodeDepositAndCall), + 0, + flagsAllFieldsSet, // all fields are set + ), + data: ABIPack(t, + memo.ArgReceiver(fAddress), + memo.ArgPayload(fBytes), + memo.ArgRevertAddress(fString), + memo.ArgAbortAddress(fAddress), + memo.ArgRevertMessage(fBytes)), + expectedMemo: memo.InboundMemo{ + Header: memo.Header{ + Version: 0, + EncodingFmt: memo.EncodingFmtABI, + OpCode: memo.OpCodeDepositAndCall, + DataFlags: 0b00011111, + }, + FieldsV0: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), // it's a ZEVM address + RevertMessage: fBytes, + }, + }, + }, + }, + { + name: "decode memo with compact encoding", + head: MakeHead( + 0, + uint8(memo.EncodingFmtCompactLong), + uint8(memo.OpCodeDepositAndCall), + 0, + flagsAllFieldsSet, // all fields are set + ), + data: CompactPack( + memo.EncodingFmtCompactLong, + memo.ArgReceiver(fAddress), + memo.ArgPayload(fBytes), + memo.ArgRevertAddress(fString), + memo.ArgAbortAddress(fAddress), + memo.ArgRevertMessage(fBytes)), + expectedMemo: memo.InboundMemo{ + Header: memo.Header{ + Version: 0, + EncodingFmt: memo.EncodingFmtCompactLong, + OpCode: memo.OpCodeDepositAndCall, + DataFlags: 0b00011111, + }, + FieldsV0: memo.FieldsV0{ + Receiver: fAddress, + Payload: fBytes, + RevertOptions: crosschaintypes.RevertOptions{ + RevertAddress: fString, + CallOnRevert: true, + AbortAddress: fAddress.String(), // it's a ZEVM address + RevertMessage: fBytes, + }, + }, + }, + }, + { + name: "failed to decode memo header", + head: MakeHead(0, uint8(memo.EncodingFmtABI), uint8(memo.OpCodeInvalid), 0, 0), + data: ABIPack(t, memo.ArgReceiver(fAddress)), + errMsg: "failed to decode memo header", + }, + { + name: "failed to decode if version is invalid", + head: MakeHead(1, uint8(memo.EncodingFmtABI), uint8(memo.OpCodeDeposit), 0, 0), + data: ABIPack(t, memo.ArgReceiver(fAddress)), + errMsg: "invalid memo version", + }, + { + name: "failed to decode compact encoded data with ABI encoding format", + head: MakeHead( + 0, + uint8(memo.EncodingFmtABI), + uint8(memo.OpCodeDepositAndCall), + 0, + 0, + ), // header says ABI encoding + data: CompactPack( + memo.EncodingFmtCompactShort, + memo.ArgReceiver(fAddress), + ), // but data is compact encoded + errMsg: "failed to unpack memo fields", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data := append(tt.head, tt.data...) + memo, err := memo.DecodeFromBytes(data) + if tt.errMsg != "" { + require.ErrorContains(t, err, tt.errMsg) + return + } + require.NoError(t, err) + require.Equal(t, tt.expectedMemo, *memo) + }) + } +} + +func Test_DecodeLegacyMemoHex(t *testing.T) { + expectedShortMsgResult, err := hex.DecodeString("1a2b3c4d5e6f708192a3b4c5d6e7f808") + require.NoError(t, err) + tests := []struct { + name string + message string + expectAddr common.Address + expectData []byte + wantErr bool + }{ + { + "valid msg", + "95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5", + common.HexToAddress("95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5"), + []byte{}, + false, + }, + {"empty msg", "", common.Address{}, nil, false}, + {"invalid hex", "invalidHex", common.Address{}, nil, true}, + {"short msg", "1a2b3c4d5e6f708192a3b4c5d6e7f808", common.Address{}, expectedShortMsgResult, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + addr, data, err := memo.DecodeLegacyMemoHex(tt.message) + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tt.expectAddr, addr) + require.Equal(t, tt.expectData, data) + } + }) + } +} diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index c672686c1a..be08873bba 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -14,6 +14,7 @@ import ( "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" + "github.com/zeta-chain/node/pkg/memo" "github.com/zeta-chain/node/x/crosschain/types" fungibletypes "github.com/zeta-chain/node/x/fungible/types" ) @@ -78,7 +79,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo // in protocol version 2, the destination of the deposit is always the to address, the message is the data to be sent to the contract if cctx.ProtocolContractVersion == types.ProtocolContractVersion_V1 { var parsedAddress ethcommon.Address - parsedAddress, message, err = chains.ParseAddressAndData(cctx.RelayedMessage) + parsedAddress, message, err = memo.DecodeLegacyMemoHex(cctx.RelayedMessage) if err != nil { return false, errors.Wrap(types.ErrUnableToParseAddress, err.Error()) } diff --git a/zetaclient/chains/bitcoin/observer/inbound.go b/zetaclient/chains/bitcoin/observer/inbound.go index fad3c87230..1461096763 100644 --- a/zetaclient/chains/bitcoin/observer/inbound.go +++ b/zetaclient/chains/bitcoin/observer/inbound.go @@ -14,8 +14,8 @@ import ( "github.com/pkg/errors" "github.com/rs/zerolog" - "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" + "github.com/zeta-chain/node/pkg/memo" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" "github.com/zeta-chain/node/zetaclient/chains/bitcoin" "github.com/zeta-chain/node/zetaclient/chains/interfaces" @@ -419,7 +419,7 @@ func (ob *Observer) GetInboundVoteMessageFromBtcEvent(inbound *BTCInboundEvent) // TODO(revamp): move all compliance related functions in a specific file func (ob *Observer) DoesInboundContainsRestrictedAddress(inTx *BTCInboundEvent) bool { receiver := "" - parsedAddress, _, err := chains.ParseAddressAndData(hex.EncodeToString(inTx.MemoBytes)) + parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(inTx.MemoBytes)) if err == nil && parsedAddress != (ethcommon.Address{}) { receiver = parsedAddress.Hex() } diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index c662fc2d60..aebd661ae3 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -20,9 +20,9 @@ import ( "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/erc20custody.sol" "github.com/zeta-chain/protocol-contracts/v1/pkg/contracts/evm/zetaconnector.non-eth.sol" - "github.com/zeta-chain/node/pkg/chains" "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/pkg/constant" + "github.com/zeta-chain/node/pkg/memo" "github.com/zeta-chain/node/pkg/ticker" "github.com/zeta-chain/node/x/crosschain/types" "github.com/zeta-chain/node/zetaclient/chains/evm" @@ -622,7 +622,7 @@ func (ob *Observer) BuildInboundVoteMsgForDepositedEvent( ) *types.MsgVoteInbound { // compliance check maybeReceiver := "" - parsedAddress, _, err := chains.ParseAddressAndData(hex.EncodeToString(event.Message)) + parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(event.Message)) if err == nil && parsedAddress != (ethcommon.Address{}) { maybeReceiver = parsedAddress.Hex() } @@ -732,7 +732,7 @@ func (ob *Observer) BuildInboundVoteMsgForTokenSentToTSS( // compliance check maybeReceiver := "" - parsedAddress, _, err := chains.ParseAddressAndData(message) + parsedAddress, _, err := memo.DecodeLegacyMemoHex(message) if err == nil && parsedAddress != (ethcommon.Address{}) { maybeReceiver = parsedAddress.Hex() } diff --git a/zetaclient/compliance/compliance.go b/zetaclient/compliance/compliance.go index 163cca65e4..f0135c3ad9 100644 --- a/zetaclient/compliance/compliance.go +++ b/zetaclient/compliance/compliance.go @@ -7,7 +7,7 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" - "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/pkg/memo" crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" "github.com/zeta-chain/node/zetaclient/chains/base" "github.com/zeta-chain/node/zetaclient/config" @@ -66,7 +66,7 @@ func PrintComplianceLog( func DoesInboundContainsRestrictedAddress(event *clienttypes.InboundEvent, logger *base.ObserverLogger) bool { // parse memo-specified receiver receiver := "" - parsedAddress, _, err := chains.ParseAddressAndData(hex.EncodeToString(event.Memo)) + parsedAddress, _, err := memo.DecodeLegacyMemoHex(hex.EncodeToString(event.Memo)) if err == nil && parsedAddress != (ethcommon.Address{}) { receiver = parsedAddress.Hex() } From 920779b96e11f3e31b336fc4c56a3988c9e04814 Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Thu, 17 Oct 2024 14:15:38 +0200 Subject: [PATCH 30/36] test(precompiles): add missing test in staking (#3017) * test(precompiles): add missing test in staking * remove redundant require --- precompiles/staking/staking_test.go | 103 ++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/precompiles/staking/staking_test.go b/precompiles/staking/staking_test.go index 94c1a432c1..3155dd2b4b 100644 --- a/precompiles/staking/staking_test.go +++ b/precompiles/staking/staking_test.go @@ -23,6 +23,7 @@ import ( "github.com/zeta-chain/ethermint/x/evm/statedb" "github.com/zeta-chain/node/cmd/zetacored/config" "github.com/zeta-chain/node/precompiles/prototype" + ptypes "github.com/zeta-chain/node/precompiles/types" "github.com/zeta-chain/node/testutil/keeper" "github.com/zeta-chain/node/testutil/sample" @@ -238,6 +239,33 @@ func Test_InvalidABI(t *testing.T) { } func Test_Stake(t *testing.T) { + t.Run("should fail in read only mode", func(t *testing.T) { + // ARRANGE + ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + methodID := abi.Methods[StakeMethodName] + r := rand.New(rand.NewSource(42)) + validator := sample.Validator(t, r) + + staker := sample.Bech32AccAddress() + stakerEthAddr := common.BytesToAddress(staker.Bytes()) + coins := sample.Coins() + err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + require.NoError(t, err) + err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + require.NoError(t, err) + + stakerAddr := common.BytesToAddress(staker.Bytes()) + mockVMContract.CallerAddress = stakerAddr + args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + mockVMContract.Input = packInputArgs(t, methodID, args...) + + // ACT + _, err = contract.Run(mockEVM, mockVMContract, true) + + // ASSERT + require.ErrorIs(t, err, ptypes.ErrWriteMethod{Method: StakeMethodName}) + }) + t.Run("should fail if validator doesn't exist", func(t *testing.T) { // ARRANGE ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) @@ -483,6 +511,34 @@ func Test_Stake(t *testing.T) { } func Test_Unstake(t *testing.T) { + t.Run("should fail in read only method", func(t *testing.T) { + // ARRANGE + ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + methodID := abi.Methods[UnstakeMethodName] + r := rand.New(rand.NewSource(42)) + validator := sample.Validator(t, r) + + staker := sample.Bech32AccAddress() + stakerEthAddr := common.BytesToAddress(staker.Bytes()) + coins := sample.Coins() + err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + require.NoError(t, err) + err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + require.NoError(t, err) + + stakerAddr := common.BytesToAddress(staker.Bytes()) + mockVMContract.CallerAddress = stakerAddr + + args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + mockVMContract.Input = packInputArgs(t, methodID, args...) + + // ACT + _, err = contract.Run(mockEVM, mockVMContract, true) + + // ASSERT + require.ErrorIs(t, err, ptypes.ErrWriteMethod{Method: UnstakeMethodName}) + }) + t.Run("should fail if validator doesn't exist", func(t *testing.T) { // ARRANGE ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) @@ -721,6 +777,53 @@ func Test_Unstake(t *testing.T) { } func Test_MoveStake(t *testing.T) { + t.Run("should fail in read only method", func(t *testing.T) { + // ARRANGE + ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + methodID := abi.Methods[MoveStakeMethodName] + r := rand.New(rand.NewSource(42)) + validatorSrc := sample.Validator(t, r) + sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + validatorDest := sample.Validator(t, r) + + staker := sample.Bech32AccAddress() + stakerEthAddr := common.BytesToAddress(staker.Bytes()) + coins := sample.Coins() + err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + require.NoError(t, err) + err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + require.NoError(t, err) + + stakerAddr := common.BytesToAddress(staker.Bytes()) + mockVMContract.CallerAddress = stakerAddr + + argsStake := []interface{}{ + stakerEthAddr, + validatorSrc.OperatorAddress, + coins.AmountOf(config.BaseDenom).BigInt(), + } + + // stake to validator src + stakeMethodID := abi.Methods[StakeMethodName] + mockVMContract.Input = packInputArgs(t, stakeMethodID, argsStake...) + _, err = contract.Run(mockEVM, mockVMContract, false) + require.NoError(t, err) + + argsMoveStake := []interface{}{ + stakerEthAddr, + validatorSrc.OperatorAddress, + validatorDest.OperatorAddress, + coins.AmountOf(config.BaseDenom).BigInt(), + } + mockVMContract.Input = packInputArgs(t, methodID, argsMoveStake...) + + // ACT + _, err = contract.Run(mockEVM, mockVMContract, true) + + // ASSERT + require.ErrorIs(t, err, ptypes.ErrWriteMethod{Method: MoveStakeMethodName}) + }) + t.Run("should fail if validator dest doesn't exist", func(t *testing.T) { // ARRANGE ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) From 05c07695dfe457129a8bd03e2f79642c66f5e972 Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Thu, 17 Oct 2024 16:01:34 +0200 Subject: [PATCH 31/36] chore(precompiles): disable stake, unstake and moveStake (#3010) * GH3005: disable stake, unstake and moveStake * explicitly check for failed tx when staking * fix lint govet * rebase * fix duplicated import --- cmd/zetae2e/local/local.go | 3 +- e2e/e2etests/e2etests.go | 2 +- e2e/e2etests/test_precompiles_staking.go | 52 + precompiles/staking/staking.go | 18 + precompiles/staking/staking_test.go | 1831 ++++++++++++---------- precompiles/types/errors.go | 8 + 6 files changed, 1055 insertions(+), 859 deletions(-) diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 2d404ba391..de46edf450 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -330,7 +330,8 @@ func localE2ETest(cmd *cobra.Command, _ []string) { e2etests.TestPrecompilesPrototypeName, e2etests.TestPrecompilesPrototypeThroughContractName, e2etests.TestPrecompilesStakingName, - e2etests.TestPrecompilesStakingThroughContractName, + // Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. + // e2etests.TestPrecompilesStakingThroughContractName, e2etests.TestPrecompilesBankName, e2etests.TestPrecompilesBankFailName, e2etests.TestPrecompilesBankThroughContractName, diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index 2d6eea998f..fe6428385d 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -930,7 +930,7 @@ var AllE2ETests = []runner.E2ETest{ TestPrecompilesStakingName, "test stateful precompiled contracts staking", []runner.ArgDefinition{}, - TestPrecompilesStaking, + TestPrecompilesStakingIsDisabled, ), runner.NewE2ETest( TestPrecompilesStakingThroughContractName, diff --git a/e2e/e2etests/test_precompiles_staking.go b/e2e/e2etests/test_precompiles_staking.go index 7b1fc44e1c..37a7e152de 100644 --- a/e2e/e2etests/test_precompiles_staking.go +++ b/e2e/e2etests/test_precompiles_staking.go @@ -13,6 +13,58 @@ import ( "github.com/zeta-chain/node/precompiles/staking" ) +func TestPrecompilesStakingIsDisabled(r *runner.E2ERunner, args []string) { + require.Len(r, args, 0, "No arguments expected") + + stakingContract, err := staking.NewIStaking(staking.ContractAddress, r.ZEVMClient) + require.NoError(r, err, "Failed to create staking contract caller") + + previousGasLimit := r.ZEVMAuth.GasLimit + r.ZEVMAuth.GasLimit = 10000000 + defer func() { + r.ZEVMAuth.GasLimit = previousGasLimit + }() + + validators, err := stakingContract.GetAllValidators(&bind.CallOpts{}) + require.NoError(r, err) + require.GreaterOrEqual(r, len(validators), 2) + + CleanValidatorDelegations(r, stakingContract, validators) + + // shares are 0 for both validators at the start + sharesBeforeVal1, err := stakingContract.GetShares(&bind.CallOpts{}, r.ZEVMAuth.From, validators[0].OperatorAddress) + require.NoError(r, err) + require.Equal(r, int64(0), sharesBeforeVal1.Int64()) + + sharesBeforeVal2, err := stakingContract.GetShares(&bind.CallOpts{}, r.ZEVMAuth.From, validators[1].OperatorAddress) + require.NoError(r, err) + require.Equal(r, int64(0), sharesBeforeVal2.Int64()) + + // stake 3 to validator1 + tx, err := stakingContract.Stake(r.ZEVMAuth, r.ZEVMAuth.From, validators[0].OperatorAddress, big.NewInt(3)) + require.NoError(r, err) + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequiredTxFailed(r, receipt) + + // unstake 1 from validator1 + tx, err = stakingContract.Unstake(r.ZEVMAuth, r.ZEVMAuth.From, validators[0].OperatorAddress, big.NewInt(1)) + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequiredTxFailed(r, receipt) + + // move 1 stake from validator1 to validator2 + tx, err = stakingContract.MoveStake( + r.ZEVMAuth, + r.ZEVMAuth.From, + validators[0].OperatorAddress, + validators[1].OperatorAddress, + big.NewInt(1), + ) + require.NoError(r, err) + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequiredTxFailed(r, receipt) +} + func TestPrecompilesStaking(r *runner.E2ERunner, args []string) { require.Len(r, args, 0, "No arguments expected") diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index f3a01a541e..fea0d0f9f2 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -415,6 +415,12 @@ func (c *Contract) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]byt } return res, nil case StakeMethodName: + // Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. + return nil, ptypes.ErrDisabledMethod{ + Method: method.Name, + } + + //nolint:govet if readOnly { return nil, ptypes.ErrWriteMethod{ Method: method.Name, @@ -431,6 +437,12 @@ func (c *Contract) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]byt } return res, nil case UnstakeMethodName: + // Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. + return nil, ptypes.ErrDisabledMethod{ + Method: method.Name, + } + + //nolint:govet if readOnly { return nil, ptypes.ErrWriteMethod{ Method: method.Name, @@ -447,6 +459,12 @@ func (c *Contract) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) ([]byt } return res, nil case MoveStakeMethodName: + // Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. + return nil, ptypes.ErrDisabledMethod{ + Method: method.Name, + } + + //nolint:govet if readOnly { return nil, ptypes.ErrWriteMethod{ Method: method.Name, diff --git a/precompiles/staking/staking_test.go b/precompiles/staking/staking_test.go index 3155dd2b4b..aaea87f94d 100644 --- a/precompiles/staking/staking_test.go +++ b/precompiles/staking/staking_test.go @@ -239,7 +239,8 @@ func Test_InvalidABI(t *testing.T) { } func Test_Stake(t *testing.T) { - t.Run("should fail in read only mode", func(t *testing.T) { + // Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. + t.Run("should fail with error disabled", func(t *testing.T) { // ARRANGE ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) methodID := abi.Methods[StakeMethodName] @@ -259,627 +260,295 @@ func Test_Stake(t *testing.T) { args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} mockVMContract.Input = packInputArgs(t, methodID, args...) - // ACT - _, err = contract.Run(mockEVM, mockVMContract, true) - - // ASSERT - require.ErrorIs(t, err, ptypes.ErrWriteMethod{Method: StakeMethodName}) - }) - - t.Run("should fail if validator doesn't exist", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[StakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - mockVMContract.Input = packInputArgs(t, methodID, args...) - - // ACT - _, err = contract.Run(mockEVM, mockVMContract, false) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should stake", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[StakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - mockVMContract.Input = packInputArgs(t, methodID, args...) - - // ACT - _, err = contract.Run(mockEVM, mockVMContract, false) - - // ASSERT - require.NoError(t, err) - }) - - t.Run("should fail if no input args", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[StakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - mockVMContract.Input = methodID.ID - - // ACT - _, err = contract.Run(mockEVM, mockVMContract, false) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if caller is not staker", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[StakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - - nonStakerAddr := common.BytesToAddress(sample.Bech32AccAddress().Bytes()) - args := []interface{}{nonStakerAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - mockVMContract.Input = packInputArgs(t, methodID, args...) - - // ACT - _, err = contract.Run(mockEVM, mockVMContract, false) - - // ASSERT - require.ErrorContains(t, err, "caller is not staker address") - }) - - t.Run("should fail if staking fails", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[StakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - // staker without funds - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - mockVMContract.Input = packInputArgs(t, methodID, args...) - - // ACT - _, err := contract.Run(mockEVM, mockVMContract, false) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if wrong args amount", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[StakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - args := []interface{}{stakerEthAddr, validator.OperatorAddress} - - // ACT - _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if staker is not eth addr", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[StakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - args := []interface{}{staker, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - - // ACT - _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if validator is not valid string", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[StakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - args := []interface{}{stakerEthAddr, 42, coins.AmountOf(config.BaseDenom).BigInt()} - - // ACT - _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if amount is not int64", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[StakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).Uint64()} - - // ACT - _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) - - // ASSERT - require.Error(t, err) - }) -} - -func Test_Unstake(t *testing.T) { - t.Run("should fail in read only method", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[UnstakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - mockVMContract.Input = packInputArgs(t, methodID, args...) - - // ACT - _, err = contract.Run(mockEVM, mockVMContract, true) - - // ASSERT - require.ErrorIs(t, err, ptypes.ErrWriteMethod{Method: UnstakeMethodName}) - }) - - t.Run("should fail if validator doesn't exist", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[UnstakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - mockVMContract.Input = packInputArgs(t, methodID, args...) - - // ACT - _, err = contract.Run(mockEVM, mockVMContract, false) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should unstake", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[UnstakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - - // stake first - stakeMethodID := abi.Methods[StakeMethodName] - mockVMContract.Input = packInputArgs(t, stakeMethodID, args...) - _, err = contract.Run(mockEVM, mockVMContract, false) - require.NoError(t, err) - - // ACT - mockVMContract.Input = packInputArgs(t, methodID, args...) - _, err = contract.Run(mockEVM, mockVMContract, false) - - // ASSERT - require.NoError(t, err) - }) - - t.Run("should fail if caller is not staker", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[UnstakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - // stake first - stakeMethodID := abi.Methods[StakeMethodName] - mockVMContract.Input = packInputArgs(t, stakeMethodID, args...) - _, err = contract.Run(mockEVM, mockVMContract, false) - require.NoError(t, err) - - callerEthAddr := common.BytesToAddress(sample.Bech32AccAddress().Bytes()) - mockVMContract.CallerAddress = callerEthAddr - mockVMContract.Input = packInputArgs(t, methodID, args...) - - // ACT - _, err = contract.Run(mockEVM, mockVMContract, false) - - // ASSERT - require.ErrorContains(t, err, "caller is not staker address") - }) - - t.Run("should fail if no previous staking", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[UnstakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - mockVMContract.Input = packInputArgs(t, methodID, args...) - - // ACT - _, err = contract.Run(mockEVM, mockVMContract, false) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if wrong args amount", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[UnstakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - args := []interface{}{stakerEthAddr, validator.OperatorAddress} - - // ACT - _, err = contract.Unstake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if staker is not eth addr", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[UnstakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - args := []interface{}{staker, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} - - // ACT - _, err = contract.Unstake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if validator is not valid string", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[UnstakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - args := []interface{}{stakerEthAddr, 42, coins.AmountOf(config.BaseDenom).BigInt()} - - // ACT - _, err = contract.Unstake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if amount is not int64", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[UnstakeMethodName] - r := rand.New(rand.NewSource(42)) - validator := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validator) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).Uint64()} - - // ACT - _, err = contract.Unstake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) - - // ASSERT - require.Error(t, err) - }) -} - -func Test_MoveStake(t *testing.T) { - t.Run("should fail in read only method", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[MoveStakeMethodName] - r := rand.New(rand.NewSource(42)) - validatorSrc := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) - validatorDest := sample.Validator(t, r) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - - argsStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // stake to validator src - stakeMethodID := abi.Methods[StakeMethodName] - mockVMContract.Input = packInputArgs(t, stakeMethodID, argsStake...) - _, err = contract.Run(mockEVM, mockVMContract, false) - require.NoError(t, err) - - argsMoveStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - validatorDest.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - mockVMContract.Input = packInputArgs(t, methodID, argsMoveStake...) - - // ACT - _, err = contract.Run(mockEVM, mockVMContract, true) - - // ASSERT - require.ErrorIs(t, err, ptypes.ErrWriteMethod{Method: MoveStakeMethodName}) - }) - - t.Run("should fail if validator dest doesn't exist", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[MoveStakeMethodName] - r := rand.New(rand.NewSource(42)) - validatorSrc := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) - validatorDest := sample.Validator(t, r) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - mockVMContract.CallerAddress = stakerAddr - - argsStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // stake to validator src - stakeMethodID := abi.Methods[StakeMethodName] - mockVMContract.Input = packInputArgs(t, stakeMethodID, argsStake...) - _, err = contract.Run(mockEVM, mockVMContract, false) - require.NoError(t, err) - - argsMoveStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - validatorDest.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - mockVMContract.Input = packInputArgs(t, methodID, argsMoveStake...) - // ACT _, err = contract.Run(mockEVM, mockVMContract, false) // ASSERT require.Error(t, err) + require.ErrorIs(t, err, ptypes.ErrDisabledMethod{ + Method: StakeMethodName, + }) }) - t.Run("should move stake", func(t *testing.T) { + // t.Run("should fail in read only mode", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + // mockVMContract.Input = packInputArgs(t, methodID, args...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, true) + + // // ASSERT + // require.ErrorIs(t, err, ptypes.ErrWriteMethod{Method: StakeMethodName}) + // }) + + // t.Run("should fail if validator doesn't exist", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + // mockVMContract.Input = packInputArgs(t, methodID, args...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should stake", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + // mockVMContract.Input = packInputArgs(t, methodID, args...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.NoError(t, err) + // }) + + // t.Run("should fail if no input args", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + // mockVMContract.Input = methodID.ID + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if caller is not staker", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + + // nonStakerAddr := common.BytesToAddress(sample.Bech32AccAddress().Bytes()) + // args := []interface{}{nonStakerAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + // mockVMContract.Input = packInputArgs(t, methodID, args...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.ErrorContains(t, err, "caller is not staker address") + // }) + + // t.Run("should fail if staking fails", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // // staker without funds + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + // mockVMContract.Input = packInputArgs(t, methodID, args...) + + // // ACT + // _, err := contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if wrong args amount", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress} + + // // ACT + // _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if staker is not eth addr", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // args := []interface{}{staker, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + + // // ACT + // _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if validator is not valid string", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // args := []interface{}{stakerEthAddr, 42, coins.AmountOf(config.BaseDenom).BigInt()} + + // // ACT + // _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if amount is not int64", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[StakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).Uint64()} + + // // ACT + // _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) + + // // ASSERT + // require.Error(t, err) + // }) +} + +func Test_Unstake(t *testing.T) { + // Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. + t.Run("should fail with error disabled", func(t *testing.T) { // ARRANGE ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) - methodID := abi.Methods[MoveStakeMethodName] + methodID := abi.Methods[UnstakeMethodName] r := rand.New(rand.NewSource(42)) - validatorSrc := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) - validatorDest := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) + validator := sample.Validator(t, r) staker := sample.Bech32AccAddress() stakerEthAddr := common.BytesToAddress(staker.Bytes()) @@ -891,255 +560,288 @@ func Test_MoveStake(t *testing.T) { stakerAddr := common.BytesToAddress(staker.Bytes()) mockVMContract.CallerAddress = stakerAddr - argsStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - // stake to validator src - stakeMethodID := abi.Methods[StakeMethodName] - mockVMContract.Input = packInputArgs(t, stakeMethodID, argsStake...) - _, err = contract.Run(mockEVM, mockVMContract, false) - require.NoError(t, err) - - argsMoveStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - validatorDest.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - mockVMContract.Input = packInputArgs(t, methodID, argsMoveStake...) + args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + mockVMContract.Input = packInputArgs(t, methodID, args...) // ACT - // move stake to validator dest _, err = contract.Run(mockEVM, mockVMContract, false) - // ASSERT - require.NoError(t, err) - }) - - t.Run("should fail if staker is invalid arg", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[MoveStakeMethodName] - r := rand.New(rand.NewSource(42)) - validatorSrc := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) - validatorDest := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - argsStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // stake to validator src - stakeMethodID := abi.Methods[StakeMethodName] - _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) - require.NoError(t, err) - - argsMoveStake := []interface{}{ - 42, - validatorSrc.OperatorAddress, - validatorDest.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // ACT - _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if validator src is invalid arg", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[MoveStakeMethodName] - r := rand.New(rand.NewSource(42)) - validatorSrc := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) - validatorDest := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - argsStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // stake to validator src - stakeMethodID := abi.Methods[StakeMethodName] - _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) - require.NoError(t, err) - - argsMoveStake := []interface{}{ - stakerEthAddr, - 42, - validatorDest.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // ACT - _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if validator dest is invalid arg", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[MoveStakeMethodName] - r := rand.New(rand.NewSource(42)) - validatorSrc := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) - validatorDest := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - argsStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // stake to validator src - stakeMethodID := abi.Methods[StakeMethodName] - _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) - require.NoError(t, err) - - argsMoveStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - 42, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // ACT - _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) - - // ASSERT - require.Error(t, err) - }) - - t.Run("should fail if amount is invalid arg", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[MoveStakeMethodName] - r := rand.New(rand.NewSource(42)) - validatorSrc := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) - validatorDest := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - argsStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // stake to validator src - stakeMethodID := abi.Methods[StakeMethodName] - _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) - require.NoError(t, err) - - argsMoveStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - validatorDest.OperatorAddress, - coins.AmountOf(config.BaseDenom).Uint64(), - } - - // ACT - _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) - // ASSERT require.Error(t, err) + require.ErrorIs(t, err, ptypes.ErrDisabledMethod{ + Method: UnstakeMethodName, + }) }) - t.Run("should fail if wrong args amount", func(t *testing.T) { - // ARRANGE - ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) - methodID := abi.Methods[MoveStakeMethodName] - r := rand.New(rand.NewSource(42)) - validatorSrc := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) - validatorDest := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) - - staker := sample.Bech32AccAddress() - stakerEthAddr := common.BytesToAddress(staker.Bytes()) - coins := sample.Coins() - err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) - require.NoError(t, err) - err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) - require.NoError(t, err) - - stakerAddr := common.BytesToAddress(staker.Bytes()) - - argsStake := []interface{}{ - stakerEthAddr, - validatorSrc.OperatorAddress, - coins.AmountOf(config.BaseDenom).BigInt(), - } - - // stake to validator src - stakeMethodID := abi.Methods[StakeMethodName] - _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) - require.NoError(t, err) - - argsMoveStake := []interface{}{stakerEthAddr, validatorSrc.OperatorAddress, validatorDest.OperatorAddress} - - // ACT - _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) - - // ASSERT - require.Error(t, err) - }) + // t.Run("should fail in read only method", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[UnstakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + // mockVMContract.Input = packInputArgs(t, methodID, args...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, true) + + // // ASSERT + // require.ErrorIs(t, err, ptypes.ErrWriteMethod{Method: UnstakeMethodName}) + // }) + + // t.Run("should fail if validator doesn't exist", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[UnstakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + // mockVMContract.Input = packInputArgs(t, methodID, args...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should unstake", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[UnstakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + + // // stake first + // stakeMethodID := abi.Methods[StakeMethodName] + // mockVMContract.Input = packInputArgs(t, stakeMethodID, args...) + // _, err = contract.Run(mockEVM, mockVMContract, false) + // require.NoError(t, err) + + // // ACT + // mockVMContract.Input = packInputArgs(t, methodID, args...) + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.NoError(t, err) + // }) + + // t.Run("should fail if caller is not staker", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[UnstakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + // // stake first + // stakeMethodID := abi.Methods[StakeMethodName] + // mockVMContract.Input = packInputArgs(t, stakeMethodID, args...) + // _, err = contract.Run(mockEVM, mockVMContract, false) + // require.NoError(t, err) + + // callerEthAddr := common.BytesToAddress(sample.Bech32AccAddress().Bytes()) + // mockVMContract.CallerAddress = callerEthAddr + // mockVMContract.Input = packInputArgs(t, methodID, args...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.ErrorContains(t, err, "caller is not staker address") + // }) + + // t.Run("should fail if no previous staking", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[UnstakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + // mockVMContract.Input = packInputArgs(t, methodID, args...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if wrong args amount", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[UnstakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress} + + // // ACT + // _, err = contract.Unstake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if staker is not eth addr", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[UnstakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // args := []interface{}{staker, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).BigInt()} + + // // ACT + // _, err = contract.Unstake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if validator is not valid string", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[UnstakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // args := []interface{}{stakerEthAddr, 42, coins.AmountOf(config.BaseDenom).BigInt()} + + // // ACT + // _, err = contract.Unstake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if amount is not int64", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[UnstakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validator := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validator) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // args := []interface{}{stakerEthAddr, validator.OperatorAddress, coins.AmountOf(config.BaseDenom).Uint64()} + + // // ACT + // _, err = contract.Unstake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, args) + + // // ASSERT + // require.Error(t, err) + // }) +} - t.Run("should fail if caller is not staker", func(t *testing.T) { +func Test_MoveStake(t *testing.T) { + // Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. + t.Run("should fail with error disabled", func(t *testing.T) { // ARRANGE ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) methodID := abi.Methods[MoveStakeMethodName] @@ -1147,7 +849,6 @@ func Test_MoveStake(t *testing.T) { validatorSrc := sample.Validator(t, r) sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) validatorDest := sample.Validator(t, r) - sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) staker := sample.Bech32AccAddress() stakerEthAddr := common.BytesToAddress(staker.Bytes()) @@ -1159,6 +860,7 @@ func Test_MoveStake(t *testing.T) { stakerAddr := common.BytesToAddress(staker.Bytes()) mockVMContract.CallerAddress = stakerAddr + argsStake := []interface{}{ stakerEthAddr, validatorSrc.OperatorAddress, @@ -1169,7 +871,10 @@ func Test_MoveStake(t *testing.T) { stakeMethodID := abi.Methods[StakeMethodName] mockVMContract.Input = packInputArgs(t, stakeMethodID, argsStake...) _, err = contract.Run(mockEVM, mockVMContract, false) - require.NoError(t, err) + require.Error(t, err) + require.ErrorIs(t, err, ptypes.ErrDisabledMethod{ + Method: StakeMethodName, + }) argsMoveStake := []interface{}{ stakerEthAddr, @@ -1179,15 +884,427 @@ func Test_MoveStake(t *testing.T) { } mockVMContract.Input = packInputArgs(t, methodID, argsMoveStake...) - callerEthAddr := common.BytesToAddress(sample.Bech32AccAddress().Bytes()) - mockVMContract.CallerAddress = callerEthAddr - // ACT _, err = contract.Run(mockEVM, mockVMContract, false) // ASSERT - require.ErrorContains(t, err, "caller is not staker") + require.Error(t, err) + require.ErrorIs(t, err, ptypes.ErrDisabledMethod{ + Method: MoveStakeMethodName, + }) }) + + // t.Run("should fail in read only method", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[MoveStakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validatorSrc := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + // validatorDest := sample.Validator(t, r) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + + // argsStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // stake to validator src + // stakeMethodID := abi.Methods[StakeMethodName] + // mockVMContract.Input = packInputArgs(t, stakeMethodID, argsStake...) + // _, err = contract.Run(mockEVM, mockVMContract, false) + // require.NoError(t, err) + + // argsMoveStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // validatorDest.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + // mockVMContract.Input = packInputArgs(t, methodID, argsMoveStake...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, true) + + // // ASSERT + // require.ErrorIs(t, err, ptypes.ErrWriteMethod{Method: MoveStakeMethodName}) + // }) + + // t.Run("should fail if validator dest doesn't exist", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[MoveStakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validatorSrc := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + // validatorDest := sample.Validator(t, r) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + + // argsStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // stake to validator src + // stakeMethodID := abi.Methods[StakeMethodName] + // mockVMContract.Input = packInputArgs(t, stakeMethodID, argsStake...) + // _, err = contract.Run(mockEVM, mockVMContract, false) + // require.NoError(t, err) + + // argsMoveStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // validatorDest.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + // mockVMContract.Input = packInputArgs(t, methodID, argsMoveStake...) + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should move stake", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[MoveStakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validatorSrc := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + // validatorDest := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + // argsStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // stake to validator src + // stakeMethodID := abi.Methods[StakeMethodName] + // mockVMContract.Input = packInputArgs(t, stakeMethodID, argsStake...) + // _, err = contract.Run(mockEVM, mockVMContract, false) + // require.NoError(t, err) + + // argsMoveStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // validatorDest.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + // mockVMContract.Input = packInputArgs(t, methodID, argsMoveStake...) + + // // ACT + // // move stake to validator dest + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.NoError(t, err) + // }) + + // t.Run("should fail if staker is invalid arg", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[MoveStakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validatorSrc := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + // validatorDest := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // argsStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // stake to validator src + // stakeMethodID := abi.Methods[StakeMethodName] + // _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) + // require.NoError(t, err) + + // argsMoveStake := []interface{}{ + // 42, + // validatorSrc.OperatorAddress, + // validatorDest.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // ACT + // _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if validator src is invalid arg", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[MoveStakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validatorSrc := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + // validatorDest := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // argsStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // stake to validator src + // stakeMethodID := abi.Methods[StakeMethodName] + // _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) + // require.NoError(t, err) + + // argsMoveStake := []interface{}{ + // stakerEthAddr, + // 42, + // validatorDest.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // ACT + // _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if validator dest is invalid arg", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[MoveStakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validatorSrc := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + // validatorDest := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // argsStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // stake to validator src + // stakeMethodID := abi.Methods[StakeMethodName] + // _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) + // require.NoError(t, err) + + // argsMoveStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // 42, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // ACT + // _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if amount is invalid arg", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[MoveStakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validatorSrc := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + // validatorDest := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // argsStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // stake to validator src + // stakeMethodID := abi.Methods[StakeMethodName] + // _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) + // require.NoError(t, err) + + // argsMoveStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // validatorDest.OperatorAddress, + // coins.AmountOf(config.BaseDenom).Uint64(), + // } + + // // ACT + // _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if wrong args amount", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, _ := setup(t) + // methodID := abi.Methods[MoveStakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validatorSrc := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + // validatorDest := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + + // argsStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // stake to validator src + // stakeMethodID := abi.Methods[StakeMethodName] + // _, err = contract.Stake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &stakeMethodID, argsStake) + // require.NoError(t, err) + + // argsMoveStake := []interface{}{stakerEthAddr, validatorSrc.OperatorAddress, validatorDest.OperatorAddress} + + // // ACT + // _, err = contract.MoveStake(ctx, mockEVM, &vm.Contract{CallerAddress: stakerAddr}, &methodID, argsMoveStake) + + // // ASSERT + // require.Error(t, err) + // }) + + // t.Run("should fail if caller is not staker", func(t *testing.T) { + // // ARRANGE + // ctx, contract, abi, sdkKeepers, mockEVM, mockVMContract := setup(t) + // methodID := abi.Methods[MoveStakeMethodName] + // r := rand.New(rand.NewSource(42)) + // validatorSrc := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorSrc) + // validatorDest := sample.Validator(t, r) + // sdkKeepers.StakingKeeper.SetValidator(ctx, validatorDest) + + // staker := sample.Bech32AccAddress() + // stakerEthAddr := common.BytesToAddress(staker.Bytes()) + // coins := sample.Coins() + // err := sdkKeepers.BankKeeper.MintCoins(ctx, fungibletypes.ModuleName, sample.Coins()) + // require.NoError(t, err) + // err = sdkKeepers.BankKeeper.SendCoinsFromModuleToAccount(ctx, fungibletypes.ModuleName, staker, coins) + // require.NoError(t, err) + + // stakerAddr := common.BytesToAddress(staker.Bytes()) + // mockVMContract.CallerAddress = stakerAddr + // argsStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + + // // stake to validator src + // stakeMethodID := abi.Methods[StakeMethodName] + // mockVMContract.Input = packInputArgs(t, stakeMethodID, argsStake...) + // _, err = contract.Run(mockEVM, mockVMContract, false) + // require.NoError(t, err) + + // argsMoveStake := []interface{}{ + // stakerEthAddr, + // validatorSrc.OperatorAddress, + // validatorDest.OperatorAddress, + // coins.AmountOf(config.BaseDenom).BigInt(), + // } + // mockVMContract.Input = packInputArgs(t, methodID, argsMoveStake...) + + // callerEthAddr := common.BytesToAddress(sample.Bech32AccAddress().Bytes()) + // mockVMContract.CallerAddress = callerEthAddr + + // // ACT + // _, err = contract.Run(mockEVM, mockVMContract, false) + + // // ASSERT + // require.ErrorContains(t, err, "caller is not staker") + // }) } func Test_GetAllValidators(t *testing.T) { diff --git a/precompiles/types/errors.go b/precompiles/types/errors.go index a624ab27af..b1ad69d258 100644 --- a/precompiles/types/errors.go +++ b/precompiles/types/errors.go @@ -94,6 +94,14 @@ func (e ErrInvalidMethod) Error() string { return fmt.Sprintf("invalid method: %s", e.Method) } +type ErrDisabledMethod struct { + Method string +} + +func (e ErrDisabledMethod) Error() string { + return fmt.Sprintf("method %s is disabled", e.Method) +} + type ErrWriteMethod struct { Method string } From 72b517dcb28113b024d94e7586bd7658e2c63d9a Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Thu, 17 Oct 2024 16:17:41 +0200 Subject: [PATCH 32/36] feat: add fungible keeper ability to lock/unlock ZRC20 tokens (#2979) * feat: add lockZRC20 capability to fungible keeper * extract functions to fungible * cleaning up * modify e2e tests * fix unit testing * make deposit and withdraw fail with amount 0 * first round of review * add full unit testing suite * add reviewed changes * add review suggestions --- changelog.md | 1 + e2e/e2etests/test_precompiles_bank.go | 19 +- .../test_precompiles_bank_through_contract.go | 19 +- precompiles/bank/method_deposit.go | 75 +--- precompiles/bank/method_test.go | 45 +- precompiles/bank/method_withdraw.go | 82 +--- .../keeper/zrc20_cosmos_coin_mapping_test.go | 414 ++++++++++++++++++ .../keeper/zrc20_cosmos_coins_mapping.go | 192 ++++++++ x/fungible/keeper/zrc20_methods.go | 305 +++++++++++++ x/fungible/keeper/zrc20_methods_test.go | 341 +++++++++++++++ x/fungible/types/errors.go | 5 + x/fungible/types/keys.go | 9 +- 12 files changed, 1331 insertions(+), 176 deletions(-) create mode 100644 x/fungible/keeper/zrc20_cosmos_coin_mapping_test.go create mode 100644 x/fungible/keeper/zrc20_cosmos_coins_mapping.go create mode 100644 x/fungible/keeper/zrc20_methods.go create mode 100644 x/fungible/keeper/zrc20_methods_test.go diff --git a/changelog.md b/changelog.md index 3f8206a9f1..2dd8e75f9a 100644 --- a/changelog.md +++ b/changelog.md @@ -19,6 +19,7 @@ * [2957](https://github.com/zeta-chain/node/pull/2957) - enable Bitcoin inscription support on testnet * [2896](https://github.com/zeta-chain/node/pull/2896) - add TON inbound observation * [2987](https://github.com/zeta-chain/node/pull/2987) - add non-EVM standard inbound memo package +* [2979](https://github.com/zeta-chain/node/pull/2979) - add fungible keeper ability to lock/unlock ZRC20 tokens ### Refactor diff --git a/e2e/e2etests/test_precompiles_bank.go b/e2e/e2etests/test_precompiles_bank.go index 2517410339..308f684572 100644 --- a/e2e/e2etests/test_precompiles_bank.go +++ b/e2e/e2etests/test_precompiles_bank.go @@ -20,6 +20,7 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { higherBalanceAmount := big.NewInt(1001) higherAllowanceAmount := big.NewInt(501) spender := r.EVMAddress() + bankAddress := bank.ContractAddress // Increase the gasLimit. It's required because of the gas consumed by precompiled functions. previousGasLimit := r.ZEVMAuth.GasLimit @@ -29,7 +30,7 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { // Reset the allowance to 0; this is needed when running upgrade tests where // this test runs twice. - tx, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, bank.ContractAddress, big.NewInt(0)) + tx, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, bankAddress, big.NewInt(0)) require.NoError(r, err) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) utils.RequireTxSuccessful(r, receipt, "Resetting allowance failed") @@ -59,7 +60,7 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { require.Equal(r, uint64(0), cosmosBalance.Uint64(), "spender cosmos coin balance should be 0") // Approve allowance of 500 ERC20ZRC20 tokens for the bank contract. Should pass. - tx, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, bank.ContractAddress, depositAmount) + tx, err := r.ERC20ZRC20.Approve(r.ZEVMAuth, bankAddress, depositAmount) require.NoError(r, err) receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) utils.RequireTxSuccessful(r, receipt, "Approve ETHZRC20 bank allowance tx failed") @@ -72,7 +73,7 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { utils.RequiredTxFailed(r, receipt, "Depositting an amount higher than allowed should fail") // Approve allowance of 1000 ERC20ZRC20 tokens. - tx, err = r.ERC20ZRC20.Approve(r.ZEVMAuth, bank.ContractAddress, big.NewInt(1e3)) + tx, err = r.ERC20ZRC20.Approve(r.ZEVMAuth, bankAddress, big.NewInt(1e3)) require.NoError(r, err) receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) utils.RequireTxSuccessful(r, receipt, "Approve ETHZRC20 bank allowance tx failed") @@ -103,7 +104,7 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { require.Equal(r, uint64(500), cosmosBalance.Uint64(), "spender cosmos coin balance should be 500") // Bank: ERC20ZRC20 balance should be 500 tokens locked. - bankZRC20Balance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bank.ContractAddress) + bankZRC20Balance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bankAddress) require.NoError(r, err, "Call ERC20ZRC20.BalanceOf") require.Equal(r, uint64(500), bankZRC20Balance.Uint64(), "bank ERC20ZRC20 balance should be 500") @@ -115,7 +116,7 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { // Bank: ERC20ZRC20 balance should be 500 tokens locked after a failed withdraw. // No tokens should be unlocked with a failed withdraw. - bankZRC20Balance, err = r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bank.ContractAddress) + bankZRC20Balance, err = r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bankAddress) require.NoError(r, err, "Call ERC20ZRC20.BalanceOf") require.Equal(r, uint64(500), bankZRC20Balance.Uint64(), "bank ERC20ZRC20 balance should be 500") @@ -143,7 +144,7 @@ func TestPrecompilesBank(r *runner.E2ERunner, args []string) { require.Equal(r, uint64(1000), zrc20Balance.Uint64(), "spender ERC20ZRC20 balance should be 1000") // Bank: ERC20ZRC20 balance should be 0 tokens locked. - bankZRC20Balance, err = r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bank.ContractAddress) + bankZRC20Balance, err = r.ERC20ZRC20.BalanceOf(&bind.CallOpts{Context: r.Ctx}, bankAddress) require.NoError(r, err, "Call ERC20ZRC20.BalanceOf") require.Equal(r, uint64(0), bankZRC20Balance.Uint64(), "bank ERC20ZRC20 balance should be 0") } @@ -158,7 +159,7 @@ func TestPrecompilesBankNonZRC20(r *runner.E2ERunner, args []string) { r.ZEVMAuth.GasLimit = previousGasLimit }() - spender, bankAddr := r.EVMAddress(), bank.ContractAddress + spender, bankAddress := r.EVMAddress(), bank.ContractAddress // Create a bank contract caller. bankContract, err := bank.NewIBank(bank.ContractAddress, r.ZEVMClient) @@ -179,13 +180,13 @@ func TestPrecompilesBankNonZRC20(r *runner.E2ERunner, args []string) { ) // Allow the bank contract to spend 25 WZeta tokens. - tx, err := r.WZeta.Approve(r.ZEVMAuth, bankAddr, big.NewInt(25)) + tx, err := r.WZeta.Approve(r.ZEVMAuth, bankAddress, big.NewInt(25)) require.NoError(r, err, "Error approving allowance for bank contract") receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) require.EqualValues(r, uint64(1), receipt.Status, "approve allowance tx failed") // Check the allowance of the bank in WZeta tokens. Should be 25. - allowance, err := r.WZeta.Allowance(&bind.CallOpts{Context: r.Ctx}, spender, bankAddr) + allowance, err := r.WZeta.Allowance(&bind.CallOpts{Context: r.Ctx}, spender, bankAddress) require.NoError(r, err, "Error retrieving bank allowance") require.EqualValues(r, uint64(25), allowance.Uint64(), "Error allowance for bank contract") diff --git a/e2e/e2etests/test_precompiles_bank_through_contract.go b/e2e/e2etests/test_precompiles_bank_through_contract.go index 480663284e..6d6384fd9e 100644 --- a/e2e/e2etests/test_precompiles_bank_through_contract.go +++ b/e2e/e2etests/test_precompiles_bank_through_contract.go @@ -18,6 +18,7 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { require.Len(r, args, 0, "No arguments expected") spender := r.EVMAddress() + bankAddress := bank.ContractAddress zrc20Address := r.ERC20ZRC20Addr oneThousand := big.NewInt(1e3) oneThousandOne := big.NewInt(1001) @@ -59,7 +60,7 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { // Check initial balances. balanceShouldBe(r, 0, checkCosmosBalance(r, testBank, zrc20Address, spender)) balanceShouldBe(r, 1000, checkZRC20Balance(r, spender)) - balanceShouldBe(r, 0, checkZRC20Balance(r, bank.ContractAddress)) + balanceShouldBe(r, 0, checkZRC20Balance(r, bankAddress)) // Deposit without previous alllowance should fail. receipt = depositThroughTestBank(r, testBank, zrc20Address, oneThousand) @@ -68,10 +69,10 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { // Check balances, should be the same. balanceShouldBe(r, 0, checkCosmosBalance(r, testBank, zrc20Address, spender)) balanceShouldBe(r, 1000, checkZRC20Balance(r, spender)) - balanceShouldBe(r, 0, checkZRC20Balance(r, bank.ContractAddress)) + balanceShouldBe(r, 0, checkZRC20Balance(r, bankAddress)) // Allow 500 ZRC20 to bank precompile. - approveAllowance(r, bank.ContractAddress, fiveHundred) + approveAllowance(r, bankAddress, fiveHundred) // Deposit 501 ERC20ZRC20 tokens to the bank contract, through TestBank. // It's higher than allowance but lower than balance, should fail. @@ -81,10 +82,10 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { // Balances shouldn't change. balanceShouldBe(r, 0, checkCosmosBalance(r, testBank, zrc20Address, spender)) balanceShouldBe(r, 1000, checkZRC20Balance(r, spender)) - balanceShouldBe(r, 0, checkZRC20Balance(r, bank.ContractAddress)) + balanceShouldBe(r, 0, checkZRC20Balance(r, bankAddress)) // Allow 1000 ZRC20 to bank precompile. - approveAllowance(r, bank.ContractAddress, oneThousand) + approveAllowance(r, bankAddress, oneThousand) // Deposit 1001 ERC20ZRC20 tokens to the bank contract. // It's higher than spender balance but within approved allowance, should fail. @@ -94,7 +95,7 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { // Balances shouldn't change. balanceShouldBe(r, 0, checkCosmosBalance(r, testBank, zrc20Address, spender)) balanceShouldBe(r, 1000, checkZRC20Balance(r, spender)) - balanceShouldBe(r, 0, checkZRC20Balance(r, bank.ContractAddress)) + balanceShouldBe(r, 0, checkZRC20Balance(r, bankAddress)) // Deposit 500 ERC20ZRC20 tokens to the bank contract, it's within allowance and balance. Should pass. receipt = depositThroughTestBank(r, testBank, zrc20Address, fiveHundred) @@ -103,7 +104,7 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { // Balances should be transferred. Bank now locks 500 ZRC20 tokens. balanceShouldBe(r, 500, checkCosmosBalance(r, testBank, zrc20Address, spender)) balanceShouldBe(r, 500, checkZRC20Balance(r, spender)) - balanceShouldBe(r, 500, checkZRC20Balance(r, bank.ContractAddress)) + balanceShouldBe(r, 500, checkZRC20Balance(r, bankAddress)) // Check the deposit event. eventDeposit, err := bankPrecompileCaller.ParseDeposit(*receipt.Logs[0]) @@ -119,7 +120,7 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { // Balances shouldn't change. balanceShouldBe(r, 500, checkCosmosBalance(r, testBank, zrc20Address, spender)) balanceShouldBe(r, 500, checkZRC20Balance(r, spender)) - balanceShouldBe(r, 500, checkZRC20Balance(r, bank.ContractAddress)) + balanceShouldBe(r, 500, checkZRC20Balance(r, bankAddress)) // Try to withdraw 500 ERC20ZRC20 tokens. Should pass. receipt = withdrawThroughTestBank(r, testBank, zrc20Address, fiveHundred) @@ -128,7 +129,7 @@ func TestPrecompilesBankThroughContract(r *runner.E2ERunner, args []string) { // Balances should be reverted to initial state. balanceShouldBe(r, 0, checkCosmosBalance(r, testBank, zrc20Address, spender)) balanceShouldBe(r, 1000, checkZRC20Balance(r, spender)) - balanceShouldBe(r, 0, checkZRC20Balance(r, bank.ContractAddress)) + balanceShouldBe(r, 0, checkZRC20Balance(r, bankAddress)) // Check the withdraw event. eventWithdraw, err := bankPrecompileCaller.ParseWithdraw(*receipt.Logs[0]) diff --git a/precompiles/bank/method_deposit.go b/precompiles/bank/method_deposit.go index 2f57944723..1d5792d8a3 100644 --- a/precompiles/bank/method_deposit.go +++ b/precompiles/bank/method_deposit.go @@ -18,7 +18,7 @@ import ( // The caller cosmos address will be calculated from the EVM caller address. by executing toAddr := sdk.AccAddress(addr.Bytes()). // This function can be think of a permissionless way of minting cosmos coins. // This is how deposit works: -// - The caller has to allow the bank contract to spend a certain amount ZRC20 token coins on its behalf. This is mandatory. +// - The caller has to allow the bank precompile address to spend a certain amount ZRC20 token coins on its behalf. This is mandatory. // - Then, the caller calls deposit(ZRC20 address, amount), to deposit the amount and receive cosmos coins. // - The bank will check there's enough balance, the caller is not a blocked address, and the token is a not paused ZRC20. // - Then the cosmos coins "zrc20/0x12345" will be minted and sent to the caller's cosmos address. @@ -59,22 +59,6 @@ func (c *Contract) deposit( return nil, err } - // Safety check: token has to be a valid whitelisted ZRC20 and not be paused. - t, found := c.fungibleKeeper.GetForeignCoins(ctx, zrc20Addr.String()) - if !found { - return nil, &ptypes.ErrInvalidToken{ - Got: zrc20Addr.String(), - Reason: "token is not a whitelisted ZRC20", - } - } - - if t.Paused { - return nil, &ptypes.ErrInvalidToken{ - Got: zrc20Addr.String(), - Reason: "token is paused", - } - } - // Check for enough balance. // function balanceOf(address account) public view virtual override returns (uint256) resBalanceOf, err := c.CallContract( @@ -105,71 +89,24 @@ func (c *Contract) deposit( } } - // Check for enough bank's allowance. - // function allowance(address owner, address spender) public view virtual override returns (uint256) - resAllowance, err := c.CallContract( - ctx, - &c.fungibleKeeper, - c.zrc20ABI, - zrc20Addr, - "allowance", - []interface{}{caller, ContractAddress}, - ) - if err != nil { - return nil, &ptypes.ErrUnexpected{ - When: "allowance", - Got: err.Error(), - } - } - - allowance, ok := resAllowance[0].(*big.Int) - if !ok { - return nil, &ptypes.ErrUnexpected{ - Got: "ZRC20 allowance returned an unexpected type", - } - } - - if allowance.Cmp(amount) < 0 || allowance.Cmp(big.NewInt(0)) <= 0 { - return nil, &ptypes.ErrInvalidAmount{ - Got: allowance.String(), - } - } - // The process of creating a new cosmos coin is: // - Generate the new coin denom using ZRC20 address, // this way we map ZRC20 addresses to cosmos denoms "zevm/0x12345". - // - Mint coins. - // - Send coins to the caller. + // - Mint coins to the fungible module. + // - Send coins from fungible to the caller. coinSet, err := createCoinSet(ZRC20ToCosmosDenom(zrc20Addr), amount) if err != nil { return nil, err } // 2. Effect: subtract balance. - // function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) - resTransferFrom, err := c.CallContract( - ctx, - &c.fungibleKeeper, - c.zrc20ABI, - zrc20Addr, - "transferFrom", - []interface{}{caller, ContractAddress, amount}, - ) - if err != nil { + if err := c.fungibleKeeper.LockZRC20(ctx, c.zrc20ABI, zrc20Addr, c.Address(), caller, c.Address(), amount); err != nil { return nil, &ptypes.ErrUnexpected{ - When: "transferFrom", + When: "LockZRC20InBank", Got: err.Error(), } } - transferred, ok := resTransferFrom[0].(bool) - if !ok || !transferred { - return nil, &ptypes.ErrUnexpected{ - When: "transferFrom", - Got: "transaction not successful", - } - } - // 3. Interactions: create cosmos coin and send. if err := c.bankKeeper.MintCoins(ctx, types.ModuleName, coinSet); err != nil { return nil, &ptypes.ErrUnexpected{ @@ -205,7 +142,7 @@ func unpackDepositArgs(args []interface{}) (zrc20Addr common.Address, amount *bi } amount, ok = args[1].(*big.Int) - if !ok || amount.Sign() < 0 || amount == nil || amount == new(big.Int) { + if !ok || amount == nil || amount.Sign() <= 0 { return common.Address{}, nil, &ptypes.ErrInvalidAmount{ Got: amount.String(), } diff --git a/precompiles/bank/method_test.go b/precompiles/bank/method_test.go index 107439c576..e416187490 100644 --- a/precompiles/bank/method_test.go +++ b/precompiles/bank/method_test.go @@ -130,18 +130,12 @@ func Test_Methods(t *testing.T) { ts.mockVMContract.Input = packInputArgs( t, methodID, - []interface{}{ts.zrc20Address, big.NewInt(0)}..., + []interface{}{ts.zrc20Address, big.NewInt(1000)}..., ) success, err := ts.bankContract.Run(ts.mockEVM, ts.mockVMContract, false) require.Error(t, err) - require.ErrorAs( - t, - ptypes.ErrInvalidAmount{ - Got: "0", - }, - err, - ) + require.Contains(t, err.Error(), "invalid allowance, got 0") res, err := ts.bankABI.Methods[DepositMethodName].Outputs.Unpack(success) require.NoError(t, err) @@ -150,6 +144,33 @@ func Test_Methods(t *testing.T) { require.False(t, ok) }) + t.Run("should fail when trying to deposit 0", func(t *testing.T) { + ts := setupChain(t) + caller := fungibletypes.ModuleAddressEVM + ts.fungibleKeeper.DepositZRC20(ts.ctx, ts.zrc20Address, caller, big.NewInt(1000)) + + methodID := ts.bankABI.Methods[DepositMethodName] + + // Allow bank to spend 500 ZRC20 tokens. + allowBank(t, ts, big.NewInt(500)) + + // Set CallerAddress and evm.Origin to the caller address. + // Caller does not have any balance, and bank does not have any allowance. + ts.mockVMContract.CallerAddress = caller + ts.mockEVM.Origin = caller + + // Set the input arguments for the deposit method. + ts.mockVMContract.Input = packInputArgs( + t, + methodID, + []interface{}{ts.zrc20Address, big.NewInt(0)}..., + ) + + _, err := ts.bankContract.Run(ts.mockEVM, ts.mockVMContract, false) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid token amount: 0") + }) + t.Run("should fail when trying to deposit more than allowed to bank", func(t *testing.T) { ts := setupChain(t) caller := fungibletypes.ModuleAddressEVM @@ -173,12 +194,10 @@ func Test_Methods(t *testing.T) { success, err := ts.bankContract.Run(ts.mockEVM, ts.mockVMContract, false) require.Error(t, err) - require.ErrorAs( + require.Contains( t, - ptypes.ErrInvalidAmount{ - Got: "500", - }, - err, + err.Error(), + "unexpected error in LockZRC20InBank: failed allowance check: invalid allowance, got 500, wanted 501", ) res, err := ts.bankABI.Methods[DepositMethodName].Outputs.Unpack(success) diff --git a/precompiles/bank/method_withdraw.go b/precompiles/bank/method_withdraw.go index 99cb4f763c..e071ed04cd 100644 --- a/precompiles/bank/method_withdraw.go +++ b/precompiles/bank/method_withdraw.go @@ -55,19 +55,11 @@ func (c *Contract) withdraw( return nil, err } - // Safety check: token has to be a valid whitelisted ZRC20 and not be paused. - t, found := c.fungibleKeeper.GetForeignCoins(ctx, zrc20Addr.String()) - if !found { + // Safety check: token has to be a non-paused whitelisted ZRC20. + if err := c.fungibleKeeper.IsValidZRC20(ctx, zrc20Addr); err != nil { return nil, &ptypes.ErrInvalidToken{ Got: zrc20Addr.String(), - Reason: "token is not a whitelisted ZRC20", - } - } - - if t.Paused { - return nil, &ptypes.ErrInvalidToken{ - Got: zrc20Addr.String(), - Reason: "token is paused", + Reason: err.Error(), } } @@ -92,33 +84,11 @@ func (c *Contract) withdraw( return nil, err } - // Check for bank's ZRC20 balance. - // function balanceOf(address account) public view virtual override returns (uint256) - resBalanceOf, err := c.CallContract( - ctx, - &c.fungibleKeeper, - c.zrc20ABI, - zrc20Addr, - "balanceOf", - []interface{}{ContractAddress}, - ) - if err != nil { - return nil, &ptypes.ErrUnexpected{ - When: "balanceOf", - Got: err.Error(), - } - } - - balance, ok := resBalanceOf[0].(*big.Int) - if !ok { - return nil, &ptypes.ErrUnexpected{ - Got: "ZRC20 balanceOf returned an unexpected type", - } - } - - if balance.Cmp(amount) == -1 { - return nil, &ptypes.ErrInvalidAmount{ - Got: balance.String(), + // Check if bank address has enough ZRC20 balance. + if err := c.fungibleKeeper.CheckZRC20Balance(ctx, c.zrc20ABI, zrc20Addr, c.Address(), amount); err != nil { + return nil, &ptypes.ErrInsufficientBalance{ + Requested: amount.String(), + Got: err.Error(), } } @@ -137,45 +107,21 @@ func (c *Contract) withdraw( } } - if err := c.addEventLog(ctx, evm.StateDB, WithdrawEventName, eventData{caller, zrc20Addr, fromAddr.String(), coinSet.Denoms()[0], amount}); err != nil { + // 3. Interactions: send ZRC20. + if err := c.fungibleKeeper.UnlockZRC20(ctx, c.zrc20ABI, zrc20Addr, caller, c.Address(), amount); err != nil { return nil, &ptypes.ErrUnexpected{ - When: "AddWithdrawLog", + When: "UnlockZRC20InBank", Got: err.Error(), } } - // 3. Interactions: send to module and burn. - - // function transfer(address recipient, uint256 amount) public virtual override returns (bool) - resTransfer, err := c.CallContract( - ctx, - &c.fungibleKeeper, - c.zrc20ABI, - zrc20Addr, - "transfer", - []interface{}{caller /* sender */, amount}, - ) - if err != nil { + if err := c.addEventLog(ctx, evm.StateDB, WithdrawEventName, eventData{caller, zrc20Addr, fromAddr.String(), coinSet.Denoms()[0], amount}); err != nil { return nil, &ptypes.ErrUnexpected{ - When: "transfer", + When: "AddWithdrawLog", Got: err.Error(), } } - transferred, ok := resTransfer[0].(bool) - if !ok { - return nil, &ptypes.ErrUnexpected{ - Got: "ZRC20 transfer returned an unexpected type", - } - } - - if !transferred { - return nil, &ptypes.ErrUnexpected{ - When: "transfer", - Got: "transaction not successful", - } - } - return method.Outputs.Pack(true) } @@ -188,7 +134,7 @@ func unpackWithdrawArgs(args []interface{}) (zrc20Addr common.Address, amount *b } amount, ok = args[1].(*big.Int) - if !ok || amount.Sign() < 0 || amount == nil || amount == new(big.Int) { + if !ok || amount == nil || amount.Sign() <= 0 { return common.Address{}, nil, &ptypes.ErrInvalidAmount{ Got: amount.String(), } diff --git a/x/fungible/keeper/zrc20_cosmos_coin_mapping_test.go b/x/fungible/keeper/zrc20_cosmos_coin_mapping_test.go new file mode 100644 index 0000000000..16803a917c --- /dev/null +++ b/x/fungible/keeper/zrc20_cosmos_coin_mapping_test.go @@ -0,0 +1,414 @@ +package keeper_test + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/testutil/keeper" + "github.com/zeta-chain/node/testutil/sample" + fungiblekeeper "github.com/zeta-chain/node/x/fungible/keeper" + fungibletypes "github.com/zeta-chain/node/x/fungible/types" + "github.com/zeta-chain/protocol-contracts/v2/pkg/zrc20.sol" +) + +func Test_LockZRC20(t *testing.T) { + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + require.NoError(t, err) + + ts := setupChain(t) + + owner := fungibletypes.ModuleAddressEVM + locker := sample.EthAddress() + depositTotal := big.NewInt(1000) + allowanceTotal := big.NewInt(100) + higherThanAllowance := big.NewInt(101) + smallerThanAllowance := big.NewInt(99) + + // Make sure locker account exists in state. + accAddress := sdk.AccAddress(locker.Bytes()) + ts.fungibleKeeper.GetAuthKeeper().SetAccount(ts.ctx, authtypes.NewBaseAccount(accAddress, nil, 0, 0)) + + // Deposit 1000 ZRC20 tokens into the fungible. + ts.fungibleKeeper.DepositZRC20(ts.ctx, ts.zrc20Address, owner, depositTotal) + + t.Run("should fail when trying to lock zero amount", func(t *testing.T) { + // Check lock with zero amount. + err = ts.fungibleKeeper.LockZRC20(ts.ctx, zrc20ABI, ts.zrc20Address, locker, owner, locker, big.NewInt(0)) + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrInvalidAmount) + }) + + t.Run("should fail when ZRC20 ABI is not properly initialized", func(t *testing.T) { + // Check lock with nil ABI. + err = ts.fungibleKeeper.LockZRC20(ts.ctx, nil, ts.zrc20Address, locker, owner, locker, big.NewInt(10)) + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrZRC20NilABI) + }) + + t.Run("should fail when trying to lock a zero address ZRC20", func(t *testing.T) { + // Check lock with ZRC20 zero address. + err = ts.fungibleKeeper.LockZRC20(ts.ctx, zrc20ABI, common.Address{}, locker, owner, locker, big.NewInt(10)) + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrZRC20ZeroAddress) + }) + + t.Run("should fail when trying to lock a non whitelisted ZRC20", func(t *testing.T) { + // Check lock with non whitelisted ZRC20. + err = ts.fungibleKeeper.LockZRC20(ts.ctx, zrc20ABI, sample.EthAddress(), locker, owner, locker, big.NewInt(10)) + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrZRC20NotWhiteListed) + }) + + t.Run("should fail when trying to lock a higher amount than totalSupply", func(t *testing.T) { + approveAllowance(t, ts, zrc20ABI, owner, locker, big.NewInt(1000000000000000)) + + // Check lock with higher amount than totalSupply. + err = ts.fungibleKeeper.LockZRC20( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + locker, + owner, + locker, + big.NewInt(1000000000000000), + ) + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrInvalidAmount) + }) + + t.Run("should fail when trying to lock a higher amount than owned balance", func(t *testing.T) { + approveAllowance(t, ts, zrc20ABI, owner, locker, big.NewInt(1001)) + + // Check allowance smaller, equal and bigger than the amount. + err = ts.fungibleKeeper.LockZRC20(ts.ctx, zrc20ABI, ts.zrc20Address, locker, owner, locker, big.NewInt(1001)) + require.Error(t, err) + + // We do not check in LockZRC20 explicitly if the amount is bigger than the balance. + // Instead, the ERC20 transferFrom function will revert the transaction if the amount is bigger than the balance. + require.Contains(t, err.Error(), "execution reverted") + }) + + t.Run("should fail when trying to lock an amount higher than approved", func(t *testing.T) { + approveAllowance(t, ts, zrc20ABI, owner, locker, allowanceTotal) + + // Check allowance smaller, equal and bigger than the amount. + err = ts.fungibleKeeper.LockZRC20(ts.ctx, zrc20ABI, ts.zrc20Address, locker, owner, locker, higherThanAllowance) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid allowance, got 100") + }) + + t.Run("should pass when trying to lock a valid approved amount", func(t *testing.T) { + approveAllowance(t, ts, zrc20ABI, owner, locker, allowanceTotal) + + err = ts.fungibleKeeper.LockZRC20(ts.ctx, zrc20ABI, ts.zrc20Address, locker, owner, locker, allowanceTotal) + require.NoError(t, err) + + ownerBalance, err := ts.fungibleKeeper.ZRC20BalanceOf(ts.ctx, zrc20ABI, ts.zrc20Address, owner) + require.NoError(t, err) + require.Equal(t, uint64(900), ownerBalance.Uint64()) + + lockerBalance, err := ts.fungibleKeeper.ZRC20BalanceOf(ts.ctx, zrc20ABI, ts.zrc20Address, locker) + require.NoError(t, err) + require.Equal(t, uint64(100), lockerBalance.Uint64()) + }) + + t.Run("should pass when trying to lock an amount smaller than approved", func(t *testing.T) { + approveAllowance(t, ts, zrc20ABI, owner, locker, allowanceTotal) + + err = ts.fungibleKeeper.LockZRC20( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + locker, + owner, + locker, + smallerThanAllowance, + ) + require.NoError(t, err) + + // Note that balances are cumulative for all tests. That's why we check 801 and 199 here. + ownerBalance, err := ts.fungibleKeeper.ZRC20BalanceOf(ts.ctx, zrc20ABI, ts.zrc20Address, owner) + require.NoError(t, err) + require.Equal(t, uint64(801), ownerBalance.Uint64()) + + lockerBalance, err := ts.fungibleKeeper.ZRC20BalanceOf(ts.ctx, zrc20ABI, ts.zrc20Address, locker) + require.NoError(t, err) + require.Equal(t, uint64(199), lockerBalance.Uint64()) + }) +} + +func Test_UnlockZRC20(t *testing.T) { + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + require.NoError(t, err) + + ts := setupChain(t) + + owner := fungibletypes.ModuleAddressEVM + locker := sample.EthAddress() + depositTotal := big.NewInt(1000) + allowanceTotal := big.NewInt(100) + + // Make sure locker account exists in state. + accAddress := sdk.AccAddress(locker.Bytes()) + ts.fungibleKeeper.GetAuthKeeper().SetAccount(ts.ctx, authtypes.NewBaseAccount(accAddress, nil, 0, 0)) + + // Deposit 1000 ZRC20 tokens into the fungible. + ts.fungibleKeeper.DepositZRC20(ts.ctx, ts.zrc20Address, owner, depositTotal) + + // Approve allowance for locker to spend owner's ZRC20 tokens. + approveAllowance(t, ts, zrc20ABI, owner, locker, allowanceTotal) + + // Lock 100 ZRC20. + err = ts.fungibleKeeper.LockZRC20(ts.ctx, zrc20ABI, ts.zrc20Address, locker, owner, locker, allowanceTotal) + require.NoError(t, err) + + t.Run("should fail when trying to unlock zero amount", func(t *testing.T) { + err = ts.fungibleKeeper.UnlockZRC20(ts.ctx, zrc20ABI, ts.zrc20Address, owner, locker, big.NewInt(0)) + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrInvalidAmount) + }) + + t.Run("should fail when ZRC20 ABI is not properly initialized", func(t *testing.T) { + err = ts.fungibleKeeper.UnlockZRC20(ts.ctx, nil, ts.zrc20Address, owner, locker, big.NewInt(10)) + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrZRC20NilABI) + }) + + t.Run("should fail when trying to unlock a zero address ZRC20", func(t *testing.T) { + err = ts.fungibleKeeper.UnlockZRC20(ts.ctx, zrc20ABI, common.Address{}, owner, locker, big.NewInt(10)) + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrZRC20ZeroAddress) + }) + + t.Run("should fail when trying to unlock a non whitelisted ZRC20", func(t *testing.T) { + err = ts.fungibleKeeper.UnlockZRC20(ts.ctx, zrc20ABI, sample.EthAddress(), owner, locker, big.NewInt(10)) + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrZRC20NotWhiteListed) + }) + + t.Run("should fail when trying to unlock an amount bigger than locker's balance", func(t *testing.T) { + err = ts.fungibleKeeper.UnlockZRC20(ts.ctx, zrc20ABI, ts.zrc20Address, owner, locker, big.NewInt(1001)) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid balance, got 100") + }) + + t.Run("should pass when trying to unlock a correct amount", func(t *testing.T) { + err = ts.fungibleKeeper.UnlockZRC20(ts.ctx, zrc20ABI, ts.zrc20Address, owner, locker, allowanceTotal) + require.NoError(t, err) + + ownerBalance, err := ts.fungibleKeeper.ZRC20BalanceOf(ts.ctx, zrc20ABI, ts.zrc20Address, owner) + require.NoError(t, err) + require.Equal(t, uint64(1000), ownerBalance.Uint64()) + + lockerBalance, err := ts.fungibleKeeper.ZRC20BalanceOf(ts.ctx, zrc20ABI, ts.zrc20Address, locker) + require.NoError(t, err) + require.Equal(t, uint64(0), lockerBalance.Uint64()) + }) +} + +func Test_CheckZRC20Allowance(t *testing.T) { + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + require.NoError(t, err) + + ts := setupChain(t) + + owner := fungibletypes.ModuleAddressEVM + spender := sample.EthAddress() + depositTotal := big.NewInt(1000) + allowanceTotal := big.NewInt(100) + higherThanAllowance := big.NewInt(101) + smallerThanAllowance := big.NewInt(99) + + // Make sure locker account exists in state. + accAddress := sdk.AccAddress(spender.Bytes()) + ts.fungibleKeeper.GetAuthKeeper().SetAccount(ts.ctx, authtypes.NewBaseAccount(accAddress, nil, 0, 0)) + + // Deposit ZRC20 tokens into the fungible. + ts.fungibleKeeper.DepositZRC20(ts.ctx, ts.zrc20Address, fungibletypes.ModuleAddressEVM, depositTotal) + + t.Run("should fail when checking zero amount", func(t *testing.T) { + err = ts.fungibleKeeper.CheckZRC20Allowance(ts.ctx, zrc20ABI, owner, spender, ts.zrc20Address, big.NewInt(0)) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrInvalidAmount) + }) + + t.Run("should fail when allowance is not approved", func(t *testing.T) { + err = ts.fungibleKeeper.CheckZRC20Allowance(ts.ctx, zrc20ABI, owner, spender, ts.zrc20Address, big.NewInt(10)) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid allowance, got 0") + }) + + t.Run("should fail when checking a higher amount than approved", func(t *testing.T) { + approveAllowance(t, ts, zrc20ABI, owner, spender, allowanceTotal) + + err = ts.fungibleKeeper.CheckZRC20Allowance( + ts.ctx, + zrc20ABI, + owner, + spender, + ts.zrc20Address, + higherThanAllowance, + ) + require.Error(t, err) + require.Contains(t, err.Error(), "invalid allowance, got 100") + }) + + t.Run("should pass when checking the same amount as approved", func(t *testing.T) { + approveAllowance(t, ts, zrc20ABI, owner, spender, allowanceTotal) + + err = ts.fungibleKeeper.CheckZRC20Allowance(ts.ctx, zrc20ABI, owner, spender, ts.zrc20Address, allowanceTotal) + require.NoError(t, err) + }) + + t.Run("should pass when checking a lower amount than approved", func(t *testing.T) { + approveAllowance(t, ts, zrc20ABI, owner, spender, allowanceTotal) + + err = ts.fungibleKeeper.CheckZRC20Allowance( + ts.ctx, + zrc20ABI, + owner, + spender, + ts.zrc20Address, + smallerThanAllowance, + ) + require.NoError(t, err) + }) +} + +func Test_IsValidZRC20(t *testing.T) { + ts := setupChain(t) + + t.Run("should fail when zrc20 address is zero", func(t *testing.T) { + err := ts.fungibleKeeper.IsValidZRC20(ts.ctx, common.Address{}) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZeroAddress) + }) + + t.Run("should fail when zrc20 is not whitelisted", func(t *testing.T) { + err := ts.fungibleKeeper.IsValidZRC20(ts.ctx, sample.EthAddress()) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20NotWhiteListed) + }) + + t.Run("should pass when zrc20 is a valid whitelisted token", func(t *testing.T) { + err := ts.fungibleKeeper.IsValidZRC20(ts.ctx, ts.zrc20Address) + require.NoError(t, err) + }) +} + +func Test_IsValidDepositAmount(t *testing.T) { + ts := setupChain(t) + + t.Run("should fail when any input is nil", func(t *testing.T) { + isValid := ts.fungibleKeeper.IsValidDepositAmount(nil, big.NewInt(0), big.NewInt(0)) + require.False(t, isValid) + + isValid = ts.fungibleKeeper.IsValidDepositAmount(big.NewInt(0), nil, big.NewInt(0)) + require.False(t, isValid) + + isValid = ts.fungibleKeeper.IsValidDepositAmount(big.NewInt(0), big.NewInt(0), nil) + require.False(t, isValid) + }) + + t.Run("should fail when alreadyLocked + amountToDeposit > totalSupply", func(t *testing.T) { + isValid := ts.fungibleKeeper.IsValidDepositAmount(big.NewInt(1000), big.NewInt(500), big.NewInt(501)) + require.False(t, isValid) + }) + + t.Run("should pass when alreadyLocked + amountToDeposit = totalSupply", func(t *testing.T) { + isValid := ts.fungibleKeeper.IsValidDepositAmount(big.NewInt(1000), big.NewInt(500), big.NewInt(500)) + require.True(t, isValid) + }) + + t.Run("should pass when alreadyLocked + amountToDeposit < totalSupply", func(t *testing.T) { + isValid := ts.fungibleKeeper.IsValidDepositAmount(big.NewInt(1000), big.NewInt(500), big.NewInt(499)) + require.True(t, isValid) + }) +} + +/* + Test utils. +*/ + +type testSuite struct { + ctx sdk.Context + fungibleKeeper *fungiblekeeper.Keeper + sdkKeepers keeper.SDKKeepers + zrc20Address common.Address +} + +func setupChain(t *testing.T) testSuite { + // Initialize basic parameters to mock the chain. + fungibleKeeper, ctx, sdkKeepers, _ := keeper.FungibleKeeper(t) + chainID := getValidChainID(t) + + // Make sure the account store is initialized. + // This is completely needed for accounts to be created in the state. + fungibleKeeper.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + + // Deploy system contracts in order to deploy a ZRC20 token. + deploySystemContracts(t, ctx, fungibleKeeper, sdkKeepers.EvmKeeper) + + zrc20Address := setupGasCoin(t, ctx, fungibleKeeper, sdkKeepers.EvmKeeper, chainID, "ZRC20", "ZRC20") + + return testSuite{ + ctx, + fungibleKeeper, + sdkKeepers, + zrc20Address, + } +} + +func approveAllowance(t *testing.T, ts testSuite, zrc20ABI *abi.ABI, owner, spender common.Address, amount *big.Int) { + resAllowance, err := callEVM( + t, + ts.ctx, + ts.fungibleKeeper, + zrc20ABI, + owner, + ts.zrc20Address, + "approve", + []interface{}{spender, amount}, + ) + require.NoError(t, err, "error allowing bank to spend ZRC20 tokens") + + allowed, ok := resAllowance[0].(bool) + require.True(t, ok) + require.True(t, allowed) +} + +func callEVM( + t *testing.T, + ctx sdk.Context, + fungibleKeeper *fungiblekeeper.Keeper, + abi *abi.ABI, + from common.Address, + dst common.Address, + method string, + args []interface{}, +) ([]interface{}, error) { + res, err := fungibleKeeper.CallEVM( + ctx, // ctx + *abi, // abi + from, // from + dst, // to + big.NewInt(0), // value + nil, // gasLimit + true, // commit + true, // noEthereumTxEvent + method, // method + args..., // args + ) + require.NoError(t, err, "CallEVM error") + require.Equal(t, "", res.VmError, "res.VmError should be empty") + + ret, err := abi.Methods[method].Outputs.Unpack(res.Ret) + require.NoError(t, err, "Unpack error") + + return ret, nil +} diff --git a/x/fungible/keeper/zrc20_cosmos_coins_mapping.go b/x/fungible/keeper/zrc20_cosmos_coins_mapping.go new file mode 100644 index 0000000000..f7d152f749 --- /dev/null +++ b/x/fungible/keeper/zrc20_cosmos_coins_mapping.go @@ -0,0 +1,192 @@ +package keeper + +import ( + "fmt" + "math/big" + + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + "github.com/zeta-chain/node/pkg/crypto" + fungibletypes "github.com/zeta-chain/node/x/fungible/types" +) + +// LockZRC20 locks ZRC20 tokens in the specified address +// The caller must have approved the locker contract to spend the amount of ZRC20 tokens. +// Warning: This function does not mint cosmos coins, if the depositor needs to be rewarded +// it has to be implemented by the caller of this function. +func (k Keeper) LockZRC20( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address, spender, owner, locker common.Address, + amount *big.Int, +) error { + // owner is the EOA owner of the ZRC20 tokens. + // locker is the address that will lock the ZRC20 tokens, i.e: bank precompile. + if err := k.CheckZRC20Allowance(ctx, zrc20ABI, owner, locker, zrc20Address, amount); err != nil { + return errors.Wrap(err, "failed allowance check") + } + + // Check amount_to_be_locked <= total_erc20_balance - already_locked + // Max amount of ZRC20 tokens that exists in zEVM are the total supply. + totalSupply, err := k.ZRC20TotalSupply(ctx, zrc20ABI, zrc20Address) + if err != nil { + return errors.Wrap(err, "failed totalSupply check") + } + + // The alreadyLocked amount is the amount of ZRC20 tokens that have been locked by the locker. + // TODO: Implement list of whitelisted locker addresses (https://github.com/zeta-chain/node/issues/2991) + alreadyLocked, err := k.ZRC20BalanceOf(ctx, zrc20ABI, zrc20Address, locker) + if err != nil { + return errors.Wrap(err, "failed getting the ZRC20 already locked amount") + } + + if !k.IsValidDepositAmount(totalSupply, alreadyLocked, amount) { + return errors.Wrap(fungibletypes.ErrInvalidAmount, "amount to be locked is not valid") + } + + // Initiate a transferFrom the owner to the locker. This will lock the ZRC20 tokens. + // locker has to initiate the transaction and have enough allowance from owner. + transferred, err := k.ZRC20TransferFrom(ctx, zrc20ABI, zrc20Address, spender, owner, locker, amount) + if err != nil { + return errors.Wrap(err, "failed executing transferFrom") + } + + if !transferred { + return fmt.Errorf("transferFrom returned false (no success)") + } + + return nil +} + +// UnlockZRC20 unlocks ZRC20 tokens and sends them to the owner. +// Warning: Before unlocking ZRC20 tokens, the caller must check if +// the owner has enough collateral (cosmos coins) to be exchanged (burnt) for the ZRC20 tokens. +func (k Keeper) UnlockZRC20( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address, owner, locker common.Address, + amount *big.Int, +) error { + // Check if the account locking the ZRC20 tokens has enough balance. + if err := k.CheckZRC20Balance(ctx, zrc20ABI, zrc20Address, locker, amount); err != nil { + return errors.Wrap(err, "failed balance check") + } + + // transfer from the EOA locking the assets to the owner. + transferred, err := k.ZRC20Transfer(ctx, zrc20ABI, zrc20Address, locker, owner, amount) + if err != nil { + return errors.Wrap(err, "failed executing transfer") + } + + if !transferred { + return fmt.Errorf("transfer returned false (no success)") + } + + return nil +} + +// CheckZRC20Allowance checks if the allowance of ZRC20 tokens, +// is equal or greater than the provided amount. +func (k Keeper) CheckZRC20Allowance( + ctx sdk.Context, + zrc20ABI *abi.ABI, + owner, spender, zrc20Address common.Address, + amount *big.Int, +) error { + if zrc20ABI == nil { + return fungibletypes.ErrZRC20NilABI + } + + if amount.Sign() <= 0 || amount == nil { + return fungibletypes.ErrInvalidAmount + } + + if crypto.IsEmptyAddress(owner) || crypto.IsEmptyAddress(spender) { + return fungibletypes.ErrZeroAddress + } + + if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { + return errors.Wrap(err, "ZRC20 is not valid") + } + + allowanceValue, err := k.ZRC20Allowance(ctx, zrc20ABI, zrc20Address, owner, spender) + if err != nil { + return errors.Wrap(err, "failed while checking spender's allowance") + } + + if allowanceValue.Cmp(amount) < 0 || allowanceValue.Cmp(big.NewInt(0)) <= 0 { + return fmt.Errorf("invalid allowance, got %s, wanted %s", allowanceValue.String(), amount.String()) + } + + return nil +} + +// CheckZRC20Balance checks if the balance of ZRC20 tokens, +// is equal or greater than the provided amount. +func (k Keeper) CheckZRC20Balance( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address, owner common.Address, + amount *big.Int, +) error { + if zrc20ABI == nil { + return fungibletypes.ErrZRC20NilABI + } + + if amount.Sign() <= 0 || amount == nil { + return fungibletypes.ErrInvalidAmount + } + + if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { + return errors.Wrap(err, "ZRC20 is not valid") + } + + if crypto.IsEmptyAddress(owner) { + return fungibletypes.ErrZeroAddress + } + + // Check the ZRC20 balance of a given account. + // function balanceOf(address account) + balance, err := k.ZRC20BalanceOf(ctx, zrc20ABI, zrc20Address, owner) + if err != nil { + return errors.Wrap(err, "failed getting owner's ZRC20 balance") + } + + if balance.Cmp(amount) < 0 { + return fmt.Errorf("invalid balance, got %s, wanted %s", balance.String(), amount.String()) + } + + return nil +} + +// IsValidZRC20 returns an error whenever a ZRC20 is not whitelisted or paused. +func (k Keeper) IsValidZRC20(ctx sdk.Context, zrc20Address common.Address) error { + if crypto.IsEmptyAddress(zrc20Address) { + return fungibletypes.ErrZRC20ZeroAddress + } + + t, found := k.GetForeignCoins(ctx, zrc20Address.String()) + if !found { + return fungibletypes.ErrZRC20NotWhiteListed + } + + if t.Paused { + return fungibletypes.ErrPausedZRC20 + } + + return nil +} + +// IsValidDepositAmount checks "totalSupply >= amount_to_be_locked + amount_already_locked". +// A failure here means the user is trying to lock more than the available ZRC20 supply. +// This suggests that an actor is minting ZRC20 tokens out of thin air. +func (k Keeper) IsValidDepositAmount(totalSupply, alreadyLocked, amountToDeposit *big.Int) bool { + if totalSupply == nil || alreadyLocked == nil || amountToDeposit == nil { + return false + } + + return totalSupply.Cmp(alreadyLocked.Add(alreadyLocked, amountToDeposit)) >= 0 +} diff --git a/x/fungible/keeper/zrc20_methods.go b/x/fungible/keeper/zrc20_methods.go new file mode 100644 index 0000000000..5c9f2d4645 --- /dev/null +++ b/x/fungible/keeper/zrc20_methods.go @@ -0,0 +1,305 @@ +package keeper + +import ( + "fmt" + "math/big" + + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + "github.com/zeta-chain/node/pkg/crypto" + fungibletypes "github.com/zeta-chain/node/x/fungible/types" +) + +const ( + allowance = "allowance" + balanceOf = "balanceOf" + totalSupply = "totalSupply" + transfer = "transfer" + transferFrom = "transferFrom" +) + +// ZRC20Allowance returns the ZRC20 allowance for a given spender. +// The allowance has to be previously approved by the ZRC20 tokens owner. +func (k Keeper) ZRC20Allowance( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address, owner, spender common.Address, +) (*big.Int, error) { + if zrc20ABI == nil { + return nil, fungibletypes.ErrZRC20NilABI + } + + if crypto.IsEmptyAddress(owner) || crypto.IsEmptyAddress(spender) { + return nil, fungibletypes.ErrZeroAddress + } + + if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { + return nil, err + } + + // function allowance(address owner, address spender) + args := []interface{}{owner, spender} + res, err := k.CallEVM( + ctx, + *zrc20ABI, + fungibletypes.ModuleAddressEVM, + zrc20Address, + big.NewInt(0), + nil, + true, + true, + allowance, + args..., + ) + if err != nil { + return nil, errors.Wrap(err, "EVM error calling ZRC20 allowance function") + } + + if res.VmError != "" { + return nil, fmt.Errorf("EVM execution error calling allowance: %s", res.VmError) + } + + ret, err := zrc20ABI.Methods[allowance].Outputs.Unpack(res.Ret) + if err != nil { + return nil, errors.Wrap(err, "failed to unpack ZRC20 allowance return value") + } + + if len(ret) == 0 { + return nil, fmt.Errorf("no data returned from 'allowance' method") + } + + allowanceValue, ok := ret[0].(*big.Int) + if !ok { + return nil, fmt.Errorf("ZRC20 allowance returned an unexpected type") + } + + return allowanceValue, nil +} + +// ZRC20BalanceOf checks the ZRC20 balance of a given EOA. +func (k Keeper) ZRC20BalanceOf( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address, owner common.Address, +) (*big.Int, error) { + if zrc20ABI == nil { + return nil, fungibletypes.ErrZRC20NilABI + } + + if crypto.IsEmptyAddress(owner) { + return nil, fungibletypes.ErrZeroAddress + } + + if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { + return nil, err + } + + // function balanceOf(address account) + res, err := k.CallEVM( + ctx, + *zrc20ABI, + fungibletypes.ModuleAddressEVM, + zrc20Address, + big.NewInt(0), + nil, + true, + true, + balanceOf, + owner, + ) + if err != nil { + return nil, errors.Wrap(err, "EVM error calling ZRC20 balanceOf function") + } + + if res.VmError != "" { + return nil, fmt.Errorf("EVM execution error calling balanceOf: %s", res.VmError) + } + + ret, err := zrc20ABI.Methods[balanceOf].Outputs.Unpack(res.Ret) + if err != nil { + return nil, errors.Wrap(err, "failed to unpack ZRC20 balanceOf return value") + } + + if len(ret) == 0 { + return nil, fmt.Errorf("no data returned from 'balanceOf' method") + } + + balance, ok := ret[0].(*big.Int) + if !ok { + return nil, fmt.Errorf("ZRC20 balanceOf returned an unexpected type") + } + + return balance, nil +} + +// ZRC20TotalSupply returns the total supply of a ZRC20 token. +func (k Keeper) ZRC20TotalSupply( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address common.Address, +) (*big.Int, error) { + if zrc20ABI == nil { + return nil, fungibletypes.ErrZRC20NilABI + } + + if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { + return nil, err + } + + // function totalSupply() public view virtual override returns (uint256) + res, err := k.CallEVM( + ctx, + *zrc20ABI, + fungibletypes.ModuleAddressEVM, + zrc20Address, + big.NewInt(0), + nil, + true, + true, + totalSupply, + ) + if err != nil { + return nil, errors.Wrap(err, "EVM error calling ZRC20 totalSupply function") + } + + if res.VmError != "" { + return nil, fmt.Errorf("EVM execution error calling totalSupply: %s", res.VmError) + } + + ret, err := zrc20ABI.Methods[totalSupply].Outputs.Unpack(res.Ret) + if err != nil { + return nil, errors.Wrap(err, "failed to unpack ZRC20 totalSupply return value") + } + + if len(ret) == 0 { + return nil, fmt.Errorf("no data returned from 'totalSupply' method") + } + + totalSupply, ok := ret[0].(*big.Int) + if !ok { + return nil, fmt.Errorf("ZRC20 totalSupply returned an unexpected type") + } + + return totalSupply, nil +} + +// ZRC20Transfer transfers ZRC20 tokens from the sender to the recipient. +func (k Keeper) ZRC20Transfer( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address, from, to common.Address, + amount *big.Int, +) (bool, error) { + if zrc20ABI == nil { + return false, fungibletypes.ErrZRC20NilABI + } + + if crypto.IsEmptyAddress(from) || crypto.IsEmptyAddress(to) { + return false, fungibletypes.ErrZeroAddress + } + + if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { + return false, err + } + + // function transfer(address recipient, uint256 amount) + args := []interface{}{to, amount} + res, err := k.CallEVM( + ctx, + *zrc20ABI, + from, + zrc20Address, + big.NewInt(0), + nil, + true, + true, + transfer, + args..., + ) + if err != nil { + return false, errors.Wrap(err, "EVM error calling ZRC20 transfer function") + } + + if res.VmError != "" { + return false, fmt.Errorf("EVM execution error in transfer: %s", res.VmError) + } + + ret, err := zrc20ABI.Methods[transfer].Outputs.Unpack(res.Ret) + if err != nil { + return false, errors.Wrap(err, "failed to unpack ZRC20 transfer return value") + } + + if len(ret) == 0 { + return false, fmt.Errorf("no data returned from 'transfer' method") + } + + transferred, ok := ret[0].(bool) + if !ok { + return false, fmt.Errorf("transfer returned an unexpected value") + } + + return transferred, nil +} + +// ZRC20TransferFrom transfers ZRC20 tokens "from" to the EOA "to". +// The transaction is started by the spender. +// Requisite: the original EOA must have approved the spender to spend the tokens. +func (k Keeper) ZRC20TransferFrom( + ctx sdk.Context, + zrc20ABI *abi.ABI, + zrc20Address, spender, from, to common.Address, + amount *big.Int, +) (bool, error) { + if zrc20ABI == nil { + return false, fungibletypes.ErrZRC20NilABI + } + + if crypto.IsEmptyAddress(from) || crypto.IsEmptyAddress(to) || crypto.IsEmptyAddress(spender) { + return false, fungibletypes.ErrZeroAddress + } + + if err := k.IsValidZRC20(ctx, zrc20Address); err != nil { + return false, err + } + + // function transferFrom(address sender, address recipient, uint256 amount) + args := []interface{}{from, to, amount} + res, err := k.CallEVM( + ctx, + *zrc20ABI, + spender, + zrc20Address, + big.NewInt(0), + nil, + true, + true, + transferFrom, + args..., + ) + if err != nil { + return false, errors.Wrap(err, "EVM error calling ZRC20 transferFrom function") + } + + if res.VmError != "" { + return false, fmt.Errorf("EVM execution error in transferFrom: %s", res.VmError) + } + + ret, err := zrc20ABI.Methods[transferFrom].Outputs.Unpack(res.Ret) + if err != nil { + return false, errors.Wrap(err, "failed to unpack ZRC20 transferFrom return value") + } + + if len(ret) == 0 { + return false, fmt.Errorf("no data returned from 'transferFrom' method") + } + + transferred, ok := ret[0].(bool) + if !ok { + return false, fmt.Errorf("transferFrom returned an unexpected value") + } + + return transferred, nil +} diff --git a/x/fungible/keeper/zrc20_methods_test.go b/x/fungible/keeper/zrc20_methods_test.go new file mode 100644 index 0000000000..7b124f3050 --- /dev/null +++ b/x/fungible/keeper/zrc20_methods_test.go @@ -0,0 +1,341 @@ +package keeper_test + +import ( + "math/big" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/node/testutil/sample" + fungibletypes "github.com/zeta-chain/node/x/fungible/types" + "github.com/zeta-chain/protocol-contracts/v2/pkg/zrc20.sol" +) + +func Test_ZRC20Allowance(t *testing.T) { + // Instantiate the ZRC20 ABI only one time. + // This avoids instantiating it every time deposit or withdraw are called. + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + require.NoError(t, err) + + ts := setupChain(t) + + t.Run("should fail when ZRC20ABI is nil", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20Allowance(ts.ctx, nil, ts.zrc20Address, common.Address{}, common.Address{}) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20NilABI) + }) + + t.Run("should fail when owner is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20Allowance( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + common.Address{}, + sample.EthAddress(), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZeroAddress) + }) + + t.Run("should fail when spender is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20Allowance( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + sample.EthAddress(), + common.Address{}, + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZeroAddress) + }) + + t.Run("should fail when zrc20 address is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20Allowance( + ts.ctx, + zrc20ABI, + common.Address{}, + sample.EthAddress(), + fungibletypes.ModuleAddressEVM, + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20ZeroAddress) + }) + + t.Run("should pass with correct input", func(t *testing.T) { + allowance, err := ts.fungibleKeeper.ZRC20Allowance( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + fungibletypes.ModuleAddressEVM, + sample.EthAddress(), + ) + require.NoError(t, err) + require.Equal(t, uint64(0), allowance.Uint64()) + }) +} + +func Test_ZRC20BalanceOf(t *testing.T) { + // Instantiate the ZRC20 ABI only one time. + // This avoids instantiating it every time deposit or withdraw are called. + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + require.NoError(t, err) + + ts := setupChain(t) + + t.Run("should fail when ZRC20ABI is nil", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20BalanceOf(ts.ctx, nil, ts.zrc20Address, common.Address{}) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20NilABI) + }) + + t.Run("should fail when owner is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20BalanceOf(ts.ctx, zrc20ABI, ts.zrc20Address, common.Address{}) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZeroAddress) + }) + + t.Run("should fail when zrc20 address is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20BalanceOf(ts.ctx, zrc20ABI, common.Address{}, sample.EthAddress()) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20ZeroAddress) + }) + + t.Run("should pass with correct input", func(t *testing.T) { + balance, err := ts.fungibleKeeper.ZRC20BalanceOf( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + fungibletypes.ModuleAddressEVM, + ) + require.NoError(t, err) + require.Equal(t, uint64(0), balance.Uint64()) + }) +} + +func Test_ZRC20TotalSupply(t *testing.T) { + // Instantiate the ZRC20 ABI only one time. + // This avoids instantiating it every time deposit or withdraw are called. + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + require.NoError(t, err) + + ts := setupChain(t) + + t.Run("should fail when ZRC20ABI is nil", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20TotalSupply(ts.ctx, nil, ts.zrc20Address) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20NilABI) + }) + + t.Run("should fail when zrc20 address is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20TotalSupply(ts.ctx, zrc20ABI, common.Address{}) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20ZeroAddress) + }) + + t.Run("should pass with correct input", func(t *testing.T) { + totalSupply, err := ts.fungibleKeeper.ZRC20TotalSupply(ts.ctx, zrc20ABI, ts.zrc20Address) + require.NoError(t, err) + require.Equal(t, uint64(10000000), totalSupply.Uint64()) + }) +} + +func Test_ZRC20Transfer(t *testing.T) { + // Instantiate the ZRC20 ABI only one time. + // This avoids instantiating it every time deposit or withdraw are called. + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + require.NoError(t, err) + + ts := setupChain(t) + + // Make sure sample.EthAddress() exists as an ethermint account in state. + accAddress := sdk.AccAddress(sample.EthAddress().Bytes()) + ts.fungibleKeeper.GetAuthKeeper().SetAccount(ts.ctx, authtypes.NewBaseAccount(accAddress, nil, 0, 0)) + + t.Run("should fail when ZRC20ABI is nil", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20Transfer( + ts.ctx, + nil, + ts.zrc20Address, + common.Address{}, + common.Address{}, + big.NewInt(0), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20NilABI) + }) + + t.Run("should fail when owner is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20Transfer( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + common.Address{}, + sample.EthAddress(), + big.NewInt(0), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZeroAddress) + }) + + t.Run("should fail when spender is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20Transfer( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + sample.EthAddress(), + common.Address{}, + big.NewInt(0), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZeroAddress) + }) + + t.Run("should fail when zrc20 address is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20Transfer( + ts.ctx, + zrc20ABI, + common.Address{}, + sample.EthAddress(), + fungibletypes.ModuleAddressEVM, + big.NewInt(0), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20ZeroAddress) + }) + + t.Run("should pass with correct input", func(t *testing.T) { + ts.fungibleKeeper.DepositZRC20(ts.ctx, ts.zrc20Address, fungibletypes.ModuleAddressEVM, big.NewInt(10)) + transferred, err := ts.fungibleKeeper.ZRC20Transfer( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + fungibletypes.ModuleAddressEVM, + sample.EthAddress(), + big.NewInt(10), + ) + require.NoError(t, err) + require.True(t, transferred) + }) +} + +func Test_ZRC20TransferFrom(t *testing.T) { + // Instantiate the ZRC20 ABI only one time. + // This avoids instantiating it every time deposit or withdraw are called. + zrc20ABI, err := zrc20.ZRC20MetaData.GetAbi() + require.NoError(t, err) + + ts := setupChain(t) + + // Make sure sample.EthAddress() exists as an ethermint account in state. + accAddress := sdk.AccAddress(sample.EthAddress().Bytes()) + ts.fungibleKeeper.GetAuthKeeper().SetAccount(ts.ctx, authtypes.NewBaseAccount(accAddress, nil, 0, 0)) + + t.Run("should fail when ZRC20ABI is nil", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20TransferFrom( + ts.ctx, + nil, + ts.zrc20Address, + common.Address{}, + common.Address{}, + common.Address{}, + big.NewInt(0), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20NilABI) + }) + + t.Run("should fail when from is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20TransferFrom( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + sample.EthAddress(), + common.Address{}, + sample.EthAddress(), + big.NewInt(0), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZeroAddress) + }) + + t.Run("should fail when to is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20TransferFrom( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + sample.EthAddress(), + sample.EthAddress(), + common.Address{}, + big.NewInt(0), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZeroAddress) + }) + + t.Run("should fail when spender is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20TransferFrom( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + common.Address{}, + sample.EthAddress(), + sample.EthAddress(), + big.NewInt(0), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZeroAddress) + }) + + t.Run("should fail when zrc20 address is zero address", func(t *testing.T) { + _, err := ts.fungibleKeeper.ZRC20TransferFrom( + ts.ctx, + zrc20ABI, + common.Address{}, + sample.EthAddress(), + sample.EthAddress(), + fungibletypes.ModuleAddressEVM, + big.NewInt(0), + ) + require.Error(t, err) + require.ErrorAs(t, err, &fungibletypes.ErrZRC20ZeroAddress) + }) + + t.Run("should fail without an allowance approval", func(t *testing.T) { + // Deposit ZRC20 into fungible EOA. + ts.fungibleKeeper.DepositZRC20(ts.ctx, ts.zrc20Address, fungibletypes.ModuleAddressEVM, big.NewInt(1000)) + + // Transferring the tokens with transferFrom without approval should fail. + _, err = ts.fungibleKeeper.ZRC20TransferFrom( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + fungibletypes.ModuleAddressEVM, + sample.EthAddress(), + fungibletypes.ModuleAddressEVM, + big.NewInt(10), + ) + require.Error(t, err) + }) + + t.Run("should success with an allowance approval", func(t *testing.T) { + // Deposit ZRC20 into fungible EOA. + ts.fungibleKeeper.DepositZRC20(ts.ctx, ts.zrc20Address, fungibletypes.ModuleAddressEVM, big.NewInt(1000)) + + // Approve allowance to sample.EthAddress() to spend 10 ZRC20 tokens. + approveAllowance(t, ts, zrc20ABI, fungibletypes.ModuleAddressEVM, sample.EthAddress(), big.NewInt(10)) + + // Transferring the tokens with transferFrom without approval should fail. + _, err = ts.fungibleKeeper.ZRC20TransferFrom( + ts.ctx, + zrc20ABI, + ts.zrc20Address, + fungibletypes.ModuleAddressEVM, + sample.EthAddress(), + fungibletypes.ModuleAddressEVM, + big.NewInt(10), + ) + require.Error(t, err) + }) +} diff --git a/x/fungible/types/errors.go b/x/fungible/types/errors.go index 7e426a3178..cf333c9545 100644 --- a/x/fungible/types/errors.go +++ b/x/fungible/types/errors.go @@ -29,4 +29,9 @@ var ( ErrNilGasPrice = cosmoserrors.Register(ModuleName, 1127, "nil gas price") ErrAccountNotFound = cosmoserrors.Register(ModuleName, 1128, "account not found") ErrGatewayContractNotSet = cosmoserrors.Register(ModuleName, 1129, "gateway contract not set") + ErrZRC20ZeroAddress = cosmoserrors.Register(ModuleName, 1130, "ZRC20 address cannot be zero") + ErrZRC20NotWhiteListed = cosmoserrors.Register(ModuleName, 1131, "ZRC20 is not whitelisted") + ErrZRC20NilABI = cosmoserrors.Register(ModuleName, 1132, "ZRC20 ABI is nil") + ErrZeroAddress = cosmoserrors.Register(ModuleName, 1133, "address cannot be zero") + ErrInvalidAmount = cosmoserrors.Register(ModuleName, 1134, "invalid amount") ) diff --git a/x/fungible/types/keys.go b/x/fungible/types/keys.go index 777cfd7c41..4c02d9c2ef 100644 --- a/x/fungible/types/keys.go +++ b/x/fungible/types/keys.go @@ -27,17 +27,10 @@ func KeyPrefix(p string) []byte { } var ( - ModuleAddress = authtypes.NewModuleAddress(ModuleName) - //ModuleAddressEVM common.EVMAddress + ModuleAddress = authtypes.NewModuleAddress(ModuleName) ModuleAddressEVM = common.BytesToAddress(ModuleAddress.Bytes()) - AdminAddress = "zeta1rx9r8hff0adaqhr5tuadkzj4e7ns2ntg446vtt" ) -func init() { - //fmt.Printf("ModuleAddressEVM of %s: %s\n", ModuleName, ModuleAddressEVM.String()) - // 0x735b14BB79463307AAcBED86DAf3322B1e6226aB -} - const ( SystemContractKey = "SystemContract-value-" ) From 923b9364fa6295286a5702e294b67e4b0a1ff26a Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Thu, 17 Oct 2024 19:23:42 +0200 Subject: [PATCH 33/36] ci: remove v2 migration test from scheduled CI and release workflow (#3013) --- .github/workflows/e2e.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c3d413ee54..773775e816 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -89,7 +89,6 @@ jobs: core.setOutput('SOLANA_TESTS', true); core.setOutput('TON_TESTS', true); core.setOutput('V2_TESTS', true); // for v2 tests, TODO: remove this once we fully migrate to v2 (https://github.com/zeta-chain/node/issues/2627) - core.setOutput('V2_MIGRATION_TESTS', true); // for v2 tests, TODO: remove this once we fully migrate to v2 (https://github.com/zeta-chain/node/issues/2627) } else if (context.eventName === 'schedule') { core.setOutput('DEFAULT_TESTS', true); core.setOutput('UPGRADE_TESTS', true); @@ -102,7 +101,6 @@ jobs: core.setOutput('SOLANA_TESTS', true); core.setOutput('TON_TESTS', true); core.setOutput('V2_TESTS', true); // for v2 tests, TODO: remove this once we fully migrate to v2 (https://github.com/zeta-chain/node/issues/2627) - core.setOutput('V2_MIGRATION_TESTS', true); // for v2 tests, TODO: remove this once we fully migrate to v2 (https://github.com/zeta-chain/node/issues/2627) } else if (context.eventName === 'workflow_dispatch') { const makeTargets = context.payload.inputs['make-targets'].split(','); core.setOutput('DEFAULT_TESTS', makeTargets.includes('default-test')); From 93471653698e954de81c3c83b39e7bce6cb30bd6 Mon Sep 17 00:00:00 2001 From: skosito Date: Fri, 18 Oct 2024 11:54:42 +0100 Subject: [PATCH 34/36] feat: erc20 auth calls (#3012) * bump protocol contracts to use erc20 auth calls * bump protocol contracts and fix test dapp * rename current test to arbitrary call * rename existing tests * e2e test wip * new test fix * fix test * fix * PR comment * revert staking abi change * fmt * changelog * fix test * PR comment * PR comment * fix test --- changelog.md | 1 + cmd/zetae2e/local/v2.go | 1 + e2e/e2etests/e2etests.go | 11 +- ...st_v2_erc20_withdraw_and_arbitrary_call.go | 41 +++++++ .../test_v2_erc20_withdraw_and_call.go | 30 +++-- .../test_v2_erc20_withdraw_and_call_revert.go | 2 +- ...rc20_withdraw_and_call_revert_with_call.go | 2 +- ...test_v2_eth_withdraw_and_arbitrary_call.go | 2 +- e2e/e2etests/test_v2_eth_withdraw_and_call.go | 7 +- .../test_v2_eth_withdraw_and_call_revert.go | 13 ++- ..._eth_withdraw_and_call_revert_with_call.go | 2 +- ..._eth_withdraw_and_call_through_contract.go | 23 +--- .../test_v2_zevm_to_evm_arbitrary_call.go | 10 +- e2e/e2etests/test_v2_zevm_to_evm_call.go | 7 +- ...st_v2_zevm_to_evm_call_through_contract.go | 26 +---- e2e/runner/v2_zevm.go | 65 ++++++++--- go.mod | 2 +- go.sum | 4 +- pkg/contracts/testdappv2/TestDAppV2.abi | 90 ++++++--------- pkg/contracts/testdappv2/TestDAppV2.bin | 2 +- pkg/contracts/testdappv2/TestDAppV2.go | 104 +++++------------- pkg/contracts/testdappv2/TestDAppV2.json | 92 ++++++---------- pkg/contracts/testdappv2/TestDAppV2.sol | 10 +- zetaclient/chains/evm/signer/outbound_data.go | 28 ++++- zetaclient/chains/evm/signer/v2_sign.go | 36 +++--- zetaclient/chains/evm/signer/v2_signer.go | 2 +- 26 files changed, 290 insertions(+), 323 deletions(-) create mode 100644 e2e/e2etests/test_v2_erc20_withdraw_and_arbitrary_call.go diff --git a/changelog.md b/changelog.md index 2dd8e75f9a..fb4435cade 100644 --- a/changelog.md +++ b/changelog.md @@ -20,6 +20,7 @@ * [2896](https://github.com/zeta-chain/node/pull/2896) - add TON inbound observation * [2987](https://github.com/zeta-chain/node/pull/2987) - add non-EVM standard inbound memo package * [2979](https://github.com/zeta-chain/node/pull/2979) - add fungible keeper ability to lock/unlock ZRC20 tokens +* [3012](https://github.com/zeta-chain/node/pull/3012) - integrate authenticated calls erc20 smart contract functionality into protocol ### Refactor diff --git a/cmd/zetae2e/local/v2.go b/cmd/zetae2e/local/v2.go index fa98ef6677..3ef5ff880a 100644 --- a/cmd/zetae2e/local/v2.go +++ b/cmd/zetae2e/local/v2.go @@ -34,6 +34,7 @@ func startV2Tests(eg *errgroup.Group, conf config.Config, deployerRunner *runner e2etests.TestV2ERC20DepositName, e2etests.TestV2ERC20DepositAndCallName, e2etests.TestV2ERC20WithdrawName, + e2etests.TestV2ERC20WithdrawAndArbitraryCallName, e2etests.TestV2ERC20WithdrawAndCallName, )) diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index fe6428385d..c94eb8f89d 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -143,6 +143,7 @@ const ( TestV2ERC20DepositAndCallRevertName = "v2_erc20_deposit_and_call_revert" TestV2ERC20DepositAndCallRevertWithCallName = "v2_erc20_deposit_and_call_revert_with_call" TestV2ERC20WithdrawName = "v2_erc20_withdraw" + TestV2ERC20WithdrawAndArbitraryCallName = "v2_erc20_withdraw_and_arbitrary_call" TestV2ERC20WithdrawAndCallName = "v2_erc20_withdraw_and_call" TestV2ERC20WithdrawAndCallRevertName = "v2_erc20_withdraw_and_call_revert" TestV2ERC20WithdrawAndCallRevertWithCallName = "v2_erc20_withdraw_and_call_revert_with_call" @@ -835,11 +836,17 @@ var AllE2ETests = []runner.E2ETest{ TestV2ERC20Withdraw, ), runner.NewE2ETest( - TestV2ERC20WithdrawAndCallName, - "withdraw ERC20 from ZEVM and call a contract using V2 contract", + TestV2ERC20WithdrawAndArbitraryCallName, + "withdraw ERC20 from ZEVM and arbitrary call a contract using V2 contract", []runner.ArgDefinition{ {Description: "amount", DefaultValue: "1000"}, }, + TestV2ERC20WithdrawAndArbitraryCall, + ), + runner.NewE2ETest( + TestV2ERC20WithdrawAndCallName, + "withdraw ERC20 from ZEVM and authenticated call a contract using V2 contract", + []runner.ArgDefinition{}, TestV2ERC20WithdrawAndCall, ), runner.NewE2ETest( diff --git a/e2e/e2etests/test_v2_erc20_withdraw_and_arbitrary_call.go b/e2e/e2etests/test_v2_erc20_withdraw_and_arbitrary_call.go new file mode 100644 index 0000000000..ca48f4be8b --- /dev/null +++ b/e2e/e2etests/test_v2_erc20_withdraw_and_arbitrary_call.go @@ -0,0 +1,41 @@ +package e2etests + +import ( + "math/big" + + "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol" + + "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/utils" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +const payloadMessageWithdrawERC20 = "this is a test ERC20 withdraw and call payload" + +func TestV2ERC20WithdrawAndArbitraryCall(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) + + amount, ok := big.NewInt(0).SetString(args[0], 10) + require.True(r, ok, "Invalid amount specified for TestV2ERC20WithdrawAndCall") + + r.AssertTestDAppEVMCalled(false, payloadMessageWithdrawERC20, amount) + + r.ApproveERC20ZRC20(r.GatewayZEVMAddr) + r.ApproveETHZRC20(r.GatewayZEVMAddr) + + // perform the withdraw + tx := r.V2ERC20WithdrawAndArbitraryCall( + r.TestDAppV2EVMAddr, + amount, + r.EncodeERC20Call(r.ERC20Addr, amount, payloadMessageWithdrawERC20), + gatewayzevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, + ) + + // wait for the cctx to be mined + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "withdraw") + require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + + r.AssertTestDAppEVMCalled(true, payloadMessageWithdrawERC20, amount) +} diff --git a/e2e/e2etests/test_v2_erc20_withdraw_and_call.go b/e2e/e2etests/test_v2_erc20_withdraw_and_call.go index 6773e84f17..4596ba12da 100644 --- a/e2e/e2etests/test_v2_erc20_withdraw_and_call.go +++ b/e2e/e2etests/test_v2_erc20_withdraw_and_call.go @@ -3,6 +3,7 @@ package e2etests import ( "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/stretchr/testify/require" "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol" @@ -11,15 +12,20 @@ import ( crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" ) -const payloadMessageWithdrawERC20 = "this is a test ERC20 withdraw and call payload" +const payloadMessageWithdrawAuthenticatedCallERC20 = "this is a test ERC20 withdraw and authenticated call payload" -func TestV2ERC20WithdrawAndCall(r *runner.E2ERunner, args []string) { - require.Len(r, args, 1) +func TestV2ERC20WithdrawAndCall(r *runner.E2ERunner, _ []string) { + previousGasLimit := r.ZEVMAuth.GasLimit + r.ZEVMAuth.GasLimit = 10000000 + defer func() { + r.ZEVMAuth.GasLimit = previousGasLimit + }() - amount, ok := big.NewInt(0).SetString(args[0], 10) - require.True(r, ok, "Invalid amount specified for TestV2ERC20WithdrawAndCall") + // called with fixed amount without arg since onCall implementation is for TestDappV2 is simple and generic + // without decoding the payload and amount handling for erc20, purpose of test is to verify correct sender and payload are used + amount := big.NewInt(10000) - r.AssertTestDAppEVMCalled(false, payloadMessageWithdrawERC20, amount) + r.AssertTestDAppEVMCalled(false, payloadMessageWithdrawAuthenticatedCallERC20, amount) r.ApproveERC20ZRC20(r.GatewayZEVMAddr) r.ApproveETHZRC20(r.GatewayZEVMAddr) @@ -28,7 +34,7 @@ func TestV2ERC20WithdrawAndCall(r *runner.E2ERunner, args []string) { tx := r.V2ERC20WithdrawAndCall( r.TestDAppV2EVMAddr, amount, - r.EncodeERC20Call(r.ERC20Addr, amount, payloadMessageWithdrawERC20), + []byte(payloadMessageWithdrawAuthenticatedCallERC20), gatewayzevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, ) @@ -37,5 +43,13 @@ func TestV2ERC20WithdrawAndCall(r *runner.E2ERunner, args []string) { r.Logger.CCTX(*cctx, "withdraw") require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) - r.AssertTestDAppEVMCalled(true, payloadMessageWithdrawERC20, amount) + r.AssertTestDAppEVMCalled(true, payloadMessageWithdrawAuthenticatedCallERC20, big.NewInt(0)) + + // check expected sender was used + senderForMsg, err := r.TestDAppV2EVM.SenderWithMessage( + &bind.CallOpts{}, + []byte(payloadMessageWithdrawAuthenticatedCallERC20), + ) + require.NoError(r, err) + require.Equal(r, r.ZEVMAuth.From, senderForMsg) } diff --git a/e2e/e2etests/test_v2_erc20_withdraw_and_call_revert.go b/e2e/e2etests/test_v2_erc20_withdraw_and_call_revert.go index 8454d09710..8ca60a238b 100644 --- a/e2e/e2etests/test_v2_erc20_withdraw_and_call_revert.go +++ b/e2e/e2etests/test_v2_erc20_withdraw_and_call_revert.go @@ -29,7 +29,7 @@ func TestV2ERC20WithdrawAndCallRevert(r *runner.E2ERunner, args []string) { require.EqualValues(r, int64(0), balance.Int64()) // perform the withdraw - tx := r.V2ERC20WithdrawAndCall( + tx := r.V2ERC20WithdrawAndArbitraryCall( r.TestDAppV2EVMAddr, amount, r.EncodeERC20CallRevert(r.ERC20Addr, amount), diff --git a/e2e/e2etests/test_v2_erc20_withdraw_and_call_revert_with_call.go b/e2e/e2etests/test_v2_erc20_withdraw_and_call_revert_with_call.go index 45bab52ae6..fb3b3201ff 100644 --- a/e2e/e2etests/test_v2_erc20_withdraw_and_call_revert_with_call.go +++ b/e2e/e2etests/test_v2_erc20_withdraw_and_call_revert_with_call.go @@ -26,7 +26,7 @@ func TestV2ERC20WithdrawAndCallRevertWithCall(r *runner.E2ERunner, args []string r.ApproveETHZRC20(r.GatewayZEVMAddr) // perform the withdraw - tx := r.V2ERC20WithdrawAndCall( + tx := r.V2ERC20WithdrawAndArbitraryCall( r.TestDAppV2EVMAddr, amount, r.EncodeERC20CallRevert(r.ERC20Addr, amount), diff --git a/e2e/e2etests/test_v2_eth_withdraw_and_arbitrary_call.go b/e2e/e2etests/test_v2_eth_withdraw_and_arbitrary_call.go index 932034d963..b290e33fcb 100644 --- a/e2e/e2etests/test_v2_eth_withdraw_and_arbitrary_call.go +++ b/e2e/e2etests/test_v2_eth_withdraw_and_arbitrary_call.go @@ -24,7 +24,7 @@ func TestV2ETHWithdrawAndArbitraryCall(r *runner.E2ERunner, args []string) { r.ApproveETHZRC20(r.GatewayZEVMAddr) // perform the withdraw - tx := r.V2ETHWithdrawAndCall( + tx := r.V2ETHWithdrawAndArbitraryCall( r.TestDAppV2EVMAddr, amount, r.EncodeGasCall(payloadMessageWithdrawETH), diff --git a/e2e/e2etests/test_v2_eth_withdraw_and_call.go b/e2e/e2etests/test_v2_eth_withdraw_and_call.go index de0cadabcf..bffd037e72 100644 --- a/e2e/e2etests/test_v2_eth_withdraw_and_call.go +++ b/e2e/e2etests/test_v2_eth_withdraw_and_call.go @@ -30,13 +30,8 @@ func TestV2ETHWithdrawAndCall(r *runner.E2ERunner, args []string) { r.ApproveETHZRC20(r.GatewayZEVMAddr) - // set expected sender - tx, err := r.TestDAppV2EVM.SetExpectedOnCallSender(r.EVMAuth, r.ZEVMAuth.From) - require.NoError(r, err) - utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - // perform the withdraw - tx = r.V2ETHWithdrawAndAuthenticatedCall( + tx := r.V2ETHWithdrawAndCall( r.TestDAppV2EVMAddr, amount, []byte(payloadMessageAuthenticatedWithdrawETH), diff --git a/e2e/e2etests/test_v2_eth_withdraw_and_call_revert.go b/e2e/e2etests/test_v2_eth_withdraw_and_call_revert.go index 6df64c9a69..bfa0172e7b 100644 --- a/e2e/e2etests/test_v2_eth_withdraw_and_call_revert.go +++ b/e2e/e2etests/test_v2_eth_withdraw_and_call_revert.go @@ -28,10 +28,15 @@ func TestV2ETHWithdrawAndCallRevert(r *runner.E2ERunner, args []string) { require.EqualValues(r, int64(0), balance.Int64()) // perform the withdraw - tx := r.V2ETHWithdrawAndCall(r.TestDAppV2EVMAddr, amount, r.EncodeGasCall("revert"), gatewayzevm.RevertOptions{ - RevertAddress: revertAddress, - OnRevertGasLimit: big.NewInt(0), - }) + tx := r.V2ETHWithdrawAndArbitraryCall( + r.TestDAppV2EVMAddr, + amount, + r.EncodeGasCall("revert"), + gatewayzevm.RevertOptions{ + RevertAddress: revertAddress, + OnRevertGasLimit: big.NewInt(0), + }, + ) // wait for the cctx to be mined cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) diff --git a/e2e/e2etests/test_v2_eth_withdraw_and_call_revert_with_call.go b/e2e/e2etests/test_v2_eth_withdraw_and_call_revert_with_call.go index f4d31d5d14..f613ebffc2 100644 --- a/e2e/e2etests/test_v2_eth_withdraw_and_call_revert_with_call.go +++ b/e2e/e2etests/test_v2_eth_withdraw_and_call_revert_with_call.go @@ -25,7 +25,7 @@ func TestV2ETHWithdrawAndCallRevertWithCall(r *runner.E2ERunner, args []string) r.ApproveETHZRC20(r.GatewayZEVMAddr) // perform the withdraw - tx := r.V2ETHWithdrawAndCall( + tx := r.V2ETHWithdrawAndArbitraryCall( r.TestDAppV2EVMAddr, amount, r.EncodeGasCall("revert"), diff --git a/e2e/e2etests/test_v2_eth_withdraw_and_call_through_contract.go b/e2e/e2etests/test_v2_eth_withdraw_and_call_through_contract.go index f2d4949032..28c36ee69d 100644 --- a/e2e/e2etests/test_v2_eth_withdraw_and_call_through_contract.go +++ b/e2e/e2etests/test_v2_eth_withdraw_and_call_through_contract.go @@ -40,13 +40,8 @@ func TestV2ETHWithdrawAndCallThroughContract(r *runner.E2ERunner, args []string) require.NoError(r, err) utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - // set expected sender - tx, err = r.TestDAppV2EVM.SetExpectedOnCallSender(r.EVMAuth, gatewayCallerAddr) - require.NoError(r, err) - utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - // perform the authenticated call - tx = r.V2ETHWithdrawAndAuthenticatedCallThroughContract(gatewayCaller, r.TestDAppV2EVMAddr, + tx = r.V2ETHWithdrawAndCallThroughContract(gatewayCaller, r.TestDAppV2EVMAddr, amount, []byte(payloadMessageAuthenticatedWithdrawETHThroughContract), gatewayzevmcaller.RevertOptions{OnRevertGasLimit: big.NewInt(0)}) @@ -65,20 +60,4 @@ func TestV2ETHWithdrawAndCallThroughContract(r *runner.E2ERunner, args []string) ) require.NoError(r, err) require.Equal(r, gatewayCallerAddr, senderForMsg) - - // set expected sender to wrong one - tx, err = r.TestDAppV2EVM.SetExpectedOnCallSender(r.EVMAuth, r.ZEVMAuth.From) - require.NoError(r, err) - utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - - // repeat authenticated call through contract, should revert because of wrong sender - tx = r.V2ETHWithdrawAndAuthenticatedCallThroughContract(gatewayCaller, r.TestDAppV2EVMAddr, - amount, - []byte(payloadMessageAuthenticatedWithdrawETHThroughContract), - gatewayzevmcaller.RevertOptions{OnRevertGasLimit: big.NewInt(0)}) - - utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - cctx = utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - r.Logger.CCTX(*cctx, "withdraw") - require.Equal(r, crosschaintypes.CctxStatus_Reverted, cctx.CctxStatus.Status) } diff --git a/e2e/e2etests/test_v2_zevm_to_evm_arbitrary_call.go b/e2e/e2etests/test_v2_zevm_to_evm_arbitrary_call.go index 21104767f9..4b722fc4ae 100644 --- a/e2e/e2etests/test_v2_zevm_to_evm_arbitrary_call.go +++ b/e2e/e2etests/test_v2_zevm_to_evm_arbitrary_call.go @@ -22,9 +22,13 @@ func TestV2ZEVMToEVMArbitraryCall(r *runner.E2ERunner, args []string) { r.ApproveETHZRC20(r.GatewayZEVMAddr) // perform the call - tx := r.V2ZEVMToEMVCall(r.TestDAppV2EVMAddr, r.EncodeSimpleCall(payloadMessageEVMCall), gatewayzevm.RevertOptions{ - OnRevertGasLimit: big.NewInt(0), - }) + tx := r.V2ZEVMToEMVArbitraryCall( + r.TestDAppV2EVMAddr, + r.EncodeSimpleCall(payloadMessageEVMCall), + gatewayzevm.RevertOptions{ + OnRevertGasLimit: big.NewInt(0), + }, + ) // wait for the cctx to be mined cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) diff --git a/e2e/e2etests/test_v2_zevm_to_evm_call.go b/e2e/e2etests/test_v2_zevm_to_evm_call.go index ba9d5fba6f..9641778e3c 100644 --- a/e2e/e2etests/test_v2_zevm_to_evm_call.go +++ b/e2e/e2etests/test_v2_zevm_to_evm_call.go @@ -22,13 +22,8 @@ func TestV2ZEVMToEVMCall(r *runner.E2ERunner, args []string) { // necessary approval for fee payment r.ApproveETHZRC20(r.GatewayZEVMAddr) - // set expected sender - tx, err := r.TestDAppV2EVM.SetExpectedOnCallSender(r.EVMAuth, r.ZEVMAuth.From) - require.NoError(r, err) - utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - // perform the authenticated call - tx = r.V2ZEVMToEMVAuthenticatedCall( + tx := r.V2ZEVMToEMVCall( r.TestDAppV2EVMAddr, []byte(payloadMessageEVMAuthenticatedCall), gatewayzevm.RevertOptions{ diff --git a/e2e/e2etests/test_v2_zevm_to_evm_call_through_contract.go b/e2e/e2etests/test_v2_zevm_to_evm_call_through_contract.go index a46b9f09f9..7ff9158365 100644 --- a/e2e/e2etests/test_v2_zevm_to_evm_call_through_contract.go +++ b/e2e/e2etests/test_v2_zevm_to_evm_call_through_contract.go @@ -33,13 +33,8 @@ func TestV2ZEVMToEVMCallThroughContract(r *runner.E2ERunner, args []string) { require.NoError(r, err) utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - // set expected sender - tx, err = r.TestDAppV2EVM.SetExpectedOnCallSender(r.EVMAuth, gatewayCallerAddr) - require.NoError(r, err) - utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - // perform the authenticated call - tx = r.V2ZEVMToEMVAuthenticatedCallThroughContract( + tx = r.V2ZEVMToEMVCallThroughContract( gatewayCaller, r.TestDAppV2EVMAddr, []byte(payloadMessageEVMAuthenticatedCallThroughContract), @@ -61,23 +56,4 @@ func TestV2ZEVMToEVMCallThroughContract(r *runner.E2ERunner, args []string) { ) require.NoError(r, err) require.Equal(r, gatewayCallerAddr, senderForMsg) - - // set expected sender to wrong one - tx, err = r.TestDAppV2EVM.SetExpectedOnCallSender(r.EVMAuth, r.ZEVMAuth.From) - require.NoError(r, err) - utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, tx, r.Logger, r.ReceiptTimeout) - - // repeat authenticated call through contract, should revert because of wrong sender - tx = r.V2ZEVMToEMVAuthenticatedCallThroughContract( - gatewayCaller, - r.TestDAppV2EVMAddr, - []byte(payloadMessageEVMAuthenticatedCallThroughContract), - gatewayzevmcaller.RevertOptions{ - OnRevertGasLimit: big.NewInt(0), - }, - ) - utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - cctx = utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - r.Logger.CCTX(*cctx, "call") - require.Equal(r, crosschaintypes.CctxStatus_Reverted, cctx.CctxStatus.Status) } diff --git a/e2e/runner/v2_zevm.go b/e2e/runner/v2_zevm.go index 4824884bd0..5153f2c823 100644 --- a/e2e/runner/v2_zevm.go +++ b/e2e/runner/v2_zevm.go @@ -31,20 +31,20 @@ func (r *E2ERunner) V2ETHWithdraw( return tx } -// V2ETHWithdrawAndCall calls WithdrawAndCall of Gateway with gas token on ZEVM -func (r *E2ERunner) V2ETHWithdrawAndCall( +// V2ETHWithdrawAndCall calls WithdrawAndCall of Gateway with gas token on ZEVM using arbitrary call +func (r *E2ERunner) V2ETHWithdrawAndArbitraryCall( receiver ethcommon.Address, amount *big.Int, payload []byte, revertOptions gatewayzevm.RevertOptions, ) *ethtypes.Transaction { - tx, err := r.GatewayZEVM.WithdrawAndCall( + tx, err := r.GatewayZEVM.WithdrawAndCall0( r.ZEVMAuth, receiver.Bytes(), amount, r.ETHZRC20Addr, payload, - gasLimit, + gatewayzevm.CallOptions{GasLimit: gasLimit, IsArbitraryCall: true}, revertOptions, ) require.NoError(r, err) @@ -53,13 +53,13 @@ func (r *E2ERunner) V2ETHWithdrawAndCall( } // V2ETHWithdrawAndCall calls WithdrawAndCall of Gateway with gas token on ZEVM using authenticated call -func (r *E2ERunner) V2ETHWithdrawAndAuthenticatedCall( +func (r *E2ERunner) V2ETHWithdrawAndCall( receiver ethcommon.Address, amount *big.Int, payload []byte, revertOptions gatewayzevm.RevertOptions, ) *ethtypes.Transaction { - tx, err := r.GatewayZEVM.WithdrawAndCall2( + tx, err := r.GatewayZEVM.WithdrawAndCall0( r.ZEVMAuth, receiver.Bytes(), amount, @@ -78,7 +78,7 @@ func (r *E2ERunner) V2ETHWithdrawAndAuthenticatedCall( // V2ETHWithdrawAndCall calls WithdrawAndCall of Gateway with gas token on ZEVM using authenticated call // through contract -func (r *E2ERunner) V2ETHWithdrawAndAuthenticatedCallThroughContract( +func (r *E2ERunner) V2ETHWithdrawAndCallThroughContract( gatewayZEVMCaller *gatewayzevmcaller.GatewayZEVMCaller, receiver ethcommon.Address, amount *big.Int, @@ -120,7 +120,36 @@ func (r *E2ERunner) V2ERC20Withdraw( return tx } -// V2ERC20WithdrawAndCall calls WithdrawAndCall of Gateway with erc20 token on ZEVM +// V2ERC20WithdrawAndCall calls WithdrawAndCall of Gateway with erc20 token on ZEVM using arbitrary call +func (r *E2ERunner) V2ERC20WithdrawAndArbitraryCall( + receiver ethcommon.Address, + amount *big.Int, + payload []byte, + revertOptions gatewayzevm.RevertOptions, +) *ethtypes.Transaction { + // this function take more gas than default 500k + // so we need to increase the gas limit + previousGasLimit := r.ZEVMAuth.GasLimit + r.ZEVMAuth.GasLimit = 10000000 + defer func() { + r.ZEVMAuth.GasLimit = previousGasLimit + }() + + tx, err := r.GatewayZEVM.WithdrawAndCall0( + r.ZEVMAuth, + receiver.Bytes(), + amount, + r.ERC20ZRC20Addr, + payload, + gatewayzevm.CallOptions{GasLimit: gasLimit, IsArbitraryCall: true}, + revertOptions, + ) + require.NoError(r, err) + + return tx +} + +// V2ERC20WithdrawAndCall calls WithdrawAndCall of Gateway with erc20 token on ZEVM using authenticated call func (r *E2ERunner) V2ERC20WithdrawAndCall( receiver ethcommon.Address, amount *big.Int, @@ -135,13 +164,13 @@ func (r *E2ERunner) V2ERC20WithdrawAndCall( r.ZEVMAuth.GasLimit = previousGasLimit }() - tx, err := r.GatewayZEVM.WithdrawAndCall( + tx, err := r.GatewayZEVM.WithdrawAndCall0( r.ZEVMAuth, receiver.Bytes(), amount, r.ERC20ZRC20Addr, payload, - gasLimit, + gatewayzevm.CallOptions{GasLimit: gasLimit, IsArbitraryCall: false}, revertOptions, ) require.NoError(r, err) @@ -149,18 +178,18 @@ func (r *E2ERunner) V2ERC20WithdrawAndCall( return tx } -// V2ZEVMToEMVCall calls Call of Gateway on ZEVM -func (r *E2ERunner) V2ZEVMToEMVCall( +// V2ZEVMToEMVCall calls Call of Gateway on ZEVM using arbitrary call +func (r *E2ERunner) V2ZEVMToEMVArbitraryCall( receiver ethcommon.Address, payload []byte, revertOptions gatewayzevm.RevertOptions, ) *ethtypes.Transaction { - tx, err := r.GatewayZEVM.Call0( + tx, err := r.GatewayZEVM.Call( r.ZEVMAuth, receiver.Bytes(), r.ETHZRC20Addr, payload, - gasLimit, + gatewayzevm.CallOptions{GasLimit: gasLimit, IsArbitraryCall: true}, revertOptions, ) require.NoError(r, err) @@ -168,8 +197,8 @@ func (r *E2ERunner) V2ZEVMToEMVCall( return tx } -// V2ZEVMToEMVCall calls authenticated Call of Gateway on ZEVM -func (r *E2ERunner) V2ZEVMToEMVAuthenticatedCall( +// V2ZEVMToEMVCall calls authenticated Call of Gateway on ZEVM using authenticated call +func (r *E2ERunner) V2ZEVMToEMVCall( receiver ethcommon.Address, payload []byte, revertOptions gatewayzevm.RevertOptions, @@ -190,8 +219,8 @@ func (r *E2ERunner) V2ZEVMToEMVAuthenticatedCall( return tx } -// V2ZEVMToEMVCall calls authenticated Call of Gateway on ZEVM through contract -func (r *E2ERunner) V2ZEVMToEMVAuthenticatedCallThroughContract( +// V2ZEVMToEMVCall calls authenticated Call of Gateway on ZEVM through contract using authenticated call +func (r *E2ERunner) V2ZEVMToEMVCallThroughContract( gatewayZEVMCaller *gatewayzevmcaller.GatewayZEVMCaller, receiver ethcommon.Address, payload []byte, diff --git a/go.mod b/go.mod index cb746a49bf..faa6709809 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/zeta-chain/ethermint v0.0.0-20241010181243-044e22bdb7e7 github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 - github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241014093550-f7f6d9fd971a + github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241016134610-c70fec4d66a6 gitlab.com/thorchain/tss/go-tss v1.6.5 go.nhat.io/grpcmock v0.25.0 golang.org/x/crypto v0.23.0 diff --git a/go.sum b/go.sum index 8842365a96..8f884485e3 100644 --- a/go.sum +++ b/go.sum @@ -4208,8 +4208,8 @@ github.com/zeta-chain/go-tss v0.0.0-20240916173049-89fee4b0ae7f h1:XqUvw9a3EnDa2 github.com/zeta-chain/go-tss v0.0.0-20240916173049-89fee4b0ae7f/go.mod h1:B1FDE6kHs8hozKSX1/iXgCdvlFbS6+FeAupoBHDK0Cc= github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 h1:vck/FcIIpFOvpBUm0NO17jbEtmSz/W/a5Y4jRuSJl6I= github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138/go.mod h1:U494OsZTWsU75hqoriZgMdSsgSGP1mUL1jX+wN/Aez8= -github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241014093550-f7f6d9fd971a h1:xsup+oupCrBtZT/jEaBGcL3k6KUlXWR7iXw/3RHBIpU= -github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241014093550-f7f6d9fd971a/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w= +github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241016134610-c70fec4d66a6 h1:9xfE77UtF316hcsX7H2/OjROWtxBZyk8k1sQN3exIVM= +github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241016134610-c70fec4d66a6/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w= github.com/zeta-chain/tss-lib v0.0.0-20240916163010-2e6b438bd901 h1:9whtN5fjYHfk4yXIuAsYP2EHxImwDWDVUOnZJ2pfL3w= github.com/zeta-chain/tss-lib v0.0.0-20240916163010-2e6b438bd901/go.mod h1:d2iTC62s9JwKiCMPhcDDXbIZmuzAyJ4lwso0H5QyRbk= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= diff --git a/pkg/contracts/testdappv2/TestDAppV2.abi b/pkg/contracts/testdappv2/TestDAppV2.abi index 95618cf9db..c2846866a1 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.abi +++ b/pkg/contracts/testdappv2/TestDAppV2.abi @@ -60,19 +60,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "expectedOnCallSender", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -124,37 +111,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "internalType": "struct TestDAppV2.MessageContext", - "name": "messageContext", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "message", - "type": "bytes" - } - ], - "name": "onCall", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "function" - }, { "inputs": [ { @@ -195,11 +151,42 @@ "type": "bytes" } ], - "name": "onCrossChainCall", + "name": "onCall", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "internalType": "struct TestDAppV2.MessageContext", + "name": "messageContext", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + } + ], + "name": "onCall", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -254,19 +241,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "_expectedOnCallSender", - "type": "address" - } - ], - "name": "setExpectedOnCallSender", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { diff --git a/pkg/contracts/testdappv2/TestDAppV2.bin b/pkg/contracts/testdappv2/TestDAppV2.bin index 1c087ef1b5..d5b99ed321 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.bin +++ b/pkg/contracts/testdappv2/TestDAppV2.bin @@ -1 +1 @@ -608060405234801561001057600080fd5b5061150a806100206000396000f3fe6080604052600436106100c65760003560e01c8063c234fecf1161007f578063de43156e11610059578063de43156e14610267578063e2842ed714610290578063f592cbfb146102cd578063f936ae851461030a576100cd565b8063c234fecf146101ec578063c7a339a914610215578063c9028a361461023e576100cd565b806336e980a0146100d25780634297a263146100fb57806359f4a77714610138578063676cc054146101635780639291fe2614610193578063a799911f146101d0576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610de7565b610347565b005b34801561010757600080fd5b50610122600480360381019061011d9190610d02565b610371565b60405161012f9190611173565b60405180910390f35b34801561014457600080fd5b5061014d610389565b60405161015a91906110c4565b60405180910390f35b61017d60048036038101906101789190610e30565b6103ad565b60405161018a9190611131565b60405180910390f35b34801561019f57600080fd5b506101ba60048036038101906101b59190610de7565b610562565b6040516101c79190611173565b60405180910390f35b6101ea60048036038101906101e59190610de7565b6105a5565b005b3480156101f857600080fd5b50610213600480360381019061020e9190610ca8565b6105ce565b005b34801561022157600080fd5b5061023c60048036038101906102379190610d78565b610611565b005b34801561024a57600080fd5b5061026560048036038101906102609190610e90565b6106d4565b005b34801561027357600080fd5b5061028e60048036038101906102899190610ed9565b61080e565b005b34801561029c57600080fd5b506102b760048036038101906102b29190610d02565b610907565b6040516102c49190611116565b60405180910390f35b3480156102d957600080fd5b506102f460048036038101906102ef9190610de7565b610927565b6040516103019190611116565b60405180910390f35b34801561031657600080fd5b50610331600480360381019061032c9190610d2f565b610977565b60405161033e91906110c4565b60405180910390f35b610350816109c0565b1561035a57600080fd5b61036381610a16565b61036e816000610a6a565b50565b60036020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160208101906103f99190610ca8565b73ffffffffffffffffffffffffffffffffffffffff161461044f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044690611153565b60405180910390fd5b61049c83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b6104ea83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505034610a6a565b8360000160208101906104fd9190610ca8565b6002848460405161050f92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060036000836040516020016105799190611098565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105ae816109c0565b156105b857600080fd5b6105c181610a16565b6105cb8134610a6a565b50565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61061a816109c0565b1561062457600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b8152600401610661939291906110df565b602060405180830381600087803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190610cd5565b6106bc57600080fd5b6106c581610a16565b6106cf8183610a6a565b505050565b61072f8180606001906106e7919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61078c818060600190610742919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000610a6a565b80600001602081019061079f9190610ca8565b60028280606001906107b1919061118e565b6040516107bf92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61085b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506109c0565b1561086557600080fd5b6108b282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61090082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a6a565b5050505050565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600160008360405160200161093e9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6002818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040516020016109d1906110af565b60405160208183030381529060405280519060200120826040516020016109f89190611098565b60405160208183030381529060405280519060200120149050919050565b600180600083604051602001610a2c9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806003600084604051602001610a809190611098565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000610abf610aba84611216565b6111f1565b905082815260208101848484011115610adb57610ada6113ef565b5b610ae684828561132a565b509392505050565b6000610b01610afc84611247565b6111f1565b905082815260208101848484011115610b1d57610b1c6113ef565b5b610b2884828561132a565b509392505050565b600081359050610b3f81611461565b92915050565b600081519050610b5481611478565b92915050565b600081359050610b698161148f565b92915050565b60008083601f840112610b8557610b846113d1565b5b8235905067ffffffffffffffff811115610ba257610ba16113cc565b5b602083019150836001820283011115610bbe57610bbd6113e5565b5b9250929050565b600082601f830112610bda57610bd96113d1565b5b8135610bea848260208601610aac565b91505092915050565b600081359050610c02816114a6565b92915050565b600082601f830112610c1d57610c1c6113d1565b5b8135610c2d848260208601610aee565b91505092915050565b600060208284031215610c4c57610c4b6113db565b5b81905092915050565b600060808284031215610c6b57610c6a6113db565b5b81905092915050565b600060608284031215610c8a57610c896113db565b5b81905092915050565b600081359050610ca2816114bd565b92915050565b600060208284031215610cbe57610cbd6113f9565b5b6000610ccc84828501610b30565b91505092915050565b600060208284031215610ceb57610cea6113f9565b5b6000610cf984828501610b45565b91505092915050565b600060208284031215610d1857610d176113f9565b5b6000610d2684828501610b5a565b91505092915050565b600060208284031215610d4557610d446113f9565b5b600082013567ffffffffffffffff811115610d6357610d626113f4565b5b610d6f84828501610bc5565b91505092915050565b600080600060608486031215610d9157610d906113f9565b5b6000610d9f86828701610bf3565b9350506020610db086828701610c93565b925050604084013567ffffffffffffffff811115610dd157610dd06113f4565b5b610ddd86828701610c08565b9150509250925092565b600060208284031215610dfd57610dfc6113f9565b5b600082013567ffffffffffffffff811115610e1b57610e1a6113f4565b5b610e2784828501610c08565b91505092915050565b600080600060408486031215610e4957610e486113f9565b5b6000610e5786828701610c36565b935050602084013567ffffffffffffffff811115610e7857610e776113f4565b5b610e8486828701610b6f565b92509250509250925092565b600060208284031215610ea657610ea56113f9565b5b600082013567ffffffffffffffff811115610ec457610ec36113f4565b5b610ed084828501610c55565b91505092915050565b600080600080600060808688031215610ef557610ef46113f9565b5b600086013567ffffffffffffffff811115610f1357610f126113f4565b5b610f1f88828901610c74565b9550506020610f3088828901610b30565b9450506040610f4188828901610c93565b935050606086013567ffffffffffffffff811115610f6257610f616113f4565b5b610f6e88828901610b6f565b92509250509295509295909350565b610f86816112c6565b82525050565b610f95816112d8565b82525050565b6000610fa7838561129f565b9350610fb483858461132a565b82840190509392505050565b6000610fcb82611278565b610fd5818561128e565b9350610fe5818560208601611339565b610fee816113fe565b840191505092915050565b600061100482611283565b61100e81856112bb565b935061101e818560208601611339565b80840191505092915050565b60006110376016836112aa565b91506110428261140f565b602082019050919050565b600061105a6006836112bb565b915061106582611438565b600682019050919050565b61107981611320565b82525050565b600061108c828486610f9b565b91508190509392505050565b60006110a48284610ff9565b915081905092915050565b60006110ba8261104d565b9150819050919050565b60006020820190506110d96000830184610f7d565b92915050565b60006060820190506110f46000830186610f7d565b6111016020830185610f7d565b61110e6040830184611070565b949350505050565b600060208201905061112b6000830184610f8c565b92915050565b6000602082019050818103600083015261114b8184610fc0565b905092915050565b6000602082019050818103600083015261116c8161102a565b9050919050565b60006020820190506111886000830184611070565b92915050565b600080833560016020038436030381126111ab576111aa6113e0565b5b80840192508235915067ffffffffffffffff8211156111cd576111cc6113d6565b5b6020830192506001820236038313156111e9576111e86113ea565b5b509250929050565b60006111fb61120c565b9050611207828261136c565b919050565b6000604051905090565b600067ffffffffffffffff8211156112315761123061139d565b5b61123a826113fe565b9050602081019050919050565b600067ffffffffffffffff8211156112625761126161139d565b5b61126b826113fe565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006112d182611300565b9050919050565b60008115159050919050565b6000819050919050565b60006112f9826112c6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561135757808201518184015260208101905061133c565b83811115611366576000848401525b50505050565b611375826113fe565b810181811067ffffffffffffffff821117156113945761139361139d565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f756e61757468656e746963617465642073656e64657200000000000000000000600082015250565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61146a816112c6565b811461147557600080fd5b50565b611481816112d8565b811461148c57600080fd5b50565b611498816112e4565b81146114a357600080fd5b50565b6114af816112ee565b81146114ba57600080fd5b50565b6114c681611320565b81146114d157600080fd5b5056fea2646970667358221220da9e50cb7b79ace99166ed06c9234f984bc9599fca79796389af6656411f73f964736f6c63430008070033 +608060405234801561001057600080fd5b5061130b806100206000396000f3fe6080604052600436106100a05760003560e01c8063a799911f11610064578063a799911f146101a8578063c7a339a9146101c4578063c9028a36146101ed578063e2842ed714610216578063f592cbfb14610253578063f936ae8514610290576100a7565b806336e980a0146100ac5780634297a263146100d55780635bcfd61614610112578063676cc0541461013b5780639291fe261461016b576100a7565b366100a757005b600080fd5b3480156100b857600080fd5b506100d360048036038101906100ce9190610c65565b6102cd565b005b3480156100e157600080fd5b506100fc60048036038101906100f79190610b80565b6102f7565b6040516101099190610fae565b60405180910390f35b34801561011e57600080fd5b5061013960048036038101906101349190610d57565b61030f565b005b61015560048036038101906101509190610cae565b610408565b6040516101629190610f8c565b60405180910390f35b34801561017757600080fd5b50610192600480360381019061018d9190610c65565b61051d565b60405161019f9190610fae565b60405180910390f35b6101c260048036038101906101bd9190610c65565b610560565b005b3480156101d057600080fd5b506101eb60048036038101906101e69190610bf6565b610589565b005b3480156101f957600080fd5b50610214600480360381019061020f9190610d0e565b61064c565b005b34801561022257600080fd5b5061023d60048036038101906102389190610b80565b610786565b60405161024a9190610f71565b60405180910390f35b34801561025f57600080fd5b5061027a60048036038101906102759190610c65565b6107a6565b6040516102879190610f71565b60405180910390f35b34801561029c57600080fd5b506102b760048036038101906102b29190610bad565b6107f5565b6040516102c49190610f1f565b60405180910390f35b6102d68161083e565b156102e057600080fd5b6102e981610894565b6102f48160006108e8565b50565b60026020528060005260406000206000915090505481565b61035c82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061083e565b1561036657600080fd5b6103b382828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b61040182828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050846108e8565b5050505050565b606061045783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6104a583838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050346108e8565b8360000160208101906104b89190610b26565b600184846040516104ca929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060026000836040516020016105349190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105698161083e565b1561057357600080fd5b61057c81610894565b61058681346108e8565b50565b6105928161083e565b1561059c57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016105d993929190610f3a565b602060405180830381600087803b1580156105f357600080fd5b505af1158015610607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062b9190610b53565b61063457600080fd5b61063d81610894565b61064781836108e8565b505050565b6106a781806060019061065f9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6107048180606001906106ba9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060006108e8565b8060000160208101906107179190610b26565b60018280606001906107299190610fc9565b604051610737929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000836040516020016107bc9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6001818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060405160200161084f90610f0a565b60405160208183030381529060405280519060200120826040516020016108769190610ef3565b60405160208183030381529060405280519060200120149050919050565b6001600080836040516020016108aa9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b8060026000846040516020016108fe9190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b600061093d61093884611051565b61102c565b90508281526020810184848401111561095957610958611219565b5b610964848285611154565b509392505050565b600061097f61097a84611082565b61102c565b90508281526020810184848401111561099b5761099a611219565b5b6109a6848285611154565b509392505050565b6000813590506109bd81611262565b92915050565b6000815190506109d281611279565b92915050565b6000813590506109e781611290565b92915050565b60008083601f840112610a0357610a026111fb565b5b8235905067ffffffffffffffff811115610a2057610a1f6111f6565b5b602083019150836001820283011115610a3c57610a3b61120f565b5b9250929050565b600082601f830112610a5857610a576111fb565b5b8135610a6884826020860161092a565b91505092915050565b600081359050610a80816112a7565b92915050565b600082601f830112610a9b57610a9a6111fb565b5b8135610aab84826020860161096c565b91505092915050565b600060208284031215610aca57610ac9611205565b5b81905092915050565b600060808284031215610ae957610ae8611205565b5b81905092915050565b600060608284031215610b0857610b07611205565b5b81905092915050565b600081359050610b20816112be565b92915050565b600060208284031215610b3c57610b3b611223565b5b6000610b4a848285016109ae565b91505092915050565b600060208284031215610b6957610b68611223565b5b6000610b77848285016109c3565b91505092915050565b600060208284031215610b9657610b95611223565b5b6000610ba4848285016109d8565b91505092915050565b600060208284031215610bc357610bc2611223565b5b600082013567ffffffffffffffff811115610be157610be061121e565b5b610bed84828501610a43565b91505092915050565b600080600060608486031215610c0f57610c0e611223565b5b6000610c1d86828701610a71565b9350506020610c2e86828701610b11565b925050604084013567ffffffffffffffff811115610c4f57610c4e61121e565b5b610c5b86828701610a86565b9150509250925092565b600060208284031215610c7b57610c7a611223565b5b600082013567ffffffffffffffff811115610c9957610c9861121e565b5b610ca584828501610a86565b91505092915050565b600080600060408486031215610cc757610cc6611223565b5b6000610cd586828701610ab4565b935050602084013567ffffffffffffffff811115610cf657610cf561121e565b5b610d02868287016109ed565b92509250509250925092565b600060208284031215610d2457610d23611223565b5b600082013567ffffffffffffffff811115610d4257610d4161121e565b5b610d4e84828501610ad3565b91505092915050565b600080600080600060808688031215610d7357610d72611223565b5b600086013567ffffffffffffffff811115610d9157610d9061121e565b5b610d9d88828901610af2565b9550506020610dae888289016109ae565b9450506040610dbf88828901610b11565b935050606086013567ffffffffffffffff811115610de057610ddf61121e565b5b610dec888289016109ed565b92509250509295509295909350565b610e04816110f0565b82525050565b610e1381611102565b82525050565b6000610e2583856110da565b9350610e32838584611154565b82840190509392505050565b6000610e49826110b3565b610e5381856110c9565b9350610e63818560208601611163565b610e6c81611228565b840191505092915050565b6000610e82826110be565b610e8c81856110e5565b9350610e9c818560208601611163565b80840191505092915050565b6000610eb56006836110e5565b9150610ec082611239565b600682019050919050565b610ed48161114a565b82525050565b6000610ee7828486610e19565b91508190509392505050565b6000610eff8284610e77565b915081905092915050565b6000610f1582610ea8565b9150819050919050565b6000602082019050610f346000830184610dfb565b92915050565b6000606082019050610f4f6000830186610dfb565b610f5c6020830185610dfb565b610f696040830184610ecb565b949350505050565b6000602082019050610f866000830184610e0a565b92915050565b60006020820190508181036000830152610fa68184610e3e565b905092915050565b6000602082019050610fc36000830184610ecb565b92915050565b60008083356001602003843603038112610fe657610fe561120a565b5b80840192508235915067ffffffffffffffff82111561100857611007611200565b5b60208301925060018202360383131561102457611023611214565b5b509250929050565b6000611036611047565b90506110428282611196565b919050565b6000604051905090565b600067ffffffffffffffff82111561106c5761106b6111c7565b5b61107582611228565b9050602081019050919050565b600067ffffffffffffffff82111561109d5761109c6111c7565b5b6110a682611228565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600081905092915050565b60006110fb8261112a565b9050919050565b60008115159050919050565b6000819050919050565b6000611123826110f0565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015611181578082015181840152602081019050611166565b83811115611190576000848401525b50505050565b61119f82611228565b810181811067ffffffffffffffff821117156111be576111bd6111c7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61126b816110f0565b811461127657600080fd5b50565b61128281611102565b811461128d57600080fd5b50565b6112998161110e565b81146112a457600080fd5b50565b6112b081611118565b81146112bb57600080fd5b50565b6112c78161114a565b81146112d257600080fd5b5056fea26469706673582212201f295f137d0ea146883fdaa6858baa14e4c467a843ff4e7829fd9df0d4c2aede64736f6c63430008070033 diff --git a/pkg/contracts/testdappv2/TestDAppV2.go b/pkg/contracts/testdappv2/TestDAppV2.go index 5c32fe96f8..967c261e60 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.go +++ b/pkg/contracts/testdappv2/TestDAppV2.go @@ -51,8 +51,8 @@ type TestDAppV2zContext struct { // TestDAppV2MetaData contains all meta data concerning the TestDAppV2 contract. var TestDAppV2MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"amountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"calledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"erc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"erc20Call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"expectedOnCallSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"gasCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getAmountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getCalledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"internalType\":\"structTestDAppV2.MessageContext\",\"name\":\"messageContext\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"origin\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainID\",\"type\":\"uint256\"}],\"internalType\":\"structTestDAppV2.zContext\",\"name\":\"_context\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_zrc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCrossChainCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"revertMessage\",\"type\":\"bytes\"}],\"internalType\":\"structTestDAppV2.RevertContext\",\"name\":\"revertContext\",\"type\":\"tuple\"}],\"name\":\"onRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"senderWithMessage\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_expectedOnCallSender\",\"type\":\"address\"}],\"name\":\"setExpectedOnCallSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"simpleCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x608060405234801561001057600080fd5b5061150a806100206000396000f3fe6080604052600436106100c65760003560e01c8063c234fecf1161007f578063de43156e11610059578063de43156e14610267578063e2842ed714610290578063f592cbfb146102cd578063f936ae851461030a576100cd565b8063c234fecf146101ec578063c7a339a914610215578063c9028a361461023e576100cd565b806336e980a0146100d25780634297a263146100fb57806359f4a77714610138578063676cc054146101635780639291fe2614610193578063a799911f146101d0576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610de7565b610347565b005b34801561010757600080fd5b50610122600480360381019061011d9190610d02565b610371565b60405161012f9190611173565b60405180910390f35b34801561014457600080fd5b5061014d610389565b60405161015a91906110c4565b60405180910390f35b61017d60048036038101906101789190610e30565b6103ad565b60405161018a9190611131565b60405180910390f35b34801561019f57600080fd5b506101ba60048036038101906101b59190610de7565b610562565b6040516101c79190611173565b60405180910390f35b6101ea60048036038101906101e59190610de7565b6105a5565b005b3480156101f857600080fd5b50610213600480360381019061020e9190610ca8565b6105ce565b005b34801561022157600080fd5b5061023c60048036038101906102379190610d78565b610611565b005b34801561024a57600080fd5b5061026560048036038101906102609190610e90565b6106d4565b005b34801561027357600080fd5b5061028e60048036038101906102899190610ed9565b61080e565b005b34801561029c57600080fd5b506102b760048036038101906102b29190610d02565b610907565b6040516102c49190611116565b60405180910390f35b3480156102d957600080fd5b506102f460048036038101906102ef9190610de7565b610927565b6040516103019190611116565b60405180910390f35b34801561031657600080fd5b50610331600480360381019061032c9190610d2f565b610977565b60405161033e91906110c4565b60405180910390f35b610350816109c0565b1561035a57600080fd5b61036381610a16565b61036e816000610a6a565b50565b60036020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160208101906103f99190610ca8565b73ffffffffffffffffffffffffffffffffffffffff161461044f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044690611153565b60405180910390fd5b61049c83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b6104ea83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505034610a6a565b8360000160208101906104fd9190610ca8565b6002848460405161050f92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060036000836040516020016105799190611098565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105ae816109c0565b156105b857600080fd5b6105c181610a16565b6105cb8134610a6a565b50565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61061a816109c0565b1561062457600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b8152600401610661939291906110df565b602060405180830381600087803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190610cd5565b6106bc57600080fd5b6106c581610a16565b6106cf8183610a6a565b505050565b61072f8180606001906106e7919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61078c818060600190610742919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000610a6a565b80600001602081019061079f9190610ca8565b60028280606001906107b1919061118e565b6040516107bf92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61085b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506109c0565b1561086557600080fd5b6108b282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61090082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a6a565b5050505050565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600160008360405160200161093e9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6002818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040516020016109d1906110af565b60405160208183030381529060405280519060200120826040516020016109f89190611098565b60405160208183030381529060405280519060200120149050919050565b600180600083604051602001610a2c9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806003600084604051602001610a809190611098565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000610abf610aba84611216565b6111f1565b905082815260208101848484011115610adb57610ada6113ef565b5b610ae684828561132a565b509392505050565b6000610b01610afc84611247565b6111f1565b905082815260208101848484011115610b1d57610b1c6113ef565b5b610b2884828561132a565b509392505050565b600081359050610b3f81611461565b92915050565b600081519050610b5481611478565b92915050565b600081359050610b698161148f565b92915050565b60008083601f840112610b8557610b846113d1565b5b8235905067ffffffffffffffff811115610ba257610ba16113cc565b5b602083019150836001820283011115610bbe57610bbd6113e5565b5b9250929050565b600082601f830112610bda57610bd96113d1565b5b8135610bea848260208601610aac565b91505092915050565b600081359050610c02816114a6565b92915050565b600082601f830112610c1d57610c1c6113d1565b5b8135610c2d848260208601610aee565b91505092915050565b600060208284031215610c4c57610c4b6113db565b5b81905092915050565b600060808284031215610c6b57610c6a6113db565b5b81905092915050565b600060608284031215610c8a57610c896113db565b5b81905092915050565b600081359050610ca2816114bd565b92915050565b600060208284031215610cbe57610cbd6113f9565b5b6000610ccc84828501610b30565b91505092915050565b600060208284031215610ceb57610cea6113f9565b5b6000610cf984828501610b45565b91505092915050565b600060208284031215610d1857610d176113f9565b5b6000610d2684828501610b5a565b91505092915050565b600060208284031215610d4557610d446113f9565b5b600082013567ffffffffffffffff811115610d6357610d626113f4565b5b610d6f84828501610bc5565b91505092915050565b600080600060608486031215610d9157610d906113f9565b5b6000610d9f86828701610bf3565b9350506020610db086828701610c93565b925050604084013567ffffffffffffffff811115610dd157610dd06113f4565b5b610ddd86828701610c08565b9150509250925092565b600060208284031215610dfd57610dfc6113f9565b5b600082013567ffffffffffffffff811115610e1b57610e1a6113f4565b5b610e2784828501610c08565b91505092915050565b600080600060408486031215610e4957610e486113f9565b5b6000610e5786828701610c36565b935050602084013567ffffffffffffffff811115610e7857610e776113f4565b5b610e8486828701610b6f565b92509250509250925092565b600060208284031215610ea657610ea56113f9565b5b600082013567ffffffffffffffff811115610ec457610ec36113f4565b5b610ed084828501610c55565b91505092915050565b600080600080600060808688031215610ef557610ef46113f9565b5b600086013567ffffffffffffffff811115610f1357610f126113f4565b5b610f1f88828901610c74565b9550506020610f3088828901610b30565b9450506040610f4188828901610c93565b935050606086013567ffffffffffffffff811115610f6257610f616113f4565b5b610f6e88828901610b6f565b92509250509295509295909350565b610f86816112c6565b82525050565b610f95816112d8565b82525050565b6000610fa7838561129f565b9350610fb483858461132a565b82840190509392505050565b6000610fcb82611278565b610fd5818561128e565b9350610fe5818560208601611339565b610fee816113fe565b840191505092915050565b600061100482611283565b61100e81856112bb565b935061101e818560208601611339565b80840191505092915050565b60006110376016836112aa565b91506110428261140f565b602082019050919050565b600061105a6006836112bb565b915061106582611438565b600682019050919050565b61107981611320565b82525050565b600061108c828486610f9b565b91508190509392505050565b60006110a48284610ff9565b915081905092915050565b60006110ba8261104d565b9150819050919050565b60006020820190506110d96000830184610f7d565b92915050565b60006060820190506110f46000830186610f7d565b6111016020830185610f7d565b61110e6040830184611070565b949350505050565b600060208201905061112b6000830184610f8c565b92915050565b6000602082019050818103600083015261114b8184610fc0565b905092915050565b6000602082019050818103600083015261116c8161102a565b9050919050565b60006020820190506111886000830184611070565b92915050565b600080833560016020038436030381126111ab576111aa6113e0565b5b80840192508235915067ffffffffffffffff8211156111cd576111cc6113d6565b5b6020830192506001820236038313156111e9576111e86113ea565b5b509250929050565b60006111fb61120c565b9050611207828261136c565b919050565b6000604051905090565b600067ffffffffffffffff8211156112315761123061139d565b5b61123a826113fe565b9050602081019050919050565b600067ffffffffffffffff8211156112625761126161139d565b5b61126b826113fe565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006112d182611300565b9050919050565b60008115159050919050565b6000819050919050565b60006112f9826112c6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561135757808201518184015260208101905061133c565b83811115611366576000848401525b50505050565b611375826113fe565b810181811067ffffffffffffffff821117156113945761139361139d565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f756e61757468656e746963617465642073656e64657200000000000000000000600082015250565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61146a816112c6565b811461147557600080fd5b50565b611481816112d8565b811461148c57600080fd5b50565b611498816112e4565b81146114a357600080fd5b50565b6114af816112ee565b81146114ba57600080fd5b50565b6114c681611320565b81146114d157600080fd5b5056fea2646970667358221220da9e50cb7b79ace99166ed06c9234f984bc9599fca79796389af6656411f73f964736f6c63430008070033", + ABI: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"amountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"calledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"erc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"erc20Call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"gasCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getAmountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getCalledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"origin\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainID\",\"type\":\"uint256\"}],\"internalType\":\"structTestDAppV2.zContext\",\"name\":\"_context\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_zrc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"internalType\":\"structTestDAppV2.MessageContext\",\"name\":\"messageContext\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"revertMessage\",\"type\":\"bytes\"}],\"internalType\":\"structTestDAppV2.RevertContext\",\"name\":\"revertContext\",\"type\":\"tuple\"}],\"name\":\"onRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"senderWithMessage\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"simpleCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x608060405234801561001057600080fd5b5061130b806100206000396000f3fe6080604052600436106100a05760003560e01c8063a799911f11610064578063a799911f146101a8578063c7a339a9146101c4578063c9028a36146101ed578063e2842ed714610216578063f592cbfb14610253578063f936ae8514610290576100a7565b806336e980a0146100ac5780634297a263146100d55780635bcfd61614610112578063676cc0541461013b5780639291fe261461016b576100a7565b366100a757005b600080fd5b3480156100b857600080fd5b506100d360048036038101906100ce9190610c65565b6102cd565b005b3480156100e157600080fd5b506100fc60048036038101906100f79190610b80565b6102f7565b6040516101099190610fae565b60405180910390f35b34801561011e57600080fd5b5061013960048036038101906101349190610d57565b61030f565b005b61015560048036038101906101509190610cae565b610408565b6040516101629190610f8c565b60405180910390f35b34801561017757600080fd5b50610192600480360381019061018d9190610c65565b61051d565b60405161019f9190610fae565b60405180910390f35b6101c260048036038101906101bd9190610c65565b610560565b005b3480156101d057600080fd5b506101eb60048036038101906101e69190610bf6565b610589565b005b3480156101f957600080fd5b50610214600480360381019061020f9190610d0e565b61064c565b005b34801561022257600080fd5b5061023d60048036038101906102389190610b80565b610786565b60405161024a9190610f71565b60405180910390f35b34801561025f57600080fd5b5061027a60048036038101906102759190610c65565b6107a6565b6040516102879190610f71565b60405180910390f35b34801561029c57600080fd5b506102b760048036038101906102b29190610bad565b6107f5565b6040516102c49190610f1f565b60405180910390f35b6102d68161083e565b156102e057600080fd5b6102e981610894565b6102f48160006108e8565b50565b60026020528060005260406000206000915090505481565b61035c82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061083e565b1561036657600080fd5b6103b382828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b61040182828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050846108e8565b5050505050565b606061045783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6104a583838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050346108e8565b8360000160208101906104b89190610b26565b600184846040516104ca929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060026000836040516020016105349190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105698161083e565b1561057357600080fd5b61057c81610894565b61058681346108e8565b50565b6105928161083e565b1561059c57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016105d993929190610f3a565b602060405180830381600087803b1580156105f357600080fd5b505af1158015610607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062b9190610b53565b61063457600080fd5b61063d81610894565b61064781836108e8565b505050565b6106a781806060019061065f9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6107048180606001906106ba9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060006108e8565b8060000160208101906107179190610b26565b60018280606001906107299190610fc9565b604051610737929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000836040516020016107bc9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6001818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060405160200161084f90610f0a565b60405160208183030381529060405280519060200120826040516020016108769190610ef3565b60405160208183030381529060405280519060200120149050919050565b6001600080836040516020016108aa9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b8060026000846040516020016108fe9190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b600061093d61093884611051565b61102c565b90508281526020810184848401111561095957610958611219565b5b610964848285611154565b509392505050565b600061097f61097a84611082565b61102c565b90508281526020810184848401111561099b5761099a611219565b5b6109a6848285611154565b509392505050565b6000813590506109bd81611262565b92915050565b6000815190506109d281611279565b92915050565b6000813590506109e781611290565b92915050565b60008083601f840112610a0357610a026111fb565b5b8235905067ffffffffffffffff811115610a2057610a1f6111f6565b5b602083019150836001820283011115610a3c57610a3b61120f565b5b9250929050565b600082601f830112610a5857610a576111fb565b5b8135610a6884826020860161092a565b91505092915050565b600081359050610a80816112a7565b92915050565b600082601f830112610a9b57610a9a6111fb565b5b8135610aab84826020860161096c565b91505092915050565b600060208284031215610aca57610ac9611205565b5b81905092915050565b600060808284031215610ae957610ae8611205565b5b81905092915050565b600060608284031215610b0857610b07611205565b5b81905092915050565b600081359050610b20816112be565b92915050565b600060208284031215610b3c57610b3b611223565b5b6000610b4a848285016109ae565b91505092915050565b600060208284031215610b6957610b68611223565b5b6000610b77848285016109c3565b91505092915050565b600060208284031215610b9657610b95611223565b5b6000610ba4848285016109d8565b91505092915050565b600060208284031215610bc357610bc2611223565b5b600082013567ffffffffffffffff811115610be157610be061121e565b5b610bed84828501610a43565b91505092915050565b600080600060608486031215610c0f57610c0e611223565b5b6000610c1d86828701610a71565b9350506020610c2e86828701610b11565b925050604084013567ffffffffffffffff811115610c4f57610c4e61121e565b5b610c5b86828701610a86565b9150509250925092565b600060208284031215610c7b57610c7a611223565b5b600082013567ffffffffffffffff811115610c9957610c9861121e565b5b610ca584828501610a86565b91505092915050565b600080600060408486031215610cc757610cc6611223565b5b6000610cd586828701610ab4565b935050602084013567ffffffffffffffff811115610cf657610cf561121e565b5b610d02868287016109ed565b92509250509250925092565b600060208284031215610d2457610d23611223565b5b600082013567ffffffffffffffff811115610d4257610d4161121e565b5b610d4e84828501610ad3565b91505092915050565b600080600080600060808688031215610d7357610d72611223565b5b600086013567ffffffffffffffff811115610d9157610d9061121e565b5b610d9d88828901610af2565b9550506020610dae888289016109ae565b9450506040610dbf88828901610b11565b935050606086013567ffffffffffffffff811115610de057610ddf61121e565b5b610dec888289016109ed565b92509250509295509295909350565b610e04816110f0565b82525050565b610e1381611102565b82525050565b6000610e2583856110da565b9350610e32838584611154565b82840190509392505050565b6000610e49826110b3565b610e5381856110c9565b9350610e63818560208601611163565b610e6c81611228565b840191505092915050565b6000610e82826110be565b610e8c81856110e5565b9350610e9c818560208601611163565b80840191505092915050565b6000610eb56006836110e5565b9150610ec082611239565b600682019050919050565b610ed48161114a565b82525050565b6000610ee7828486610e19565b91508190509392505050565b6000610eff8284610e77565b915081905092915050565b6000610f1582610ea8565b9150819050919050565b6000602082019050610f346000830184610dfb565b92915050565b6000606082019050610f4f6000830186610dfb565b610f5c6020830185610dfb565b610f696040830184610ecb565b949350505050565b6000602082019050610f866000830184610e0a565b92915050565b60006020820190508181036000830152610fa68184610e3e565b905092915050565b6000602082019050610fc36000830184610ecb565b92915050565b60008083356001602003843603038112610fe657610fe561120a565b5b80840192508235915067ffffffffffffffff82111561100857611007611200565b5b60208301925060018202360383131561102457611023611214565b5b509250929050565b6000611036611047565b90506110428282611196565b919050565b6000604051905090565b600067ffffffffffffffff82111561106c5761106b6111c7565b5b61107582611228565b9050602081019050919050565b600067ffffffffffffffff82111561109d5761109c6111c7565b5b6110a682611228565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600081905092915050565b60006110fb8261112a565b9050919050565b60008115159050919050565b6000819050919050565b6000611123826110f0565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015611181578082015181840152602081019050611166565b83811115611190576000848401525b50505050565b61119f82611228565b810181811067ffffffffffffffff821117156111be576111bd6111c7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61126b816110f0565b811461127657600080fd5b50565b61128281611102565b811461128d57600080fd5b50565b6112998161110e565b81146112a457600080fd5b50565b6112b081611118565b81146112bb57600080fd5b50565b6112c78161114a565b81146112d257600080fd5b5056fea26469706673582212201f295f137d0ea146883fdaa6858baa14e4c467a843ff4e7829fd9df0d4c2aede64736f6c63430008070033", } // TestDAppV2ABI is the input ABI used to generate the binding from. @@ -284,37 +284,6 @@ func (_TestDAppV2 *TestDAppV2CallerSession) CalledWithMessage(arg0 [32]byte) (bo return _TestDAppV2.Contract.CalledWithMessage(&_TestDAppV2.CallOpts, arg0) } -// ExpectedOnCallSender is a free data retrieval call binding the contract method 0x59f4a777. -// -// Solidity: function expectedOnCallSender() view returns(address) -func (_TestDAppV2 *TestDAppV2Caller) ExpectedOnCallSender(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _TestDAppV2.contract.Call(opts, &out, "expectedOnCallSender") - - if err != nil { - return *new(common.Address), err - } - - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) - - return out0, err - -} - -// ExpectedOnCallSender is a free data retrieval call binding the contract method 0x59f4a777. -// -// Solidity: function expectedOnCallSender() view returns(address) -func (_TestDAppV2 *TestDAppV2Session) ExpectedOnCallSender() (common.Address, error) { - return _TestDAppV2.Contract.ExpectedOnCallSender(&_TestDAppV2.CallOpts) -} - -// ExpectedOnCallSender is a free data retrieval call binding the contract method 0x59f4a777. -// -// Solidity: function expectedOnCallSender() view returns(address) -func (_TestDAppV2 *TestDAppV2CallerSession) ExpectedOnCallSender() (common.Address, error) { - return _TestDAppV2.Contract.ExpectedOnCallSender(&_TestDAppV2.CallOpts) -} - // GetAmountWithMessage is a free data retrieval call binding the contract method 0x9291fe26. // // Solidity: function getAmountWithMessage(string message) view returns(uint256) @@ -450,46 +419,46 @@ func (_TestDAppV2 *TestDAppV2TransactorSession) GasCall(message string) (*types. return _TestDAppV2.Contract.GasCall(&_TestDAppV2.TransactOpts, message) } -// OnCall is a paid mutator transaction binding the contract method 0x676cc054. +// OnCall is a paid mutator transaction binding the contract method 0x5bcfd616. // -// Solidity: function onCall((address) messageContext, bytes message) payable returns(bytes) -func (_TestDAppV2 *TestDAppV2Transactor) OnCall(opts *bind.TransactOpts, messageContext TestDAppV2MessageContext, message []byte) (*types.Transaction, error) { - return _TestDAppV2.contract.Transact(opts, "onCall", messageContext, message) +// Solidity: function onCall((bytes,address,uint256) _context, address _zrc20, uint256 amount, bytes message) returns() +func (_TestDAppV2 *TestDAppV2Transactor) OnCall(opts *bind.TransactOpts, _context TestDAppV2zContext, _zrc20 common.Address, amount *big.Int, message []byte) (*types.Transaction, error) { + return _TestDAppV2.contract.Transact(opts, "onCall", _context, _zrc20, amount, message) } -// OnCall is a paid mutator transaction binding the contract method 0x676cc054. +// OnCall is a paid mutator transaction binding the contract method 0x5bcfd616. // -// Solidity: function onCall((address) messageContext, bytes message) payable returns(bytes) -func (_TestDAppV2 *TestDAppV2Session) OnCall(messageContext TestDAppV2MessageContext, message []byte) (*types.Transaction, error) { - return _TestDAppV2.Contract.OnCall(&_TestDAppV2.TransactOpts, messageContext, message) +// Solidity: function onCall((bytes,address,uint256) _context, address _zrc20, uint256 amount, bytes message) returns() +func (_TestDAppV2 *TestDAppV2Session) OnCall(_context TestDAppV2zContext, _zrc20 common.Address, amount *big.Int, message []byte) (*types.Transaction, error) { + return _TestDAppV2.Contract.OnCall(&_TestDAppV2.TransactOpts, _context, _zrc20, amount, message) } -// OnCall is a paid mutator transaction binding the contract method 0x676cc054. +// OnCall is a paid mutator transaction binding the contract method 0x5bcfd616. // -// Solidity: function onCall((address) messageContext, bytes message) payable returns(bytes) -func (_TestDAppV2 *TestDAppV2TransactorSession) OnCall(messageContext TestDAppV2MessageContext, message []byte) (*types.Transaction, error) { - return _TestDAppV2.Contract.OnCall(&_TestDAppV2.TransactOpts, messageContext, message) +// Solidity: function onCall((bytes,address,uint256) _context, address _zrc20, uint256 amount, bytes message) returns() +func (_TestDAppV2 *TestDAppV2TransactorSession) OnCall(_context TestDAppV2zContext, _zrc20 common.Address, amount *big.Int, message []byte) (*types.Transaction, error) { + return _TestDAppV2.Contract.OnCall(&_TestDAppV2.TransactOpts, _context, _zrc20, amount, message) } -// OnCrossChainCall is a paid mutator transaction binding the contract method 0xde43156e. +// OnCall0 is a paid mutator transaction binding the contract method 0x676cc054. // -// Solidity: function onCrossChainCall((bytes,address,uint256) _context, address _zrc20, uint256 amount, bytes message) returns() -func (_TestDAppV2 *TestDAppV2Transactor) OnCrossChainCall(opts *bind.TransactOpts, _context TestDAppV2zContext, _zrc20 common.Address, amount *big.Int, message []byte) (*types.Transaction, error) { - return _TestDAppV2.contract.Transact(opts, "onCrossChainCall", _context, _zrc20, amount, message) +// Solidity: function onCall((address) messageContext, bytes message) payable returns(bytes) +func (_TestDAppV2 *TestDAppV2Transactor) OnCall0(opts *bind.TransactOpts, messageContext TestDAppV2MessageContext, message []byte) (*types.Transaction, error) { + return _TestDAppV2.contract.Transact(opts, "onCall0", messageContext, message) } -// OnCrossChainCall is a paid mutator transaction binding the contract method 0xde43156e. +// OnCall0 is a paid mutator transaction binding the contract method 0x676cc054. // -// Solidity: function onCrossChainCall((bytes,address,uint256) _context, address _zrc20, uint256 amount, bytes message) returns() -func (_TestDAppV2 *TestDAppV2Session) OnCrossChainCall(_context TestDAppV2zContext, _zrc20 common.Address, amount *big.Int, message []byte) (*types.Transaction, error) { - return _TestDAppV2.Contract.OnCrossChainCall(&_TestDAppV2.TransactOpts, _context, _zrc20, amount, message) +// Solidity: function onCall((address) messageContext, bytes message) payable returns(bytes) +func (_TestDAppV2 *TestDAppV2Session) OnCall0(messageContext TestDAppV2MessageContext, message []byte) (*types.Transaction, error) { + return _TestDAppV2.Contract.OnCall0(&_TestDAppV2.TransactOpts, messageContext, message) } -// OnCrossChainCall is a paid mutator transaction binding the contract method 0xde43156e. +// OnCall0 is a paid mutator transaction binding the contract method 0x676cc054. // -// Solidity: function onCrossChainCall((bytes,address,uint256) _context, address _zrc20, uint256 amount, bytes message) returns() -func (_TestDAppV2 *TestDAppV2TransactorSession) OnCrossChainCall(_context TestDAppV2zContext, _zrc20 common.Address, amount *big.Int, message []byte) (*types.Transaction, error) { - return _TestDAppV2.Contract.OnCrossChainCall(&_TestDAppV2.TransactOpts, _context, _zrc20, amount, message) +// Solidity: function onCall((address) messageContext, bytes message) payable returns(bytes) +func (_TestDAppV2 *TestDAppV2TransactorSession) OnCall0(messageContext TestDAppV2MessageContext, message []byte) (*types.Transaction, error) { + return _TestDAppV2.Contract.OnCall0(&_TestDAppV2.TransactOpts, messageContext, message) } // OnRevert is a paid mutator transaction binding the contract method 0xc9028a36. @@ -513,27 +482,6 @@ func (_TestDAppV2 *TestDAppV2TransactorSession) OnRevert(revertContext TestDAppV return _TestDAppV2.Contract.OnRevert(&_TestDAppV2.TransactOpts, revertContext) } -// SetExpectedOnCallSender is a paid mutator transaction binding the contract method 0xc234fecf. -// -// Solidity: function setExpectedOnCallSender(address _expectedOnCallSender) returns() -func (_TestDAppV2 *TestDAppV2Transactor) SetExpectedOnCallSender(opts *bind.TransactOpts, _expectedOnCallSender common.Address) (*types.Transaction, error) { - return _TestDAppV2.contract.Transact(opts, "setExpectedOnCallSender", _expectedOnCallSender) -} - -// SetExpectedOnCallSender is a paid mutator transaction binding the contract method 0xc234fecf. -// -// Solidity: function setExpectedOnCallSender(address _expectedOnCallSender) returns() -func (_TestDAppV2 *TestDAppV2Session) SetExpectedOnCallSender(_expectedOnCallSender common.Address) (*types.Transaction, error) { - return _TestDAppV2.Contract.SetExpectedOnCallSender(&_TestDAppV2.TransactOpts, _expectedOnCallSender) -} - -// SetExpectedOnCallSender is a paid mutator transaction binding the contract method 0xc234fecf. -// -// Solidity: function setExpectedOnCallSender(address _expectedOnCallSender) returns() -func (_TestDAppV2 *TestDAppV2TransactorSession) SetExpectedOnCallSender(_expectedOnCallSender common.Address) (*types.Transaction, error) { - return _TestDAppV2.Contract.SetExpectedOnCallSender(&_TestDAppV2.TransactOpts, _expectedOnCallSender) -} - // SimpleCall is a paid mutator transaction binding the contract method 0x36e980a0. // // Solidity: function simpleCall(string message) returns() diff --git a/pkg/contracts/testdappv2/TestDAppV2.json b/pkg/contracts/testdappv2/TestDAppV2.json index 632521fa63..2ea4bd665d 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.json +++ b/pkg/contracts/testdappv2/TestDAppV2.json @@ -61,19 +61,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "expectedOnCallSender", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { @@ -125,37 +112,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "internalType": "struct TestDAppV2.MessageContext", - "name": "messageContext", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "message", - "type": "bytes" - } - ], - "name": "onCall", - "outputs": [ - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "function" - }, { "inputs": [ { @@ -196,11 +152,42 @@ "type": "bytes" } ], - "name": "onCrossChainCall", + "name": "onCall", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "internalType": "struct TestDAppV2.MessageContext", + "name": "messageContext", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "message", + "type": "bytes" + } + ], + "name": "onCall", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "function" + }, { "inputs": [ { @@ -255,19 +242,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "_expectedOnCallSender", - "type": "address" - } - ], - "name": "setExpectedOnCallSender", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -286,5 +260,5 @@ "type": "receive" } ], - "bin": "608060405234801561001057600080fd5b5061150a806100206000396000f3fe6080604052600436106100c65760003560e01c8063c234fecf1161007f578063de43156e11610059578063de43156e14610267578063e2842ed714610290578063f592cbfb146102cd578063f936ae851461030a576100cd565b8063c234fecf146101ec578063c7a339a914610215578063c9028a361461023e576100cd565b806336e980a0146100d25780634297a263146100fb57806359f4a77714610138578063676cc054146101635780639291fe2614610193578063a799911f146101d0576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610de7565b610347565b005b34801561010757600080fd5b50610122600480360381019061011d9190610d02565b610371565b60405161012f9190611173565b60405180910390f35b34801561014457600080fd5b5061014d610389565b60405161015a91906110c4565b60405180910390f35b61017d60048036038101906101789190610e30565b6103ad565b60405161018a9190611131565b60405180910390f35b34801561019f57600080fd5b506101ba60048036038101906101b59190610de7565b610562565b6040516101c79190611173565b60405180910390f35b6101ea60048036038101906101e59190610de7565b6105a5565b005b3480156101f857600080fd5b50610213600480360381019061020e9190610ca8565b6105ce565b005b34801561022157600080fd5b5061023c60048036038101906102379190610d78565b610611565b005b34801561024a57600080fd5b5061026560048036038101906102609190610e90565b6106d4565b005b34801561027357600080fd5b5061028e60048036038101906102899190610ed9565b61080e565b005b34801561029c57600080fd5b506102b760048036038101906102b29190610d02565b610907565b6040516102c49190611116565b60405180910390f35b3480156102d957600080fd5b506102f460048036038101906102ef9190610de7565b610927565b6040516103019190611116565b60405180910390f35b34801561031657600080fd5b50610331600480360381019061032c9190610d2f565b610977565b60405161033e91906110c4565b60405180910390f35b610350816109c0565b1561035a57600080fd5b61036381610a16565b61036e816000610a6a565b50565b60036020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606060008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160208101906103f99190610ca8565b73ffffffffffffffffffffffffffffffffffffffff161461044f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044690611153565b60405180910390fd5b61049c83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b6104ea83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505034610a6a565b8360000160208101906104fd9190610ca8565b6002848460405161050f92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060036000836040516020016105799190611098565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105ae816109c0565b156105b857600080fd5b6105c181610a16565b6105cb8134610a6a565b50565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61061a816109c0565b1561062457600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b8152600401610661939291906110df565b602060405180830381600087803b15801561067b57600080fd5b505af115801561068f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106b39190610cd5565b6106bc57600080fd5b6106c581610a16565b6106cf8183610a6a565b505050565b61072f8180606001906106e7919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61078c818060600190610742919061118e565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506000610a6a565b80600001602081019061079f9190610ca8565b60028280606001906107b1919061118e565b6040516107bf92919061107f565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61085b82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506109c0565b1561086557600080fd5b6108b282828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610a16565b61090082828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505084610a6a565b5050505050565b60016020528060005260406000206000915054906101000a900460ff1681565b6000600160008360405160200161093e9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6002818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006040516020016109d1906110af565b60405160208183030381529060405280519060200120826040516020016109f89190611098565b60405160208183030381529060405280519060200120149050919050565b600180600083604051602001610a2c9190611098565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806003600084604051602001610a809190611098565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000610abf610aba84611216565b6111f1565b905082815260208101848484011115610adb57610ada6113ef565b5b610ae684828561132a565b509392505050565b6000610b01610afc84611247565b6111f1565b905082815260208101848484011115610b1d57610b1c6113ef565b5b610b2884828561132a565b509392505050565b600081359050610b3f81611461565b92915050565b600081519050610b5481611478565b92915050565b600081359050610b698161148f565b92915050565b60008083601f840112610b8557610b846113d1565b5b8235905067ffffffffffffffff811115610ba257610ba16113cc565b5b602083019150836001820283011115610bbe57610bbd6113e5565b5b9250929050565b600082601f830112610bda57610bd96113d1565b5b8135610bea848260208601610aac565b91505092915050565b600081359050610c02816114a6565b92915050565b600082601f830112610c1d57610c1c6113d1565b5b8135610c2d848260208601610aee565b91505092915050565b600060208284031215610c4c57610c4b6113db565b5b81905092915050565b600060808284031215610c6b57610c6a6113db565b5b81905092915050565b600060608284031215610c8a57610c896113db565b5b81905092915050565b600081359050610ca2816114bd565b92915050565b600060208284031215610cbe57610cbd6113f9565b5b6000610ccc84828501610b30565b91505092915050565b600060208284031215610ceb57610cea6113f9565b5b6000610cf984828501610b45565b91505092915050565b600060208284031215610d1857610d176113f9565b5b6000610d2684828501610b5a565b91505092915050565b600060208284031215610d4557610d446113f9565b5b600082013567ffffffffffffffff811115610d6357610d626113f4565b5b610d6f84828501610bc5565b91505092915050565b600080600060608486031215610d9157610d906113f9565b5b6000610d9f86828701610bf3565b9350506020610db086828701610c93565b925050604084013567ffffffffffffffff811115610dd157610dd06113f4565b5b610ddd86828701610c08565b9150509250925092565b600060208284031215610dfd57610dfc6113f9565b5b600082013567ffffffffffffffff811115610e1b57610e1a6113f4565b5b610e2784828501610c08565b91505092915050565b600080600060408486031215610e4957610e486113f9565b5b6000610e5786828701610c36565b935050602084013567ffffffffffffffff811115610e7857610e776113f4565b5b610e8486828701610b6f565b92509250509250925092565b600060208284031215610ea657610ea56113f9565b5b600082013567ffffffffffffffff811115610ec457610ec36113f4565b5b610ed084828501610c55565b91505092915050565b600080600080600060808688031215610ef557610ef46113f9565b5b600086013567ffffffffffffffff811115610f1357610f126113f4565b5b610f1f88828901610c74565b9550506020610f3088828901610b30565b9450506040610f4188828901610c93565b935050606086013567ffffffffffffffff811115610f6257610f616113f4565b5b610f6e88828901610b6f565b92509250509295509295909350565b610f86816112c6565b82525050565b610f95816112d8565b82525050565b6000610fa7838561129f565b9350610fb483858461132a565b82840190509392505050565b6000610fcb82611278565b610fd5818561128e565b9350610fe5818560208601611339565b610fee816113fe565b840191505092915050565b600061100482611283565b61100e81856112bb565b935061101e818560208601611339565b80840191505092915050565b60006110376016836112aa565b91506110428261140f565b602082019050919050565b600061105a6006836112bb565b915061106582611438565b600682019050919050565b61107981611320565b82525050565b600061108c828486610f9b565b91508190509392505050565b60006110a48284610ff9565b915081905092915050565b60006110ba8261104d565b9150819050919050565b60006020820190506110d96000830184610f7d565b92915050565b60006060820190506110f46000830186610f7d565b6111016020830185610f7d565b61110e6040830184611070565b949350505050565b600060208201905061112b6000830184610f8c565b92915050565b6000602082019050818103600083015261114b8184610fc0565b905092915050565b6000602082019050818103600083015261116c8161102a565b9050919050565b60006020820190506111886000830184611070565b92915050565b600080833560016020038436030381126111ab576111aa6113e0565b5b80840192508235915067ffffffffffffffff8211156111cd576111cc6113d6565b5b6020830192506001820236038313156111e9576111e86113ea565b5b509250929050565b60006111fb61120c565b9050611207828261136c565b919050565b6000604051905090565b600067ffffffffffffffff8211156112315761123061139d565b5b61123a826113fe565b9050602081019050919050565b600067ffffffffffffffff8211156112625761126161139d565b5b61126b826113fe565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006112d182611300565b9050919050565b60008115159050919050565b6000819050919050565b60006112f9826112c6565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b8381101561135757808201518184015260208101905061133c565b83811115611366576000848401525b50505050565b611375826113fe565b810181811067ffffffffffffffff821117156113945761139361139d565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f756e61757468656e746963617465642073656e64657200000000000000000000600082015250565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61146a816112c6565b811461147557600080fd5b50565b611481816112d8565b811461148c57600080fd5b50565b611498816112e4565b81146114a357600080fd5b50565b6114af816112ee565b81146114ba57600080fd5b50565b6114c681611320565b81146114d157600080fd5b5056fea2646970667358221220da9e50cb7b79ace99166ed06c9234f984bc9599fca79796389af6656411f73f964736f6c63430008070033" + "bin": "608060405234801561001057600080fd5b5061130b806100206000396000f3fe6080604052600436106100a05760003560e01c8063a799911f11610064578063a799911f146101a8578063c7a339a9146101c4578063c9028a36146101ed578063e2842ed714610216578063f592cbfb14610253578063f936ae8514610290576100a7565b806336e980a0146100ac5780634297a263146100d55780635bcfd61614610112578063676cc0541461013b5780639291fe261461016b576100a7565b366100a757005b600080fd5b3480156100b857600080fd5b506100d360048036038101906100ce9190610c65565b6102cd565b005b3480156100e157600080fd5b506100fc60048036038101906100f79190610b80565b6102f7565b6040516101099190610fae565b60405180910390f35b34801561011e57600080fd5b5061013960048036038101906101349190610d57565b61030f565b005b61015560048036038101906101509190610cae565b610408565b6040516101629190610f8c565b60405180910390f35b34801561017757600080fd5b50610192600480360381019061018d9190610c65565b61051d565b60405161019f9190610fae565b60405180910390f35b6101c260048036038101906101bd9190610c65565b610560565b005b3480156101d057600080fd5b506101eb60048036038101906101e69190610bf6565b610589565b005b3480156101f957600080fd5b50610214600480360381019061020f9190610d0e565b61064c565b005b34801561022257600080fd5b5061023d60048036038101906102389190610b80565b610786565b60405161024a9190610f71565b60405180910390f35b34801561025f57600080fd5b5061027a60048036038101906102759190610c65565b6107a6565b6040516102879190610f71565b60405180910390f35b34801561029c57600080fd5b506102b760048036038101906102b29190610bad565b6107f5565b6040516102c49190610f1f565b60405180910390f35b6102d68161083e565b156102e057600080fd5b6102e981610894565b6102f48160006108e8565b50565b60026020528060005260406000206000915090505481565b61035c82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061083e565b1561036657600080fd5b6103b382828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b61040182828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050846108e8565b5050505050565b606061045783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6104a583838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050346108e8565b8360000160208101906104b89190610b26565b600184846040516104ca929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060026000836040516020016105349190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105698161083e565b1561057357600080fd5b61057c81610894565b61058681346108e8565b50565b6105928161083e565b1561059c57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016105d993929190610f3a565b602060405180830381600087803b1580156105f357600080fd5b505af1158015610607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062b9190610b53565b61063457600080fd5b61063d81610894565b61064781836108e8565b505050565b6106a781806060019061065f9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6107048180606001906106ba9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060006108e8565b8060000160208101906107179190610b26565b60018280606001906107299190610fc9565b604051610737929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000836040516020016107bc9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6001818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060405160200161084f90610f0a565b60405160208183030381529060405280519060200120826040516020016108769190610ef3565b60405160208183030381529060405280519060200120149050919050565b6001600080836040516020016108aa9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b8060026000846040516020016108fe9190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b600061093d61093884611051565b61102c565b90508281526020810184848401111561095957610958611219565b5b610964848285611154565b509392505050565b600061097f61097a84611082565b61102c565b90508281526020810184848401111561099b5761099a611219565b5b6109a6848285611154565b509392505050565b6000813590506109bd81611262565b92915050565b6000815190506109d281611279565b92915050565b6000813590506109e781611290565b92915050565b60008083601f840112610a0357610a026111fb565b5b8235905067ffffffffffffffff811115610a2057610a1f6111f6565b5b602083019150836001820283011115610a3c57610a3b61120f565b5b9250929050565b600082601f830112610a5857610a576111fb565b5b8135610a6884826020860161092a565b91505092915050565b600081359050610a80816112a7565b92915050565b600082601f830112610a9b57610a9a6111fb565b5b8135610aab84826020860161096c565b91505092915050565b600060208284031215610aca57610ac9611205565b5b81905092915050565b600060808284031215610ae957610ae8611205565b5b81905092915050565b600060608284031215610b0857610b07611205565b5b81905092915050565b600081359050610b20816112be565b92915050565b600060208284031215610b3c57610b3b611223565b5b6000610b4a848285016109ae565b91505092915050565b600060208284031215610b6957610b68611223565b5b6000610b77848285016109c3565b91505092915050565b600060208284031215610b9657610b95611223565b5b6000610ba4848285016109d8565b91505092915050565b600060208284031215610bc357610bc2611223565b5b600082013567ffffffffffffffff811115610be157610be061121e565b5b610bed84828501610a43565b91505092915050565b600080600060608486031215610c0f57610c0e611223565b5b6000610c1d86828701610a71565b9350506020610c2e86828701610b11565b925050604084013567ffffffffffffffff811115610c4f57610c4e61121e565b5b610c5b86828701610a86565b9150509250925092565b600060208284031215610c7b57610c7a611223565b5b600082013567ffffffffffffffff811115610c9957610c9861121e565b5b610ca584828501610a86565b91505092915050565b600080600060408486031215610cc757610cc6611223565b5b6000610cd586828701610ab4565b935050602084013567ffffffffffffffff811115610cf657610cf561121e565b5b610d02868287016109ed565b92509250509250925092565b600060208284031215610d2457610d23611223565b5b600082013567ffffffffffffffff811115610d4257610d4161121e565b5b610d4e84828501610ad3565b91505092915050565b600080600080600060808688031215610d7357610d72611223565b5b600086013567ffffffffffffffff811115610d9157610d9061121e565b5b610d9d88828901610af2565b9550506020610dae888289016109ae565b9450506040610dbf88828901610b11565b935050606086013567ffffffffffffffff811115610de057610ddf61121e565b5b610dec888289016109ed565b92509250509295509295909350565b610e04816110f0565b82525050565b610e1381611102565b82525050565b6000610e2583856110da565b9350610e32838584611154565b82840190509392505050565b6000610e49826110b3565b610e5381856110c9565b9350610e63818560208601611163565b610e6c81611228565b840191505092915050565b6000610e82826110be565b610e8c81856110e5565b9350610e9c818560208601611163565b80840191505092915050565b6000610eb56006836110e5565b9150610ec082611239565b600682019050919050565b610ed48161114a565b82525050565b6000610ee7828486610e19565b91508190509392505050565b6000610eff8284610e77565b915081905092915050565b6000610f1582610ea8565b9150819050919050565b6000602082019050610f346000830184610dfb565b92915050565b6000606082019050610f4f6000830186610dfb565b610f5c6020830185610dfb565b610f696040830184610ecb565b949350505050565b6000602082019050610f866000830184610e0a565b92915050565b60006020820190508181036000830152610fa68184610e3e565b905092915050565b6000602082019050610fc36000830184610ecb565b92915050565b60008083356001602003843603038112610fe657610fe561120a565b5b80840192508235915067ffffffffffffffff82111561100857611007611200565b5b60208301925060018202360383131561102457611023611214565b5b509250929050565b6000611036611047565b90506110428282611196565b919050565b6000604051905090565b600067ffffffffffffffff82111561106c5761106b6111c7565b5b61107582611228565b9050602081019050919050565b600067ffffffffffffffff82111561109d5761109c6111c7565b5b6110a682611228565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600081905092915050565b60006110fb8261112a565b9050919050565b60008115159050919050565b6000819050919050565b6000611123826110f0565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015611181578082015181840152602081019050611166565b83811115611190576000848401525b50505050565b61119f82611228565b810181811067ffffffffffffffff821117156111be576111bd6111c7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61126b816110f0565b811461127657600080fd5b50565b61128281611102565b811461128d57600080fd5b50565b6112998161110e565b81146112a457600080fd5b50565b6112b081611118565b81146112bb57600080fd5b50565b6112c78161114a565b81146112d257600080fd5b5056fea26469706673582212201f295f137d0ea146883fdaa6858baa14e4c467a843ff4e7829fd9df0d4c2aede64736f6c63430008070033" } diff --git a/pkg/contracts/testdappv2/TestDAppV2.sol b/pkg/contracts/testdappv2/TestDAppV2.sol index 7919d13b5d..c460c87025 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.sol +++ b/pkg/contracts/testdappv2/TestDAppV2.sol @@ -30,8 +30,6 @@ contract TestDAppV2 { address sender; } - address public expectedOnCallSender; - // these structures allow to assess contract calls mapping(bytes32 => bool) public calledWithMessage; mapping(bytes => address) public senderWithMessage; @@ -53,7 +51,7 @@ contract TestDAppV2 { } // Universal contract interface - function onCrossChainCall( + function onCall( zContext calldata _context, address _zrc20, uint256 amount, @@ -105,12 +103,8 @@ contract TestDAppV2 { senderWithMessage[revertContext.revertMessage] = revertContext.sender; } - function setExpectedOnCallSender(address _expectedOnCallSender) external { - expectedOnCallSender = _expectedOnCallSender; - } - + // Callable interface function onCall(MessageContext calldata messageContext, bytes calldata message) external payable returns (bytes memory) { - require(messageContext.sender == expectedOnCallSender, "unauthenticated sender"); setCalledWithMessage(string(message)); setAmountWithMessage(string(message), msg.value); senderWithMessage[message] = messageContext.sender; diff --git a/zetaclient/chains/evm/signer/outbound_data.go b/zetaclient/chains/evm/signer/outbound_data.go index 0cc65c19e2..200ae1f70b 100644 --- a/zetaclient/chains/evm/signer/outbound_data.go +++ b/zetaclient/chains/evm/signer/outbound_data.go @@ -10,6 +10,7 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/rs/zerolog" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/x/crosschain/types" @@ -42,6 +43,9 @@ type OutboundData struct { // revertOptions field contains data detailing the revert options revertOptions types.RevertOptions + + // callOptions field determinenes if call is arbitrary or authenticated and contains gasLimit + callOptions types.CallOptions } // NewOutboundData creates OutboundData from the given CCTX. @@ -67,14 +71,16 @@ func NewOutboundData( } var ( - to ethcommon.Address - toChainID *big.Int + to ethcommon.Address + toChainID *big.Int + callOptions types.CallOptions ) // in protocol contract v2, receiver is always set in the outbound if cctx.ProtocolContractVersion == types.ProtocolContractVersion_V2 { to = ethcommon.HexToAddress(cctx.GetCurrentOutboundParam().Receiver) toChainID = big.NewInt(cctx.GetCurrentOutboundParam().ReceiverChainId) + callOptions = *cctx.GetCurrentOutboundParam().CallOptions } else { // recipient + destination chain var skip bool @@ -140,9 +146,27 @@ func NewOutboundData( outboundParams: outboundParams, revertOptions: cctx.RevertOptions, + + callOptions: callOptions, }, false, nil } +func (o OutboundData) MessageContext() (gatewayevm.MessageContext, error) { + if o.callOptions == (types.CallOptions{}) { + return gatewayevm.MessageContext{}, errors.New("call options not found") + } + // if sender is provided in messageContext call is authenticated and target is Callable.onCall + // otherwise, call is arbitrary + messageContext := gatewayevm.MessageContext{ + Sender: o.sender, + } + if o.callOptions.IsArbitraryCall { + messageContext.Sender = ethcommon.Address{} + } + + return messageContext, nil +} + func getCCTXIndex(cctx *types.CrossChainTx) ([32]byte, error) { // `0x` + `64 chars`. Two chars ranging `00...FF` represent one byte (64 chars = 32 bytes) if len(cctx.Index) != (2 + 64) { diff --git a/zetaclient/chains/evm/signer/v2_sign.go b/zetaclient/chains/evm/signer/v2_sign.go index 3a00a86c48..443f304785 100644 --- a/zetaclient/chains/evm/signer/v2_sign.go +++ b/zetaclient/chains/evm/signer/v2_sign.go @@ -19,7 +19,6 @@ import ( // bytes calldata data func (signer *Signer) signGatewayExecute( ctx context.Context, - sender string, txData *OutboundData, ) (*ethtypes.Transaction, error) { gatewayABI, err := gatewayevm.GatewayEVMMetaData.GetAbi() @@ -27,21 +26,16 @@ func (signer *Signer) signGatewayExecute( return nil, errors.Wrap(err, "unable to get GatewayEVMMetaData ABI") } + messageContext, err := txData.MessageContext() + if err != nil { + return nil, err + } + var data []byte - if txData.outboundParams.CallOptions.IsArbitraryCall { - data, err = gatewayABI.Pack("execute", txData.to, txData.message) - if err != nil { - return nil, fmt.Errorf("execute pack error: %w", err) - } - } else { - messageContext := gatewayevm.MessageContext{ - Sender: common.HexToAddress(sender), - } - data, err = gatewayABI.Pack("execute0", messageContext, txData.to, txData.message) - if err != nil { - return nil, fmt.Errorf("execute0 pack error: %w", err) - } + data, err = gatewayABI.Pack("execute", messageContext, txData.to, txData.message) + if err != nil { + return nil, fmt.Errorf("execute pack error: %w", err) } tx, _, _, err := signer.Sign( @@ -155,7 +149,19 @@ func (signer *Signer) signERC20CustodyWithdrawAndCall( return nil, errors.Wrap(err, "unable to get ERC20CustodyMetaData ABI") } - data, err := erc20CustodyV2ABI.Pack("withdrawAndCall", txData.to, txData.asset, txData.amount, txData.message) + messageContext, err := txData.MessageContext() + if err != nil { + return nil, err + } + + data, err := erc20CustodyV2ABI.Pack( + "withdrawAndCall", + messageContext, + txData.to, + txData.asset, + txData.amount, + txData.message, + ) if err != nil { return nil, fmt.Errorf("withdraw pack error: %w", err) } diff --git a/zetaclient/chains/evm/signer/v2_signer.go b/zetaclient/chains/evm/signer/v2_signer.go index e687454b3b..664663cf0f 100644 --- a/zetaclient/chains/evm/signer/v2_signer.go +++ b/zetaclient/chains/evm/signer/v2_signer.go @@ -27,7 +27,7 @@ func (signer *Signer) SignOutboundFromCCTXV2( case evm.OutboundTypeGasWithdrawAndCall, evm.OutboundTypeCall: // both gas withdraw and call and no-asset call uses gateway execute // no-asset call simply hash msg.value == 0 - return signer.signGatewayExecute(ctx, cctx.InboundParams.Sender, outboundData) + return signer.signGatewayExecute(ctx, outboundData) case evm.OutboundTypeGasWithdrawRevertAndCallOnRevert: return signer.signGatewayExecuteRevert(ctx, cctx.InboundParams.Sender, outboundData) case evm.OutboundTypeERC20WithdrawRevertAndCallOnRevert: From 41ec1174a5e1f776f8d80c9f33efc21c45efa411 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Tue, 22 Oct 2024 11:34:06 +0200 Subject: [PATCH 35/36] fix: support `depositAndCall` and `withdrawAndCall` with empty message (#3018) * add no message tests * add is crosschain call inbound field * use noew protocol contract version * fix used commit * try make deposit no message work * add new contract interface * fix ctx initializer * fix unit test * changelog * support withdraw and call no message * fix withdraw test and push back test * prepare tests * intialize a few more test * gomod * add erc20 withdraw and call no message test * fix sender and origin * lint import * remove fungible type dep from crosschain * keepertest --- changelog.md | 1 + cmd/zetae2e/local/v2.go | 3 + docs/openapi/openapi.swagger.yaml | 5 + docs/spec/crosschain/messages.md | 1 + e2e/e2etests/e2etests.go | 34 +++ .../test_v2_erc20_deposit_and_call.go | 2 +- ...st_v2_erc20_deposit_and_call_no_message.go | 48 +++ .../test_v2_erc20_deposit_and_call_revert.go | 2 +- ...erc20_deposit_and_call_revert_with_call.go | 2 +- ...t_v2_erc20_withdraw_and_call_no_message.go | 55 ++++ ...test_v2_eth_deposit_and_call_no_message.go | 46 +++ ...est_v2_eth_withdraw_and_call_no_message.go | 54 ++++ e2e/runner/v2_zevm.go | 8 +- go.mod | 2 +- go.sum | 4 +- pkg/contracts/testdappv2/TestDAppV2.abi | 32 ++ pkg/contracts/testdappv2/TestDAppV2.bin | 2 +- pkg/contracts/testdappv2/TestDAppV2.go | 66 ++++- pkg/contracts/testdappv2/TestDAppV2.json | 34 ++- pkg/contracts/testdappv2/TestDAppV2.sol | 32 +- pkg/contracts/testdappv2/bindings.go | 2 +- .../zetacore/crosschain/cross_chain_tx.proto | 4 + proto/zetachain/zetacore/crosschain/tx.proto | 3 + testutil/keeper/crosschain.go | 1 + testutil/keeper/mocks/crosschain/fungible.go | 22 +- testutil/sample/crosschain.go | 12 +- .../crosschain/cross_chain_tx_pb.d.ts | 8 + .../zetachain/zetacore/crosschain/tx_pb.d.ts | 7 + x/crosschain/keeper/evm_deposit.go | 1 + x/crosschain/keeper/evm_deposit_test.go | 10 + x/crosschain/keeper/evm_hooks_test.go | 80 ++--- x/crosschain/keeper/v2_zevm_inbound.go | 250 ++++------------ x/crosschain/types/cctx.go | 1 + x/crosschain/types/cross_chain_tx.pb.go | 218 ++++++++------ x/crosschain/types/expected_keepers.go | 1 + x/crosschain/types/inbound_parsing.go | 246 ++++++++++++++++ x/crosschain/types/inbound_parsing_test.go | 89 ++++++ x/crosschain/types/message_vote_inbound.go | 8 + .../types/message_vote_inbound_test.go | 65 +++++ x/crosschain/types/tx.pb.go | 275 ++++++++++-------- x/fungible/keeper/deposits.go | 13 +- x/fungible/keeper/deposits_test.go | 11 + x/fungible/keeper/v2_deposits.go | 22 +- x/fungible/keeper/v2_deposits_test.go | 118 ++++++++ zetaclient/chains/evm/cctx.go | 12 +- zetaclient/chains/evm/cctx_test.go | 105 +++++++ zetaclient/chains/evm/constant.go | 4 + zetaclient/chains/evm/observer/inbound.go | 9 + zetaclient/chains/evm/observer/v2_inbound.go | 145 +++++++++ 49 files changed, 1684 insertions(+), 491 deletions(-) create mode 100644 e2e/e2etests/test_v2_erc20_deposit_and_call_no_message.go create mode 100644 e2e/e2etests/test_v2_erc20_withdraw_and_call_no_message.go create mode 100644 e2e/e2etests/test_v2_eth_deposit_and_call_no_message.go create mode 100644 e2e/e2etests/test_v2_eth_withdraw_and_call_no_message.go create mode 100644 x/crosschain/types/inbound_parsing.go create mode 100644 x/crosschain/types/inbound_parsing_test.go create mode 100644 zetaclient/chains/evm/cctx_test.go diff --git a/changelog.md b/changelog.md index fb4435cade..56ccf83d84 100644 --- a/changelog.md +++ b/changelog.md @@ -54,6 +54,7 @@ * [2853](https://github.com/zeta-chain/node/pull/2853) - calling precompile through sc with sc state update * [2925](https://github.com/zeta-chain/node/pull/2925) - add recover to init chainer to diplay informative message when starting a node from block 1 * [2909](https://github.com/zeta-chain/node/pull/2909) - add legacy messages back to codec for querier backward compatibility +* [3018](https://github.com/zeta-chain/node/pull/3018) - support `DepositAndCall` and `WithdrawAndCall` with empty payload ## v20.0.0 diff --git a/cmd/zetae2e/local/v2.go b/cmd/zetae2e/local/v2.go index 3ef5ff880a..22de8a6c51 100644 --- a/cmd/zetae2e/local/v2.go +++ b/cmd/zetae2e/local/v2.go @@ -26,6 +26,8 @@ func startV2Tests(eg *errgroup.Group, conf config.Config, deployerRunner *runner e2etests.TestV2ZEVMToEVMCallName, e2etests.TestV2ZEVMToEVMCallThroughContractName, e2etests.TestV2EVMToZEVMCallName, + e2etests.TestV2ETHDepositAndCallNoMessageName, + e2etests.TestV2ETHWithdrawAndCallNoMessageName, )) // Test happy paths for erc20 token workflow @@ -36,6 +38,7 @@ func startV2Tests(eg *errgroup.Group, conf config.Config, deployerRunner *runner e2etests.TestV2ERC20WithdrawName, e2etests.TestV2ERC20WithdrawAndArbitraryCallName, e2etests.TestV2ERC20WithdrawAndCallName, + e2etests.TestV2ERC20DepositAndCallNoMessageName, )) // Test revert cases for gas token workflow diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index dfa9349794..9dc72eabb9 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -57202,6 +57202,11 @@ definitions: format: uint64 tx_finalization_status: $ref: '#/definitions/crosschainTxFinalizationStatus' + is_cross_chain_call: + type: boolean + title: |- + this field describes if a smart contract call should be made for a inbound + with assets only used for protocol contract version 2 crosschainInboundTracker: type: object properties: diff --git a/docs/spec/crosschain/messages.md b/docs/spec/crosschain/messages.md index b12149de9e..3182bec082 100644 --- a/docs/spec/crosschain/messages.md +++ b/docs/spec/crosschain/messages.md @@ -191,6 +191,7 @@ message MsgVoteInbound { ProtocolContractVersion protocol_contract_version = 16; RevertOptions revert_options = 17; CallOptions call_options = 18; + bool is_cross_chain_call = 19; } ``` diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index c94eb8f89d..979876b352 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -130,21 +130,25 @@ const ( */ TestV2ETHDepositName = "v2_eth_deposit" TestV2ETHDepositAndCallName = "v2_eth_deposit_and_call" + TestV2ETHDepositAndCallNoMessageName = "v2_eth_deposit_and_call_no_message" TestV2ETHDepositAndCallRevertName = "v2_eth_deposit_and_call_revert" TestV2ETHDepositAndCallRevertWithCallName = "v2_eth_deposit_and_call_revert_with_call" TestV2ETHWithdrawName = "v2_eth_withdraw" TestV2ETHWithdrawAndArbitraryCallName = "v2_eth_withdraw_and_arbitrary_call" TestV2ETHWithdrawAndCallName = "v2_eth_withdraw_and_call" + TestV2ETHWithdrawAndCallNoMessageName = "v2_eth_withdraw_and_call_no_message" TestV2ETHWithdrawAndCallThroughContractName = "v2_eth_withdraw_and_call_through_contract" TestV2ETHWithdrawAndCallRevertName = "v2_eth_withdraw_and_call_revert" TestV2ETHWithdrawAndCallRevertWithCallName = "v2_eth_withdraw_and_call_revert_with_call" TestV2ERC20DepositName = "v2_erc20_deposit" TestV2ERC20DepositAndCallName = "v2_erc20_deposit_and_call" + TestV2ERC20DepositAndCallNoMessageName = "v2_erc20_deposit_and_call_no_message" TestV2ERC20DepositAndCallRevertName = "v2_erc20_deposit_and_call_revert" TestV2ERC20DepositAndCallRevertWithCallName = "v2_erc20_deposit_and_call_revert_with_call" TestV2ERC20WithdrawName = "v2_erc20_withdraw" TestV2ERC20WithdrawAndArbitraryCallName = "v2_erc20_withdraw_and_arbitrary_call" TestV2ERC20WithdrawAndCallName = "v2_erc20_withdraw_and_call" + TestV2ERC20WithdrawAndCallNoMessageName = "v2_erc20_withdraw_and_call_no_message" TestV2ERC20WithdrawAndCallRevertName = "v2_erc20_withdraw_and_call_revert" TestV2ERC20WithdrawAndCallRevertWithCallName = "v2_erc20_withdraw_and_call_revert_with_call" TestV2ZEVMToEVMArbitraryCallName = "v2_zevm_to_evm_arbitrary_call" @@ -731,6 +735,14 @@ var AllE2ETests = []runner.E2ETest{ }, TestV2ETHDepositAndCall, ), + runner.NewE2ETest( + TestV2ETHDepositAndCallNoMessageName, + "deposit Ether into ZEVM and call a contract using V2 contract using no message content", + []runner.ArgDefinition{ + {Description: "amount in wei", DefaultValue: "10000000000000000"}, + }, + TestV2ETHDepositAndCallNoMessage, + ), runner.NewE2ETest( TestV2ETHDepositAndCallRevertName, "deposit Ether into ZEVM and call a contract using V2 contract that reverts", @@ -771,6 +783,14 @@ var AllE2ETests = []runner.E2ETest{ }, TestV2ETHWithdrawAndCall, ), + runner.NewE2ETest( + TestV2ETHWithdrawAndCallNoMessageName, + "withdraw Ether from ZEVM call a contract using V2 contract with no message content", + []runner.ArgDefinition{ + {Description: "amount in wei", DefaultValue: "100000"}, + }, + TestV2ETHWithdrawAndCallNoMessage, + ), runner.NewE2ETest( TestV2ETHWithdrawAndCallThroughContractName, "withdraw Ether from ZEVM call a contract using V2 contract through intermediary contract", @@ -811,6 +831,14 @@ var AllE2ETests = []runner.E2ETest{ }, TestV2ERC20DepositAndCall, ), + runner.NewE2ETest( + TestV2ERC20DepositAndCallNoMessageName, + "deposit ERC20 into ZEVM and call a contract using V2 contract with no message content", + []runner.ArgDefinition{ + {Description: "amount", DefaultValue: "100000"}, + }, + TestV2ERC20DepositAndCallNoMessage, + ), runner.NewE2ETest( TestV2ERC20DepositAndCallRevertName, "deposit ERC20 into ZEVM and call a contract using V2 contract that reverts", @@ -849,6 +877,12 @@ var AllE2ETests = []runner.E2ETest{ []runner.ArgDefinition{}, TestV2ERC20WithdrawAndCall, ), + runner.NewE2ETest( + TestV2ERC20WithdrawAndCallNoMessageName, + "withdraw ERC20 from ZEVM and authenticated call a contract using V2 contract with no message", + []runner.ArgDefinition{}, + TestV2ERC20WithdrawAndCallNoMessage, + ), runner.NewE2ETest( TestV2ERC20WithdrawAndCallRevertName, "withdraw ERC20 from ZEVM and call a contract using V2 contract that reverts", diff --git a/e2e/e2etests/test_v2_erc20_deposit_and_call.go b/e2e/e2etests/test_v2_erc20_deposit_and_call.go index 6328998e81..332f2d6009 100644 --- a/e2e/e2etests/test_v2_erc20_deposit_and_call.go +++ b/e2e/e2etests/test_v2_erc20_deposit_and_call.go @@ -37,7 +37,7 @@ func TestV2ERC20DepositAndCall(r *runner.E2ERunner, args []string) { // wait for the cctx to be mined cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - r.Logger.CCTX(*cctx, "deposit") + r.Logger.CCTX(*cctx, "deposit_and_call") require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) // check the payload was received on the contract diff --git a/e2e/e2etests/test_v2_erc20_deposit_and_call_no_message.go b/e2e/e2etests/test_v2_erc20_deposit_and_call_no_message.go new file mode 100644 index 0000000000..ff6adf74e6 --- /dev/null +++ b/e2e/e2etests/test_v2_erc20_deposit_and_call_no_message.go @@ -0,0 +1,48 @@ +package e2etests + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" + + "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/utils" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +func TestV2ERC20DepositAndCallNoMessage(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) + + amount, ok := big.NewInt(0).SetString(args[0], 10) + require.True(r, ok, "Invalid amount specified for TestV2ERC20DepositAndCallNoMessage") + + r.ApproveERC20OnEVM(r.GatewayEVMAddr) + + oldBalance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.TestDAppV2ZEVMAddr) + require.NoError(r, err) + + // perform the deposit + tx := r.V2ERC20DepositAndCall( + r.TestDAppV2ZEVMAddr, + amount, + []byte{}, + gatewayevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, + ) + + // wait for the cctx to be mined + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "deposit_and_call") + require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + + // check the payload was received on the contract + messageIndex, err := r.TestDAppV2ZEVM.GetNoMessageIndex(&bind.CallOpts{}, r.EVMAddress()) + require.NoError(r, err) + r.AssertTestDAppZEVMCalled(true, messageIndex, amount) + + // check the balance was updated + newBalance, err := r.ERC20ZRC20.BalanceOf(&bind.CallOpts{}, r.TestDAppV2ZEVMAddr) + require.NoError(r, err) + require.Equal(r, new(big.Int).Add(oldBalance, amount), newBalance) +} diff --git a/e2e/e2etests/test_v2_erc20_deposit_and_call_revert.go b/e2e/e2etests/test_v2_erc20_deposit_and_call_revert.go index ba2d031710..91d3f23a77 100644 --- a/e2e/e2etests/test_v2_erc20_deposit_and_call_revert.go +++ b/e2e/e2etests/test_v2_erc20_deposit_and_call_revert.go @@ -35,7 +35,7 @@ func TestV2ERC20DepositAndCallRevert(r *runner.E2ERunner, args []string) { // wait for the cctx to be reverted cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - r.Logger.CCTX(*cctx, "deposit") + r.Logger.CCTX(*cctx, "deposit_and_call") require.Equal(r, crosschaintypes.CctxStatus_Reverted, cctx.CctxStatus.Status) // check the balance is more than 0 diff --git a/e2e/e2etests/test_v2_erc20_deposit_and_call_revert_with_call.go b/e2e/e2etests/test_v2_erc20_deposit_and_call_revert_with_call.go index 41b92fee4f..0bee6ff837 100644 --- a/e2e/e2etests/test_v2_erc20_deposit_and_call_revert_with_call.go +++ b/e2e/e2etests/test_v2_erc20_deposit_and_call_revert_with_call.go @@ -34,7 +34,7 @@ func TestV2ERC20DepositAndCallRevertWithCall(r *runner.E2ERunner, args []string) // wait for the cctx to be reverted cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - r.Logger.CCTX(*cctx, "deposit") + r.Logger.CCTX(*cctx, "deposit_and_call") require.Equal(r, crosschaintypes.CctxStatus_Reverted, cctx.CctxStatus.Status) // check the payload was received on the contract diff --git a/e2e/e2etests/test_v2_erc20_withdraw_and_call_no_message.go b/e2e/e2etests/test_v2_erc20_withdraw_and_call_no_message.go new file mode 100644 index 0000000000..50396ee58c --- /dev/null +++ b/e2e/e2etests/test_v2_erc20_withdraw_and_call_no_message.go @@ -0,0 +1,55 @@ +package e2etests + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol" + + "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/utils" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +func TestV2ERC20WithdrawAndCallNoMessage(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) + + previousGasLimit := r.ZEVMAuth.GasLimit + r.ZEVMAuth.GasLimit = 10000000 + defer func() { + r.ZEVMAuth.GasLimit = previousGasLimit + }() + + amount, ok := big.NewInt(0).SetString(args[0], 10) + require.True(r, ok, "Invalid amount specified for TestV2ERC20WithdrawAndCallNoMessage") + + r.ApproveERC20ZRC20(r.GatewayZEVMAddr) + r.ApproveETHZRC20(r.GatewayZEVMAddr) + + // perform the withdraw + tx := r.V2ERC20WithdrawAndCall( + r.TestDAppV2EVMAddr, + amount, + []byte{}, + gatewayzevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, + ) + + // wait for the cctx to be mined + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "withdraw_and_call") + require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + + // check called + messageIndex, err := r.TestDAppV2EVM.GetNoMessageIndex(&bind.CallOpts{}, r.EVMAddress()) + require.NoError(r, err) + r.AssertTestDAppEVMCalled(true, messageIndex, amount) + + // check expected sender was used + senderForMsg, err := r.TestDAppV2EVM.SenderWithMessage( + &bind.CallOpts{}, + []byte(messageIndex), + ) + require.NoError(r, err) + require.Equal(r, r.ZEVMAuth.From, senderForMsg) +} diff --git a/e2e/e2etests/test_v2_eth_deposit_and_call_no_message.go b/e2e/e2etests/test_v2_eth_deposit_and_call_no_message.go new file mode 100644 index 0000000000..be8b55cdc8 --- /dev/null +++ b/e2e/e2etests/test_v2_eth_deposit_and_call_no_message.go @@ -0,0 +1,46 @@ +package e2etests + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayevm.sol" + + "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/utils" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +func TestV2ETHDepositAndCallNoMessage(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) + + amount, ok := big.NewInt(0).SetString(args[0], 10) + require.True(r, ok, "Invalid amount specified for TestV2ETHDepositAndCallNoMessage") + + oldBalance, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.TestDAppV2ZEVMAddr) + require.NoError(r, err) + + // perform the deposit and call to the TestDAppV2ZEVMAddr + tx := r.V2ETHDepositAndCall( + r.TestDAppV2ZEVMAddr, + amount, + []byte{}, + gatewayevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, + ) + + // wait for the cctx to be mined + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "deposit_and_call") + require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + + // check the payload was received on the contract + messageIndex, err := r.TestDAppV2ZEVM.GetNoMessageIndex(&bind.CallOpts{}, r.EVMAddress()) + require.NoError(r, err) + r.AssertTestDAppZEVMCalled(true, messageIndex, amount) + + // check the balance was updated + newBalance, err := r.ETHZRC20.BalanceOf(&bind.CallOpts{}, r.TestDAppV2ZEVMAddr) + require.NoError(r, err) + require.Equal(r, new(big.Int).Add(oldBalance, amount), newBalance) +} diff --git a/e2e/e2etests/test_v2_eth_withdraw_and_call_no_message.go b/e2e/e2etests/test_v2_eth_withdraw_and_call_no_message.go new file mode 100644 index 0000000000..2e7531f9f1 --- /dev/null +++ b/e2e/e2etests/test_v2_eth_withdraw_and_call_no_message.go @@ -0,0 +1,54 @@ +package e2etests + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol" + + "github.com/zeta-chain/node/e2e/runner" + "github.com/zeta-chain/node/e2e/utils" + crosschaintypes "github.com/zeta-chain/node/x/crosschain/types" +) + +func TestV2ETHWithdrawAndCallNoMessage(r *runner.E2ERunner, args []string) { + require.Len(r, args, 1) + + previousGasLimit := r.ZEVMAuth.GasLimit + r.ZEVMAuth.GasLimit = 10000000 + defer func() { + r.ZEVMAuth.GasLimit = previousGasLimit + }() + + amount, ok := big.NewInt(0).SetString(args[0], 10) + require.True(r, ok, "Invalid amount specified for TestV2ETHWithdrawAndCallNoMessage") + + r.ApproveETHZRC20(r.GatewayZEVMAddr) + + // perform the withdraw + tx := r.V2ETHWithdrawAndCall( + r.TestDAppV2EVMAddr, + amount, + []byte{}, + gatewayzevm.RevertOptions{OnRevertGasLimit: big.NewInt(0)}, + ) + + // wait for the cctx to be mined + cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "withdraw_and_call") + require.Equal(r, crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status) + + // check called + messageIndex, err := r.TestDAppV2EVM.GetNoMessageIndex(&bind.CallOpts{}, r.EVMAddress()) + require.NoError(r, err) + r.AssertTestDAppEVMCalled(true, messageIndex, amount) + + // check expected sender was used + senderForMsg, err := r.TestDAppV2EVM.SenderWithMessage( + &bind.CallOpts{}, + []byte(messageIndex), + ) + require.NoError(r, err) + require.Equal(r, r.ZEVMAuth.From, senderForMsg) +} diff --git a/e2e/runner/v2_zevm.go b/e2e/runner/v2_zevm.go index 5153f2c823..45dd8c6761 100644 --- a/e2e/runner/v2_zevm.go +++ b/e2e/runner/v2_zevm.go @@ -76,7 +76,7 @@ func (r *E2ERunner) V2ETHWithdrawAndCall( return tx } -// V2ETHWithdrawAndCall calls WithdrawAndCall of Gateway with gas token on ZEVM using authenticated call +// V2ETHWithdrawAndCallThroughContract calls WithdrawAndCall of Gateway with gas token on ZEVM using authenticated call // through contract func (r *E2ERunner) V2ETHWithdrawAndCallThroughContract( gatewayZEVMCaller *gatewayzevmcaller.GatewayZEVMCaller, @@ -120,7 +120,7 @@ func (r *E2ERunner) V2ERC20Withdraw( return tx } -// V2ERC20WithdrawAndCall calls WithdrawAndCall of Gateway with erc20 token on ZEVM using arbitrary call +// V2ERC20WithdrawAndArbitraryCall calls WithdrawAndCall of Gateway with erc20 token on ZEVM using arbitrary call func (r *E2ERunner) V2ERC20WithdrawAndArbitraryCall( receiver ethcommon.Address, amount *big.Int, @@ -178,7 +178,7 @@ func (r *E2ERunner) V2ERC20WithdrawAndCall( return tx } -// V2ZEVMToEMVCall calls Call of Gateway on ZEVM using arbitrary call +// V2ZEVMToEMVArbitraryCall calls Call of Gateway on ZEVM using arbitrary call func (r *E2ERunner) V2ZEVMToEMVArbitraryCall( receiver ethcommon.Address, payload []byte, @@ -219,7 +219,7 @@ func (r *E2ERunner) V2ZEVMToEMVCall( return tx } -// V2ZEVMToEMVCall calls authenticated Call of Gateway on ZEVM through contract using authenticated call +// V2ZEVMToEMVCallThroughContract calls authenticated Call of Gateway on ZEVM through contract using authenticated call func (r *E2ERunner) V2ZEVMToEMVCallThroughContract( gatewayZEVMCaller *gatewayzevmcaller.GatewayZEVMCaller, receiver ethcommon.Address, diff --git a/go.mod b/go.mod index faa6709809..524a63d8be 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/zeta-chain/ethermint v0.0.0-20241010181243-044e22bdb7e7 github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 - github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241016134610-c70fec4d66a6 + github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241021075719-d40d2e28467c gitlab.com/thorchain/tss/go-tss v1.6.5 go.nhat.io/grpcmock v0.25.0 golang.org/x/crypto v0.23.0 diff --git a/go.sum b/go.sum index 8f884485e3..04150048bc 100644 --- a/go.sum +++ b/go.sum @@ -4208,8 +4208,8 @@ github.com/zeta-chain/go-tss v0.0.0-20240916173049-89fee4b0ae7f h1:XqUvw9a3EnDa2 github.com/zeta-chain/go-tss v0.0.0-20240916173049-89fee4b0ae7f/go.mod h1:B1FDE6kHs8hozKSX1/iXgCdvlFbS6+FeAupoBHDK0Cc= github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138 h1:vck/FcIIpFOvpBUm0NO17jbEtmSz/W/a5Y4jRuSJl6I= github.com/zeta-chain/keystone/keys v0.0.0-20240826165841-3874f358c138/go.mod h1:U494OsZTWsU75hqoriZgMdSsgSGP1mUL1jX+wN/Aez8= -github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241016134610-c70fec4d66a6 h1:9xfE77UtF316hcsX7H2/OjROWtxBZyk8k1sQN3exIVM= -github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241016134610-c70fec4d66a6/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w= +github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241021075719-d40d2e28467c h1:ZoFxMMZtivRLquXVq1sEVlT45UnTPMO1MSXtc88nDv4= +github.com/zeta-chain/protocol-contracts v1.0.2-athens3.0.20241021075719-d40d2e28467c/go.mod h1:SjT7QirtJE8stnAe1SlNOanxtfSfijJm3MGJ+Ax7w7w= github.com/zeta-chain/tss-lib v0.0.0-20240916163010-2e6b438bd901 h1:9whtN5fjYHfk4yXIuAsYP2EHxImwDWDVUOnZJ2pfL3w= github.com/zeta-chain/tss-lib v0.0.0-20240916163010-2e6b438bd901/go.mod h1:d2iTC62s9JwKiCMPhcDDXbIZmuzAyJ4lwso0H5QyRbk= github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= diff --git a/pkg/contracts/testdappv2/TestDAppV2.abi b/pkg/contracts/testdappv2/TestDAppV2.abi index c2846866a1..33270e31e3 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.abi +++ b/pkg/contracts/testdappv2/TestDAppV2.abi @@ -1,4 +1,17 @@ [ + { + "inputs": [], + "name": "NO_MESSAGE_CALL", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -111,6 +124,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "getNoMessageIndex", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, { "inputs": [ { diff --git a/pkg/contracts/testdappv2/TestDAppV2.bin b/pkg/contracts/testdappv2/TestDAppV2.bin index d5b99ed321..b53d34a684 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.bin +++ b/pkg/contracts/testdappv2/TestDAppV2.bin @@ -1 +1 @@ -608060405234801561001057600080fd5b5061130b806100206000396000f3fe6080604052600436106100a05760003560e01c8063a799911f11610064578063a799911f146101a8578063c7a339a9146101c4578063c9028a36146101ed578063e2842ed714610216578063f592cbfb14610253578063f936ae8514610290576100a7565b806336e980a0146100ac5780634297a263146100d55780635bcfd61614610112578063676cc0541461013b5780639291fe261461016b576100a7565b366100a757005b600080fd5b3480156100b857600080fd5b506100d360048036038101906100ce9190610c65565b6102cd565b005b3480156100e157600080fd5b506100fc60048036038101906100f79190610b80565b6102f7565b6040516101099190610fae565b60405180910390f35b34801561011e57600080fd5b5061013960048036038101906101349190610d57565b61030f565b005b61015560048036038101906101509190610cae565b610408565b6040516101629190610f8c565b60405180910390f35b34801561017757600080fd5b50610192600480360381019061018d9190610c65565b61051d565b60405161019f9190610fae565b60405180910390f35b6101c260048036038101906101bd9190610c65565b610560565b005b3480156101d057600080fd5b506101eb60048036038101906101e69190610bf6565b610589565b005b3480156101f957600080fd5b50610214600480360381019061020f9190610d0e565b61064c565b005b34801561022257600080fd5b5061023d60048036038101906102389190610b80565b610786565b60405161024a9190610f71565b60405180910390f35b34801561025f57600080fd5b5061027a60048036038101906102759190610c65565b6107a6565b6040516102879190610f71565b60405180910390f35b34801561029c57600080fd5b506102b760048036038101906102b29190610bad565b6107f5565b6040516102c49190610f1f565b60405180910390f35b6102d68161083e565b156102e057600080fd5b6102e981610894565b6102f48160006108e8565b50565b60026020528060005260406000206000915090505481565b61035c82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061083e565b1561036657600080fd5b6103b382828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b61040182828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050846108e8565b5050505050565b606061045783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6104a583838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050346108e8565b8360000160208101906104b89190610b26565b600184846040516104ca929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060026000836040516020016105349190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105698161083e565b1561057357600080fd5b61057c81610894565b61058681346108e8565b50565b6105928161083e565b1561059c57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016105d993929190610f3a565b602060405180830381600087803b1580156105f357600080fd5b505af1158015610607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062b9190610b53565b61063457600080fd5b61063d81610894565b61064781836108e8565b505050565b6106a781806060019061065f9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6107048180606001906106ba9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060006108e8565b8060000160208101906107179190610b26565b60018280606001906107299190610fc9565b604051610737929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000836040516020016107bc9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6001818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060405160200161084f90610f0a565b60405160208183030381529060405280519060200120826040516020016108769190610ef3565b60405160208183030381529060405280519060200120149050919050565b6001600080836040516020016108aa9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b8060026000846040516020016108fe9190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b600061093d61093884611051565b61102c565b90508281526020810184848401111561095957610958611219565b5b610964848285611154565b509392505050565b600061097f61097a84611082565b61102c565b90508281526020810184848401111561099b5761099a611219565b5b6109a6848285611154565b509392505050565b6000813590506109bd81611262565b92915050565b6000815190506109d281611279565b92915050565b6000813590506109e781611290565b92915050565b60008083601f840112610a0357610a026111fb565b5b8235905067ffffffffffffffff811115610a2057610a1f6111f6565b5b602083019150836001820283011115610a3c57610a3b61120f565b5b9250929050565b600082601f830112610a5857610a576111fb565b5b8135610a6884826020860161092a565b91505092915050565b600081359050610a80816112a7565b92915050565b600082601f830112610a9b57610a9a6111fb565b5b8135610aab84826020860161096c565b91505092915050565b600060208284031215610aca57610ac9611205565b5b81905092915050565b600060808284031215610ae957610ae8611205565b5b81905092915050565b600060608284031215610b0857610b07611205565b5b81905092915050565b600081359050610b20816112be565b92915050565b600060208284031215610b3c57610b3b611223565b5b6000610b4a848285016109ae565b91505092915050565b600060208284031215610b6957610b68611223565b5b6000610b77848285016109c3565b91505092915050565b600060208284031215610b9657610b95611223565b5b6000610ba4848285016109d8565b91505092915050565b600060208284031215610bc357610bc2611223565b5b600082013567ffffffffffffffff811115610be157610be061121e565b5b610bed84828501610a43565b91505092915050565b600080600060608486031215610c0f57610c0e611223565b5b6000610c1d86828701610a71565b9350506020610c2e86828701610b11565b925050604084013567ffffffffffffffff811115610c4f57610c4e61121e565b5b610c5b86828701610a86565b9150509250925092565b600060208284031215610c7b57610c7a611223565b5b600082013567ffffffffffffffff811115610c9957610c9861121e565b5b610ca584828501610a86565b91505092915050565b600080600060408486031215610cc757610cc6611223565b5b6000610cd586828701610ab4565b935050602084013567ffffffffffffffff811115610cf657610cf561121e565b5b610d02868287016109ed565b92509250509250925092565b600060208284031215610d2457610d23611223565b5b600082013567ffffffffffffffff811115610d4257610d4161121e565b5b610d4e84828501610ad3565b91505092915050565b600080600080600060808688031215610d7357610d72611223565b5b600086013567ffffffffffffffff811115610d9157610d9061121e565b5b610d9d88828901610af2565b9550506020610dae888289016109ae565b9450506040610dbf88828901610b11565b935050606086013567ffffffffffffffff811115610de057610ddf61121e565b5b610dec888289016109ed565b92509250509295509295909350565b610e04816110f0565b82525050565b610e1381611102565b82525050565b6000610e2583856110da565b9350610e32838584611154565b82840190509392505050565b6000610e49826110b3565b610e5381856110c9565b9350610e63818560208601611163565b610e6c81611228565b840191505092915050565b6000610e82826110be565b610e8c81856110e5565b9350610e9c818560208601611163565b80840191505092915050565b6000610eb56006836110e5565b9150610ec082611239565b600682019050919050565b610ed48161114a565b82525050565b6000610ee7828486610e19565b91508190509392505050565b6000610eff8284610e77565b915081905092915050565b6000610f1582610ea8565b9150819050919050565b6000602082019050610f346000830184610dfb565b92915050565b6000606082019050610f4f6000830186610dfb565b610f5c6020830185610dfb565b610f696040830184610ecb565b949350505050565b6000602082019050610f866000830184610e0a565b92915050565b60006020820190508181036000830152610fa68184610e3e565b905092915050565b6000602082019050610fc36000830184610ecb565b92915050565b60008083356001602003843603038112610fe657610fe561120a565b5b80840192508235915067ffffffffffffffff82111561100857611007611200565b5b60208301925060018202360383131561102457611023611214565b5b509250929050565b6000611036611047565b90506110428282611196565b919050565b6000604051905090565b600067ffffffffffffffff82111561106c5761106b6111c7565b5b61107582611228565b9050602081019050919050565b600067ffffffffffffffff82111561109d5761109c6111c7565b5b6110a682611228565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600081905092915050565b60006110fb8261112a565b9050919050565b60008115159050919050565b6000819050919050565b6000611123826110f0565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015611181578082015181840152602081019050611166565b83811115611190576000848401525b50505050565b61119f82611228565b810181811067ffffffffffffffff821117156111be576111bd6111c7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61126b816110f0565b811461127657600080fd5b50565b61128281611102565b811461128d57600080fd5b50565b6112998161110e565b81146112a457600080fd5b50565b6112b081611118565b81146112bb57600080fd5b50565b6112c78161114a565b81146112d257600080fd5b5056fea26469706673582212201f295f137d0ea146883fdaa6858baa14e4c467a843ff4e7829fd9df0d4c2aede64736f6c63430008070033 +6080604052348015600f57600080fd5b506115288061001f6000396000f3fe6080604052600436106100c65760003560e01c8063ad23b28b1161007f578063c9028a3611610059578063c9028a361461027b578063e2842ed7146102a4578063f592cbfb146102e1578063f936ae851461031e576100cd565b8063ad23b28b146101ea578063c7a339a914610227578063c85f843414610250576100cd565b806336e980a0146100d25780634297a263146100fb5780635bcfd61614610138578063676cc054146101615780639291fe2614610191578063a799911f146101ce576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610b86565b61035b565b005b34801561010757600080fd5b50610122600480360381019061011d9190610c05565b610385565b60405161012f9190610c4b565b60405180910390f35b34801561014457600080fd5b5061015f600480360381019061015a9190610d74565b61039d565b005b61017b60048036038101906101769190610e37565b610483565b6040516101889190610f16565b60405180910390f35b34801561019d57600080fd5b506101b860048036038101906101b39190610b86565b610595565b6040516101c59190610c4b565b60405180910390f35b6101e860048036038101906101e39190610b86565b6105d8565b005b3480156101f657600080fd5b50610211600480360381019061020c9190610f38565b610601565b60405161021e9190610fba565b60405180910390f35b34801561023357600080fd5b5061024e6004803603810190610249919061101a565b610661565b005b34801561025c57600080fd5b50610265610715565b6040516102729190610fba565b60405180910390f35b34801561028757600080fd5b506102a2600480360381019061029d91906110a8565b61074e565b005b3480156102b057600080fd5b506102cb60048036038101906102c69190610c05565b610888565b6040516102d8919061110c565b60405180910390f35b3480156102ed57600080fd5b5061030860048036038101906103039190610b86565b6108a8565b604051610315919061110c565b60405180910390f35b34801561032a57600080fd5b50610345600480360381019061034091906111c8565b6108f7565b6040516103529190611220565b60405180910390f35b61036481610940565b1561036e57600080fd5b61037781610996565b6103828160006109ea565b50565b60026020528060005260406000206000915090505481565b6103ea82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610940565b156103f457600080fd5b600080838390501461044a5782828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610466565b6104658660200160208101906104609190610f38565b610601565b5b905061047181610996565b61047b81856109ea565b505050505050565b606060008084849050146104db5783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506104f7565b6104f68560000160208101906104f19190610f38565b610601565b5b905061050281610996565b61050c81346109ea565b84600001602081019061051f9190610f38565b60018260405161052f9190611277565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550604051806020016040528060008152509150509392505050565b600060026000836040516020016105ac91906112ca565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105e181610940565b156105eb57600080fd5b6105f481610996565b6105fe81346109ea565b50565b60606040518060400160405280601681526020017f63616c6c65642077697468206e6f206d657373616765000000000000000000008152508260405160200161064b929190611329565b6040516020818303038152906040529050919050565b61066a81610940565b1561067457600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016106b193929190611351565b6020604051808303816000875af11580156106d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f491906113b4565b6106fd57600080fd5b61070681610996565b61071081836109ea565b505050565b6040518060400160405280601681526020017f63616c6c65642077697468206e6f206d6573736167650000000000000000000081525081565b6107a981806060019061076191906113f0565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610996565b6108068180606001906107bc91906113f0565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060006109ea565b8060000160208101906108199190610f38565b600182806060019061082b91906113f0565b604051610839929190611478565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000836040516020016108be91906112ca565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6001818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000604051602001610951906114dd565b604051602081830303815290604052805190602001208260405160200161097891906112ca565b60405160208183030381529060405280519060200120149050919050565b6001600080836040516020016109ac91906112ca565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806002600084604051602001610a0091906112ca565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610a9382610a4a565b810181811067ffffffffffffffff82111715610ab257610ab1610a5b565b5b80604052505050565b6000610ac5610a2c565b9050610ad18282610a8a565b919050565b600067ffffffffffffffff821115610af157610af0610a5b565b5b610afa82610a4a565b9050602081019050919050565b82818337600083830152505050565b6000610b29610b2484610ad6565b610abb565b905082815260208101848484011115610b4557610b44610a45565b5b610b50848285610b07565b509392505050565b600082601f830112610b6d57610b6c610a40565b5b8135610b7d848260208601610b16565b91505092915050565b600060208284031215610b9c57610b9b610a36565b5b600082013567ffffffffffffffff811115610bba57610bb9610a3b565b5b610bc684828501610b58565b91505092915050565b6000819050919050565b610be281610bcf565b8114610bed57600080fd5b50565b600081359050610bff81610bd9565b92915050565b600060208284031215610c1b57610c1a610a36565b5b6000610c2984828501610bf0565b91505092915050565b6000819050919050565b610c4581610c32565b82525050565b6000602082019050610c606000830184610c3c565b92915050565b600080fd5b600060608284031215610c8157610c80610c66565b5b81905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cb582610c8a565b9050919050565b610cc581610caa565b8114610cd057600080fd5b50565b600081359050610ce281610cbc565b92915050565b610cf181610c32565b8114610cfc57600080fd5b50565b600081359050610d0e81610ce8565b92915050565b600080fd5b600080fd5b60008083601f840112610d3457610d33610a40565b5b8235905067ffffffffffffffff811115610d5157610d50610d14565b5b602083019150836001820283011115610d6d57610d6c610d19565b5b9250929050565b600080600080600060808688031215610d9057610d8f610a36565b5b600086013567ffffffffffffffff811115610dae57610dad610a3b565b5b610dba88828901610c6b565b9550506020610dcb88828901610cd3565b9450506040610ddc88828901610cff565b935050606086013567ffffffffffffffff811115610dfd57610dfc610a3b565b5b610e0988828901610d1e565b92509250509295509295909350565b600060208284031215610e2e57610e2d610c66565b5b81905092915050565b600080600060408486031215610e5057610e4f610a36565b5b6000610e5e86828701610e18565b935050602084013567ffffffffffffffff811115610e7f57610e7e610a3b565b5b610e8b86828701610d1e565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b60005b83811015610ed1578082015181840152602081019050610eb6565b60008484015250505050565b6000610ee882610e97565b610ef28185610ea2565b9350610f02818560208601610eb3565b610f0b81610a4a565b840191505092915050565b60006020820190508181036000830152610f308184610edd565b905092915050565b600060208284031215610f4e57610f4d610a36565b5b6000610f5c84828501610cd3565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000610f8c82610f65565b610f968185610f70565b9350610fa6818560208601610eb3565b610faf81610a4a565b840191505092915050565b60006020820190508181036000830152610fd48184610f81565b905092915050565b6000610fe782610caa565b9050919050565b610ff781610fdc565b811461100257600080fd5b50565b60008135905061101481610fee565b92915050565b60008060006060848603121561103357611032610a36565b5b600061104186828701611005565b935050602061105286828701610cff565b925050604084013567ffffffffffffffff81111561107357611072610a3b565b5b61107f86828701610b58565b9150509250925092565b60006080828403121561109f5761109e610c66565b5b81905092915050565b6000602082840312156110be576110bd610a36565b5b600082013567ffffffffffffffff8111156110dc576110db610a3b565b5b6110e884828501611089565b91505092915050565b60008115159050919050565b611106816110f1565b82525050565b600060208201905061112160008301846110fd565b92915050565b600067ffffffffffffffff82111561114257611141610a5b565b5b61114b82610a4a565b9050602081019050919050565b600061116b61116684611127565b610abb565b90508281526020810184848401111561118757611186610a45565b5b611192848285610b07565b509392505050565b600082601f8301126111af576111ae610a40565b5b81356111bf848260208601611158565b91505092915050565b6000602082840312156111de576111dd610a36565b5b600082013567ffffffffffffffff8111156111fc576111fb610a3b565b5b6112088482850161119a565b91505092915050565b61121a81610caa565b82525050565b60006020820190506112356000830184611211565b92915050565b600081905092915050565b600061125182610e97565b61125b818561123b565b935061126b818560208601610eb3565b80840191505092915050565b60006112838284611246565b915081905092915050565b600081905092915050565b60006112a482610f65565b6112ae818561128e565b93506112be818560208601610eb3565b80840191505092915050565b60006112d68284611299565b915081905092915050565b60008160601b9050919050565b60006112f9826112e1565b9050919050565b600061130b826112ee565b9050919050565b61132361131e82610caa565b611300565b82525050565b60006113358285611299565b91506113418284611312565b6014820191508190509392505050565b60006060820190506113666000830186611211565b6113736020830185611211565b6113806040830184610c3c565b949350505050565b611391816110f1565b811461139c57600080fd5b50565b6000815190506113ae81611388565b92915050565b6000602082840312156113ca576113c9610a36565b5b60006113d88482850161139f565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261140d5761140c6113e1565b5b80840192508235915067ffffffffffffffff82111561142f5761142e6113e6565b5b60208301925060018202360383131561144b5761144a6113eb565b5b509250929050565b600061145f838561123b565b935061146c838584610b07565b82840190509392505050565b6000611485828486611453565b91508190509392505050565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b60006114c760068361128e565b91506114d282611491565b600682019050919050565b60006114e8826114ba565b915081905091905056fea26469706673582212205747e512af435680fec20f1d2e088f93d6c12052fee7e353f45e5e49a671377b64736f6c634300081a0033 diff --git a/pkg/contracts/testdappv2/TestDAppV2.go b/pkg/contracts/testdappv2/TestDAppV2.go index 967c261e60..7414aaccf2 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.go +++ b/pkg/contracts/testdappv2/TestDAppV2.go @@ -51,8 +51,8 @@ type TestDAppV2zContext struct { // TestDAppV2MetaData contains all meta data concerning the TestDAppV2 contract. var TestDAppV2MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"amountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"calledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"erc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"erc20Call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"gasCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getAmountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getCalledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"origin\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainID\",\"type\":\"uint256\"}],\"internalType\":\"structTestDAppV2.zContext\",\"name\":\"_context\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_zrc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"internalType\":\"structTestDAppV2.MessageContext\",\"name\":\"messageContext\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"revertMessage\",\"type\":\"bytes\"}],\"internalType\":\"structTestDAppV2.RevertContext\",\"name\":\"revertContext\",\"type\":\"tuple\"}],\"name\":\"onRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"senderWithMessage\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"simpleCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", - Bin: "0x608060405234801561001057600080fd5b5061130b806100206000396000f3fe6080604052600436106100a05760003560e01c8063a799911f11610064578063a799911f146101a8578063c7a339a9146101c4578063c9028a36146101ed578063e2842ed714610216578063f592cbfb14610253578063f936ae8514610290576100a7565b806336e980a0146100ac5780634297a263146100d55780635bcfd61614610112578063676cc0541461013b5780639291fe261461016b576100a7565b366100a757005b600080fd5b3480156100b857600080fd5b506100d360048036038101906100ce9190610c65565b6102cd565b005b3480156100e157600080fd5b506100fc60048036038101906100f79190610b80565b6102f7565b6040516101099190610fae565b60405180910390f35b34801561011e57600080fd5b5061013960048036038101906101349190610d57565b61030f565b005b61015560048036038101906101509190610cae565b610408565b6040516101629190610f8c565b60405180910390f35b34801561017757600080fd5b50610192600480360381019061018d9190610c65565b61051d565b60405161019f9190610fae565b60405180910390f35b6101c260048036038101906101bd9190610c65565b610560565b005b3480156101d057600080fd5b506101eb60048036038101906101e69190610bf6565b610589565b005b3480156101f957600080fd5b50610214600480360381019061020f9190610d0e565b61064c565b005b34801561022257600080fd5b5061023d60048036038101906102389190610b80565b610786565b60405161024a9190610f71565b60405180910390f35b34801561025f57600080fd5b5061027a60048036038101906102759190610c65565b6107a6565b6040516102879190610f71565b60405180910390f35b34801561029c57600080fd5b506102b760048036038101906102b29190610bad565b6107f5565b6040516102c49190610f1f565b60405180910390f35b6102d68161083e565b156102e057600080fd5b6102e981610894565b6102f48160006108e8565b50565b60026020528060005260406000206000915090505481565b61035c82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061083e565b1561036657600080fd5b6103b382828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b61040182828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050846108e8565b5050505050565b606061045783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6104a583838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050346108e8565b8360000160208101906104b89190610b26565b600184846040516104ca929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060026000836040516020016105349190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105698161083e565b1561057357600080fd5b61057c81610894565b61058681346108e8565b50565b6105928161083e565b1561059c57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016105d993929190610f3a565b602060405180830381600087803b1580156105f357600080fd5b505af1158015610607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062b9190610b53565b61063457600080fd5b61063d81610894565b61064781836108e8565b505050565b6106a781806060019061065f9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6107048180606001906106ba9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060006108e8565b8060000160208101906107179190610b26565b60018280606001906107299190610fc9565b604051610737929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000836040516020016107bc9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6001818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060405160200161084f90610f0a565b60405160208183030381529060405280519060200120826040516020016108769190610ef3565b60405160208183030381529060405280519060200120149050919050565b6001600080836040516020016108aa9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b8060026000846040516020016108fe9190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b600061093d61093884611051565b61102c565b90508281526020810184848401111561095957610958611219565b5b610964848285611154565b509392505050565b600061097f61097a84611082565b61102c565b90508281526020810184848401111561099b5761099a611219565b5b6109a6848285611154565b509392505050565b6000813590506109bd81611262565b92915050565b6000815190506109d281611279565b92915050565b6000813590506109e781611290565b92915050565b60008083601f840112610a0357610a026111fb565b5b8235905067ffffffffffffffff811115610a2057610a1f6111f6565b5b602083019150836001820283011115610a3c57610a3b61120f565b5b9250929050565b600082601f830112610a5857610a576111fb565b5b8135610a6884826020860161092a565b91505092915050565b600081359050610a80816112a7565b92915050565b600082601f830112610a9b57610a9a6111fb565b5b8135610aab84826020860161096c565b91505092915050565b600060208284031215610aca57610ac9611205565b5b81905092915050565b600060808284031215610ae957610ae8611205565b5b81905092915050565b600060608284031215610b0857610b07611205565b5b81905092915050565b600081359050610b20816112be565b92915050565b600060208284031215610b3c57610b3b611223565b5b6000610b4a848285016109ae565b91505092915050565b600060208284031215610b6957610b68611223565b5b6000610b77848285016109c3565b91505092915050565b600060208284031215610b9657610b95611223565b5b6000610ba4848285016109d8565b91505092915050565b600060208284031215610bc357610bc2611223565b5b600082013567ffffffffffffffff811115610be157610be061121e565b5b610bed84828501610a43565b91505092915050565b600080600060608486031215610c0f57610c0e611223565b5b6000610c1d86828701610a71565b9350506020610c2e86828701610b11565b925050604084013567ffffffffffffffff811115610c4f57610c4e61121e565b5b610c5b86828701610a86565b9150509250925092565b600060208284031215610c7b57610c7a611223565b5b600082013567ffffffffffffffff811115610c9957610c9861121e565b5b610ca584828501610a86565b91505092915050565b600080600060408486031215610cc757610cc6611223565b5b6000610cd586828701610ab4565b935050602084013567ffffffffffffffff811115610cf657610cf561121e565b5b610d02868287016109ed565b92509250509250925092565b600060208284031215610d2457610d23611223565b5b600082013567ffffffffffffffff811115610d4257610d4161121e565b5b610d4e84828501610ad3565b91505092915050565b600080600080600060808688031215610d7357610d72611223565b5b600086013567ffffffffffffffff811115610d9157610d9061121e565b5b610d9d88828901610af2565b9550506020610dae888289016109ae565b9450506040610dbf88828901610b11565b935050606086013567ffffffffffffffff811115610de057610ddf61121e565b5b610dec888289016109ed565b92509250509295509295909350565b610e04816110f0565b82525050565b610e1381611102565b82525050565b6000610e2583856110da565b9350610e32838584611154565b82840190509392505050565b6000610e49826110b3565b610e5381856110c9565b9350610e63818560208601611163565b610e6c81611228565b840191505092915050565b6000610e82826110be565b610e8c81856110e5565b9350610e9c818560208601611163565b80840191505092915050565b6000610eb56006836110e5565b9150610ec082611239565b600682019050919050565b610ed48161114a565b82525050565b6000610ee7828486610e19565b91508190509392505050565b6000610eff8284610e77565b915081905092915050565b6000610f1582610ea8565b9150819050919050565b6000602082019050610f346000830184610dfb565b92915050565b6000606082019050610f4f6000830186610dfb565b610f5c6020830185610dfb565b610f696040830184610ecb565b949350505050565b6000602082019050610f866000830184610e0a565b92915050565b60006020820190508181036000830152610fa68184610e3e565b905092915050565b6000602082019050610fc36000830184610ecb565b92915050565b60008083356001602003843603038112610fe657610fe561120a565b5b80840192508235915067ffffffffffffffff82111561100857611007611200565b5b60208301925060018202360383131561102457611023611214565b5b509250929050565b6000611036611047565b90506110428282611196565b919050565b6000604051905090565b600067ffffffffffffffff82111561106c5761106b6111c7565b5b61107582611228565b9050602081019050919050565b600067ffffffffffffffff82111561109d5761109c6111c7565b5b6110a682611228565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600081905092915050565b60006110fb8261112a565b9050919050565b60008115159050919050565b6000819050919050565b6000611123826110f0565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015611181578082015181840152602081019050611166565b83811115611190576000848401525b50505050565b61119f82611228565b810181811067ffffffffffffffff821117156111be576111bd6111c7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61126b816110f0565b811461127657600080fd5b50565b61128281611102565b811461128d57600080fd5b50565b6112998161110e565b81146112a457600080fd5b50565b6112b081611118565b81146112bb57600080fd5b50565b6112c78161114a565b81146112d257600080fd5b5056fea26469706673582212201f295f137d0ea146883fdaa6858baa14e4c467a843ff4e7829fd9df0d4c2aede64736f6c63430008070033", + ABI: "[{\"inputs\":[],\"name\":\"NO_MESSAGE_CALL\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"amountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"calledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contractIERC20\",\"name\":\"erc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"erc20Call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"gasCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getAmountWithMessage\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"getCalledWithMessage\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"getNoMessageIndex\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"origin\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"chainID\",\"type\":\"uint256\"}],\"internalType\":\"structTestDAppV2.zContext\",\"name\":\"_context\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"_zrc20\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"internalType\":\"structTestDAppV2.MessageContext\",\"name\":\"messageContext\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"onCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"revertMessage\",\"type\":\"bytes\"}],\"internalType\":\"structTestDAppV2.RevertContext\",\"name\":\"revertContext\",\"type\":\"tuple\"}],\"name\":\"onRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"senderWithMessage\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"simpleCall\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x6080604052348015600f57600080fd5b506115288061001f6000396000f3fe6080604052600436106100c65760003560e01c8063ad23b28b1161007f578063c9028a3611610059578063c9028a361461027b578063e2842ed7146102a4578063f592cbfb146102e1578063f936ae851461031e576100cd565b8063ad23b28b146101ea578063c7a339a914610227578063c85f843414610250576100cd565b806336e980a0146100d25780634297a263146100fb5780635bcfd61614610138578063676cc054146101615780639291fe2614610191578063a799911f146101ce576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610b86565b61035b565b005b34801561010757600080fd5b50610122600480360381019061011d9190610c05565b610385565b60405161012f9190610c4b565b60405180910390f35b34801561014457600080fd5b5061015f600480360381019061015a9190610d74565b61039d565b005b61017b60048036038101906101769190610e37565b610483565b6040516101889190610f16565b60405180910390f35b34801561019d57600080fd5b506101b860048036038101906101b39190610b86565b610595565b6040516101c59190610c4b565b60405180910390f35b6101e860048036038101906101e39190610b86565b6105d8565b005b3480156101f657600080fd5b50610211600480360381019061020c9190610f38565b610601565b60405161021e9190610fba565b60405180910390f35b34801561023357600080fd5b5061024e6004803603810190610249919061101a565b610661565b005b34801561025c57600080fd5b50610265610715565b6040516102729190610fba565b60405180910390f35b34801561028757600080fd5b506102a2600480360381019061029d91906110a8565b61074e565b005b3480156102b057600080fd5b506102cb60048036038101906102c69190610c05565b610888565b6040516102d8919061110c565b60405180910390f35b3480156102ed57600080fd5b5061030860048036038101906103039190610b86565b6108a8565b604051610315919061110c565b60405180910390f35b34801561032a57600080fd5b50610345600480360381019061034091906111c8565b6108f7565b6040516103529190611220565b60405180910390f35b61036481610940565b1561036e57600080fd5b61037781610996565b6103828160006109ea565b50565b60026020528060005260406000206000915090505481565b6103ea82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610940565b156103f457600080fd5b600080838390501461044a5782828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610466565b6104658660200160208101906104609190610f38565b610601565b5b905061047181610996565b61047b81856109ea565b505050505050565b606060008084849050146104db5783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506104f7565b6104f68560000160208101906104f19190610f38565b610601565b5b905061050281610996565b61050c81346109ea565b84600001602081019061051f9190610f38565b60018260405161052f9190611277565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550604051806020016040528060008152509150509392505050565b600060026000836040516020016105ac91906112ca565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105e181610940565b156105eb57600080fd5b6105f481610996565b6105fe81346109ea565b50565b60606040518060400160405280601681526020017f63616c6c65642077697468206e6f206d657373616765000000000000000000008152508260405160200161064b929190611329565b6040516020818303038152906040529050919050565b61066a81610940565b1561067457600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016106b193929190611351565b6020604051808303816000875af11580156106d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f491906113b4565b6106fd57600080fd5b61070681610996565b61071081836109ea565b505050565b6040518060400160405280601681526020017f63616c6c65642077697468206e6f206d6573736167650000000000000000000081525081565b6107a981806060019061076191906113f0565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610996565b6108068180606001906107bc91906113f0565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060006109ea565b8060000160208101906108199190610f38565b600182806060019061082b91906113f0565b604051610839929190611478565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000836040516020016108be91906112ca565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6001818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000604051602001610951906114dd565b604051602081830303815290604052805190602001208260405160200161097891906112ca565b60405160208183030381529060405280519060200120149050919050565b6001600080836040516020016109ac91906112ca565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806002600084604051602001610a0091906112ca565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610a9382610a4a565b810181811067ffffffffffffffff82111715610ab257610ab1610a5b565b5b80604052505050565b6000610ac5610a2c565b9050610ad18282610a8a565b919050565b600067ffffffffffffffff821115610af157610af0610a5b565b5b610afa82610a4a565b9050602081019050919050565b82818337600083830152505050565b6000610b29610b2484610ad6565b610abb565b905082815260208101848484011115610b4557610b44610a45565b5b610b50848285610b07565b509392505050565b600082601f830112610b6d57610b6c610a40565b5b8135610b7d848260208601610b16565b91505092915050565b600060208284031215610b9c57610b9b610a36565b5b600082013567ffffffffffffffff811115610bba57610bb9610a3b565b5b610bc684828501610b58565b91505092915050565b6000819050919050565b610be281610bcf565b8114610bed57600080fd5b50565b600081359050610bff81610bd9565b92915050565b600060208284031215610c1b57610c1a610a36565b5b6000610c2984828501610bf0565b91505092915050565b6000819050919050565b610c4581610c32565b82525050565b6000602082019050610c606000830184610c3c565b92915050565b600080fd5b600060608284031215610c8157610c80610c66565b5b81905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cb582610c8a565b9050919050565b610cc581610caa565b8114610cd057600080fd5b50565b600081359050610ce281610cbc565b92915050565b610cf181610c32565b8114610cfc57600080fd5b50565b600081359050610d0e81610ce8565b92915050565b600080fd5b600080fd5b60008083601f840112610d3457610d33610a40565b5b8235905067ffffffffffffffff811115610d5157610d50610d14565b5b602083019150836001820283011115610d6d57610d6c610d19565b5b9250929050565b600080600080600060808688031215610d9057610d8f610a36565b5b600086013567ffffffffffffffff811115610dae57610dad610a3b565b5b610dba88828901610c6b565b9550506020610dcb88828901610cd3565b9450506040610ddc88828901610cff565b935050606086013567ffffffffffffffff811115610dfd57610dfc610a3b565b5b610e0988828901610d1e565b92509250509295509295909350565b600060208284031215610e2e57610e2d610c66565b5b81905092915050565b600080600060408486031215610e5057610e4f610a36565b5b6000610e5e86828701610e18565b935050602084013567ffffffffffffffff811115610e7f57610e7e610a3b565b5b610e8b86828701610d1e565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b60005b83811015610ed1578082015181840152602081019050610eb6565b60008484015250505050565b6000610ee882610e97565b610ef28185610ea2565b9350610f02818560208601610eb3565b610f0b81610a4a565b840191505092915050565b60006020820190508181036000830152610f308184610edd565b905092915050565b600060208284031215610f4e57610f4d610a36565b5b6000610f5c84828501610cd3565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000610f8c82610f65565b610f968185610f70565b9350610fa6818560208601610eb3565b610faf81610a4a565b840191505092915050565b60006020820190508181036000830152610fd48184610f81565b905092915050565b6000610fe782610caa565b9050919050565b610ff781610fdc565b811461100257600080fd5b50565b60008135905061101481610fee565b92915050565b60008060006060848603121561103357611032610a36565b5b600061104186828701611005565b935050602061105286828701610cff565b925050604084013567ffffffffffffffff81111561107357611072610a3b565b5b61107f86828701610b58565b9150509250925092565b60006080828403121561109f5761109e610c66565b5b81905092915050565b6000602082840312156110be576110bd610a36565b5b600082013567ffffffffffffffff8111156110dc576110db610a3b565b5b6110e884828501611089565b91505092915050565b60008115159050919050565b611106816110f1565b82525050565b600060208201905061112160008301846110fd565b92915050565b600067ffffffffffffffff82111561114257611141610a5b565b5b61114b82610a4a565b9050602081019050919050565b600061116b61116684611127565b610abb565b90508281526020810184848401111561118757611186610a45565b5b611192848285610b07565b509392505050565b600082601f8301126111af576111ae610a40565b5b81356111bf848260208601611158565b91505092915050565b6000602082840312156111de576111dd610a36565b5b600082013567ffffffffffffffff8111156111fc576111fb610a3b565b5b6112088482850161119a565b91505092915050565b61121a81610caa565b82525050565b60006020820190506112356000830184611211565b92915050565b600081905092915050565b600061125182610e97565b61125b818561123b565b935061126b818560208601610eb3565b80840191505092915050565b60006112838284611246565b915081905092915050565b600081905092915050565b60006112a482610f65565b6112ae818561128e565b93506112be818560208601610eb3565b80840191505092915050565b60006112d68284611299565b915081905092915050565b60008160601b9050919050565b60006112f9826112e1565b9050919050565b600061130b826112ee565b9050919050565b61132361131e82610caa565b611300565b82525050565b60006113358285611299565b91506113418284611312565b6014820191508190509392505050565b60006060820190506113666000830186611211565b6113736020830185611211565b6113806040830184610c3c565b949350505050565b611391816110f1565b811461139c57600080fd5b50565b6000815190506113ae81611388565b92915050565b6000602082840312156113ca576113c9610a36565b5b60006113d88482850161139f565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261140d5761140c6113e1565b5b80840192508235915067ffffffffffffffff82111561142f5761142e6113e6565b5b60208301925060018202360383131561144b5761144a6113eb565b5b509250929050565b600061145f838561123b565b935061146c838584610b07565b82840190509392505050565b6000611485828486611453565b91508190509392505050565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b60006114c760068361128e565b91506114d282611491565b600682019050919050565b60006114e8826114ba565b915081905091905056fea26469706673582212205747e512af435680fec20f1d2e088f93d6c12052fee7e353f45e5e49a671377b64736f6c634300081a0033", } // TestDAppV2ABI is the input ABI used to generate the binding from. @@ -222,6 +222,37 @@ func (_TestDAppV2 *TestDAppV2TransactorRaw) Transact(opts *bind.TransactOpts, me return _TestDAppV2.Contract.contract.Transact(opts, method, params...) } +// NOMESSAGECALL is a free data retrieval call binding the contract method 0xc85f8434. +// +// Solidity: function NO_MESSAGE_CALL() view returns(string) +func (_TestDAppV2 *TestDAppV2Caller) NOMESSAGECALL(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _TestDAppV2.contract.Call(opts, &out, "NO_MESSAGE_CALL") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// NOMESSAGECALL is a free data retrieval call binding the contract method 0xc85f8434. +// +// Solidity: function NO_MESSAGE_CALL() view returns(string) +func (_TestDAppV2 *TestDAppV2Session) NOMESSAGECALL() (string, error) { + return _TestDAppV2.Contract.NOMESSAGECALL(&_TestDAppV2.CallOpts) +} + +// NOMESSAGECALL is a free data retrieval call binding the contract method 0xc85f8434. +// +// Solidity: function NO_MESSAGE_CALL() view returns(string) +func (_TestDAppV2 *TestDAppV2CallerSession) NOMESSAGECALL() (string, error) { + return _TestDAppV2.Contract.NOMESSAGECALL(&_TestDAppV2.CallOpts) +} + // AmountWithMessage is a free data retrieval call binding the contract method 0x4297a263. // // Solidity: function amountWithMessage(bytes32 ) view returns(uint256) @@ -346,6 +377,37 @@ func (_TestDAppV2 *TestDAppV2CallerSession) GetCalledWithMessage(message string) return _TestDAppV2.Contract.GetCalledWithMessage(&_TestDAppV2.CallOpts, message) } +// GetNoMessageIndex is a free data retrieval call binding the contract method 0xad23b28b. +// +// Solidity: function getNoMessageIndex(address sender) pure returns(string) +func (_TestDAppV2 *TestDAppV2Caller) GetNoMessageIndex(opts *bind.CallOpts, sender common.Address) (string, error) { + var out []interface{} + err := _TestDAppV2.contract.Call(opts, &out, "getNoMessageIndex", sender) + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// GetNoMessageIndex is a free data retrieval call binding the contract method 0xad23b28b. +// +// Solidity: function getNoMessageIndex(address sender) pure returns(string) +func (_TestDAppV2 *TestDAppV2Session) GetNoMessageIndex(sender common.Address) (string, error) { + return _TestDAppV2.Contract.GetNoMessageIndex(&_TestDAppV2.CallOpts, sender) +} + +// GetNoMessageIndex is a free data retrieval call binding the contract method 0xad23b28b. +// +// Solidity: function getNoMessageIndex(address sender) pure returns(string) +func (_TestDAppV2 *TestDAppV2CallerSession) GetNoMessageIndex(sender common.Address) (string, error) { + return _TestDAppV2.Contract.GetNoMessageIndex(&_TestDAppV2.CallOpts, sender) +} + // SenderWithMessage is a free data retrieval call binding the contract method 0xf936ae85. // // Solidity: function senderWithMessage(bytes ) view returns(address) diff --git a/pkg/contracts/testdappv2/TestDAppV2.json b/pkg/contracts/testdappv2/TestDAppV2.json index 2ea4bd665d..189d8b853f 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.json +++ b/pkg/contracts/testdappv2/TestDAppV2.json @@ -1,5 +1,18 @@ { "abi": [ + { + "inputs": [], + "name": "NO_MESSAGE_CALL", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -112,6 +125,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "getNoMessageIndex", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + }, { "inputs": [ { @@ -260,5 +292,5 @@ "type": "receive" } ], - "bin": "608060405234801561001057600080fd5b5061130b806100206000396000f3fe6080604052600436106100a05760003560e01c8063a799911f11610064578063a799911f146101a8578063c7a339a9146101c4578063c9028a36146101ed578063e2842ed714610216578063f592cbfb14610253578063f936ae8514610290576100a7565b806336e980a0146100ac5780634297a263146100d55780635bcfd61614610112578063676cc0541461013b5780639291fe261461016b576100a7565b366100a757005b600080fd5b3480156100b857600080fd5b506100d360048036038101906100ce9190610c65565b6102cd565b005b3480156100e157600080fd5b506100fc60048036038101906100f79190610b80565b6102f7565b6040516101099190610fae565b60405180910390f35b34801561011e57600080fd5b5061013960048036038101906101349190610d57565b61030f565b005b61015560048036038101906101509190610cae565b610408565b6040516101629190610f8c565b60405180910390f35b34801561017757600080fd5b50610192600480360381019061018d9190610c65565b61051d565b60405161019f9190610fae565b60405180910390f35b6101c260048036038101906101bd9190610c65565b610560565b005b3480156101d057600080fd5b506101eb60048036038101906101e69190610bf6565b610589565b005b3480156101f957600080fd5b50610214600480360381019061020f9190610d0e565b61064c565b005b34801561022257600080fd5b5061023d60048036038101906102389190610b80565b610786565b60405161024a9190610f71565b60405180910390f35b34801561025f57600080fd5b5061027a60048036038101906102759190610c65565b6107a6565b6040516102879190610f71565b60405180910390f35b34801561029c57600080fd5b506102b760048036038101906102b29190610bad565b6107f5565b6040516102c49190610f1f565b60405180910390f35b6102d68161083e565b156102e057600080fd5b6102e981610894565b6102f48160006108e8565b50565b60026020528060005260406000206000915090505481565b61035c82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061083e565b1561036657600080fd5b6103b382828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b61040182828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050846108e8565b5050505050565b606061045783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6104a583838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050346108e8565b8360000160208101906104b89190610b26565b600184846040516104ca929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055509392505050565b600060026000836040516020016105349190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105698161083e565b1561057357600080fd5b61057c81610894565b61058681346108e8565b50565b6105928161083e565b1561059c57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016105d993929190610f3a565b602060405180830381600087803b1580156105f357600080fd5b505af1158015610607573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061062b9190610b53565b61063457600080fd5b61063d81610894565b61064781836108e8565b505050565b6106a781806060019061065f9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610894565b6107048180606001906106ba9190610fc9565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060006108e8565b8060000160208101906107179190610b26565b60018280606001906107299190610fc9565b604051610737929190610eda565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000836040516020016107bc9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6001818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060405160200161084f90610f0a565b60405160208183030381529060405280519060200120826040516020016108769190610ef3565b60405160208183030381529060405280519060200120149050919050565b6001600080836040516020016108aa9190610ef3565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b8060026000846040516020016108fe9190610ef3565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b600061093d61093884611051565b61102c565b90508281526020810184848401111561095957610958611219565b5b610964848285611154565b509392505050565b600061097f61097a84611082565b61102c565b90508281526020810184848401111561099b5761099a611219565b5b6109a6848285611154565b509392505050565b6000813590506109bd81611262565b92915050565b6000815190506109d281611279565b92915050565b6000813590506109e781611290565b92915050565b60008083601f840112610a0357610a026111fb565b5b8235905067ffffffffffffffff811115610a2057610a1f6111f6565b5b602083019150836001820283011115610a3c57610a3b61120f565b5b9250929050565b600082601f830112610a5857610a576111fb565b5b8135610a6884826020860161092a565b91505092915050565b600081359050610a80816112a7565b92915050565b600082601f830112610a9b57610a9a6111fb565b5b8135610aab84826020860161096c565b91505092915050565b600060208284031215610aca57610ac9611205565b5b81905092915050565b600060808284031215610ae957610ae8611205565b5b81905092915050565b600060608284031215610b0857610b07611205565b5b81905092915050565b600081359050610b20816112be565b92915050565b600060208284031215610b3c57610b3b611223565b5b6000610b4a848285016109ae565b91505092915050565b600060208284031215610b6957610b68611223565b5b6000610b77848285016109c3565b91505092915050565b600060208284031215610b9657610b95611223565b5b6000610ba4848285016109d8565b91505092915050565b600060208284031215610bc357610bc2611223565b5b600082013567ffffffffffffffff811115610be157610be061121e565b5b610bed84828501610a43565b91505092915050565b600080600060608486031215610c0f57610c0e611223565b5b6000610c1d86828701610a71565b9350506020610c2e86828701610b11565b925050604084013567ffffffffffffffff811115610c4f57610c4e61121e565b5b610c5b86828701610a86565b9150509250925092565b600060208284031215610c7b57610c7a611223565b5b600082013567ffffffffffffffff811115610c9957610c9861121e565b5b610ca584828501610a86565b91505092915050565b600080600060408486031215610cc757610cc6611223565b5b6000610cd586828701610ab4565b935050602084013567ffffffffffffffff811115610cf657610cf561121e565b5b610d02868287016109ed565b92509250509250925092565b600060208284031215610d2457610d23611223565b5b600082013567ffffffffffffffff811115610d4257610d4161121e565b5b610d4e84828501610ad3565b91505092915050565b600080600080600060808688031215610d7357610d72611223565b5b600086013567ffffffffffffffff811115610d9157610d9061121e565b5b610d9d88828901610af2565b9550506020610dae888289016109ae565b9450506040610dbf88828901610b11565b935050606086013567ffffffffffffffff811115610de057610ddf61121e565b5b610dec888289016109ed565b92509250509295509295909350565b610e04816110f0565b82525050565b610e1381611102565b82525050565b6000610e2583856110da565b9350610e32838584611154565b82840190509392505050565b6000610e49826110b3565b610e5381856110c9565b9350610e63818560208601611163565b610e6c81611228565b840191505092915050565b6000610e82826110be565b610e8c81856110e5565b9350610e9c818560208601611163565b80840191505092915050565b6000610eb56006836110e5565b9150610ec082611239565b600682019050919050565b610ed48161114a565b82525050565b6000610ee7828486610e19565b91508190509392505050565b6000610eff8284610e77565b915081905092915050565b6000610f1582610ea8565b9150819050919050565b6000602082019050610f346000830184610dfb565b92915050565b6000606082019050610f4f6000830186610dfb565b610f5c6020830185610dfb565b610f696040830184610ecb565b949350505050565b6000602082019050610f866000830184610e0a565b92915050565b60006020820190508181036000830152610fa68184610e3e565b905092915050565b6000602082019050610fc36000830184610ecb565b92915050565b60008083356001602003843603038112610fe657610fe561120a565b5b80840192508235915067ffffffffffffffff82111561100857611007611200565b5b60208301925060018202360383131561102457611023611214565b5b509250929050565b6000611036611047565b90506110428282611196565b919050565b6000604051905090565b600067ffffffffffffffff82111561106c5761106b6111c7565b5b61107582611228565b9050602081019050919050565b600067ffffffffffffffff82111561109d5761109c6111c7565b5b6110a682611228565b9050602081019050919050565b600081519050919050565b600081519050919050565b600082825260208201905092915050565b600081905092915050565b600081905092915050565b60006110fb8261112a565b9050919050565b60008115159050919050565b6000819050919050565b6000611123826110f0565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b82818337600083830152505050565b60005b83811015611181578082015181840152602081019050611166565b83811115611190576000848401525b50505050565b61119f82611228565b810181811067ffffffffffffffff821117156111be576111bd6111c7565b5b80604052505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b61126b816110f0565b811461127657600080fd5b50565b61128281611102565b811461128d57600080fd5b50565b6112998161110e565b81146112a457600080fd5b50565b6112b081611118565b81146112bb57600080fd5b50565b6112c78161114a565b81146112d257600080fd5b5056fea26469706673582212201f295f137d0ea146883fdaa6858baa14e4c467a843ff4e7829fd9df0d4c2aede64736f6c63430008070033" + "bin": "6080604052348015600f57600080fd5b506115288061001f6000396000f3fe6080604052600436106100c65760003560e01c8063ad23b28b1161007f578063c9028a3611610059578063c9028a361461027b578063e2842ed7146102a4578063f592cbfb146102e1578063f936ae851461031e576100cd565b8063ad23b28b146101ea578063c7a339a914610227578063c85f843414610250576100cd565b806336e980a0146100d25780634297a263146100fb5780635bcfd61614610138578063676cc054146101615780639291fe2614610191578063a799911f146101ce576100cd565b366100cd57005b600080fd5b3480156100de57600080fd5b506100f960048036038101906100f49190610b86565b61035b565b005b34801561010757600080fd5b50610122600480360381019061011d9190610c05565b610385565b60405161012f9190610c4b565b60405180910390f35b34801561014457600080fd5b5061015f600480360381019061015a9190610d74565b61039d565b005b61017b60048036038101906101769190610e37565b610483565b6040516101889190610f16565b60405180910390f35b34801561019d57600080fd5b506101b860048036038101906101b39190610b86565b610595565b6040516101c59190610c4b565b60405180910390f35b6101e860048036038101906101e39190610b86565b6105d8565b005b3480156101f657600080fd5b50610211600480360381019061020c9190610f38565b610601565b60405161021e9190610fba565b60405180910390f35b34801561023357600080fd5b5061024e6004803603810190610249919061101a565b610661565b005b34801561025c57600080fd5b50610265610715565b6040516102729190610fba565b60405180910390f35b34801561028757600080fd5b506102a2600480360381019061029d91906110a8565b61074e565b005b3480156102b057600080fd5b506102cb60048036038101906102c69190610c05565b610888565b6040516102d8919061110c565b60405180910390f35b3480156102ed57600080fd5b5061030860048036038101906103039190610b86565b6108a8565b604051610315919061110c565b60405180910390f35b34801561032a57600080fd5b50610345600480360381019061034091906111c8565b6108f7565b6040516103529190611220565b60405180910390f35b61036481610940565b1561036e57600080fd5b61037781610996565b6103828160006109ea565b50565b60026020528060005260406000206000915090505481565b6103ea82828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610940565b156103f457600080fd5b600080838390501461044a5782828080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610466565b6104658660200160208101906104609190610f38565b610601565b5b905061047181610996565b61047b81856109ea565b505050505050565b606060008084849050146104db5783838080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506104f7565b6104f68560000160208101906104f19190610f38565b610601565b5b905061050281610996565b61050c81346109ea565b84600001602081019061051f9190610f38565b60018260405161052f9190611277565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550604051806020016040528060008152509150509392505050565b600060026000836040516020016105ac91906112ca565b604051602081830303815290604052805190602001208152602001908152602001600020549050919050565b6105e181610940565b156105eb57600080fd5b6105f481610996565b6105fe81346109ea565b50565b60606040518060400160405280601681526020017f63616c6c65642077697468206e6f206d657373616765000000000000000000008152508260405160200161064b929190611329565b6040516020818303038152906040529050919050565b61066a81610940565b1561067457600080fd5b8273ffffffffffffffffffffffffffffffffffffffff166323b872dd3330856040518463ffffffff1660e01b81526004016106b193929190611351565b6020604051808303816000875af11580156106d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f491906113b4565b6106fd57600080fd5b61070681610996565b61071081836109ea565b505050565b6040518060400160405280601681526020017f63616c6c65642077697468206e6f206d6573736167650000000000000000000081525081565b6107a981806060019061076191906113f0565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610996565b6108068180606001906107bc91906113f0565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505060006109ea565b8060000160208101906108199190610f38565b600182806060019061082b91906113f0565b604051610839929190611478565b908152602001604051809103902060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60006020528060005260406000206000915054906101000a900460ff1681565b6000806000836040516020016108be91906112ca565b60405160208183030381529060405280519060200120815260200190815260200160002060009054906101000a900460ff169050919050565b6001818051602081018201805184825260208301602085012081835280955050505050506000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000604051602001610951906114dd565b604051602081830303815290604052805190602001208260405160200161097891906112ca565b60405160208183030381529060405280519060200120149050919050565b6001600080836040516020016109ac91906112ca565b60405160208183030381529060405280519060200120815260200190815260200160002060006101000a81548160ff02191690831515021790555050565b806002600084604051602001610a0091906112ca565b604051602081830303815290604052805190602001208152602001908152602001600020819055505050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610a9382610a4a565b810181811067ffffffffffffffff82111715610ab257610ab1610a5b565b5b80604052505050565b6000610ac5610a2c565b9050610ad18282610a8a565b919050565b600067ffffffffffffffff821115610af157610af0610a5b565b5b610afa82610a4a565b9050602081019050919050565b82818337600083830152505050565b6000610b29610b2484610ad6565b610abb565b905082815260208101848484011115610b4557610b44610a45565b5b610b50848285610b07565b509392505050565b600082601f830112610b6d57610b6c610a40565b5b8135610b7d848260208601610b16565b91505092915050565b600060208284031215610b9c57610b9b610a36565b5b600082013567ffffffffffffffff811115610bba57610bb9610a3b565b5b610bc684828501610b58565b91505092915050565b6000819050919050565b610be281610bcf565b8114610bed57600080fd5b50565b600081359050610bff81610bd9565b92915050565b600060208284031215610c1b57610c1a610a36565b5b6000610c2984828501610bf0565b91505092915050565b6000819050919050565b610c4581610c32565b82525050565b6000602082019050610c606000830184610c3c565b92915050565b600080fd5b600060608284031215610c8157610c80610c66565b5b81905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610cb582610c8a565b9050919050565b610cc581610caa565b8114610cd057600080fd5b50565b600081359050610ce281610cbc565b92915050565b610cf181610c32565b8114610cfc57600080fd5b50565b600081359050610d0e81610ce8565b92915050565b600080fd5b600080fd5b60008083601f840112610d3457610d33610a40565b5b8235905067ffffffffffffffff811115610d5157610d50610d14565b5b602083019150836001820283011115610d6d57610d6c610d19565b5b9250929050565b600080600080600060808688031215610d9057610d8f610a36565b5b600086013567ffffffffffffffff811115610dae57610dad610a3b565b5b610dba88828901610c6b565b9550506020610dcb88828901610cd3565b9450506040610ddc88828901610cff565b935050606086013567ffffffffffffffff811115610dfd57610dfc610a3b565b5b610e0988828901610d1e565b92509250509295509295909350565b600060208284031215610e2e57610e2d610c66565b5b81905092915050565b600080600060408486031215610e5057610e4f610a36565b5b6000610e5e86828701610e18565b935050602084013567ffffffffffffffff811115610e7f57610e7e610a3b565b5b610e8b86828701610d1e565b92509250509250925092565b600081519050919050565b600082825260208201905092915050565b60005b83811015610ed1578082015181840152602081019050610eb6565b60008484015250505050565b6000610ee882610e97565b610ef28185610ea2565b9350610f02818560208601610eb3565b610f0b81610a4a565b840191505092915050565b60006020820190508181036000830152610f308184610edd565b905092915050565b600060208284031215610f4e57610f4d610a36565b5b6000610f5c84828501610cd3565b91505092915050565b600081519050919050565b600082825260208201905092915050565b6000610f8c82610f65565b610f968185610f70565b9350610fa6818560208601610eb3565b610faf81610a4a565b840191505092915050565b60006020820190508181036000830152610fd48184610f81565b905092915050565b6000610fe782610caa565b9050919050565b610ff781610fdc565b811461100257600080fd5b50565b60008135905061101481610fee565b92915050565b60008060006060848603121561103357611032610a36565b5b600061104186828701611005565b935050602061105286828701610cff565b925050604084013567ffffffffffffffff81111561107357611072610a3b565b5b61107f86828701610b58565b9150509250925092565b60006080828403121561109f5761109e610c66565b5b81905092915050565b6000602082840312156110be576110bd610a36565b5b600082013567ffffffffffffffff8111156110dc576110db610a3b565b5b6110e884828501611089565b91505092915050565b60008115159050919050565b611106816110f1565b82525050565b600060208201905061112160008301846110fd565b92915050565b600067ffffffffffffffff82111561114257611141610a5b565b5b61114b82610a4a565b9050602081019050919050565b600061116b61116684611127565b610abb565b90508281526020810184848401111561118757611186610a45565b5b611192848285610b07565b509392505050565b600082601f8301126111af576111ae610a40565b5b81356111bf848260208601611158565b91505092915050565b6000602082840312156111de576111dd610a36565b5b600082013567ffffffffffffffff8111156111fc576111fb610a3b565b5b6112088482850161119a565b91505092915050565b61121a81610caa565b82525050565b60006020820190506112356000830184611211565b92915050565b600081905092915050565b600061125182610e97565b61125b818561123b565b935061126b818560208601610eb3565b80840191505092915050565b60006112838284611246565b915081905092915050565b600081905092915050565b60006112a482610f65565b6112ae818561128e565b93506112be818560208601610eb3565b80840191505092915050565b60006112d68284611299565b915081905092915050565b60008160601b9050919050565b60006112f9826112e1565b9050919050565b600061130b826112ee565b9050919050565b61132361131e82610caa565b611300565b82525050565b60006113358285611299565b91506113418284611312565b6014820191508190509392505050565b60006060820190506113666000830186611211565b6113736020830185611211565b6113806040830184610c3c565b949350505050565b611391816110f1565b811461139c57600080fd5b50565b6000815190506113ae81611388565b92915050565b6000602082840312156113ca576113c9610a36565b5b60006113d88482850161139f565b91505092915050565b600080fd5b600080fd5b600080fd5b6000808335600160200384360303811261140d5761140c6113e1565b5b80840192508235915067ffffffffffffffff82111561142f5761142e6113e6565b5b60208301925060018202360383131561144b5761144a6113eb565b5b509250929050565b600061145f838561123b565b935061146c838584610b07565b82840190509392505050565b6000611485828486611453565b91508190509392505050565b7f7265766572740000000000000000000000000000000000000000000000000000600082015250565b60006114c760068361128e565b91506114d282611491565b600682019050919050565b60006114e8826114ba565b915081905091905056fea26469706673582212205747e512af435680fec20f1d2e088f93d6c12052fee7e353f45e5e49a671377b64736f6c634300081a0033" } diff --git a/pkg/contracts/testdappv2/TestDAppV2.sol b/pkg/contracts/testdappv2/TestDAppV2.sol index c460c87025..3282cbe383 100644 --- a/pkg/contracts/testdappv2/TestDAppV2.sol +++ b/pkg/contracts/testdappv2/TestDAppV2.sol @@ -1,11 +1,13 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.7; +pragma solidity ^0.8.26; interface IERC20 { function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); } contract TestDAppV2 { + string public constant NO_MESSAGE_CALL = "called with no message"; + struct zContext { bytes origin; address sender; @@ -35,9 +37,17 @@ contract TestDAppV2 { mapping(bytes => address) public senderWithMessage; mapping(bytes32 => uint256) public amountWithMessage; + // return the index used for the "WithMessage" mapping when the message for calls is empty + // this allows testing the message with empty message + // this function includes the sender of the message to avoid collisions when running parallel tests with different senders + function getNoMessageIndex(address sender) pure public returns (string memory) { + return string(abi.encodePacked(NO_MESSAGE_CALL, sender)); + } + function setCalledWithMessage(string memory message) internal { calledWithMessage[keccak256(abi.encodePacked(message))] = true; } + function setAmountWithMessage(string memory message, uint256 amount) internal { amountWithMessage[keccak256(abi.encodePacked(message))] = amount; } @@ -50,7 +60,7 @@ contract TestDAppV2 { return amountWithMessage[keccak256(abi.encodePacked(message))]; } - // Universal contract interface + // Universal contract interface on ZEVM function onCall( zContext calldata _context, address _zrc20, @@ -61,8 +71,10 @@ contract TestDAppV2 { { require(!isRevertMessage(string(message))); - setCalledWithMessage(string(message)); - setAmountWithMessage(string(message), amount); + string memory messageStr = message.length == 0 ? getNoMessageIndex(_context.sender) : string(message); + + setCalledWithMessage(messageStr); + setAmountWithMessage(messageStr, amount); } // called with gas token @@ -103,11 +115,15 @@ contract TestDAppV2 { senderWithMessage[revertContext.revertMessage] = revertContext.sender; } - // Callable interface + // Callable interface on connected EVM chains function onCall(MessageContext calldata messageContext, bytes calldata message) external payable returns (bytes memory) { - setCalledWithMessage(string(message)); - setAmountWithMessage(string(message), msg.value); - senderWithMessage[message] = messageContext.sender; + string memory messageStr = message.length == 0 ? getNoMessageIndex(messageContext.sender) : string(message); + + setCalledWithMessage(messageStr); + setAmountWithMessage(messageStr, msg.value); + senderWithMessage[bytes(messageStr)] = messageContext.sender; + + return ""; } receive() external payable {} diff --git a/pkg/contracts/testdappv2/bindings.go b/pkg/contracts/testdappv2/bindings.go index 73843ba2d2..f2dbd2bfa8 100644 --- a/pkg/contracts/testdappv2/bindings.go +++ b/pkg/contracts/testdappv2/bindings.go @@ -1,4 +1,4 @@ -//go:generate sh -c "solc TestDAppV2.sol --combined-json abi,bin | jq '.contracts.\"TestDAppV2.sol:TestDAppV2\"' > TestDAppV2.json" +//go:generate sh -c "solc TestDAppV2.sol --evm-version london --combined-json abi,bin | jq '.contracts.\"TestDAppV2.sol:TestDAppV2\"' > TestDAppV2.json" //go:generate sh -c "cat TestDAppV2.json | jq .abi > TestDAppV2.abi" //go:generate sh -c "cat TestDAppV2.json | jq .bin | tr -d '\"' > TestDAppV2.bin" //go:generate sh -c "abigen --abi TestDAppV2.abi --bin TestDAppV2.bin --pkg testdappv2 --type TestDAppV2 --out TestDAppV2.go" diff --git a/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto b/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto index 9b634a6378..8feb44d382 100644 --- a/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto +++ b/proto/zetachain/zetacore/crosschain/cross_chain_tx.proto @@ -43,6 +43,10 @@ message InboundParams { string ballot_index = 9; uint64 finalized_zeta_height = 10; TxFinalizationStatus tx_finalization_status = 11; + + // this field describes if a smart contract call should be made for a inbound + // with assets only used for protocol contract version 2 + bool is_cross_chain_call = 12; } message ZetaAccounting { diff --git a/proto/zetachain/zetacore/crosschain/tx.proto b/proto/zetachain/zetacore/crosschain/tx.proto index 9499a7c25c..cb76e53d0a 100644 --- a/proto/zetachain/zetacore/crosschain/tx.proto +++ b/proto/zetachain/zetacore/crosschain/tx.proto @@ -178,6 +178,9 @@ message MsgVoteInbound { RevertOptions revert_options = 17 [ (gogoproto.nullable) = false ]; CallOptions call_options = 18; + + // define if a smart contract call should be made with asset + bool is_cross_chain_call = 19; } message MsgVoteInboundResponse {} diff --git a/testutil/keeper/crosschain.go b/testutil/keeper/crosschain.go index aade2afdeb..8418bbdaaf 100644 --- a/testutil/keeper/crosschain.go +++ b/testutil/keeper/crosschain.go @@ -390,6 +390,7 @@ func MockRevertForHandleEVMDeposit( coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) } diff --git a/testutil/keeper/mocks/crosschain/fungible.go b/testutil/keeper/mocks/crosschain/fungible.go index d2de2b7a98..856e3e8313 100644 --- a/testutil/keeper/mocks/crosschain/fungible.go +++ b/testutil/keeper/mocks/crosschain/fungible.go @@ -697,9 +697,9 @@ func (_m *CrosschainFungibleKeeper) ZETARevertAndCallContract(ctx types.Context, return r0, r1 } -// ZRC20DepositAndCallContract provides a mock function with given fields: ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion -func (_m *CrosschainFungibleKeeper) ZRC20DepositAndCallContract(ctx types.Context, from []byte, to common.Address, amount *big.Int, senderChainID int64, data []byte, coinType coin.CoinType, asset string, protocolContractVersion crosschaintypes.ProtocolContractVersion) (*evmtypes.MsgEthereumTxResponse, bool, error) { - ret := _m.Called(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) +// ZRC20DepositAndCallContract provides a mock function with given fields: ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion, isCrossChainCall +func (_m *CrosschainFungibleKeeper) ZRC20DepositAndCallContract(ctx types.Context, from []byte, to common.Address, amount *big.Int, senderChainID int64, data []byte, coinType coin.CoinType, asset string, protocolContractVersion crosschaintypes.ProtocolContractVersion, isCrossChainCall bool) (*evmtypes.MsgEthereumTxResponse, bool, error) { + ret := _m.Called(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion, isCrossChainCall) if len(ret) == 0 { panic("no return value specified for ZRC20DepositAndCallContract") @@ -708,25 +708,25 @@ func (_m *CrosschainFungibleKeeper) ZRC20DepositAndCallContract(ctx types.Contex var r0 *evmtypes.MsgEthereumTxResponse var r1 bool var r2 error - if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion) (*evmtypes.MsgEthereumTxResponse, bool, error)); ok { - return rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) + if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion, bool) (*evmtypes.MsgEthereumTxResponse, bool, error)); ok { + return rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion, isCrossChainCall) } - if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion) *evmtypes.MsgEthereumTxResponse); ok { - r0 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) + if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion, bool) *evmtypes.MsgEthereumTxResponse); ok { + r0 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion, isCrossChainCall) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*evmtypes.MsgEthereumTxResponse) } } - if rf, ok := ret.Get(1).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion) bool); ok { - r1 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) + if rf, ok := ret.Get(1).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion, bool) bool); ok { + r1 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion, isCrossChainCall) } else { r1 = ret.Get(1).(bool) } - if rf, ok := ret.Get(2).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion) error); ok { - r2 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion) + if rf, ok := ret.Get(2).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, coin.CoinType, string, crosschaintypes.ProtocolContractVersion, bool) error); ok { + r2 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset, protocolContractVersion, isCrossChainCall) } else { r2 = ret.Error(2) } diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index ff17525734..25733e1fef 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -305,30 +305,34 @@ func ZRC20Withdrawal(to []byte, value *big.Int) *zrc20.ZRC20Withdrawal { } } +// InvalidZRC20WithdrawToExternalReceipt is a receipt for a invalid ZRC20 withdrawal to an external address // receiver is 1EYVvXLusCxtVuEwoYvWRyN5EZTXwPVvo3 -func GetInvalidZRC20WithdrawToExternal(t *testing.T) (receipt ethtypes.Receipt) { +func InvalidZRC20WithdrawToExternalReceipt(t *testing.T) (receipt ethtypes.Receipt) { block := "{\n \"type\": \"0x2\",\n \"root\": \"0x\",\n \"status\": \"0x1\",\n \"cumulativeGasUsed\": \"0x4e7a38\",\n \"logsBloom\": \"0x00000000000000000000010000020000000000000000000000000000000000020000000100000000000000000000000080000000000000000000000400200000200000000002000000000008000000000000000000000000000000000000000000000000020000000000000000800800000040000000000000000010000000000000000000000000000000000000000000000000000004000000000000000000020000000000000000000000000000000000000000000000000000000000010000000002000000000000000000000000000000000000000000000000000020000010000000000000000001000000000000000000040200000000000000000000\",\n \"logs\": [\n {\n \"address\": \"0x13a0c5930c028511dc02665e7285134b6d11a5f4\",\n \"topics\": [\n \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\n \"0x000000000000000000000000313e74f7755afbae4f90e02ca49f8f09ff934a37\",\n \"0x000000000000000000000000735b14bb79463307aacbed86daf3322b1e6226ab\"\n ],\n \"data\": \"0x0000000000000000000000000000000000000000000000000000000000003790\",\n \"blockNumber\": \"0x1a2ad3\",\n \"transactionHash\": \"0x81126c18c7ca7d1fb7ded6644a87802e91bf52154ee4af7a5b379354e24fb6e0\",\n \"transactionIndex\": \"0x10\",\n \"blockHash\": \"0x5cb338544f64a226f4bfccb7a8d977f861c13ad73f7dd4317b66b00dd95de51c\",\n \"logIndex\": \"0x46\",\n \"removed\": false\n },\n {\n \"address\": \"0x13a0c5930c028511dc02665e7285134b6d11a5f4\",\n \"topics\": [\n \"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\",\n \"0x000000000000000000000000313e74f7755afbae4f90e02ca49f8f09ff934a37\",\n \"0x00000000000000000000000013a0c5930c028511dc02665e7285134b6d11a5f4\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000000000000000006a1217\",\n \"blockNumber\": \"0x1a2ad3\",\n \"transactionHash\": \"0x81126c18c7ca7d1fb7ded6644a87802e91bf52154ee4af7a5b379354e24fb6e0\",\n \"transactionIndex\": \"0x10\",\n \"blockHash\": \"0x5cb338544f64a226f4bfccb7a8d977f861c13ad73f7dd4317b66b00dd95de51c\",\n \"logIndex\": \"0x47\",\n \"removed\": false\n },\n {\n \"address\": \"0x13a0c5930c028511dc02665e7285134b6d11a5f4\",\n \"topics\": [\n \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\n \"0x000000000000000000000000313e74f7755afbae4f90e02ca49f8f09ff934a37\",\n \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000000000000000006a0c70\",\n \"blockNumber\": \"0x1a2ad3\",\n \"transactionHash\": \"0x81126c18c7ca7d1fb7ded6644a87802e91bf52154ee4af7a5b379354e24fb6e0\",\n \"transactionIndex\": \"0x10\",\n \"blockHash\": \"0x5cb338544f64a226f4bfccb7a8d977f861c13ad73f7dd4317b66b00dd95de51c\",\n \"logIndex\": \"0x48\",\n \"removed\": false\n },\n {\n \"address\": \"0x13a0c5930c028511dc02665e7285134b6d11a5f4\",\n \"topics\": [\n \"0x9ffbffc04a397460ee1dbe8c9503e098090567d6b7f4b3c02a8617d800b6d955\",\n \"0x000000000000000000000000313e74f7755afbae4f90e02ca49f8f09ff934a37\"\n ],\n \"data\": \"0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000006a0c700000000000000000000000000000000000000000000000000000000000003790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000223145595676584c7573437874567545776f59765752794e35455a5458775056766f33000000000000000000000000000000000000000000000000000000000000\",\n \"blockNumber\": \"0x1a2ad3\",\n \"transactionHash\": \"0x81126c18c7ca7d1fb7ded6644a87802e91bf52154ee4af7a5b379354e24fb6e0\",\n \"transactionIndex\": \"0x10\",\n \"blockHash\": \"0x5cb338544f64a226f4bfccb7a8d977f861c13ad73f7dd4317b66b00dd95de51c\",\n \"logIndex\": \"0x49\",\n \"removed\": false\n }\n ],\n \"transactionHash\": \"0x81126c18c7ca7d1fb7ded6644a87802e91bf52154ee4af7a5b379354e24fb6e0\",\n \"contractAddress\": \"0x0000000000000000000000000000000000000000\",\n \"gasUsed\": \"0x12521\",\n \"blockHash\": \"0x5cb338544f64a226f4bfccb7a8d977f861c13ad73f7dd4317b66b00dd95de51c\",\n \"blockNumber\": \"0x1a2ad3\",\n \"transactionIndex\": \"0x10\"\n}\n" err := json.Unmarshal([]byte(block), &receipt) require.NoError(t, err) return } -func GetValidZrc20WithdrawToETH(t *testing.T) (receipt ethtypes.Receipt) { +// ValidZrc20WithdrawToETHReceipt is a receipt for a ZRC20 withdrawal to an external address +func ValidZrc20WithdrawToETHReceipt(t *testing.T) (receipt ethtypes.Receipt) { block := "{\n \"type\": \"0x2\",\n \"root\": \"0x\",\n \"status\": \"0x1\",\n \"cumulativeGasUsed\": \"0xdbedca\",\n \"logsBloom\": \"0x00200000001000000000000088020001000001000000000000000000000000000000020100000000000000000000000080000000000000000000000400640000000000000000000008000008020000200000000000000002000000008000000000000000020000000200000000800801000000080000000000000010000000000000000000000000000000000000001000000001000004080001404000000000028002000000000000000040000000000000000000000000000000000000000000000002000000000000008000000000000000800800001000000002000021000010000100000000000010800400000000020000000100400880000000004000\",\n \"logs\": [\n {\n \"address\": \"0x3f641963f3d9adf82d890fd8142313dcec807ba5\",\n \"topics\": [\n \"0x3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000000045400a8fd5330000\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x57\",\n \"removed\": false\n },\n {\n \"address\": \"0x5f0b1a82749cb4e2278ec87f8bf6b618dc71a8bf\",\n \"topics\": [\n \"0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000001ac7c4159f72b90000\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x58\",\n \"removed\": false\n },\n {\n \"address\": \"0x5f0b1a82749cb4e2278ec87f8bf6b618dc71a8bf\",\n \"topics\": [\n \"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\",\n \"0x0000000000000000000000002ca7d64a7efe2d62a725e2b35cf7230d6677ffee\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000001ac7c4159f72b90000\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x59\",\n \"removed\": false\n },\n {\n \"address\": \"0x5f0b1a82749cb4e2278ec87f8bf6b618dc71a8bf\",\n \"topics\": [\n \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\",\n \"0x00000000000000000000000016ef1b018026e389fda93c1e993e987cf6e852e7\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000001ac7c4159f72b90000\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x5a\",\n \"removed\": false\n },\n {\n \"address\": \"0xd97b1de3619ed2c6beb3860147e30ca8a7dc9891\",\n \"topics\": [\n \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\n \"0x00000000000000000000000016ef1b018026e389fda93c1e993e987cf6e852e7\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000000002e640d76638740f\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x5b\",\n \"removed\": false\n },\n {\n \"address\": \"0x16ef1b018026e389fda93c1e993e987cf6e852e7\",\n \"topics\": [\n \"0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1\"\n ],\n \"data\": \"0x000000000000000000000000000000000000000000000b3f1da425061770a11600000000000000000000000000000000000000000000000135be3952e251aa40\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x5c\",\n \"removed\": false\n },\n {\n \"address\": \"0x16ef1b018026e389fda93c1e993e987cf6e852e7\",\n \"topics\": [\n \"0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822\",\n \"0x0000000000000000000000002ca7d64a7efe2d62a725e2b35cf7230d6677ffee\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000001ac7c4159f72b900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e640d76638740f\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x5d\",\n \"removed\": false\n },\n {\n \"address\": \"0xd97b1de3619ed2c6beb3860147e30ca8a7dc9891\",\n \"topics\": [\n \"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\",\n \"0x000000000000000000000000d97b1de3619ed2c6beb3860147e30ca8a7dc9891\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000000000015059f36c8ec0\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x5e\",\n \"removed\": false\n },\n {\n \"address\": \"0xd97b1de3619ed2c6beb3860147e30ca8a7dc9891\",\n \"topics\": [\n \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\",\n \"0x000000000000000000000000735b14bb79463307aacbed86daf3322b1e6226ab\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000000000015059f36c8ec0\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x5f\",\n \"removed\": false\n },\n {\n \"address\": \"0xd97b1de3619ed2c6beb3860147e30ca8a7dc9891\",\n \"topics\": [\n \"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\",\n \"0x000000000000000000000000d97b1de3619ed2c6beb3860147e30ca8a7dc9891\"\n ],\n \"data\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x60\",\n \"removed\": false\n },\n {\n \"address\": \"0xd97b1de3619ed2c6beb3860147e30ca8a7dc9891\",\n \"topics\": [\n \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\",\n \"0x0000000000000000000000000000000000000000000000000000000000000000\"\n ],\n \"data\": \"0x00000000000000000000000000000000000000000000000002e4f07d72cbe54f\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x61\",\n \"removed\": false\n },\n {\n \"address\": \"0xd97b1de3619ed2c6beb3860147e30ca8a7dc9891\",\n \"topics\": [\n \"0x9ffbffc04a397460ee1dbe8c9503e098090567d6b7f4b3c02a8617d800b6d955\",\n \"0x0000000000000000000000008e0f8e7e9e121403e72151d00f4937eacb2d9ef3\"\n ],\n \"data\": \"0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000002e4f07d72cbe54f00000000000000000000000000000000000000000000000000015059f36c8ec0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000005dabfdd153aaab4a970fd953dcfeee8bf6bb946e\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x62\",\n \"removed\": false\n },\n {\n \"address\": \"0x8e0f8e7e9e121403e72151d00f4937eacb2d9ef3\",\n \"topics\": [\n \"0x97eb75cc53ffa3f4560fc62e4912dda10ac56c3d12dbc48dc8c27d5ab225cf66\"\n ],\n \"data\": \"0x0000000000000000000000005f0b1a82749cb4e2278ec87f8bf6b618dc71a8bf000000000000000000000000d97b1de3619ed2c6beb3860147e30ca8a7dc989100000000000000000000000000000000000000000000001b0d04202f47ec000000000000000000000000000000000000000000000000001ac7c4159f72b900000000000000000000000000005dabfdd153aaab4a970fd953dcfeee8bf6bb946e00000000000000000000000000000000000000000000000045400a8fd5330000\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"transactionIndex\": \"0x1f\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"logIndex\": \"0x63\",\n \"removed\": false\n }\n ],\n \"transactionHash\": \"0x87229bb05d67f42017a697b34ed52d95afc9f5e3285479e845fe088b4c77d8f0\",\n \"contractAddress\": \"0x0000000000000000000000000000000000000000\",\n \"gasUsed\": \"0x41c3c\",\n \"blockHash\": \"0xf49e7039c7f1a81cd46de150980d92fa869cc0d2e2f1fe46aedc6400396137ff\",\n \"blockNumber\": \"0x17ef22\",\n \"transactionIndex\": \"0x1f\"\n}" err := json.Unmarshal([]byte(block), &receipt) require.NoError(t, err) return } +// ValidZRC20WithdrawToBTCReceipt is a receipt for a ZRC20 withdrawal to a BTC address // receiver is bc1qysd4sp9q8my59ul9wsf5rvs9p387hf8vfwatzu -func GetValidZRC20WithdrawToBTC(t *testing.T) (receipt ethtypes.Receipt) { +func ValidZRC20WithdrawToBTCReceipt(t *testing.T) (receipt ethtypes.Receipt) { block := "{\"type\":\"0x2\",\"root\":\"0x\",\"status\":\"0x1\",\"cumulativeGasUsed\":\"0x1f25ed\",\"logsBloom\":\"0x00000000000000000000000000020000000000000000000000000000000000020000000100000000000000000040000080000000000000000000000400200000200000000002000000000008000000000000000000000000000000000000000000000000020000000000000000800800000000000000000000000010000000000000000000000000000000000000000000000000000004000000000000000000020000000001000000000000000000000000000000000000000000000000010000000002000000000000000010000000000000000000000000000000000020000010000000000000000000000000000000000000040200000000000000000000\",\"logs\":[{\"address\":\"0x13a0c5930c028511dc02665e7285134b6d11a5f4\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\"0x00000000000000000000000033ead83db0d0c682b05ead61e8d8f481bb1b4933\",\"0x000000000000000000000000735b14bb79463307aacbed86daf3322b1e6226ab\"],\"data\":\"0x0000000000000000000000000000000000000000000000000000000000003d84\",\"blockNumber\":\"0x1a00f3\",\"transactionHash\":\"0x9aaefece38fd2bd87077038a63fffb7c84cc8dd1ed01de134a8504a1f9a410c3\",\"transactionIndex\":\"0x8\",\"blockHash\":\"0x9517356f0b3877990590421266f02a4ff349b7476010ee34dd5f0dfc85c2684f\",\"logIndex\":\"0x28\",\"removed\":false},{\"address\":\"0x13a0c5930c028511dc02665e7285134b6d11a5f4\",\"topics\":[\"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\",\"0x00000000000000000000000033ead83db0d0c682b05ead61e8d8f481bb1b4933\",\"0x00000000000000000000000013a0c5930c028511dc02665e7285134b6d11a5f4\"],\"data\":\"0x0000000000000000000000000000000000000000000000000000000000978c98\",\"blockNumber\":\"0x1a00f3\",\"transactionHash\":\"0x9aaefece38fd2bd87077038a63fffb7c84cc8dd1ed01de134a8504a1f9a410c3\",\"transactionIndex\":\"0x8\",\"blockHash\":\"0x9517356f0b3877990590421266f02a4ff349b7476010ee34dd5f0dfc85c2684f\",\"logIndex\":\"0x29\",\"removed\":false},{\"address\":\"0x13a0c5930c028511dc02665e7285134b6d11a5f4\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\"0x00000000000000000000000033ead83db0d0c682b05ead61e8d8f481bb1b4933\",\"0x0000000000000000000000000000000000000000000000000000000000000000\"],\"data\":\"0x0000000000000000000000000000000000000000000000000000000000003039\",\"blockNumber\":\"0x1a00f3\",\"transactionHash\":\"0x9aaefece38fd2bd87077038a63fffb7c84cc8dd1ed01de134a8504a1f9a410c3\",\"transactionIndex\":\"0x8\",\"blockHash\":\"0x9517356f0b3877990590421266f02a4ff349b7476010ee34dd5f0dfc85c2684f\",\"logIndex\":\"0x2a\",\"removed\":false},{\"address\":\"0x13a0c5930c028511dc02665e7285134b6d11a5f4\",\"topics\":[\"0x9ffbffc04a397460ee1dbe8c9503e098090567d6b7f4b3c02a8617d800b6d955\",\"0x00000000000000000000000033ead83db0d0c682b05ead61e8d8f481bb1b4933\"],\"data\":\"0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000030390000000000000000000000000000000000000000000000000000000000003d840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a626331717973643473703971386d793539756c3977736635727673397033383768663876667761747a7500000000000000000000000000000000000000000000\",\"blockNumber\":\"0x1a00f3\",\"transactionHash\":\"0x9aaefece38fd2bd87077038a63fffb7c84cc8dd1ed01de134a8504a1f9a410c3\",\"transactionIndex\":\"0x8\",\"blockHash\":\"0x9517356f0b3877990590421266f02a4ff349b7476010ee34dd5f0dfc85c2684f\",\"logIndex\":\"0x2b\",\"removed\":false}],\"transactionHash\":\"0x9aaefece38fd2bd87077038a63fffb7c84cc8dd1ed01de134a8504a1f9a410c3\",\"contractAddress\":\"0x0000000000000000000000000000000000000000\",\"gasUsed\":\"0x12575\",\"blockHash\":\"0x9517356f0b3877990590421266f02a4ff349b7476010ee34dd5f0dfc85c2684f\",\"blockNumber\":\"0x1a00f3\",\"transactionIndex\":\"0x8\"}\n" err := json.Unmarshal([]byte(block), &receipt) require.NoError(t, err) return } -func GetValidZetaSentDestinationExternal(t *testing.T) (receipt ethtypes.Receipt) { +// ValidZetaSentDestinationExternalReceipt is a receipt for a Zeta sent to an external destination +func ValidZetaSentDestinationExternalReceipt(t *testing.T) (receipt ethtypes.Receipt) { block := "{\"root\":\"0x\",\"status\":\"0x1\",\"cumulativeGasUsed\":\"0xd75f4f\",\"logsBloom\":\"0x00000000000000000000000000000000800800000000000000000000100000000000002000000100000000000000000000000000000000000000000000240000000000000000000000000008000000000800000000440000000000008080000000000000000000000000000000000000000000000000040000000010000000000000000000000000000000000000000200000001000000000000000040000000020000000000000000000000008200000000000000000000000000000000000000000002000000000000008000000000000000000000000000080002000041000010000000000000000000000000000000000000000000400000000000000000\",\"logs\":[{\"address\":\"0x5f0b1a82749cb4e2278ec87f8bf6b618dc71a8bf\",\"topics\":[\"0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c\",\"0x000000000000000000000000f0a3f93ed1b126142e61423f9546bf1323ff82df\"],\"data\":\"0x000000000000000000000000000000000000000000000003cb71f51fc5580000\",\"blockNumber\":\"0x1bedc8\",\"transactionHash\":\"0x19d8a67a05998f1cb19fe731b96d817d5b186b62c9430c51679664959c952ef0\",\"transactionIndex\":\"0x5f\",\"blockHash\":\"0x198fdd1f4bc6b910db978602cb15bdb2bcc6fd960e9324e9b9675dc062133794\",\"logIndex\":\"0x13b\",\"removed\":false},{\"address\":\"0x5f0b1a82749cb4e2278ec87f8bf6b618dc71a8bf\",\"topics\":[\"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\",\"0x000000000000000000000000f0a3f93ed1b126142e61423f9546bf1323ff82df\",\"0x000000000000000000000000239e96c8f17c85c30100ac26f635ea15f23e9c67\"],\"data\":\"0x000000000000000000000000000000000000000000000003cb71f51fc5580000\",\"blockNumber\":\"0x1bedc8\",\"transactionHash\":\"0x19d8a67a05998f1cb19fe731b96d817d5b186b62c9430c51679664959c952ef0\",\"transactionIndex\":\"0x5f\",\"blockHash\":\"0x198fdd1f4bc6b910db978602cb15bdb2bcc6fd960e9324e9b9675dc062133794\",\"logIndex\":\"0x13c\",\"removed\":false},{\"address\":\"0x5f0b1a82749cb4e2278ec87f8bf6b618dc71a8bf\",\"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",\"0x000000000000000000000000f0a3f93ed1b126142e61423f9546bf1323ff82df\",\"0x000000000000000000000000239e96c8f17c85c30100ac26f635ea15f23e9c67\"],\"data\":\"0x000000000000000000000000000000000000000000000003cb71f51fc5580000\",\"blockNumber\":\"0x1bedc8\",\"transactionHash\":\"0x19d8a67a05998f1cb19fe731b96d817d5b186b62c9430c51679664959c952ef0\",\"transactionIndex\":\"0x5f\",\"blockHash\":\"0x198fdd1f4bc6b910db978602cb15bdb2bcc6fd960e9324e9b9675dc062133794\",\"logIndex\":\"0x13d\",\"removed\":false},{\"address\":\"0x5f0b1a82749cb4e2278ec87f8bf6b618dc71a8bf\",\"topics\":[\"0x7fcf532c15f0a6db0bd6d0e038bea71d30d808c7d98cb3bf7268a95bf5081b65\",\"0x000000000000000000000000239e96c8f17c85c30100ac26f635ea15f23e9c67\"],\"data\":\"0x000000000000000000000000000000000000000000000003cb71f51fc5580000\",\"blockNumber\":\"0x1bedc8\",\"transactionHash\":\"0x19d8a67a05998f1cb19fe731b96d817d5b186b62c9430c51679664959c952ef0\",\"transactionIndex\":\"0x5f\",\"blockHash\":\"0x198fdd1f4bc6b910db978602cb15bdb2bcc6fd960e9324e9b9675dc062133794\",\"logIndex\":\"0x13e\",\"removed\":false},{\"address\":\"0x239e96c8f17c85c30100ac26f635ea15f23e9c67\",\"topics\":[\"0x7ec1c94701e09b1652f3e1d307e60c4b9ebf99aff8c2079fd1d8c585e031c4e4\",\"0x000000000000000000000000f0a3f93ed1b126142e61423f9546bf1323ff82df\",\"0x0000000000000000000000000000000000000000000000000000000000000001\"],\"data\":\"0x00000000000000000000000060983881bdf302dcfa96603a58274d15d596620900000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000003cb71f51fc558000000000000000000000000000000000000000000000000000000000000000186a000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001460983881bdf302dcfa96603a58274d15d59662090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000\",\"blockNumber\":\"0x1bedc8\",\"transactionHash\":\"0x19d8a67a05998f1cb19fe731b96d817d5b186b62c9430c51679664959c952ef0\",\"transactionIndex\":\"0x5f\",\"blockHash\":\"0x198fdd1f4bc6b910db978602cb15bdb2bcc6fd960e9324e9b9675dc062133794\",\"logIndex\":\"0x13f\",\"removed\":false}],\"transactionHash\":\"0x19d8a67a05998f1cb19fe731b96d817d5b186b62c9430c51679664959c952ef0\",\"contractAddress\":\"0x0000000000000000000000000000000000000000\",\"gasUsed\":\"0x2406d\",\"blockHash\":\"0x198fdd1f4bc6b910db978602cb15bdb2bcc6fd960e9324e9b9675dc062133794\",\"blockNumber\":\"0x1bedc8\",\"transactionIndex\":\"0x5f\"}\n" err := json.Unmarshal([]byte(block), &receipt) require.NoError(t, err) diff --git a/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts b/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts index e5295ee133..4ac84ac5e7 100644 --- a/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts +++ b/typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts @@ -165,6 +165,14 @@ export declare class InboundParams extends Message { */ txFinalizationStatus: TxFinalizationStatus; + /** + * this field describes if a smart contract call should be made for a inbound + * with assets only used for protocol contract version 2 + * + * @generated from field: bool is_cross_chain_call = 12; + */ + isCrossChainCall: boolean; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts b/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts index caee83f0cc..f830e00a48 100644 --- a/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts +++ b/typescript/zetachain/zetacore/crosschain/tx_pb.d.ts @@ -669,6 +669,13 @@ export declare class MsgVoteInbound extends Message { */ callOptions?: CallOptions; + /** + * define if a smart contract call should be made with asset + * + * @generated from field: bool is_cross_chain_call = 19; + */ + isCrossChainCall: boolean; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index be08873bba..e57dc16d1b 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -110,6 +110,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo inboundCoinType, cctx.InboundParams.Asset, cctx.ProtocolContractVersion, + cctx.InboundParams.IsCrossChainCall, ) if fungibletypes.IsContractReverted(evmTxResponse, err) || errShouldRevertCctx(err) { return true, err diff --git a/x/crosschain/keeper/evm_deposit_test.go b/x/crosschain/keeper/evm_deposit_test.go index e933d168aa..45c0a0aecc 100644 --- a/x/crosschain/keeper/evm_deposit_test.go +++ b/x/crosschain/keeper/evm_deposit_test.go @@ -107,6 +107,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, nil) // call HandleEVMDeposit @@ -153,6 +154,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{ Logs: []*evmtypes.Log{ { @@ -216,6 +218,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{ Logs: []*evmtypes.Log{ { @@ -306,6 +309,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, errDeposit) // call HandleEVMDeposit @@ -351,6 +355,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{VmError: "reverted"}, false, errDeposit) // call HandleEVMDeposit @@ -395,6 +400,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, fungibletypes.ErrForeignCoinCapReached) // call HandleEVMDeposit @@ -439,6 +445,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, fungibletypes.ErrPausedZRC20) // call HandleEVMDeposit @@ -483,6 +490,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, fungibletypes.ErrCallNonContract) // call HandleEVMDeposit @@ -553,6 +561,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, nil) cctx.GetCurrentOutboundParam().Receiver = sample.EthAddress().String() @@ -596,6 +605,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { coin.CoinType_ERC20, mock.Anything, mock.Anything, + mock.Anything, ).Return(&evmtypes.MsgEthereumTxResponse{}, false, nil) cctx := sample.CrossChainTx(t, "foo") diff --git a/x/crosschain/keeper/evm_hooks_test.go b/x/crosschain/keeper/evm_hooks_test.go index 3f4e049d33..fff7e31f02 100644 --- a/x/crosschain/keeper/evm_hooks_test.go +++ b/x/crosschain/keeper/evm_hooks_test.go @@ -102,7 +102,7 @@ func SetupStateForProcessLogs( func TestParseZRC20WithdrawalEvent(t *testing.T) { t.Run("unable to parse an event with an invalid address in event log", func(t *testing.T) { - for i, log := range sample.GetInvalidZRC20WithdrawToExternal(t).Logs { + for i, log := range sample.InvalidZRC20WithdrawToExternalReceipt(t).Logs { event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*log) if i < 3 { require.ErrorContains(t, err, "event signature mismatch") @@ -116,7 +116,7 @@ func TestParseZRC20WithdrawalEvent(t *testing.T) { }) t.Run("successfully parse event for a valid BTC withdrawal", func(t *testing.T) { - for i, log := range sample.GetValidZRC20WithdrawToBTC(t).Logs { + for i, log := range sample.ValidZRC20WithdrawToBTCReceipt(t).Logs { event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*log) if i < 3 { require.ErrorContains(t, err, "event signature mismatch") @@ -131,7 +131,7 @@ func TestParseZRC20WithdrawalEvent(t *testing.T) { }) t.Run("successfully parse valid event for ETH withdrawal", func(t *testing.T) { - for i, log := range sample.GetValidZrc20WithdrawToETH(t).Logs { + for i, log := range sample.ValidZrc20WithdrawToETHReceipt(t).Logs { event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*log) if i != 11 { require.ErrorContains(t, err, "event signature mismatch") @@ -146,7 +146,7 @@ func TestParseZRC20WithdrawalEvent(t *testing.T) { }) t.Run("failed to parse event with a valid address but no topic present", func(t *testing.T) { - for _, log := range sample.GetValidZRC20WithdrawToBTC(t).Logs { + for _, log := range sample.ValidZRC20WithdrawToBTCReceipt(t).Logs { log.Topics = nil event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*log) require.ErrorContains(t, err, "invalid log - no topics") @@ -158,7 +158,7 @@ func TestValidateZrc20WithdrawEvent(t *testing.T) { t.Run("successfully validate a valid event", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( - *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], + *sample.ValidZRC20WithdrawToBTCReceipt(t).Logs[3], ) require.NoError(t, err) err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinMainnet.ChainId) @@ -168,7 +168,7 @@ func TestValidateZrc20WithdrawEvent(t *testing.T) { t.Run("unable to validate a btc withdrawal event with an invalid amount", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( - *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], + *sample.ValidZRC20WithdrawToBTCReceipt(t).Logs[3], ) require.NoError(t, err) @@ -186,7 +186,7 @@ func TestValidateZrc20WithdrawEvent(t *testing.T) { t.Run("unable to validate a event with an invalid chain ID", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( - *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], + *sample.ValidZRC20WithdrawToBTCReceipt(t).Logs[3], ) require.NoError(t, err) err = k.ValidateZrc20WithdrawEvent(ctx, btcMainNetWithdrawalEvent, chains.BitcoinTestnet.ChainId) @@ -196,7 +196,7 @@ func TestValidateZrc20WithdrawEvent(t *testing.T) { t.Run("unable to validate an unsupported address type", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) btcMainNetWithdrawalEvent, err := crosschainkeeper.ParseZRC20WithdrawalEvent( - *sample.GetValidZRC20WithdrawToBTC(t).Logs[3], + *sample.ValidZRC20WithdrawToBTCReceipt(t).Logs[3], ) require.NoError(t, err) btcMainNetWithdrawalEvent.To = []byte("04b2891ba8cb491828db3ebc8a780d43b169e7b3974114e6e50f9bab6ec" + @@ -248,7 +248,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { setSupportedChain(ctx, zk, []int64{chainID, senderChain.ChainId}...) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.GetValidZRC20WithdrawToBTC(t).Logs[3]) + event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.ValidZRC20WithdrawToBTCReceipt(t).Logs[3]) require.NoError(t, err) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "bitcoin", "BTC") event.Raw.Address = zrc20 @@ -274,7 +274,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { setSupportedChain(ctx, zk, []int64{chainID, senderChain.ChainId}...) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.GetValidZrc20WithdrawToETH(t).Logs[11]) + event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.ValidZrc20WithdrawToETHReceipt(t).Logs[11]) require.NoError(t, err) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "ethereum", "ETH") event.Raw.Address = zrc20 @@ -299,7 +299,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.GetValidZrc20WithdrawToETH(t).Logs[11]) + event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.ValidZrc20WithdrawToETHReceipt(t).Logs[11]) require.NoError(t, err) setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "ethereum", "ETH") emittingContract := sample.EthAddress() @@ -318,7 +318,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { chainID := chain.ChainId SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.GetValidZrc20WithdrawToETH(t).Logs[11]) + event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.ValidZrc20WithdrawToETHReceipt(t).Logs[11]) require.NoError(t, err) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "ethereum", "ETH") event.Raw.Address = zrc20 @@ -339,7 +339,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.GetValidZrc20WithdrawToETH(t).Logs[11]) + event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.ValidZrc20WithdrawToETHReceipt(t).Logs[11]) require.NoError(t, err) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "ethereum", "ETH") event.Raw.Address = zrc20 @@ -362,7 +362,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.GetValidZrc20WithdrawToETH(t).Logs[11]) + event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.ValidZrc20WithdrawToETHReceipt(t).Logs[11]) require.NoError(t, err) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "ethereum", "ETH") event.Raw.Address = zrc20 @@ -387,7 +387,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.GetValidZrc20WithdrawToETH(t).Logs[11]) + event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.ValidZrc20WithdrawToETHReceipt(t).Logs[11]) require.NoError(t, err) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "ethereum", "ETH") event.Raw.Address = zrc20 @@ -415,7 +415,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) k.RemoveGasPrice(ctx, strconv.FormatInt(chainID, 10)) - event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.GetValidZrc20WithdrawToETH(t).Logs[11]) + event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.ValidZrc20WithdrawToETHReceipt(t).Logs[11]) require.NoError(t, err) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "ethereum", "ETH") event.Raw.Address = zrc20 @@ -441,7 +441,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { Nonce: 1, }) - event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.GetValidZrc20WithdrawToETH(t).Logs[11]) + event, err := crosschainkeeper.ParseZRC20WithdrawalEvent(*sample.ValidZrc20WithdrawToETHReceipt(t).Logs[11]) require.NoError(t, err) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "ethereum", "ETH") event.Raw.Address = zrc20 @@ -456,7 +456,7 @@ func TestKeeper_ProcessZRC20WithdrawalEvent(t *testing.T) { func TestKeeper_ParseZetaSentEvent(t *testing.T) { t.Run("successfully parse a valid event", func(t *testing.T) { - logs := sample.GetValidZetaSentDestinationExternal(t).Logs + logs := sample.ValidZetaSentDestinationExternalReceipt(t).Logs for i, log := range logs { connector := log.Address event, err := crosschainkeeper.ParseZetaSentEvent(*log, connector) @@ -473,7 +473,7 @@ func TestKeeper_ParseZetaSentEvent(t *testing.T) { }) t.Run("unable to parse if topics field is empty", func(t *testing.T) { - logs := sample.GetValidZetaSentDestinationExternal(t).Logs + logs := sample.ValidZetaSentDestinationExternalReceipt(t).Logs for _, log := range logs { connector := log.Address log.Topics = nil @@ -484,7 +484,7 @@ func TestKeeper_ParseZetaSentEvent(t *testing.T) { }) t.Run("unable to parse if connector address does not match", func(t *testing.T) { - logs := sample.GetValidZetaSentDestinationExternal(t).Logs + logs := sample.ValidZetaSentDestinationExternalReceipt(t).Logs for i, log := range logs { event, err := crosschainkeeper.ParseZetaSentEvent(*log, sample.EthAddress()) if i < 4 { @@ -522,8 +522,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { require.NoError(t, err) event, err := crosschainkeeper.ParseZetaSentEvent( - *sample.GetValidZetaSentDestinationExternal(t).Logs[4], - sample.GetValidZetaSentDestinationExternal(t).Logs[4].Address, + *sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4], + sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4].Address, ) require.NoError(t, err) emittingContract := sample.EthAddress() @@ -558,8 +558,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { SetupStateForProcessLogsZetaSent(t, ctx, k, zk, sdkk, chain, admin) event, err := crosschainkeeper.ParseZetaSentEvent( - *sample.GetValidZetaSentDestinationExternal(t).Logs[4], - sample.GetValidZetaSentDestinationExternal(t).Logs[4].Address, + *sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4], + sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4].Address, ) require.NoError(t, err) emittingContract := sample.EthAddress() @@ -588,8 +588,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { require.NoError(t, err) event, err := crosschainkeeper.ParseZetaSentEvent( - *sample.GetValidZetaSentDestinationExternal(t).Logs[4], - sample.GetValidZetaSentDestinationExternal(t).Logs[4].Address, + *sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4], + sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4].Address, ) require.NoError(t, err) emittingContract := sample.EthAddress() @@ -620,8 +620,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { require.NoError(t, err) event, err := crosschainkeeper.ParseZetaSentEvent( - *sample.GetValidZetaSentDestinationExternal(t).Logs[4], - sample.GetValidZetaSentDestinationExternal(t).Logs[4].Address, + *sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4], + sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4].Address, ) require.NoError(t, err) emittingContract := sample.EthAddress() @@ -651,8 +651,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { ) require.NoError(t, err) event, err := crosschainkeeper.ParseZetaSentEvent( - *sample.GetValidZetaSentDestinationExternal(t).Logs[4], - sample.GetValidZetaSentDestinationExternal(t).Logs[4].Address, + *sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4], + sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4].Address, ) require.NoError(t, err) emittingContract := sample.EthAddress() @@ -689,8 +689,8 @@ func TestKeeper_ProcessZetaSentEvent(t *testing.T) { require.NoError(t, err) event, err := crosschainkeeper.ParseZetaSentEvent( - *sample.GetValidZetaSentDestinationExternal(t).Logs[4], - sample.GetValidZetaSentDestinationExternal(t).Logs[4].Address, + *sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4], + sample.ValidZetaSentDestinationExternalReceipt(t).Logs[4].Address, ) require.NoError(t, err) emittingContract := sample.EthAddress() @@ -712,7 +712,7 @@ func TestKeeper_ProcessLogs(t *testing.T) { setSupportedChain(ctx, zk, []int64{chainID, senderChain.ChainId}...) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - block := sample.GetValidZRC20WithdrawToBTC(t) + block := sample.ValidZRC20WithdrawToBTCReceipt(t) gasZRC20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "bitcoin", "BTC") for _, log := range block.Logs { log.Address = gasZRC20 @@ -749,7 +749,7 @@ func TestKeeper_ProcessLogs(t *testing.T) { sdk.NewCoins(sdk.NewCoin(config.BaseDenom, amount)), ) require.NoError(t, err) - block := sample.GetValidZetaSentDestinationExternal(t) + block := sample.ValidZetaSentDestinationExternalReceipt(t) system, found := zk.FungibleKeeper.GetSystemContract(ctx) require.True(t, found) for _, log := range block.Logs { @@ -779,7 +779,7 @@ func TestKeeper_ProcessLogs(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - err := k.ProcessLogs(ctx, sample.GetValidZRC20WithdrawToBTC(t).Logs, sample.EthAddress(), "") + err := k.ProcessLogs(ctx, sample.ValidZRC20WithdrawToBTCReceipt(t).Logs, sample.EthAddress(), "") require.ErrorContains(t, err, "cannot find system contract") cctxList := k.GetAllCrossChainTx(ctx) require.Len(t, cctxList, 0) @@ -794,7 +794,7 @@ func TestKeeper_ProcessLogs(t *testing.T) { setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - block := sample.GetValidZRC20WithdrawToBTC(t) + block := sample.ValidZRC20WithdrawToBTCReceipt(t) gasZRC20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "bitcoin", "BTC") for _, log := range block.Logs { log.Address = gasZRC20 @@ -817,7 +817,7 @@ func TestKeeper_ProcessLogs(t *testing.T) { setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - block := sample.GetValidZRC20WithdrawToBTC(t) + block := sample.ValidZRC20WithdrawToBTCReceipt(t) setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "bitcoin", "BTC") for _, log := range block.Logs { log.Address = sample.EthAddress() @@ -840,7 +840,7 @@ func TestKeeper_ProcessLogs(t *testing.T) { setSupportedChain(ctx, zk, []int64{chainID, senderChain.ChainId}...) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - block := sample.GetValidZRC20WithdrawToBTC(t) + block := sample.ValidZRC20WithdrawToBTCReceipt(t) gasZRC20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "bitcoin", "BTC") for _, log := range block.Logs { log.Address = gasZRC20 @@ -865,7 +865,7 @@ func TestKeeper_ProcessLogs(t *testing.T) { setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - block := sample.GetInvalidZRC20WithdrawToExternal(t) + block := sample.InvalidZRC20WithdrawToExternalReceipt(t) gasZRC20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "bitcoin", "BTC") for _, log := range block.Logs { log.Address = gasZRC20 @@ -886,7 +886,7 @@ func TestKeeper_ProcessLogs(t *testing.T) { setSupportedChain(ctx, zk, chainID) SetupStateForProcessLogs(t, ctx, k, zk, sdkk, chain) - block := sample.GetValidZRC20WithdrawToBTC(t) + block := sample.ValidZRC20WithdrawToBTCReceipt(t) gasZRC20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "bitcoin", "BTC") for _, log := range block.Logs { log.Address = gasZRC20 diff --git a/x/crosschain/keeper/v2_zevm_inbound.go b/x/crosschain/keeper/v2_zevm_inbound.go index 9efc5e1e2e..8b4d4ed742 100644 --- a/x/crosschain/keeper/v2_zevm_inbound.go +++ b/x/crosschain/keeper/v2_zevm_inbound.go @@ -1,23 +1,16 @@ package keeper import ( - "encoding/hex" "fmt" "math/big" errorsmod "cosmossdk.io/errors" - "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol" - "github.com/zeta-chain/node/pkg/chains" - "github.com/zeta-chain/node/pkg/coin" "github.com/zeta-chain/node/x/crosschain/types" - fungibletypes "github.com/zeta-chain/node/x/fungible/types" observertypes "github.com/zeta-chain/node/x/observer/types" ) @@ -30,8 +23,8 @@ func (k Keeper) ProcessZEVMInboundV2( txOrigin string, ) error { // try to parse a withdrawal event from the log - withdrawalEvent, gatewayEvent, err := k.parseGatewayEvent(*log, gatewayAddr) - if err == nil && (withdrawalEvent != nil || gatewayEvent != nil) { + withdrawalEvent, callEvent, withdrawalAndCallEvent, err := types.ParseGatewayEvent(*log, gatewayAddr) + if err == nil && (withdrawalEvent != nil || callEvent != nil || withdrawalAndCallEvent != nil) { var inbound *types.MsgVoteInbound // parse data from event and validate @@ -44,21 +37,42 @@ func (k Keeper) ProcessZEVMInboundV2( value = withdrawalEvent.Value receiver = withdrawalEvent.Receiver contractAddress = withdrawalEvent.Raw.Address - } else { - zrc20 = gatewayEvent.Zrc20 + } else if callEvent != nil { + zrc20 = callEvent.Zrc20 value = big.NewInt(0) - receiver = gatewayEvent.Receiver - contractAddress = gatewayEvent.Raw.Address + receiver = callEvent.Receiver + contractAddress = callEvent.Raw.Address + } else { + zrc20 = withdrawalAndCallEvent.Zrc20 + value = withdrawalAndCallEvent.Value + receiver = withdrawalAndCallEvent.Receiver + contractAddress = withdrawalAndCallEvent.Raw.Address } k.Logger(ctx).Error(fmt.Sprintf("processing inbound. zrc20: %s", zrc20.Hex())) + // get several information necessary for processing the inbound foreignCoin, found := k.fungibleKeeper.GetForeignCoins(ctx, zrc20.Hex()) if !found { ctx.Logger(). Info(fmt.Sprintf("cannot find foreign coin with contract address %s", contractAddress.Hex())) return nil } + receiverChain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, foreignCoin.ForeignChainId) + if !found { + return errorsmod.Wrapf( + observertypes.ErrSupportedChains, + "chain with chainID %d not supported", + foreignCoin.ForeignChainId, + ) + } + gasLimitQueried, err := k.fungibleKeeper.QueryGasLimit( + ctx, + ethcommon.HexToAddress(foreignCoin.Zrc20ContractAddress), + ) + if err != nil { + return err + } // validate data of the withdrawal event if err := k.validateZRC20Withdrawal(ctx, foreignCoin.ForeignChainId, value, receiver); err != nil { @@ -67,12 +81,39 @@ func (k Keeper) ProcessZEVMInboundV2( // create inbound object depending on the event type if withdrawalEvent != nil { - inbound, err = k.newWithdrawalInbound(ctx, txOrigin, foreignCoin, withdrawalEvent) + inbound, err = types.NewWithdrawalInbound( + ctx, + txOrigin, + foreignCoin.CoinType, + foreignCoin.Asset, + withdrawalEvent, + receiverChain, + gasLimitQueried, + ) + if err != nil { + return err + } + } else if callEvent != nil { + inbound, err = types.NewCallInbound( + ctx, + txOrigin, + callEvent, + receiverChain, + gasLimitQueried, + ) if err != nil { return err } } else { - inbound, err = k.newCallInbound(ctx, txOrigin, foreignCoin, gatewayEvent) + inbound, err = types.NewWithdrawAndCallInbound( + ctx, + txOrigin, + foreignCoin.CoinType, + foreignCoin.Asset, + withdrawalAndCallEvent, + receiverChain, + gasLimitQueried, + ) if err != nil { return err } @@ -96,182 +137,3 @@ func (k Keeper) ProcessZEVMInboundV2( return nil } - -// parseGatewayEvent parses the event from the gateway contract -func (k Keeper) parseGatewayEvent( - log ethtypes.Log, - gatewayAddr ethcommon.Address, -) (*gatewayzevm.GatewayZEVMWithdrawn, *gatewayzevm.GatewayZEVMCalled, error) { - if len(log.Topics) == 0 { - return nil, nil, errors.New("ParseGatewayCallEvent: invalid log - no topics") - } - filterer, err := gatewayzevm.NewGatewayZEVMFilterer(log.Address, bind.ContractFilterer(nil)) - if err != nil { - return nil, nil, err - } - withdrawalEvent, err := k.parseGatewayWithdrawalEvent(log, gatewayAddr, filterer) - if err == nil { - return withdrawalEvent, nil, nil - } - callEvent, err := k.parseGatewayCallEvent(log, gatewayAddr, filterer) - if err == nil { - return nil, callEvent, nil - } - return nil, nil, errors.New("ParseGatewayEvent: invalid log - no event found") -} - -// parseGatewayWithdrawalEvent parses the GatewayZEVMWithdrawal event from the log -func (k Keeper) parseGatewayWithdrawalEvent( - log ethtypes.Log, - gatewayAddr ethcommon.Address, - filterer *gatewayzevm.GatewayZEVMFilterer, -) (*gatewayzevm.GatewayZEVMWithdrawn, error) { - event, err := filterer.ParseWithdrawn(log) - if err != nil { - return nil, err - } - if event.Raw.Address != gatewayAddr { - return nil, errors.New("ParseGatewayWithdrawalEvent: invalid log - wrong contract address") - } - return event, nil -} - -// parseGatewayCallEvent parses the GatewayZEVMCall event from the log -func (k Keeper) parseGatewayCallEvent( - log ethtypes.Log, - gatewayAddr ethcommon.Address, - filterer *gatewayzevm.GatewayZEVMFilterer, -) (*gatewayzevm.GatewayZEVMCalled, error) { - event, err := filterer.ParseCalled(log) - if err != nil { - return nil, err - } - if event.Raw.Address != gatewayAddr { - return nil, errors.New("ParseGatewayCallEvent: invalid log - wrong contract address") - } - return event, nil -} - -// newWithdrawalInbound creates a new inbound object for a withdrawal -// currently inbound data is represented with a MsgVoteInbound message -// TODO: replace with a more appropriate object -// https://github.com/zeta-chain/node/issues/2658 -func (k Keeper) newWithdrawalInbound( - ctx sdk.Context, - txOrigin string, - foreignCoin fungibletypes.ForeignCoins, - event *gatewayzevm.GatewayZEVMWithdrawn, -) (*types.MsgVoteInbound, error) { - receiverChain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, foreignCoin.ForeignChainId) - if !found { - return nil, errorsmod.Wrapf( - observertypes.ErrSupportedChains, - "chain with chainID %d not supported", - foreignCoin.ForeignChainId, - ) - } - - senderChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) - if err != nil { - return nil, errors.Wrapf(err, "ProcessZEVMInboundV2: failed to convert chainID %s", ctx.ChainID()) - } - - toAddr, err := receiverChain.EncodeAddress(event.Receiver) - if err != nil { - return nil, errors.Wrapf(err, "cannot encode address %v", event.Receiver) - } - - gasLimit := event.CallOptions.GasLimit.Uint64() - if gasLimit == 0 { - gasLimitQueried, err := k.fungibleKeeper.QueryGasLimit( - ctx, - ethcommon.HexToAddress(foreignCoin.Zrc20ContractAddress), - ) - if err != nil { - return nil, errors.Wrap(err, "cannot query gas limit") - } - gasLimit = gasLimitQueried.Uint64() - } - - return types.NewMsgVoteInbound( - "", - event.Sender.Hex(), - senderChain.ChainId, - txOrigin, - toAddr, - foreignCoin.ForeignChainId, - math.NewUintFromBigInt(event.Value), - hex.EncodeToString(event.Message), - event.Raw.TxHash.String(), - event.Raw.BlockNumber, - gasLimit, - foreignCoin.CoinType, - foreignCoin.Asset, - event.Raw.Index, - types.ProtocolContractVersion_V2, - event.CallOptions.IsArbitraryCall, - types.WithZEVMRevertOptions(event.RevertOptions), - ), nil -} - -// newCallInbound creates a new inbound object for a call -// currently inbound data is represented with a MsgVoteInbound message -// TODO: replace with a more appropriate object -// https://github.com/zeta-chain/node/issues/2658 -func (k Keeper) newCallInbound( - ctx sdk.Context, - txOrigin string, - foreignCoin fungibletypes.ForeignCoins, - event *gatewayzevm.GatewayZEVMCalled, -) (*types.MsgVoteInbound, error) { - receiverChain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, foreignCoin.ForeignChainId) - if !found { - return nil, errorsmod.Wrapf( - observertypes.ErrSupportedChains, - "chain with chainID %d not supported", - foreignCoin.ForeignChainId, - ) - } - - senderChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) - if err != nil { - return nil, errors.Wrapf(err, "ProcessZEVMInboundV2: failed to convert chainID %s", ctx.ChainID()) - } - - toAddr, err := receiverChain.EncodeAddress(event.Receiver) - if err != nil { - return nil, errors.Wrapf(err, "cannot encode address %v", event.Receiver) - } - - gasLimit := event.CallOptions.GasLimit.Uint64() - if gasLimit == 0 { - gasLimitQueried, err := k.fungibleKeeper.QueryGasLimit( - ctx, - ethcommon.HexToAddress(foreignCoin.Zrc20ContractAddress), - ) - if err != nil { - return nil, errors.Wrap(err, "cannot query gas limit") - } - gasLimit = gasLimitQueried.Uint64() - } - - return types.NewMsgVoteInbound( - "", - event.Sender.Hex(), - senderChain.ChainId, - txOrigin, - toAddr, - foreignCoin.ForeignChainId, - math.ZeroUint(), - hex.EncodeToString(event.Message), - event.Raw.TxHash.String(), - event.Raw.BlockNumber, - gasLimit, - coin.CoinType_NoAssetCall, - "", - event.Raw.Index, - types.ProtocolContractVersion_V2, - event.CallOptions.IsArbitraryCall, - types.WithZEVMRevertOptions(event.RevertOptions), - ), nil -} diff --git a/x/crosschain/types/cctx.go b/x/crosschain/types/cctx.go index 91004511d4..2b84b5f26c 100644 --- a/x/crosschain/types/cctx.go +++ b/x/crosschain/types/cctx.go @@ -237,6 +237,7 @@ func NewCCTX(ctx sdk.Context, msg MsgVoteInbound, tssPubkey string) (CrossChainT FinalizedZetaHeight: 0, BallotIndex: index, CoinType: msg.CoinType, + IsCrossChainCall: msg.IsCrossChainCall, } outboundParams := &OutboundParams{ diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index 23923a9cbf..11ebc77bb3 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -130,6 +130,9 @@ type InboundParams struct { BallotIndex string `protobuf:"bytes,9,opt,name=ballot_index,json=ballotIndex,proto3" json:"ballot_index,omitempty"` FinalizedZetaHeight uint64 `protobuf:"varint,10,opt,name=finalized_zeta_height,json=finalizedZetaHeight,proto3" json:"finalized_zeta_height,omitempty"` TxFinalizationStatus TxFinalizationStatus `protobuf:"varint,11,opt,name=tx_finalization_status,json=txFinalizationStatus,proto3,enum=zetachain.zetacore.crosschain.TxFinalizationStatus" json:"tx_finalization_status,omitempty"` + // this field describes if a smart contract call should be made for a inbound + // with assets only used for protocol contract version 2 + IsCrossChainCall bool `protobuf:"varint,12,opt,name=is_cross_chain_call,json=isCrossChainCall,proto3" json:"is_cross_chain_call,omitempty"` } func (m *InboundParams) Reset() { *m = InboundParams{} } @@ -235,6 +238,13 @@ func (m *InboundParams) GetTxFinalizationStatus() TxFinalizationStatus { return TxFinalizationStatus_NotFinalized } +func (m *InboundParams) GetIsCrossChainCall() bool { + if m != nil { + return m.IsCrossChainCall + } + return false +} + type ZetaAccounting struct { // aborted_zeta_amount stores the total aborted amount for cctx of coin-type // ZETA @@ -765,93 +775,94 @@ func init() { } var fileDescriptor_d4c1966807fb5cb2 = []byte{ - // 1361 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcf, 0x6e, 0x1b, 0xb7, - 0x13, 0xf6, 0xda, 0xb2, 0x2c, 0x8d, 0xfe, 0x78, 0x4d, 0x2b, 0xce, 0xc6, 0x3f, 0x44, 0xf1, 0x4f, - 0xad, 0x13, 0xc5, 0xad, 0x25, 0x44, 0x01, 0x8a, 0xa2, 0x37, 0xdb, 0x88, 0x13, 0xb7, 0x4d, 0x6c, - 0x6c, 0x1c, 0x03, 0xc9, 0xa1, 0x5b, 0x6a, 0x97, 0x96, 0x08, 0xaf, 0x96, 0xea, 0x92, 0x32, 0xa4, - 0xa0, 0xb7, 0x9e, 0x0b, 0xf4, 0x15, 0x0a, 0xf4, 0xd0, 0x63, 0x1f, 0x23, 0xc7, 0x1c, 0x8b, 0x1e, - 0x82, 0x20, 0x79, 0x83, 0x3e, 0x41, 0xc1, 0x7f, 0x92, 0x15, 0xb8, 0x76, 0x9a, 0xf6, 0x24, 0xf2, - 0x1b, 0xf2, 0x9b, 0xd9, 0xe1, 0x7c, 0x43, 0x0a, 0x5a, 0xcf, 0x89, 0xc0, 0x61, 0x17, 0xd3, 0xa4, - 0xa9, 0x46, 0x2c, 0x25, 0xcd, 0x30, 0x65, 0x9c, 0x6b, 0x4c, 0x0d, 0x03, 0x35, 0x0e, 0xc4, 0xb0, - 0xd1, 0x4f, 0x99, 0x60, 0xe8, 0xfa, 0x78, 0x4f, 0xc3, 0xee, 0x69, 0x4c, 0xf6, 0xac, 0x56, 0x3a, - 0xac, 0xc3, 0xd4, 0xca, 0xa6, 0x1c, 0xe9, 0x4d, 0xab, 0x37, 0xcf, 0x71, 0xd4, 0x3f, 0xe9, 0x34, - 0x43, 0x26, 0xdd, 0x30, 0x9a, 0xe8, 0x75, 0xb5, 0xdf, 0x32, 0x50, 0xda, 0x4b, 0xda, 0x6c, 0x90, - 0x44, 0x07, 0x38, 0xc5, 0x3d, 0x8e, 0x56, 0x20, 0xcb, 0x49, 0x12, 0x91, 0xd4, 0x73, 0xd6, 0x9c, - 0x7a, 0xde, 0x37, 0x33, 0x74, 0x13, 0x16, 0xf5, 0xc8, 0xc4, 0x47, 0x23, 0x6f, 0x76, 0xcd, 0xa9, - 0xcf, 0xf9, 0x25, 0x0d, 0xef, 0x48, 0x74, 0x2f, 0x42, 0xff, 0x83, 0xbc, 0x18, 0x06, 0x2c, 0xa5, - 0x1d, 0x9a, 0x78, 0x73, 0x8a, 0x22, 0x27, 0x86, 0xfb, 0x6a, 0x8e, 0xb6, 0x21, 0x2f, 0x9d, 0x07, - 0x62, 0xd4, 0x27, 0x5e, 0x66, 0xcd, 0xa9, 0x97, 0x5b, 0xeb, 0x8d, 0x73, 0xbe, 0xaf, 0x7f, 0xd2, - 0x69, 0xa8, 0x28, 0x77, 0x18, 0x4d, 0x0e, 0x47, 0x7d, 0xe2, 0xe7, 0x42, 0x33, 0x42, 0x15, 0x98, - 0xc7, 0x9c, 0x13, 0xe1, 0xcd, 0x2b, 0x72, 0x3d, 0x41, 0xf7, 0x21, 0x8b, 0x7b, 0x6c, 0x90, 0x08, - 0x2f, 0x2b, 0xe1, 0xed, 0xe6, 0x8b, 0x57, 0x37, 0x66, 0xfe, 0x78, 0x75, 0xe3, 0x56, 0x87, 0x8a, - 0xee, 0xa0, 0xdd, 0x08, 0x59, 0xaf, 0x19, 0x32, 0xde, 0x63, 0xdc, 0xfc, 0x6c, 0xf2, 0xe8, 0xa4, - 0x29, 0xe3, 0xe0, 0x8d, 0x27, 0x34, 0x11, 0xbe, 0xd9, 0x8e, 0x3e, 0x82, 0x12, 0x6b, 0x73, 0x92, - 0x9e, 0x92, 0x28, 0xe8, 0x62, 0xde, 0xf5, 0x16, 0x94, 0x9b, 0xa2, 0x05, 0x1f, 0x60, 0xde, 0x45, - 0x9f, 0x83, 0x37, 0x5e, 0x44, 0x86, 0x82, 0xa4, 0x09, 0x8e, 0x83, 0x2e, 0xa1, 0x9d, 0xae, 0xf0, - 0x72, 0x6b, 0x4e, 0x3d, 0xe3, 0xaf, 0x58, 0xfb, 0x3d, 0x63, 0x7e, 0xa0, 0xac, 0xe8, 0xff, 0x50, - 0x6c, 0xe3, 0x38, 0x66, 0x22, 0xa0, 0x49, 0x44, 0x86, 0x5e, 0x5e, 0xb1, 0x17, 0x34, 0xb6, 0x27, - 0x21, 0xd4, 0x82, 0x2b, 0xc7, 0x34, 0xc1, 0x31, 0x7d, 0x4e, 0xa2, 0x40, 0xa6, 0xc4, 0x32, 0x83, - 0x62, 0x5e, 0x1e, 0x1b, 0x9f, 0x11, 0x81, 0x0d, 0x2d, 0x85, 0x15, 0x31, 0x0c, 0x8c, 0x05, 0x0b, - 0xca, 0x92, 0x80, 0x0b, 0x2c, 0x06, 0xdc, 0x2b, 0xa8, 0x2c, 0xdf, 0x6d, 0x5c, 0x58, 0x45, 0x8d, - 0xc3, 0xe1, 0xee, 0x99, 0xbd, 0x8f, 0xd5, 0x56, 0xbf, 0x22, 0xce, 0x41, 0x6b, 0xdf, 0x41, 0x59, - 0x3a, 0xde, 0x0a, 0x43, 0x99, 0x2f, 0x9a, 0x74, 0x50, 0x00, 0xcb, 0xb8, 0xcd, 0x52, 0x61, 0xc3, - 0x35, 0x07, 0xe1, 0x7c, 0xd8, 0x41, 0x2c, 0x19, 0x2e, 0xe5, 0x44, 0x31, 0xd5, 0x8e, 0xa0, 0xb0, - 0x83, 0xe3, 0x78, 0xbf, 0x2f, 0xc3, 0xe0, 0xb2, 0xc4, 0x3a, 0x98, 0x07, 0x31, 0xed, 0x51, 0xed, - 0x25, 0xe3, 0xe7, 0x3a, 0x98, 0x7f, 0x2d, 0xe7, 0x68, 0x03, 0x96, 0x28, 0x0f, 0x70, 0xda, 0xa6, - 0x22, 0xc5, 0xe9, 0x28, 0x08, 0x71, 0x1c, 0xab, 0x4a, 0xcd, 0xf9, 0x8b, 0x94, 0x6f, 0x59, 0x5c, - 0xf2, 0xd5, 0x5e, 0x67, 0xa1, 0xbc, 0x3f, 0x10, 0x67, 0xcb, 0x7f, 0x15, 0x72, 0x29, 0x09, 0x09, - 0x3d, 0x1d, 0x0b, 0x60, 0x3c, 0x47, 0xb7, 0xc1, 0xb5, 0x63, 0x2d, 0x82, 0x3d, 0xab, 0x81, 0x45, - 0x8b, 0x5b, 0x15, 0x4c, 0x15, 0xfa, 0xdc, 0x87, 0x15, 0xfa, 0xa4, 0xa4, 0x33, 0xff, 0xae, 0xa4, - 0xa5, 0x24, 0x39, 0x0f, 0x12, 0x96, 0x84, 0x44, 0xa9, 0x26, 0xe3, 0xe7, 0x04, 0xe7, 0x8f, 0xe4, - 0x7c, 0x3a, 0x99, 0xd9, 0x77, 0x92, 0x69, 0x8c, 0xfd, 0x94, 0x86, 0xc4, 0x08, 0x41, 0x1a, 0x0f, - 0xe4, 0x1c, 0xd5, 0xc1, 0x35, 0x46, 0x96, 0x52, 0x31, 0x0a, 0x8e, 0x09, 0xf1, 0xae, 0xaa, 0x35, - 0x65, 0xbd, 0x46, 0xc1, 0xbb, 0x84, 0x20, 0x04, 0x19, 0x25, 0xa5, 0x9c, 0xb2, 0xaa, 0xf1, 0xfb, - 0x08, 0xe1, 0x22, 0x95, 0xc1, 0x85, 0x2a, 0xbb, 0x06, 0x32, 0xcc, 0x60, 0xc0, 0x49, 0xe4, 0x55, - 0xd4, 0xca, 0x85, 0x0e, 0xe6, 0x4f, 0x38, 0x89, 0xd0, 0x37, 0xb0, 0x4c, 0x8e, 0x8f, 0x49, 0x28, - 0xe8, 0x29, 0x09, 0x26, 0x1f, 0x77, 0x45, 0xa5, 0xb8, 0x61, 0x52, 0x7c, 0xf3, 0x3d, 0x52, 0xbc, - 0x27, 0x6b, 0x75, 0x4c, 0x75, 0xdf, 0x66, 0xa5, 0xf1, 0x2e, 0xbf, 0xce, 0xec, 0x8a, 0x8a, 0x62, - 0x6a, 0xbd, 0x4e, 0xf1, 0x75, 0x00, 0x79, 0x38, 0xfd, 0x41, 0xfb, 0x84, 0x8c, 0x94, 0x5a, 0xf3, - 0xbe, 0x3c, 0xae, 0x03, 0x05, 0x5c, 0x20, 0xec, 0xe2, 0x7f, 0x2c, 0x6c, 0xf4, 0x10, 0x8a, 0x52, - 0x2c, 0x01, 0xd3, 0x32, 0xf3, 0xbc, 0x35, 0xa7, 0x5e, 0x68, 0x6d, 0x5c, 0xe2, 0xe0, 0x8c, 0x30, - 0xfd, 0x42, 0x38, 0x99, 0x7c, 0x99, 0xc9, 0x95, 0xdc, 0x4a, 0xed, 0xe7, 0x59, 0xc8, 0x1a, 0xfe, - 0x2d, 0xc8, 0x9a, 0xd0, 0x1d, 0x15, 0xfa, 0xed, 0xcb, 0x98, 0x43, 0x31, 0x34, 0x01, 0x9b, 0x8d, - 0x68, 0x1d, 0xca, 0x7a, 0x14, 0xf4, 0x08, 0xe7, 0xb8, 0x43, 0x94, 0xfe, 0xf2, 0x7e, 0x49, 0xa3, - 0x0f, 0x35, 0x28, 0x7b, 0x38, 0x49, 0x53, 0x96, 0x8e, 0x57, 0x65, 0x75, 0x0f, 0x57, 0xa0, 0x5d, - 0x74, 0x07, 0x2a, 0x31, 0xe6, 0xe2, 0x49, 0x3f, 0xc2, 0x82, 0x04, 0x82, 0xf6, 0x08, 0x17, 0xb8, - 0xd7, 0x57, 0x6a, 0x9d, 0xf3, 0x97, 0x27, 0xb6, 0x43, 0x6b, 0x42, 0x75, 0x90, 0x2d, 0x44, 0xb6, - 0x27, 0x9f, 0x1c, 0x0f, 0x92, 0x88, 0x44, 0x4a, 0x9a, 0xba, 0xb3, 0x9c, 0x85, 0xd1, 0x27, 0xb0, - 0x14, 0xa6, 0x04, 0xcb, 0x96, 0x38, 0x61, 0x9e, 0x57, 0xcc, 0xae, 0x31, 0x8c, 0x69, 0x6b, 0x3f, - 0xcc, 0x42, 0xc9, 0x27, 0xa7, 0x24, 0x15, 0xb6, 0xc3, 0xad, 0x43, 0x39, 0x55, 0x40, 0x80, 0xa3, - 0x28, 0x25, 0x9c, 0x9b, 0x5e, 0x54, 0xd2, 0xe8, 0x96, 0x06, 0xd1, 0xc7, 0x50, 0xd6, 0x27, 0x96, - 0x04, 0xda, 0x60, 0x1a, 0x9d, 0x3a, 0xc7, 0xfd, 0x44, 0x73, 0xca, 0x6c, 0xa8, 0x96, 0x3a, 0xe6, - 0xd2, 0xb7, 0x72, 0x51, 0x81, 0x96, 0x6a, 0xe2, 0xd1, 0xe6, 0x4c, 0x7e, 0x59, 0xd1, 0x7a, 0xb4, - 0x49, 0x7b, 0x2a, 0x5b, 0xa0, 0x5a, 0x36, 0x29, 0xed, 0xf9, 0x0f, 0xeb, 0x4e, 0xc6, 0x9f, 0x15, - 0x42, 0xed, 0xc7, 0x79, 0x28, 0xee, 0xc8, 0xd3, 0x57, 0x3d, 0xf4, 0x70, 0x88, 0x3c, 0x58, 0x50, - 0xa9, 0x62, 0xb6, 0x13, 0xdb, 0xa9, 0x7c, 0x02, 0xe8, 0xa6, 0xa1, 0x4f, 0x5f, 0x4f, 0xd0, 0xb7, - 0x90, 0x57, 0xd7, 0xcf, 0x31, 0x21, 0xdc, 0x04, 0xb5, 0xf3, 0x0f, 0x83, 0xfa, 0xf3, 0xd5, 0x0d, - 0x77, 0x84, 0x7b, 0xf1, 0x17, 0xb5, 0x31, 0x53, 0xcd, 0xcf, 0xc9, 0xf1, 0x2e, 0x21, 0x1c, 0xdd, - 0x82, 0xc5, 0x94, 0xc4, 0x78, 0x44, 0xa2, 0x77, 0x2a, 0xab, 0x6c, 0x60, 0x9b, 0xa6, 0x5d, 0x28, - 0x84, 0xa1, 0x18, 0x5a, 0xa9, 0xe6, 0x94, 0x92, 0xd6, 0x2f, 0xa9, 0x77, 0x53, 0xeb, 0x10, 0x8e, - 0xeb, 0x1e, 0x3d, 0x86, 0x32, 0xd5, 0xaf, 0xb3, 0xa0, 0xaf, 0xee, 0x27, 0xd5, 0x26, 0x0b, 0xad, - 0x4f, 0x2f, 0xa1, 0x9a, 0x7a, 0xd2, 0xf9, 0x25, 0x3a, 0xf5, 0xc2, 0x3b, 0x82, 0x45, 0x66, 0x2e, - 0x3d, 0xcb, 0x0a, 0x6b, 0x73, 0xf5, 0x42, 0x6b, 0xf3, 0x12, 0xd6, 0xe9, 0xab, 0xd2, 0x2f, 0xb3, - 0xe9, 0xab, 0x33, 0x85, 0x6b, 0xea, 0x51, 0x19, 0xb2, 0x38, 0x08, 0x59, 0x22, 0x52, 0x1c, 0x8a, - 0xe0, 0x94, 0xa4, 0x9c, 0xb2, 0xc4, 0x3c, 0x43, 0x3e, 0xbb, 0xc4, 0xc3, 0x81, 0xd9, 0xbf, 0x63, - 0xb6, 0x1f, 0xe9, 0xdd, 0xfe, 0xd5, 0xfe, 0xf9, 0x06, 0xf4, 0x74, 0x5c, 0xb6, 0xb6, 0x6b, 0x15, - 0xdf, 0x2b, 0x41, 0x53, 0x72, 0xdb, 0xce, 0xc8, 0x32, 0xb1, 0xa5, 0x6e, 0xc0, 0x8d, 0xef, 0x01, - 0x26, 0x1d, 0x08, 0x21, 0x28, 0x1f, 0x90, 0x24, 0xa2, 0x49, 0xc7, 0xe4, 0xd6, 0x9d, 0x41, 0xcb, - 0xb0, 0x68, 0x30, 0x9b, 0x19, 0xd7, 0x41, 0x4b, 0x50, 0xb2, 0xb3, 0x87, 0x34, 0x21, 0x91, 0x3b, - 0x27, 0x21, 0xb3, 0x4e, 0xbb, 0x75, 0x33, 0xa8, 0x08, 0x39, 0x3d, 0x26, 0x91, 0x3b, 0x8f, 0x0a, - 0xb0, 0xb0, 0xa5, 0x1f, 0x3d, 0x6e, 0x76, 0x35, 0xf3, 0xeb, 0x2f, 0x55, 0x67, 0xe3, 0x2b, 0xa8, - 0x9c, 0xd7, 0xba, 0x91, 0x0b, 0xc5, 0x47, 0x4c, 0xec, 0xda, 0x27, 0xa0, 0x3b, 0x83, 0x4a, 0x90, - 0x9f, 0x4c, 0x1d, 0xc9, 0x7c, 0x6f, 0x48, 0xc2, 0x81, 0x24, 0x9b, 0x35, 0x64, 0x4d, 0xb8, 0xfa, - 0x37, 0x99, 0x45, 0x59, 0x98, 0x3d, 0xba, 0xe3, 0xce, 0xa8, 0xdf, 0x96, 0xeb, 0xe8, 0x0d, 0xdb, - 0xf7, 0x5f, 0xbc, 0xa9, 0x3a, 0x2f, 0xdf, 0x54, 0x9d, 0xd7, 0x6f, 0xaa, 0xce, 0x4f, 0x6f, 0xab, - 0x33, 0x2f, 0xdf, 0x56, 0x67, 0x7e, 0x7f, 0x5b, 0x9d, 0x79, 0xb6, 0x79, 0x46, 0x49, 0x32, 0xb1, - 0x9b, 0xfa, 0x4f, 0x46, 0xc2, 0x22, 0xd2, 0x1c, 0x9e, 0xfd, 0x2f, 0xa3, 0x44, 0xd5, 0xce, 0xaa, - 0x83, 0xbb, 0xfb, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x84, 0x70, 0x56, 0x74, 0xf9, 0x0c, 0x00, - 0x00, + // 1378 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0x4d, 0x6f, 0x1b, 0x37, + 0x13, 0xf6, 0xda, 0xb2, 0x2c, 0x8d, 0x3e, 0xbc, 0xa6, 0x15, 0x67, 0xe3, 0x17, 0x51, 0xf4, 0xaa, + 0x75, 0xa2, 0xb8, 0xb5, 0x84, 0x28, 0x40, 0x51, 0xf4, 0x66, 0x1b, 0x71, 0xe2, 0xb6, 0x89, 0x8d, + 0x8d, 0x63, 0x20, 0x39, 0x74, 0x4b, 0xed, 0xd2, 0x12, 0x61, 0x69, 0xa9, 0x2e, 0x29, 0x43, 0x0a, + 0x7a, 0xeb, 0xb9, 0x40, 0xff, 0x42, 0x81, 0x1e, 0xfa, 0x53, 0x72, 0xcc, 0xb1, 0xe8, 0x21, 0x0d, + 0x92, 0x7f, 0xd0, 0x5f, 0x50, 0xf0, 0x4b, 0x1f, 0x81, 0x6b, 0xa7, 0x69, 0x4f, 0x22, 0x9f, 0x21, + 0x9f, 0x99, 0x1d, 0xce, 0x33, 0xa4, 0xa0, 0xf9, 0x9c, 0x08, 0x1c, 0x76, 0x30, 0x8d, 0x1b, 0x6a, + 0xc4, 0x12, 0xd2, 0x08, 0x13, 0xc6, 0xb9, 0xc6, 0xd4, 0x30, 0x50, 0xe3, 0x40, 0x0c, 0xeb, 0xfd, + 0x84, 0x09, 0x86, 0xae, 0x8f, 0xf7, 0xd4, 0xed, 0x9e, 0xfa, 0x64, 0xcf, 0x7a, 0xa9, 0xcd, 0xda, + 0x4c, 0xad, 0x6c, 0xc8, 0x91, 0xde, 0xb4, 0x7e, 0xf3, 0x1c, 0x47, 0xfd, 0xd3, 0x76, 0x23, 0x64, + 0xd2, 0x0d, 0xa3, 0xb1, 0x5e, 0x57, 0xfd, 0x23, 0x05, 0x85, 0xfd, 0xb8, 0xc5, 0x06, 0x71, 0x74, + 0x88, 0x13, 0xdc, 0xe3, 0x68, 0x0d, 0xd2, 0x9c, 0xc4, 0x11, 0x49, 0x3c, 0xa7, 0xe2, 0xd4, 0xb2, + 0xbe, 0x99, 0xa1, 0x9b, 0xb0, 0xac, 0x47, 0x26, 0x3e, 0x1a, 0x79, 0xf3, 0x15, 0xa7, 0xb6, 0xe0, + 0x17, 0x34, 0xbc, 0x2b, 0xd1, 0xfd, 0x08, 0xfd, 0x0f, 0xb2, 0x62, 0x18, 0xb0, 0x84, 0xb6, 0x69, + 0xec, 0x2d, 0x28, 0x8a, 0x8c, 0x18, 0x1e, 0xa8, 0x39, 0xda, 0x81, 0xac, 0x74, 0x1e, 0x88, 0x51, + 0x9f, 0x78, 0xa9, 0x8a, 0x53, 0x2b, 0x36, 0x37, 0xea, 0xe7, 0x7c, 0x5f, 0xff, 0xb4, 0x5d, 0x57, + 0x51, 0xee, 0x32, 0x1a, 0x1f, 0x8d, 0xfa, 0xc4, 0xcf, 0x84, 0x66, 0x84, 0x4a, 0xb0, 0x88, 0x39, + 0x27, 0xc2, 0x5b, 0x54, 0xe4, 0x7a, 0x82, 0xee, 0x43, 0x1a, 0xf7, 0xd8, 0x20, 0x16, 0x5e, 0x5a, + 0xc2, 0x3b, 0x8d, 0x17, 0xaf, 0x6e, 0xcc, 0xfd, 0xfe, 0xea, 0xc6, 0xad, 0x36, 0x15, 0x9d, 0x41, + 0xab, 0x1e, 0xb2, 0x5e, 0x23, 0x64, 0xbc, 0xc7, 0xb8, 0xf9, 0xd9, 0xe2, 0xd1, 0x69, 0x43, 0xc6, + 0xc1, 0xeb, 0x4f, 0x68, 0x2c, 0x7c, 0xb3, 0x1d, 0x7d, 0x04, 0x05, 0xd6, 0xe2, 0x24, 0x39, 0x23, + 0x51, 0xd0, 0xc1, 0xbc, 0xe3, 0x2d, 0x29, 0x37, 0x79, 0x0b, 0x3e, 0xc0, 0xbc, 0x83, 0x3e, 0x07, + 0x6f, 0xbc, 0x88, 0x0c, 0x05, 0x49, 0x62, 0xdc, 0x0d, 0x3a, 0x84, 0xb6, 0x3b, 0xc2, 0xcb, 0x54, + 0x9c, 0x5a, 0xca, 0x5f, 0xb3, 0xf6, 0x7b, 0xc6, 0xfc, 0x40, 0x59, 0xd1, 0xff, 0x21, 0xdf, 0xc2, + 0xdd, 0x2e, 0x13, 0x01, 0x8d, 0x23, 0x32, 0xf4, 0xb2, 0x8a, 0x3d, 0xa7, 0xb1, 0x7d, 0x09, 0xa1, + 0x26, 0x5c, 0x39, 0xa1, 0x31, 0xee, 0xd2, 0xe7, 0x24, 0x0a, 0x64, 0x4a, 0x2c, 0x33, 0x28, 0xe6, + 0xd5, 0xb1, 0xf1, 0x19, 0x11, 0xd8, 0xd0, 0x52, 0x58, 0x13, 0xc3, 0xc0, 0x58, 0xb0, 0xa0, 0x2c, + 0x0e, 0xb8, 0xc0, 0x62, 0xc0, 0xbd, 0x9c, 0xca, 0xf2, 0xdd, 0xfa, 0x85, 0x55, 0x54, 0x3f, 0x1a, + 0xee, 0x4d, 0xed, 0x7d, 0xac, 0xb6, 0xfa, 0x25, 0x71, 0x0e, 0x8a, 0xb6, 0x60, 0x95, 0xf2, 0x60, + 0xba, 0x54, 0x43, 0xdc, 0xed, 0x7a, 0xf9, 0x8a, 0x53, 0xcb, 0xf8, 0x2e, 0xe5, 0xbb, 0xd2, 0xa2, + 0xaa, 0x61, 0x17, 0x77, 0xbb, 0xd5, 0xef, 0xa0, 0x28, 0xe3, 0xdc, 0x0e, 0x43, 0x99, 0x5e, 0x1a, + 0xb7, 0x51, 0x00, 0xab, 0xb8, 0xc5, 0x12, 0x61, 0xbf, 0xce, 0x9c, 0x9b, 0xf3, 0x61, 0xe7, 0xb6, + 0x62, 0xb8, 0x94, 0x13, 0xc5, 0x54, 0x3d, 0x86, 0x9c, 0x74, 0x7d, 0xd0, 0x97, 0x51, 0x73, 0x59, + 0x91, 0x6d, 0xcc, 0x83, 0x2e, 0xed, 0x51, 0xed, 0x25, 0xe5, 0x67, 0xda, 0x98, 0x7f, 0x2d, 0xe7, + 0x68, 0x13, 0x56, 0x28, 0x0f, 0x70, 0xd2, 0xa2, 0x22, 0xc1, 0xc9, 0x48, 0x7f, 0xcb, 0xbc, 0xfa, + 0x96, 0x65, 0xca, 0xb7, 0x2d, 0xae, 0x3e, 0xe5, 0x75, 0x1a, 0x8a, 0x07, 0x03, 0x31, 0xad, 0x96, + 0x75, 0xc8, 0x24, 0x24, 0x24, 0xf4, 0x6c, 0xac, 0x97, 0xf1, 0x1c, 0xdd, 0x06, 0xd7, 0x8e, 0x75, + 0xa2, 0xf6, 0xad, 0x64, 0x96, 0x2d, 0x6e, 0x45, 0x33, 0xa3, 0x8b, 0x85, 0x0f, 0xd3, 0xc5, 0x44, + 0x01, 0xa9, 0x7f, 0xa7, 0x00, 0xa9, 0x60, 0xce, 0x83, 0x98, 0xc5, 0x21, 0x51, 0x22, 0x4b, 0xf9, + 0x19, 0xc1, 0xf9, 0x23, 0x39, 0x9f, 0x4d, 0x66, 0xfa, 0x9d, 0x64, 0x1a, 0x63, 0x3f, 0xa1, 0x21, + 0x31, 0xba, 0x91, 0xc6, 0x43, 0x39, 0x47, 0x35, 0x70, 0x8d, 0x91, 0x25, 0x54, 0x8c, 0x82, 0x13, + 0x42, 0xbc, 0xab, 0x6a, 0x4d, 0x51, 0xaf, 0x51, 0xf0, 0x1e, 0x21, 0x08, 0x41, 0x4a, 0x29, 0x2f, + 0xa3, 0xac, 0x6a, 0xfc, 0x3e, 0xba, 0xb9, 0x48, 0x94, 0x70, 0xa1, 0x28, 0xaf, 0x81, 0x0c, 0x33, + 0x18, 0x70, 0x12, 0x79, 0x25, 0xb5, 0x72, 0xa9, 0x8d, 0xf9, 0x13, 0x4e, 0x22, 0xf4, 0x0d, 0xac, + 0x92, 0x93, 0x13, 0x12, 0x0a, 0x7a, 0x46, 0x82, 0xc9, 0xc7, 0x5d, 0x51, 0x29, 0xae, 0x9b, 0x14, + 0xdf, 0x7c, 0x8f, 0x14, 0xef, 0xcb, 0x5a, 0x1d, 0x53, 0xdd, 0xb7, 0x59, 0xa9, 0xbf, 0xcb, 0xaf, + 0x33, 0xbb, 0xa6, 0xa2, 0x98, 0x59, 0xaf, 0x53, 0x7c, 0x1d, 0x40, 0x1e, 0x4e, 0x7f, 0xd0, 0x3a, + 0x25, 0x23, 0x25, 0xee, 0xac, 0x2f, 0x8f, 0xeb, 0x50, 0x01, 0x17, 0xf4, 0x81, 0xfc, 0x7f, 0xdd, + 0x07, 0x1e, 0x42, 0x5e, 0x8a, 0x25, 0x60, 0x5a, 0x66, 0x9e, 0x57, 0x71, 0x6a, 0xb9, 0xe6, 0xe6, + 0x25, 0x0e, 0xa6, 0x84, 0xe9, 0xe7, 0xc2, 0xc9, 0xe4, 0xcb, 0x54, 0xa6, 0xe0, 0x96, 0xaa, 0x3f, + 0xcf, 0x43, 0xda, 0xf0, 0x6f, 0x43, 0xda, 0x84, 0xee, 0xa8, 0xd0, 0x6f, 0x5f, 0xc6, 0x1c, 0x8a, + 0xa1, 0x09, 0xd8, 0x6c, 0x44, 0x1b, 0x50, 0xd4, 0xa3, 0xa0, 0x47, 0x38, 0xc7, 0x6d, 0xa2, 0xf4, + 0x97, 0xf5, 0x0b, 0x1a, 0x7d, 0xa8, 0x41, 0xd9, 0xf2, 0x49, 0x92, 0xb0, 0x64, 0xbc, 0x2a, 0xad, + 0x5b, 0xbe, 0x02, 0xed, 0xa2, 0x3b, 0x50, 0xea, 0x62, 0x2e, 0x9e, 0xf4, 0x23, 0x2c, 0x48, 0x20, + 0x68, 0x8f, 0x70, 0x81, 0x7b, 0x7d, 0xa5, 0xd6, 0x05, 0x7f, 0x75, 0x62, 0x3b, 0xb2, 0x26, 0x54, + 0x03, 0xd9, 0x42, 0x64, 0x7b, 0xf2, 0xc9, 0xc9, 0x20, 0x8e, 0x48, 0xa4, 0xa4, 0xa9, 0x3b, 0xcb, + 0x34, 0x8c, 0x3e, 0x81, 0x95, 0x30, 0x21, 0x58, 0xb6, 0xc4, 0x09, 0xf3, 0xa2, 0x62, 0x76, 0x8d, + 0x61, 0x4c, 0x5b, 0xfd, 0x61, 0x1e, 0x0a, 0x3e, 0x39, 0x23, 0x89, 0xb0, 0x1d, 0x6e, 0x03, 0x8a, + 0x89, 0x02, 0x02, 0x1c, 0x45, 0x09, 0xe1, 0xdc, 0xf4, 0xa2, 0x82, 0x46, 0xb7, 0x35, 0x88, 0x3e, + 0x86, 0xa2, 0x3e, 0xb1, 0x38, 0xd0, 0x06, 0xd3, 0xe8, 0xd4, 0x39, 0x1e, 0xc4, 0x9a, 0x53, 0x66, + 0x43, 0xb5, 0xd4, 0x31, 0x97, 0xbe, 0xc4, 0xf3, 0x0a, 0xb4, 0x54, 0x13, 0x8f, 0x36, 0x67, 0xf2, + 0xcb, 0xf2, 0xd6, 0xa3, 0x4d, 0xda, 0x53, 0xd9, 0x02, 0xd5, 0xb2, 0x49, 0x69, 0x2f, 0x7e, 0x58, + 0x77, 0x32, 0xfe, 0xac, 0x10, 0xaa, 0x3f, 0x2e, 0x42, 0x7e, 0x72, 0xd5, 0x1c, 0x0d, 0x91, 0x07, + 0x4b, 0x2a, 0x55, 0xcc, 0x76, 0x62, 0x3b, 0x95, 0x2f, 0x06, 0xdd, 0x34, 0xf4, 0xe9, 0xeb, 0x09, + 0xfa, 0x16, 0xb2, 0xea, 0xfa, 0x39, 0x21, 0x84, 0x9b, 0xa0, 0x76, 0xff, 0x61, 0x50, 0x7f, 0xbe, + 0xba, 0xe1, 0x8e, 0x70, 0xaf, 0xfb, 0x45, 0x75, 0xcc, 0x54, 0xf5, 0x33, 0x72, 0xbc, 0x47, 0x08, + 0x47, 0xb7, 0x60, 0x39, 0x21, 0x5d, 0x3c, 0x22, 0xd1, 0x3b, 0x95, 0x55, 0x34, 0xb0, 0x4d, 0xd3, + 0x1e, 0xe4, 0xc2, 0x50, 0x0c, 0xad, 0x54, 0x33, 0x4a, 0x49, 0x1b, 0x97, 0xd4, 0xbb, 0xa9, 0x75, + 0x08, 0xc7, 0x75, 0x8f, 0x1e, 0x43, 0x91, 0xea, 0xc7, 0x5c, 0xd0, 0x57, 0xf7, 0x93, 0x6a, 0x93, + 0xb9, 0xe6, 0xa7, 0x97, 0x50, 0xcd, 0xbc, 0x00, 0xfd, 0x02, 0x9d, 0x79, 0x10, 0x1e, 0xc3, 0x32, + 0x33, 0x97, 0x9e, 0x65, 0x85, 0xca, 0x42, 0x2d, 0xd7, 0xdc, 0xba, 0x84, 0x75, 0xf6, 0xaa, 0xf4, + 0x8b, 0x6c, 0xf6, 0xea, 0x4c, 0xe0, 0x9a, 0x7a, 0x83, 0x86, 0xac, 0x1b, 0x84, 0x2c, 0x16, 0x09, + 0x0e, 0x45, 0x70, 0x46, 0x12, 0x4e, 0x59, 0x6c, 0x5e, 0x2d, 0x9f, 0x5d, 0xe2, 0xe1, 0xd0, 0xec, + 0xdf, 0x35, 0xdb, 0x8f, 0xf5, 0x6e, 0xff, 0x6a, 0xff, 0x7c, 0x03, 0x7a, 0x3a, 0x2e, 0x5b, 0xdb, + 0xb5, 0xf2, 0xef, 0x95, 0xa0, 0x19, 0xb9, 0xed, 0xa4, 0x64, 0x99, 0xd8, 0x52, 0x37, 0xe0, 0xe6, + 0xf7, 0x00, 0x93, 0x0e, 0x84, 0x10, 0x14, 0x0f, 0x49, 0x1c, 0xd1, 0xb8, 0x6d, 0x72, 0xeb, 0xce, + 0xa1, 0x55, 0x58, 0x36, 0x98, 0xcd, 0x8c, 0xeb, 0xa0, 0x15, 0x28, 0xd8, 0xd9, 0x43, 0x1a, 0x93, + 0xc8, 0x5d, 0x90, 0x90, 0x59, 0xa7, 0xdd, 0xba, 0x29, 0x94, 0x87, 0x8c, 0x1e, 0x93, 0xc8, 0x5d, + 0x44, 0x39, 0x58, 0xda, 0xd6, 0x8f, 0x1e, 0x37, 0xbd, 0x9e, 0xfa, 0xf5, 0x97, 0xb2, 0xb3, 0xf9, + 0x15, 0x94, 0xce, 0x6b, 0xdd, 0xc8, 0x85, 0xfc, 0x23, 0x26, 0xf6, 0xec, 0x8b, 0xd1, 0x9d, 0x43, + 0x05, 0xc8, 0x4e, 0xa6, 0x8e, 0x64, 0xbe, 0x37, 0x24, 0xe1, 0x40, 0x92, 0xcd, 0x1b, 0xb2, 0x06, + 0x5c, 0xfd, 0x9b, 0xcc, 0xa2, 0x34, 0xcc, 0x1f, 0xdf, 0x71, 0xe7, 0xd4, 0x6f, 0xd3, 0x75, 0xf4, + 0x86, 0x9d, 0xfb, 0x2f, 0xde, 0x94, 0x9d, 0x97, 0x6f, 0xca, 0xce, 0xeb, 0x37, 0x65, 0xe7, 0xa7, + 0xb7, 0xe5, 0xb9, 0x97, 0x6f, 0xcb, 0x73, 0xbf, 0xbd, 0x2d, 0xcf, 0x3d, 0xdb, 0x9a, 0x52, 0x92, + 0x4c, 0xec, 0x96, 0xfe, 0x4f, 0x12, 0xb3, 0x88, 0x34, 0x86, 0xd3, 0x7f, 0x7d, 0x94, 0xa8, 0x5a, + 0x69, 0x75, 0x70, 0x77, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xa1, 0xdc, 0x72, 0x48, 0x28, 0x0d, + 0x00, 0x00, } func (m *InboundParams) Marshal() (dAtA []byte, err error) { @@ -874,6 +885,16 @@ func (m *InboundParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.IsCrossChainCall { + i-- + if m.IsCrossChainCall { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x60 + } if m.TxFinalizationStatus != 0 { i = encodeVarintCrossChainTx(dAtA, i, uint64(m.TxFinalizationStatus)) i-- @@ -1452,6 +1473,9 @@ func (m *InboundParams) Size() (n int) { if m.TxFinalizationStatus != 0 { n += 1 + sovCrossChainTx(uint64(m.TxFinalizationStatus)) } + if m.IsCrossChainCall { + n += 2 + } return n } @@ -1967,6 +1991,26 @@ func (m *InboundParams) Unmarshal(dAtA []byte) error { break } } + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsCrossChainCall", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsCrossChainCall = bool(v != 0) default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index 140c9b2db2..0f496c13d3 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -146,6 +146,7 @@ type FungibleKeeper interface { coinType coin.CoinType, asset string, protocolContractVersion ProtocolContractVersion, + isCrossChainCall bool, ) (*evmtypes.MsgEthereumTxResponse, bool, error) ProcessV2RevertDeposit( ctx sdk.Context, diff --git a/x/crosschain/types/inbound_parsing.go b/x/crosschain/types/inbound_parsing.go new file mode 100644 index 0000000000..e057183f2c --- /dev/null +++ b/x/crosschain/types/inbound_parsing.go @@ -0,0 +1,246 @@ +package types + +import ( + "encoding/hex" + "math/big" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + ethcommon "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/pkg/errors" + "github.com/zeta-chain/protocol-contracts/v2/pkg/gatewayzevm.sol" + + "github.com/zeta-chain/node/pkg/chains" + "github.com/zeta-chain/node/pkg/coin" +) + +// ParseGatewayEvent parses the event from the gateway contract +func ParseGatewayEvent( + log ethtypes.Log, + gatewayAddr ethcommon.Address, +) (*gatewayzevm.GatewayZEVMWithdrawn, *gatewayzevm.GatewayZEVMCalled, *gatewayzevm.GatewayZEVMWithdrawnAndCalled, error) { + if len(log.Topics) == 0 { + return nil, nil, nil, errors.New("ParseGatewayCallEvent: invalid log - no topics") + } + filterer, err := gatewayzevm.NewGatewayZEVMFilterer(log.Address, bind.ContractFilterer(nil)) + if err != nil { + return nil, nil, nil, err + } + withdrawalEvent, err := ParseGatewayWithdrawalEvent(log, gatewayAddr, filterer) + if err == nil { + return withdrawalEvent, nil, nil, nil + } + callEvent, err := ParseGatewayCallEvent(log, gatewayAddr, filterer) + if err == nil { + return nil, callEvent, nil, nil + } + withdrawAndCallEvent, err := ParseGatewayWithdrawAndCallEvent(log, gatewayAddr, filterer) + if err == nil { + return nil, nil, withdrawAndCallEvent, nil + } + return nil, nil, nil, errors.New("ParseGatewayEvent: invalid log - no event found") +} + +// ParseGatewayWithdrawalEvent parses the GatewayZEVMWithdrawal event from the log +func ParseGatewayWithdrawalEvent( + log ethtypes.Log, + gatewayAddr ethcommon.Address, + filterer *gatewayzevm.GatewayZEVMFilterer, +) (*gatewayzevm.GatewayZEVMWithdrawn, error) { + event, err := filterer.ParseWithdrawn(log) + if err != nil { + return nil, err + } + if event.Raw.Address != gatewayAddr { + return nil, errors.New("ParseGatewayWithdrawalEvent: invalid log - wrong contract address") + } + + return event, nil +} + +// ParseGatewayCallEvent parses the GatewayZEVMCall event from the log +func ParseGatewayCallEvent( + log ethtypes.Log, + gatewayAddr ethcommon.Address, + filterer *gatewayzevm.GatewayZEVMFilterer, +) (*gatewayzevm.GatewayZEVMCalled, error) { + event, err := filterer.ParseCalled(log) + if err != nil { + return nil, err + } + if event.Raw.Address != gatewayAddr { + return nil, errors.New("ParseGatewayCallEvent: invalid log - wrong contract address") + } + return event, nil +} + +// ParseGatewayWithdrawAndCallEvent parses the GatewayZEVMWithdrawAndCall event from the log +func ParseGatewayWithdrawAndCallEvent( + log ethtypes.Log, + gatewayAddr ethcommon.Address, + filterer *gatewayzevm.GatewayZEVMFilterer, +) (*gatewayzevm.GatewayZEVMWithdrawnAndCalled, error) { + event, err := filterer.ParseWithdrawnAndCalled(log) + if err != nil { + return nil, err + } + if event.Raw.Address != gatewayAddr { + return nil, errors.New("ParseGatewayWithdrawAndCallEvent: invalid log - wrong contract address") + } + return event, nil +} + +// NewWithdrawalInbound creates a new inbound object for a withdrawal +// currently inbound data is represented with a MsgVoteInbound message +// TODO: replace with a more appropriate object +// https://github.com/zeta-chain/node/issues/2658 +func NewWithdrawalInbound( + ctx sdk.Context, + txOrigin string, + coinType coin.CoinType, + asset string, + event *gatewayzevm.GatewayZEVMWithdrawn, + receiverChain chains.Chain, + gasLimitQueried *big.Int, +) (*MsgVoteInbound, error) { + senderChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) + if err != nil { + return nil, errors.Wrapf(err, "ProcessZEVMInboundV2: failed to convert chainID %s", ctx.ChainID()) + } + + toAddr, err := receiverChain.EncodeAddress(event.Receiver) + if err != nil { + return nil, errors.Wrapf(err, "cannot encode address %v", event.Receiver) + } + + gasLimit := event.CallOptions.GasLimit.Uint64() + if gasLimit == 0 { + gasLimit = gasLimitQueried.Uint64() + } + + // if the message is not empty, specify cross-chain call for backward compatibility with the Withdraw event + isCrossChainCall := false + if len(event.Message) > 0 { + isCrossChainCall = true + } + + return NewMsgVoteInbound( + "", + event.Sender.Hex(), + senderChain.ChainId, + txOrigin, + toAddr, + receiverChain.ChainId, + math.NewUintFromBigInt(event.Value), + hex.EncodeToString(event.Message), + event.Raw.TxHash.String(), + event.Raw.BlockNumber, + gasLimit, + coinType, + asset, + event.Raw.Index, + ProtocolContractVersion_V2, + event.CallOptions.IsArbitraryCall, + WithZEVMRevertOptions(event.RevertOptions), + WithCrossChainCall(isCrossChainCall), + ), nil +} + +// NewCallInbound creates a new inbound object for a call +// currently inbound data is represented with a MsgVoteInbound message +// TODO: replace with a more appropriate object +// https://github.com/zeta-chain/node/issues/2658 +func NewCallInbound( + ctx sdk.Context, + txOrigin string, + event *gatewayzevm.GatewayZEVMCalled, + receiverChain chains.Chain, + gasLimitQueried *big.Int, +) (*MsgVoteInbound, error) { + senderChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) + if err != nil { + return nil, errors.Wrapf(err, "ProcessZEVMInboundV2: failed to convert chainID %s", ctx.ChainID()) + } + + toAddr, err := receiverChain.EncodeAddress(event.Receiver) + if err != nil { + return nil, errors.Wrapf(err, "cannot encode address %v", event.Receiver) + } + + gasLimit := event.CallOptions.GasLimit.Uint64() + if gasLimit == 0 { + gasLimit = gasLimitQueried.Uint64() + } + + return NewMsgVoteInbound( + "", + event.Sender.Hex(), + senderChain.ChainId, + txOrigin, + toAddr, + receiverChain.ChainId, + math.ZeroUint(), + hex.EncodeToString(event.Message), + event.Raw.TxHash.String(), + event.Raw.BlockNumber, + gasLimit, + coin.CoinType_NoAssetCall, + "", + event.Raw.Index, + ProtocolContractVersion_V2, + event.CallOptions.IsArbitraryCall, + WithZEVMRevertOptions(event.RevertOptions), + ), nil +} + +// NewWithdrawAndCallInbound creates a new inbound object for a withdraw and call +// currently inbound data is represented with a MsgVoteInbound message +// TODO: replace with a more appropriate object +// https://github.com/zeta-chain/node/issues/2658 +func NewWithdrawAndCallInbound( + ctx sdk.Context, + txOrigin string, + coinType coin.CoinType, + asset string, + event *gatewayzevm.GatewayZEVMWithdrawnAndCalled, + receiverChain chains.Chain, + gasLimitQueried *big.Int, +) (*MsgVoteInbound, error) { + senderChain, err := chains.ZetaChainFromCosmosChainID(ctx.ChainID()) + if err != nil { + return nil, errors.Wrapf(err, "ProcessZEVMInboundV2: failed to convert chainID %s", ctx.ChainID()) + } + + toAddr, err := receiverChain.EncodeAddress(event.Receiver) + if err != nil { + return nil, errors.Wrapf(err, "cannot encode address %v", event.Receiver) + } + + gasLimit := event.CallOptions.GasLimit.Uint64() + if gasLimit == 0 { + gasLimit = gasLimitQueried.Uint64() + } + + return NewMsgVoteInbound( + "", + event.Sender.Hex(), + senderChain.ChainId, + txOrigin, + toAddr, + receiverChain.ChainId, + math.NewUintFromBigInt(event.Value), + hex.EncodeToString(event.Message), + event.Raw.TxHash.String(), + event.Raw.BlockNumber, + gasLimit, + coinType, + asset, + event.Raw.Index, + ProtocolContractVersion_V2, + event.CallOptions.IsArbitraryCall, + WithZEVMRevertOptions(event.RevertOptions), + WithCrossChainCall(true), + ), nil +} diff --git a/x/crosschain/types/inbound_parsing_test.go b/x/crosschain/types/inbound_parsing_test.go new file mode 100644 index 0000000000..0d030fdd3d --- /dev/null +++ b/x/crosschain/types/inbound_parsing_test.go @@ -0,0 +1,89 @@ +package types_test + +import ( + "testing" +) + +// TODO: Complete tests for this file +// https://github.com/zeta-chain/node/issues/2669 + +func TestParseGatewayEvent(t *testing.T) { + +} + +func TestParseGatewayWithdrawalEvent(t *testing.T) { + +} + +func TestParseGatewayCallEvent(t *testing.T) { + +} + +func TestParseGatewayWithdrawAndCallEvent(t *testing.T) { + +} + +func TestNewWithdrawalInbound(t *testing.T) { + //t.Run("fail if sender chain ID is not valid", func(t *testing.T) { + // _, ctx, _, _ := keepertest.CrosschainKeeper(t) + // ctx = ctx.WithChainID("invalidChainID") + // + // fc := sample.ForeignCoins(t, sample.EthAddress().Hex()) + // + // _, err := types.NewWithdrawalInbound( + // ctx, + // sample.EthAddress().Hex(), + // fc.CoinType, + // fc.Asset, + // nil, + // chains.GoerliLocalnet, + // big.NewInt(1000), + // ) + // + // require.ErrorContains(t, err, " failed to convert chainID") + //}) + +} + +func TestNewCallInbound(t *testing.T) { + //t.Run("fail if sender chain ID is not valid", func(t *testing.T) { + // _, ctx, _, _ := keepertest.CrosschainKeeper(t) + // ctx = ctx.WithChainID("invalidChainID") + // + // _, err := types.NewCallInbound( + // ctx, + // sample.EthAddress().Hex(), + // nil, + // chains.GoerliLocalnet, + // big.NewInt(1000), + // ) + // + // require.ErrorContains(t, err, " failed to convert chainID") + //}) + +} + +func TestNewWithdrawAndCallInbound(t *testing.T) { + //t.Run("fail if sender chain ID is not valid", func(t *testing.T) { + // _, ctx, _, _ := keepertest.CrosschainKeeper(t) + // ctx = ctx.WithChainID("invalidChainID") + // + // fc := sample.ForeignCoins(t, sample.EthAddress().Hex()) + // + // _, err := types.NewWithdrawAndCallInbound( + // ctx, + // sample.EthAddress().Hex(), + // fc.CoinType, + // fc.Asset, + // nil, + // chains.GoerliLocalnet, + // big.NewInt(1000), + // ) + // + // require.ErrorContains(t, err, " failed to convert chainID") + //}) + // + //t.Run("fail if receiver address can't be decoded", func(t *testing.T) { + // + //}) +} diff --git a/x/crosschain/types/message_vote_inbound.go b/x/crosschain/types/message_vote_inbound.go index c73c9a24d4..34afb68be2 100644 --- a/x/crosschain/types/message_vote_inbound.go +++ b/x/crosschain/types/message_vote_inbound.go @@ -38,6 +38,13 @@ func WithEVMRevertOptions(revertOptions gatewayevm.RevertOptions) InboundVoteOpt } } +// WithCrossChainCall sets the cross chain call to true for the inbound vote message +func WithCrossChainCall(isCrossChainCall bool) InboundVoteOption { + return func(msg *MsgVoteInbound) { + msg.IsCrossChainCall = isCrossChainCall + } +} + var _ sdk.Msg = &MsgVoteInbound{} func NewMsgVoteInbound( @@ -79,6 +86,7 @@ func NewMsgVoteInbound( EventIndex: uint64(eventIndex), ProtocolContractVersion: protocolContractVersion, RevertOptions: NewEmptyRevertOptions(), + IsCrossChainCall: false, } for _, option := range options { diff --git a/x/crosschain/types/message_vote_inbound_test.go b/x/crosschain/types/message_vote_inbound_test.go index 77631f20fd..e3e9bc7fce 100644 --- a/x/crosschain/types/message_vote_inbound_test.go +++ b/x/crosschain/types/message_vote_inbound_test.go @@ -184,6 +184,71 @@ func TestNewMsgVoteInbound(t *testing.T) { RevertGasLimit: math.ZeroUint(), }, msg.RevertOptions) }) + + t.Run("can set is cross chain call options", func(t *testing.T) { + // false by default + msg := types.NewMsgVoteInbound( + sample.AccAddress(), + sample.AccAddress(), + 42, + sample.String(), + sample.String(), + 42, + math.NewUint(42), + sample.String(), + sample.String(), + 42, + 42, + coin.CoinType_Zeta, + sample.String(), + 42, + types.ProtocolContractVersion_V1, + true, + ) + require.False(t, msg.IsCrossChainCall) + + msg = types.NewMsgVoteInbound( + sample.AccAddress(), + sample.AccAddress(), + 42, + sample.String(), + sample.String(), + 42, + math.NewUint(42), + sample.String(), + sample.String(), + 42, + 42, + coin.CoinType_Zeta, + sample.String(), + 42, + types.ProtocolContractVersion_V1, + true, + types.WithCrossChainCall(true), + ) + require.True(t, msg.IsCrossChainCall) + + msg = types.NewMsgVoteInbound( + sample.AccAddress(), + sample.AccAddress(), + 42, + sample.String(), + sample.String(), + 42, + math.NewUint(42), + sample.String(), + sample.String(), + 42, + 42, + coin.CoinType_Zeta, + sample.String(), + 42, + types.ProtocolContractVersion_V1, + true, + types.WithCrossChainCall(false), + ) + require.False(t, msg.IsCrossChainCall) + }) } func TestMsgVoteInbound_ValidateBasic(t *testing.T) { diff --git a/x/crosschain/types/tx.pb.go b/x/crosschain/types/tx.pb.go index ad8b7cbd9d..ffe5c8cec7 100644 --- a/x/crosschain/types/tx.pb.go +++ b/x/crosschain/types/tx.pb.go @@ -1012,6 +1012,8 @@ type MsgVoteInbound struct { // revert options provided by the sender RevertOptions RevertOptions `protobuf:"bytes,17,opt,name=revert_options,json=revertOptions,proto3" json:"revert_options"` CallOptions *CallOptions `protobuf:"bytes,18,opt,name=call_options,json=callOptions,proto3" json:"call_options,omitempty"` + // define if a smart contract call should be made with asset + IsCrossChainCall bool `protobuf:"varint,19,opt,name=is_cross_chain_call,json=isCrossChainCall,proto3" json:"is_cross_chain_call,omitempty"` } func (m *MsgVoteInbound) Reset() { *m = MsgVoteInbound{} } @@ -1159,6 +1161,13 @@ func (m *MsgVoteInbound) GetCallOptions() *CallOptions { return nil } +func (m *MsgVoteInbound) GetIsCrossChainCall() bool { + if m != nil { + return m.IsCrossChainCall + } + return false +} + type MsgVoteInboundResponse struct { } @@ -1724,121 +1733,122 @@ func init() { } var fileDescriptor_15f0860550897740 = []byte{ - // 1818 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x4f, 0x6f, 0xdb, 0xd8, - 0x11, 0x0f, 0x13, 0x59, 0x91, 0x46, 0xb6, 0x92, 0xbc, 0x75, 0x12, 0x9a, 0x5e, 0x2b, 0x8e, 0xd2, - 0xa4, 0xc6, 0x22, 0x91, 0x52, 0x65, 0x9b, 0x6e, 0xb3, 0x45, 0xb7, 0xb1, 0x76, 0xe3, 0x35, 0x10, - 0x25, 0x06, 0xd7, 0xd9, 0xfe, 0xb9, 0x10, 0x14, 0xf9, 0x4c, 0x13, 0x96, 0xf8, 0x04, 0xbe, 0x27, - 0xad, 0x14, 0x14, 0x68, 0x51, 0xa0, 0x40, 0x8f, 0x6d, 0xd1, 0xd3, 0x1e, 0x7a, 0xeb, 0xa1, 0xdf, - 0xa0, 0xa7, 0x9e, 0xf7, 0xb8, 0xe8, 0xa9, 0xe8, 0x21, 0x28, 0x92, 0x2f, 0xd0, 0xf6, 0xda, 0x4b, - 0xc1, 0x79, 0x8f, 0x8c, 0x44, 0xfd, 0xb5, 0x8c, 0x62, 0x2f, 0x26, 0xdf, 0x70, 0x7e, 0xf3, 0x66, - 0xe6, 0xcd, 0xbc, 0x99, 0x91, 0xe1, 0xce, 0x4b, 0x2a, 0x6c, 0xe7, 0xd8, 0xf6, 0x83, 0x2a, 0xbe, - 0xb1, 0x90, 0x56, 0x9d, 0x90, 0x71, 0x2e, 0x69, 0xa2, 0x5f, 0xe9, 0x84, 0x4c, 0x30, 0xb2, 0x95, - 0xf0, 0x55, 0x62, 0xbe, 0xca, 0x5b, 0x3e, 0x63, 0xdd, 0x63, 0x1e, 0x43, 0xce, 0x6a, 0xf4, 0x26, - 0x41, 0xc6, 0x7b, 0x13, 0x84, 0x77, 0x4e, 0xbc, 0x2a, 0x92, 0xb8, 0x7a, 0x28, 0xde, 0x3b, 0xd3, - 0x78, 0x99, 0x1f, 0xe0, 0x9f, 0x39, 0x32, 0x3b, 0x21, 0x63, 0x47, 0x5c, 0x3d, 0x14, 0xef, 0xc3, - 0xd9, 0xc6, 0x85, 0xb6, 0xa0, 0x56, 0xcb, 0x6f, 0xfb, 0x82, 0x86, 0xd6, 0x51, 0xcb, 0xf6, 0x62, - 0x5c, 0x6d, 0x36, 0x0e, 0x5f, 0x2d, 0x7c, 0xb7, 0x62, 0x07, 0x95, 0x7f, 0xaf, 0x01, 0x69, 0x70, - 0xaf, 0xe1, 0x7b, 0x91, 0xd8, 0x43, 0xce, 0x9f, 0x74, 0x03, 0x97, 0x13, 0x1d, 0x2e, 0x3a, 0x21, - 0xb5, 0x05, 0x0b, 0x75, 0x6d, 0x5b, 0xdb, 0xc9, 0x9b, 0xf1, 0x92, 0x6c, 0x40, 0x4e, 0x8a, 0xf0, - 0x5d, 0xfd, 0xfc, 0xb6, 0xb6, 0x73, 0xc1, 0xbc, 0x88, 0xeb, 0x7d, 0x97, 0xec, 0x41, 0xd6, 0x6e, - 0xb3, 0x6e, 0x20, 0xf4, 0x0b, 0x11, 0x66, 0xb7, 0xfa, 0xd5, 0xab, 0x1b, 0xe7, 0xfe, 0xf1, 0xea, - 0xc6, 0xb7, 0x3d, 0x5f, 0x1c, 0x77, 0x9b, 0x15, 0x87, 0xb5, 0xab, 0x0e, 0xe3, 0x6d, 0xc6, 0xd5, - 0xe3, 0x1e, 0x77, 0x4f, 0xaa, 0x62, 0xd0, 0xa1, 0xbc, 0xf2, 0xc2, 0x0f, 0x84, 0xa9, 0xe0, 0xe5, - 0x77, 0xc1, 0x18, 0xd7, 0xc9, 0xa4, 0xbc, 0xc3, 0x02, 0x4e, 0xcb, 0xcf, 0xe0, 0x9d, 0x06, 0xf7, - 0x5e, 0x74, 0x5c, 0xf9, 0xf1, 0xb1, 0xeb, 0x86, 0x94, 0xcf, 0x52, 0x79, 0x0b, 0x40, 0x70, 0x6e, - 0x75, 0xba, 0xcd, 0x13, 0x3a, 0x40, 0xa5, 0xf3, 0x66, 0x5e, 0x70, 0x7e, 0x80, 0x84, 0xf2, 0x16, - 0x6c, 0x4e, 0x90, 0x97, 0x6c, 0xf7, 0xc7, 0xf3, 0xb0, 0xde, 0xe0, 0xde, 0x63, 0xd7, 0xdd, 0x0f, - 0x9a, 0xac, 0x1b, 0xb8, 0x87, 0xa1, 0xed, 0x9c, 0xd0, 0x70, 0x39, 0x1f, 0x5d, 0x87, 0x8b, 0xa2, - 0x6f, 0x1d, 0xdb, 0xfc, 0x58, 0x3a, 0xc9, 0xcc, 0x8a, 0xfe, 0xa7, 0x36, 0x3f, 0x26, 0xbb, 0x90, - 0x8f, 0xc2, 0xc5, 0x8a, 0xdc, 0xa1, 0x67, 0xb6, 0xb5, 0x9d, 0x62, 0xed, 0x76, 0x65, 0x42, 0xf4, - 0x76, 0x4e, 0xbc, 0x0a, 0xc6, 0x55, 0x9d, 0xf9, 0xc1, 0xe1, 0xa0, 0x43, 0xcd, 0x9c, 0xa3, 0xde, - 0xc8, 0x23, 0x58, 0xc1, 0x40, 0xd2, 0x57, 0xb6, 0xb5, 0x9d, 0x42, 0xed, 0x5b, 0xd3, 0xf0, 0x2a, - 0xda, 0x0e, 0xa2, 0x87, 0x29, 0x21, 0x91, 0x93, 0x9a, 0x2d, 0xe6, 0x9c, 0x48, 0xdd, 0xb2, 0xd2, - 0x49, 0x48, 0x41, 0xf5, 0x36, 0x20, 0x27, 0xfa, 0x96, 0x1f, 0xb8, 0xb4, 0xaf, 0x5f, 0x94, 0x26, - 0x89, 0xfe, 0x7e, 0xb4, 0x2c, 0x97, 0xe0, 0xdd, 0x49, 0xfe, 0x49, 0x1c, 0xf8, 0x37, 0x0d, 0xae, - 0x34, 0xb8, 0xf7, 0xe3, 0x63, 0x5f, 0xd0, 0x96, 0xcf, 0xc5, 0x27, 0x66, 0xbd, 0x76, 0x7f, 0x86, - 0xf7, 0x6e, 0xc1, 0x1a, 0x0d, 0x9d, 0xda, 0x7d, 0xcb, 0x96, 0x27, 0xa1, 0x4e, 0x6c, 0x15, 0x89, - 0xf1, 0x69, 0x0f, 0xbb, 0xf8, 0xc2, 0xa8, 0x8b, 0x09, 0x64, 0x02, 0xbb, 0x2d, 0x9d, 0x98, 0x37, - 0xf1, 0x9d, 0x5c, 0x83, 0x2c, 0x1f, 0xb4, 0x9b, 0xac, 0x85, 0xae, 0xc9, 0x9b, 0x6a, 0x45, 0x0c, - 0xc8, 0xb9, 0xd4, 0xf1, 0xdb, 0x76, 0x8b, 0xa3, 0xcd, 0x6b, 0x66, 0xb2, 0x26, 0x9b, 0x90, 0xf7, - 0x6c, 0x2e, 0x33, 0x4d, 0xd9, 0x9c, 0xf3, 0x6c, 0xfe, 0x34, 0x5a, 0x97, 0x2d, 0xd8, 0x18, 0xb3, - 0x29, 0xb6, 0x38, 0xb2, 0xe0, 0xe5, 0x88, 0x05, 0xd2, 0xc2, 0xd5, 0x97, 0xc3, 0x16, 0x6c, 0x01, - 0x38, 0x4e, 0xe2, 0x53, 0x15, 0x95, 0x11, 0x45, 0x7a, 0xf5, 0xdf, 0x1a, 0x5c, 0x95, 0x6e, 0x7d, - 0xde, 0x15, 0x67, 0x8f, 0xbb, 0x75, 0x58, 0x09, 0x58, 0xe0, 0x50, 0x74, 0x56, 0xc6, 0x94, 0x8b, - 0xe1, 0x68, 0xcc, 0x8c, 0x44, 0xe3, 0x37, 0x13, 0x49, 0x3f, 0x84, 0xad, 0x89, 0x26, 0x27, 0x8e, - 0xdd, 0x02, 0xf0, 0xb9, 0x15, 0xd2, 0x36, 0xeb, 0x51, 0x17, 0xad, 0xcf, 0x99, 0x79, 0x9f, 0x9b, - 0x92, 0x50, 0xa6, 0xa0, 0x37, 0xb8, 0x27, 0x57, 0xff, 0x3f, 0xaf, 0x95, 0xcb, 0xb0, 0x3d, 0x6d, - 0x9b, 0x24, 0xe8, 0xff, 0xaa, 0xc1, 0xa5, 0x06, 0xf7, 0x3e, 0x67, 0x82, 0xee, 0xd9, 0xfc, 0x20, - 0xf4, 0x1d, 0xba, 0xb4, 0x0a, 0x9d, 0x08, 0x1d, 0xab, 0x80, 0x0b, 0x72, 0x13, 0x56, 0x3b, 0xa1, - 0xcf, 0x42, 0x5f, 0x0c, 0xac, 0x23, 0x4a, 0xd1, 0xcb, 0x19, 0xb3, 0x10, 0xd3, 0x9e, 0x50, 0x64, - 0x91, 0xc7, 0x10, 0x74, 0xdb, 0x4d, 0x1a, 0xe2, 0x01, 0x67, 0xcc, 0x02, 0xd2, 0x9e, 0x21, 0x89, - 0x18, 0x90, 0xe5, 0xdd, 0x4e, 0xa7, 0x35, 0x90, 0x59, 0xb1, 0x7b, 0x5e, 0xd7, 0x4c, 0x45, 0x29, - 0x6f, 0xc0, 0xf5, 0x94, 0xfe, 0x89, 0x6d, 0x7f, 0xca, 0x26, 0xb6, 0xc5, 0xe6, 0xcf, 0xb0, 0x6d, - 0x13, 0x30, 0xaa, 0x65, 0x34, 0xc8, 0x30, 0xcf, 0x45, 0x04, 0x0c, 0x86, 0xf7, 0xe1, 0x1a, 0x6b, - 0x72, 0x1a, 0xf6, 0xa8, 0x6b, 0x31, 0x25, 0x6b, 0xf8, 0x76, 0x5c, 0x8f, 0xbf, 0xc6, 0x1b, 0x21, - 0xaa, 0x0e, 0xa5, 0x71, 0x94, 0x8a, 0x39, 0xea, 0x7b, 0xc7, 0x42, 0x19, 0xbb, 0x99, 0x46, 0xef, - 0x62, 0x14, 0x22, 0x0b, 0xf9, 0x10, 0x8c, 0x71, 0x21, 0x51, 0xc2, 0x77, 0x39, 0x75, 0x75, 0x40, - 0x01, 0xd7, 0xd3, 0x02, 0xf6, 0x6c, 0xfe, 0x82, 0x53, 0x97, 0xfc, 0x52, 0x83, 0xdb, 0xe3, 0x68, - 0x7a, 0x74, 0x44, 0x1d, 0xe1, 0xf7, 0x28, 0xca, 0x91, 0xc7, 0x56, 0x40, 0xcf, 0x56, 0x54, 0x29, - 0xbc, 0xb3, 0x40, 0x29, 0xdc, 0x0f, 0x84, 0x79, 0x33, 0xbd, 0xf1, 0x27, 0xb1, 0xe8, 0x24, 0x9a, - 0x0e, 0xe6, 0x6b, 0x20, 0xaf, 0xae, 0x55, 0x34, 0x65, 0xa6, 0x44, 0xbc, 0xd3, 0x08, 0x83, 0x62, - 0xcf, 0x6e, 0x75, 0xa9, 0x15, 0x52, 0x87, 0xfa, 0x51, 0x86, 0xc9, 0xb0, 0xf8, 0xf4, 0x94, 0x75, - 0xfc, 0x3f, 0xaf, 0x6e, 0x5c, 0x1d, 0xd8, 0xed, 0xd6, 0xa3, 0xf2, 0xa8, 0xb8, 0xb2, 0xb9, 0x86, - 0x04, 0x53, 0xad, 0xc9, 0xc7, 0x90, 0xe5, 0xc2, 0x16, 0x5d, 0x79, 0xf7, 0x16, 0x6b, 0x77, 0xa7, - 0x16, 0x3c, 0xd9, 0x72, 0x29, 0xe0, 0x67, 0x88, 0x31, 0x15, 0x96, 0xdc, 0x86, 0x62, 0x62, 0x3f, - 0x32, 0xaa, 0x6b, 0x65, 0x2d, 0xa6, 0xd6, 0x23, 0x22, 0xb9, 0x0b, 0x24, 0x61, 0x8b, 0xda, 0x01, - 0x99, 0xd8, 0x39, 0x74, 0xce, 0xe5, 0xf8, 0xcb, 0x21, 0xe7, 0xcf, 0xf0, 0x66, 0x1c, 0x29, 0xc7, - 0xf9, 0xa5, 0xca, 0xf1, 0x50, 0x0a, 0xc5, 0x3e, 0x4f, 0x52, 0xe8, 0x2f, 0x59, 0x28, 0xaa, 0x6f, - 0xaa, 0x6a, 0xce, 0xc8, 0xa0, 0xa8, 0x78, 0xd1, 0xc0, 0xa5, 0xa1, 0x4a, 0x1f, 0xb5, 0x22, 0x77, - 0xe0, 0x92, 0x7c, 0xb3, 0x52, 0xa5, 0x70, 0x4d, 0x92, 0xeb, 0xea, 0x0a, 0x31, 0x20, 0xa7, 0x8e, - 0x20, 0x54, 0xd7, 0x7c, 0xb2, 0x8e, 0x9c, 0x17, 0xbf, 0x2b, 0xe7, 0xad, 0x48, 0x11, 0x31, 0x55, - 0x3a, 0xef, 0x6d, 0x6b, 0x97, 0x3d, 0x53, 0x6b, 0x17, 0x59, 0xd9, 0xa6, 0x9c, 0xdb, 0x9e, 0x74, - 0x7d, 0xde, 0x8c, 0x97, 0xd1, 0x7d, 0xe5, 0x07, 0x43, 0x17, 0x40, 0x1e, 0x3f, 0x17, 0x14, 0x0d, - 0xf3, 0xfe, 0x3e, 0xac, 0xc7, 0x2c, 0x23, 0xd9, 0x2e, 0x93, 0x95, 0xa8, 0x6f, 0xc3, 0x49, 0x3e, - 0x52, 0xc3, 0x0b, 0xc8, 0x96, 0xd4, 0xf0, 0xd1, 0x33, 0x5e, 0x5d, 0xae, 0xe5, 0xda, 0x84, 0xbc, - 0xe8, 0x5b, 0x2c, 0xf4, 0x3d, 0x3f, 0xd0, 0xd7, 0xa4, 0x73, 0x45, 0xff, 0x39, 0xae, 0xa3, 0xbb, - 0xdb, 0xe6, 0x9c, 0x0a, 0xbd, 0x88, 0x1f, 0xe4, 0x82, 0xdc, 0x80, 0x02, 0xed, 0xd1, 0x40, 0xa8, - 0x1a, 0x78, 0x09, 0xb5, 0x02, 0x24, 0x61, 0x19, 0x24, 0x21, 0x6c, 0x60, 0x73, 0xee, 0xb0, 0x96, - 0xe5, 0xb0, 0x40, 0x84, 0xb6, 0x23, 0xac, 0x1e, 0x0d, 0xb9, 0xcf, 0x02, 0xfd, 0x32, 0xea, 0xf9, - 0xb0, 0x32, 0x73, 0xb0, 0x89, 0x0a, 0x32, 0xe2, 0xeb, 0x0a, 0xfe, 0xb9, 0x44, 0x9b, 0xd7, 0x3b, - 0x93, 0x3f, 0x90, 0x9f, 0x46, 0x71, 0xd0, 0xa3, 0xa1, 0xb0, 0x58, 0x47, 0xf8, 0x2c, 0xe0, 0xfa, - 0x15, 0xac, 0xfc, 0x77, 0xe7, 0x6c, 0x64, 0x22, 0xe8, 0xb9, 0xc4, 0xec, 0x66, 0xa2, 0xb0, 0x88, - 0x62, 0x67, 0x88, 0x48, 0x1a, 0xb0, 0xea, 0xd8, 0xad, 0x56, 0x22, 0x98, 0xa0, 0xe0, 0xf7, 0xe6, - 0x08, 0xae, 0xdb, 0xad, 0x96, 0x92, 0x60, 0x16, 0x9c, 0xb7, 0x8b, 0xb2, 0x0e, 0xd7, 0x46, 0x33, - 0x27, 0x49, 0xaa, 0xa7, 0xd8, 0x67, 0x3e, 0x6e, 0xb2, 0x50, 0x7c, 0x26, 0xba, 0xce, 0x49, 0xbd, - 0x7e, 0xf8, 0x93, 0xd9, 0x63, 0xc1, 0xac, 0x06, 0x6c, 0x13, 0x3b, 0xbc, 0x51, 0x69, 0xc9, 0x56, - 0x3d, 0x9c, 0x09, 0x4c, 0x7a, 0xd4, 0x0d, 0x5c, 0x64, 0xa1, 0xee, 0x99, 0x76, 0x93, 0x79, 0x18, - 0x49, 0x4b, 0x7a, 0x46, 0x59, 0x00, 0xd7, 0x24, 0x55, 0x35, 0x8d, 0xaa, 0xd7, 0x1e, 0xdb, 0x37, - 0xd1, 0xeb, 0x4b, 0x0d, 0xb5, 0x96, 0xc3, 0x8c, 0x69, 0x0b, 0xfa, 0x54, 0xce, 0x89, 0x4f, 0xa2, - 0x31, 0x71, 0x86, 0x76, 0x0e, 0x90, 0xf1, 0xb1, 0x12, 0xb5, 0x2c, 0xd4, 0xaa, 0xf3, 0x42, 0x20, - 0xb5, 0x8d, 0x8a, 0x82, 0xcb, 0x61, 0x8a, 0x5e, 0xbe, 0x05, 0x37, 0xa7, 0xea, 0x96, 0x58, 0xf0, - 0x2f, 0x0d, 0xc7, 0x31, 0x35, 0xfc, 0x61, 0x5f, 0x5d, 0xef, 0x72, 0xc1, 0xdc, 0xc1, 0x19, 0x26, - 0xd3, 0x0a, 0xbc, 0x13, 0xd0, 0x2f, 0x2c, 0x47, 0x0a, 0x4a, 0xb9, 0xf8, 0x4a, 0x40, 0xbf, 0x50, - 0x5b, 0xc4, 0xbd, 0xf9, 0xd8, 0x08, 0x92, 0x99, 0x30, 0x82, 0xbc, 0xbd, 0x13, 0x57, 0xce, 0x36, - 0xee, 0x7e, 0x0c, 0xb7, 0x66, 0x58, 0x3c, 0xdc, 0xfc, 0x0e, 0x45, 0x90, 0x96, 0x8e, 0xd7, 0x36, - 0x76, 0xa5, 0xd2, 0xbb, 0xc3, 0x42, 0x0e, 0xec, 0x2e, 0x57, 0x25, 0x73, 0xf9, 0x0e, 0x34, 0x92, - 0x81, 0xee, 0xca, 0x99, 0x72, 0x51, 0xde, 0x87, 0x9d, 0x79, 0xdb, 0x2d, 0xa8, 0x79, 0xed, 0xbf, - 0x45, 0xb8, 0xd0, 0xe0, 0x1e, 0xf9, 0x8d, 0x06, 0x64, 0xc2, 0xbc, 0xf3, 0xfe, 0x9c, 0xf8, 0x9b, - 0x38, 0x32, 0x18, 0x3f, 0x58, 0x06, 0x95, 0x68, 0xfc, 0x6b, 0x0d, 0xae, 0x8c, 0x4f, 0xfc, 0x0f, - 0x16, 0x92, 0x39, 0x0a, 0x32, 0x3e, 0x5c, 0x02, 0x94, 0xe8, 0xf1, 0x3b, 0x0d, 0xae, 0x4e, 0x9e, - 0x67, 0xbe, 0x37, 0x5f, 0xec, 0x44, 0xa0, 0xf1, 0xd1, 0x92, 0xc0, 0x44, 0xa7, 0x1e, 0xac, 0x8e, - 0x8c, 0x35, 0x95, 0xf9, 0x02, 0x87, 0xf9, 0x8d, 0x87, 0xa7, 0xe3, 0x4f, 0xef, 0x9b, 0x8c, 0x1c, - 0x0b, 0xee, 0x1b, 0xf3, 0x2f, 0xba, 0x6f, 0xba, 0x57, 0x23, 0x1c, 0x0a, 0xc3, 0x7d, 0xda, 0xbd, - 0xc5, 0xc4, 0x28, 0x76, 0xe3, 0xbb, 0xa7, 0x62, 0x4f, 0x36, 0xfd, 0x39, 0x14, 0x53, 0x3f, 0x98, - 0xdc, 0x9f, 0x2f, 0x68, 0x14, 0x61, 0x7c, 0x70, 0x5a, 0x44, 0xb2, 0xfb, 0xaf, 0x34, 0xb8, 0x3c, - 0xf6, 0x03, 0x5b, 0x6d, 0xbe, 0xb8, 0x34, 0xc6, 0x78, 0x74, 0x7a, 0x4c, 0xa2, 0xc4, 0x2f, 0xe0, - 0x52, 0xfa, 0x67, 0xc9, 0xef, 0xcc, 0x17, 0x97, 0x82, 0x18, 0xdf, 0x3f, 0x35, 0x64, 0xf8, 0x0c, - 0x52, 0xcd, 0xc4, 0x02, 0x67, 0x30, 0x8a, 0x58, 0xe4, 0x0c, 0x26, 0xb7, 0x18, 0x78, 0x05, 0x8d, - 0x37, 0x18, 0x0f, 0x16, 0xc9, 0xde, 0x14, 0x68, 0x91, 0x2b, 0x68, 0x6a, 0x4b, 0x41, 0xfe, 0xa0, - 0xc1, 0xb5, 0x29, 0xfd, 0xc4, 0x07, 0x8b, 0x9e, 0x6e, 0x1a, 0x69, 0xfc, 0x68, 0x59, 0x64, 0xa2, - 0xd6, 0x97, 0x1a, 0xe8, 0x53, 0x9b, 0x84, 0x47, 0x0b, 0x1f, 0xfa, 0x18, 0xd6, 0xd8, 0x5d, 0x1e, - 0x9b, 0x28, 0xf7, 0x67, 0x0d, 0xb6, 0x66, 0x57, 0xe2, 0x8f, 0x16, 0x75, 0xc0, 0x14, 0x01, 0xc6, - 0xde, 0x19, 0x05, 0xc4, 0xba, 0xee, 0xee, 0x7d, 0xf5, 0xba, 0xa4, 0x7d, 0xfd, 0xba, 0xa4, 0xfd, - 0xf3, 0x75, 0x49, 0xfb, 0xed, 0x9b, 0xd2, 0xb9, 0xaf, 0xdf, 0x94, 0xce, 0xfd, 0xfd, 0x4d, 0xe9, - 0xdc, 0xcf, 0xee, 0x0d, 0x35, 0x32, 0xd1, 0x16, 0xf7, 0xe4, 0xff, 0x11, 0x02, 0xe6, 0xd2, 0x6a, - 0x7f, 0xe4, 0xdf, 0x2d, 0x51, 0x4f, 0xd3, 0xcc, 0xe2, 0x6c, 0xf1, 0xe0, 0x7f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0x45, 0x32, 0x2c, 0x14, 0x9c, 0x19, 0x00, 0x00, + // 1840 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x59, 0x4b, 0x6f, 0x1b, 0xc9, + 0x11, 0xf6, 0xd8, 0x12, 0x4d, 0x16, 0x25, 0x59, 0x6e, 0xcb, 0x36, 0x35, 0x5a, 0xc9, 0x32, 0x1d, + 0x3b, 0xc2, 0xc2, 0x22, 0x1d, 0x7a, 0xe3, 0x6c, 0xbc, 0x41, 0x36, 0x16, 0x77, 0xad, 0x15, 0x60, + 0xda, 0xc2, 0xac, 0xbc, 0x79, 0x5c, 0x06, 0xc3, 0x99, 0xd6, 0x68, 0x20, 0x72, 0x9a, 0x98, 0x6e, + 0x72, 0x29, 0x23, 0x40, 0x82, 0x00, 0x01, 0x72, 0x4c, 0x82, 0x9c, 0xf6, 0x90, 0x5b, 0x0e, 0xf9, + 0x13, 0x39, 0xef, 0xd1, 0xc8, 0x29, 0xc8, 0xc1, 0x08, 0xec, 0x43, 0xae, 0x49, 0xae, 0xb9, 0x04, + 0x5d, 0xdd, 0x33, 0x22, 0x87, 0x4f, 0x51, 0x08, 0xf6, 0x22, 0x76, 0x57, 0xd7, 0x57, 0x5d, 0x55, + 0x5d, 0xdd, 0x55, 0x35, 0x82, 0x7b, 0xaf, 0xa8, 0x70, 0xdc, 0x23, 0x27, 0x08, 0xcb, 0x38, 0x62, + 0x11, 0x2d, 0xbb, 0x11, 0xe3, 0x5c, 0xd1, 0x44, 0xb7, 0xd4, 0x8a, 0x98, 0x60, 0x64, 0x3d, 0xe1, + 0x2b, 0xc5, 0x7c, 0xa5, 0x53, 0x3e, 0x73, 0xc5, 0x67, 0x3e, 0x43, 0xce, 0xb2, 0x1c, 0x29, 0x90, + 0xf9, 0xfe, 0x10, 0xe1, 0xad, 0x63, 0xbf, 0x8c, 0x24, 0xae, 0x7f, 0x34, 0xef, 0xbd, 0x51, 0xbc, + 0x2c, 0x08, 0xf1, 0xcf, 0x04, 0x99, 0xad, 0x88, 0xb1, 0x43, 0xae, 0x7f, 0x34, 0xef, 0xa3, 0xf1, + 0xc6, 0x45, 0x8e, 0xa0, 0x76, 0x23, 0x68, 0x06, 0x82, 0x46, 0xf6, 0x61, 0xc3, 0xf1, 0x63, 0x5c, + 0x65, 0x3c, 0x0e, 0x87, 0x36, 0x8e, 0xed, 0xd8, 0x41, 0xc5, 0xdf, 0x1b, 0x40, 0x6a, 0xdc, 0xaf, + 0x05, 0xbe, 0x14, 0x7b, 0xc0, 0xf9, 0xd3, 0x76, 0xe8, 0x71, 0x52, 0x80, 0xcb, 0x6e, 0x44, 0x1d, + 0xc1, 0xa2, 0x82, 0xb1, 0x69, 0x6c, 0xe5, 0xac, 0x78, 0x4a, 0x56, 0x21, 0xab, 0x44, 0x04, 0x5e, + 0xe1, 0xe2, 0xa6, 0xb1, 0x75, 0xc9, 0xba, 0x8c, 0xf3, 0x3d, 0x8f, 0xec, 0x42, 0xc6, 0x69, 0xb2, + 0x76, 0x28, 0x0a, 0x97, 0x24, 0x66, 0xa7, 0xfc, 0xf5, 0x9b, 0x5b, 0x17, 0xfe, 0xfe, 0xe6, 0xd6, + 0xb7, 0xfd, 0x40, 0x1c, 0xb5, 0xeb, 0x25, 0x97, 0x35, 0xcb, 0x2e, 0xe3, 0x4d, 0xc6, 0xf5, 0xcf, + 0x36, 0xf7, 0x8e, 0xcb, 0xe2, 0xa4, 0x45, 0x79, 0xe9, 0x65, 0x10, 0x0a, 0x4b, 0xc3, 0x8b, 0xef, + 0x81, 0x39, 0xa8, 0x93, 0x45, 0x79, 0x8b, 0x85, 0x9c, 0x16, 0x9f, 0xc3, 0xb5, 0x1a, 0xf7, 0x5f, + 0xb6, 0x3c, 0xb5, 0xf8, 0xc4, 0xf3, 0x22, 0xca, 0xc7, 0xa9, 0xbc, 0x0e, 0x20, 0x38, 0xb7, 0x5b, + 0xed, 0xfa, 0x31, 0x3d, 0x41, 0xa5, 0x73, 0x56, 0x4e, 0x70, 0xbe, 0x8f, 0x84, 0xe2, 0x3a, 0xac, + 0x0d, 0x91, 0x97, 0x6c, 0xf7, 0xc7, 0x8b, 0xb0, 0x52, 0xe3, 0xfe, 0x13, 0xcf, 0xdb, 0x0b, 0xeb, + 0xac, 0x1d, 0x7a, 0x07, 0x91, 0xe3, 0x1e, 0xd3, 0x68, 0x36, 0x1f, 0xdd, 0x84, 0xcb, 0xa2, 0x6b, + 0x1f, 0x39, 0xfc, 0x48, 0x39, 0xc9, 0xca, 0x88, 0xee, 0x67, 0x0e, 0x3f, 0x22, 0x3b, 0x90, 0x93, + 0xe1, 0x62, 0x4b, 0x77, 0x14, 0xe6, 0x36, 0x8d, 0xad, 0xa5, 0xca, 0xdd, 0xd2, 0x90, 0xe8, 0x6d, + 0x1d, 0xfb, 0x25, 0x8c, 0xab, 0x2a, 0x0b, 0xc2, 0x83, 0x93, 0x16, 0xb5, 0xb2, 0xae, 0x1e, 0x91, + 0xc7, 0x30, 0x8f, 0x81, 0x54, 0x98, 0xdf, 0x34, 0xb6, 0xf2, 0x95, 0x6f, 0x8d, 0xc2, 0xeb, 0x68, + 0xdb, 0x97, 0x3f, 0x96, 0x82, 0x48, 0x27, 0xd5, 0x1b, 0xcc, 0x3d, 0x56, 0xba, 0x65, 0x94, 0x93, + 0x90, 0x82, 0xea, 0xad, 0x42, 0x56, 0x74, 0xed, 0x20, 0xf4, 0x68, 0xb7, 0x70, 0x59, 0x99, 0x24, + 0xba, 0x7b, 0x72, 0x5a, 0xdc, 0x80, 0xf7, 0x86, 0xf9, 0x27, 0x71, 0xe0, 0x5f, 0x0d, 0xb8, 0x5a, + 0xe3, 0xfe, 0x8f, 0x8f, 0x02, 0x41, 0x1b, 0x01, 0x17, 0x9f, 0x5a, 0xd5, 0xca, 0x83, 0x31, 0xde, + 0xbb, 0x03, 0x8b, 0x34, 0x72, 0x2b, 0x0f, 0x6c, 0x47, 0x9d, 0x84, 0x3e, 0xb1, 0x05, 0x24, 0xc6, + 0xa7, 0xdd, 0xeb, 0xe2, 0x4b, 0xfd, 0x2e, 0x26, 0x30, 0x17, 0x3a, 0x4d, 0xe5, 0xc4, 0x9c, 0x85, + 0x63, 0x72, 0x03, 0x32, 0xfc, 0xa4, 0x59, 0x67, 0x0d, 0x74, 0x4d, 0xce, 0xd2, 0x33, 0x62, 0x42, + 0xd6, 0xa3, 0x6e, 0xd0, 0x74, 0x1a, 0x1c, 0x6d, 0x5e, 0xb4, 0x92, 0x39, 0x59, 0x83, 0x9c, 0xef, + 0x70, 0x75, 0xd3, 0xb4, 0xcd, 0x59, 0xdf, 0xe1, 0xcf, 0xe4, 0xbc, 0x68, 0xc3, 0xea, 0x80, 0x4d, + 0xb1, 0xc5, 0xd2, 0x82, 0x57, 0x7d, 0x16, 0x28, 0x0b, 0x17, 0x5e, 0xf5, 0x5a, 0xb0, 0x0e, 0xe0, + 0xba, 0x89, 0x4f, 0x75, 0x54, 0x4a, 0x8a, 0xf2, 0xea, 0xbf, 0x0d, 0xb8, 0xae, 0xdc, 0xfa, 0xa2, + 0x2d, 0xce, 0x1f, 0x77, 0x2b, 0x30, 0x1f, 0xb2, 0xd0, 0xa5, 0xe8, 0xac, 0x39, 0x4b, 0x4d, 0x7a, + 0xa3, 0x71, 0xae, 0x2f, 0x1a, 0xbf, 0x99, 0x48, 0xfa, 0x21, 0xac, 0x0f, 0x35, 0x39, 0x71, 0xec, + 0x3a, 0x40, 0xc0, 0xed, 0x88, 0x36, 0x59, 0x87, 0x7a, 0x68, 0x7d, 0xd6, 0xca, 0x05, 0xdc, 0x52, + 0x84, 0x22, 0x85, 0x42, 0x8d, 0xfb, 0x6a, 0xf6, 0xff, 0xf3, 0x5a, 0xb1, 0x08, 0x9b, 0xa3, 0xb6, + 0x49, 0x82, 0xfe, 0x2f, 0x06, 0x5c, 0xa9, 0x71, 0xff, 0x0b, 0x26, 0xe8, 0xae, 0xc3, 0xf7, 0xa3, + 0xc0, 0xa5, 0x33, 0xab, 0xd0, 0x92, 0xe8, 0x58, 0x05, 0x9c, 0x90, 0xdb, 0xb0, 0xd0, 0x8a, 0x02, + 0x16, 0x05, 0xe2, 0xc4, 0x3e, 0xa4, 0x14, 0xbd, 0x3c, 0x67, 0xe5, 0x63, 0xda, 0x53, 0x8a, 0x2c, + 0xea, 0x18, 0xc2, 0x76, 0xb3, 0x4e, 0x23, 0x3c, 0xe0, 0x39, 0x2b, 0x8f, 0xb4, 0xe7, 0x48, 0x22, + 0x26, 0x64, 0x78, 0xbb, 0xd5, 0x6a, 0x9c, 0xa8, 0x5b, 0xb1, 0x73, 0xb1, 0x60, 0x58, 0x9a, 0x52, + 0x5c, 0x85, 0x9b, 0x29, 0xfd, 0x13, 0xdb, 0xfe, 0x94, 0x49, 0x6c, 0x8b, 0xcd, 0x1f, 0x63, 0xdb, + 0x1a, 0x60, 0x54, 0xab, 0x68, 0x50, 0x61, 0x9e, 0x95, 0x04, 0x0c, 0x86, 0x0f, 0xe0, 0x06, 0xab, + 0x73, 0x1a, 0x75, 0xa8, 0x67, 0x33, 0x2d, 0xab, 0xf7, 0x75, 0x5c, 0x89, 0x57, 0xe3, 0x8d, 0x10, + 0x55, 0x85, 0x8d, 0x41, 0x94, 0x8e, 0x39, 0x1a, 0xf8, 0x47, 0x42, 0x1b, 0xbb, 0x96, 0x46, 0xef, + 0x60, 0x14, 0x22, 0x0b, 0xf9, 0x08, 0xcc, 0x41, 0x21, 0xf2, 0xc2, 0xb7, 0x39, 0xf5, 0x0a, 0x80, + 0x02, 0x6e, 0xa6, 0x05, 0xec, 0x3a, 0xfc, 0x25, 0xa7, 0x1e, 0xf9, 0xa5, 0x01, 0x77, 0x07, 0xd1, + 0xf4, 0xf0, 0x90, 0xba, 0x22, 0xe8, 0x50, 0x94, 0xa3, 0x8e, 0x2d, 0x8f, 0x9e, 0x2d, 0xe9, 0x54, + 0x78, 0x6f, 0x8a, 0x54, 0xb8, 0x17, 0x0a, 0xeb, 0x76, 0x7a, 0xe3, 0x4f, 0x63, 0xd1, 0x49, 0x34, + 0xed, 0x4f, 0xd6, 0x40, 0x3d, 0x5d, 0x0b, 0x68, 0xca, 0x58, 0x89, 0xf8, 0xa6, 0x11, 0x06, 0x4b, + 0x1d, 0xa7, 0xd1, 0xa6, 0x76, 0x44, 0x5d, 0x1a, 0xc8, 0x1b, 0xa6, 0xc2, 0xe2, 0xb3, 0x33, 0xe6, + 0xf1, 0xff, 0xbc, 0xb9, 0x75, 0xfd, 0xc4, 0x69, 0x36, 0x1e, 0x17, 0xfb, 0xc5, 0x15, 0xad, 0x45, + 0x24, 0x58, 0x7a, 0x4e, 0x3e, 0x81, 0x0c, 0x17, 0x8e, 0x68, 0xab, 0xb7, 0x77, 0xa9, 0x72, 0x7f, + 0x64, 0xc2, 0x53, 0x25, 0x97, 0x06, 0x7e, 0x8e, 0x18, 0x4b, 0x63, 0xc9, 0x5d, 0x58, 0x4a, 0xec, + 0x47, 0x46, 0xfd, 0xac, 0x2c, 0xc6, 0xd4, 0xaa, 0x24, 0x92, 0xfb, 0x40, 0x12, 0x36, 0x59, 0x0e, + 0xa8, 0x8b, 0x9d, 0x45, 0xe7, 0x2c, 0xc7, 0x2b, 0x07, 0x9c, 0x3f, 0xc7, 0x97, 0xb1, 0x2f, 0x1d, + 0xe7, 0x66, 0x4a, 0xc7, 0x3d, 0x57, 0x28, 0xf6, 0x79, 0x72, 0x85, 0xfe, 0x99, 0x81, 0x25, 0xbd, + 0xa6, 0xb3, 0xe6, 0x98, 0x1b, 0x24, 0x93, 0x17, 0x0d, 0x3d, 0x1a, 0xe9, 0xeb, 0xa3, 0x67, 0xe4, + 0x1e, 0x5c, 0x51, 0x23, 0x3b, 0x95, 0x0a, 0x17, 0x15, 0xb9, 0xaa, 0x9f, 0x10, 0x13, 0xb2, 0xfa, + 0x08, 0x22, 0xfd, 0xcc, 0x27, 0x73, 0xe9, 0xbc, 0x78, 0xac, 0x9d, 0x37, 0xaf, 0x44, 0xc4, 0x54, + 0xe5, 0xbc, 0xd3, 0xd2, 0x2e, 0x73, 0xae, 0xd2, 0x4e, 0x5a, 0xd9, 0xa4, 0x9c, 0x3b, 0xbe, 0x72, + 0x7d, 0xce, 0x8a, 0xa7, 0xf2, 0xbd, 0x0a, 0xc2, 0x9e, 0x07, 0x20, 0x87, 0xcb, 0x79, 0x4d, 0xc3, + 0x7b, 0xff, 0x00, 0x56, 0x62, 0x96, 0xbe, 0xdb, 0xae, 0x2e, 0x2b, 0xd1, 0x6b, 0xbd, 0x97, 0xbc, + 0x2f, 0x87, 0xe7, 0x91, 0x2d, 0xc9, 0xe1, 0xfd, 0x67, 0xbc, 0x30, 0x5b, 0xc9, 0xb5, 0x06, 0x39, + 0xd1, 0xb5, 0x59, 0x14, 0xf8, 0x41, 0x58, 0x58, 0x54, 0xce, 0x15, 0xdd, 0x17, 0x38, 0x97, 0x6f, + 0xb7, 0xc3, 0x39, 0x15, 0x85, 0x25, 0x5c, 0x50, 0x13, 0x72, 0x0b, 0xf2, 0xb4, 0x43, 0x43, 0xa1, + 0x73, 0xe0, 0x15, 0xd4, 0x0a, 0x90, 0x84, 0x69, 0x90, 0x44, 0xb0, 0x8a, 0xc5, 0xb9, 0xcb, 0x1a, + 0xb6, 0xcb, 0x42, 0x11, 0x39, 0xae, 0xb0, 0x3b, 0x34, 0xe2, 0x01, 0x0b, 0x0b, 0xcb, 0xa8, 0xe7, + 0xa3, 0xd2, 0xd8, 0xc6, 0x46, 0x26, 0x64, 0xc4, 0x57, 0x35, 0xfc, 0x0b, 0x85, 0xb6, 0x6e, 0xb6, + 0x86, 0x2f, 0x90, 0x9f, 0xca, 0x38, 0xe8, 0xd0, 0x48, 0xd8, 0xac, 0x25, 0x02, 0x16, 0xf2, 0xc2, + 0x55, 0xcc, 0xfc, 0xf7, 0x27, 0x6c, 0x64, 0x21, 0xe8, 0x85, 0xc2, 0xec, 0xcc, 0xc9, 0xb0, 0x90, + 0xb1, 0xd3, 0x43, 0x24, 0x35, 0x58, 0x70, 0x9d, 0x46, 0x23, 0x11, 0x4c, 0x50, 0xf0, 0xfb, 0x13, + 0x04, 0x57, 0x9d, 0x46, 0x43, 0x4b, 0xb0, 0xf2, 0xee, 0xe9, 0x84, 0x6c, 0xc3, 0xb5, 0x80, 0xdb, + 0xbd, 0xcd, 0x8c, 0x5c, 0x2d, 0x5c, 0xc3, 0x62, 0x60, 0x39, 0xe0, 0x55, 0xb9, 0x82, 0x51, 0x2b, + 0x45, 0x14, 0x0b, 0x70, 0xa3, 0xff, 0xa2, 0x25, 0x77, 0xf0, 0x19, 0x96, 0xa5, 0x4f, 0xea, 0x2c, + 0x12, 0x9f, 0x8b, 0xb6, 0x7b, 0x5c, 0xad, 0x1e, 0xfc, 0x64, 0x7c, 0x17, 0x31, 0xae, 0x5e, 0x5b, + 0xc3, 0x82, 0xb0, 0x5f, 0x5a, 0xb2, 0x55, 0x07, 0x5b, 0x08, 0x8b, 0x1e, 0xb6, 0x43, 0x0f, 0x59, + 0xa8, 0x77, 0xae, 0xdd, 0xd4, 0xb5, 0x95, 0xd2, 0x92, 0x12, 0x53, 0xe5, 0xcb, 0x45, 0x45, 0xd5, + 0x35, 0xa6, 0x2e, 0xcd, 0x07, 0xf6, 0x4d, 0xf4, 0xfa, 0xca, 0x40, 0xad, 0x55, 0xef, 0x63, 0x39, + 0x82, 0x3e, 0x53, 0x6d, 0xe5, 0x53, 0xd9, 0x55, 0x8e, 0xd1, 0xce, 0x05, 0x32, 0xd8, 0x85, 0xa2, + 0x96, 0xf9, 0x4a, 0x79, 0x52, 0xc4, 0xa4, 0xb6, 0xd1, 0x41, 0xb3, 0x1c, 0xa5, 0xe8, 0xc5, 0x3b, + 0x70, 0x7b, 0xa4, 0x6e, 0x89, 0x05, 0xff, 0x32, 0xb0, 0x7b, 0xd3, 0xbd, 0x22, 0x96, 0xe1, 0xd5, + 0x36, 0x17, 0xcc, 0x3b, 0x39, 0x47, 0x23, 0x5b, 0x82, 0x6b, 0x21, 0xfd, 0xd2, 0x76, 0x95, 0xa0, + 0x94, 0x8b, 0xaf, 0x86, 0xf4, 0x4b, 0xbd, 0x45, 0x5c, 0xca, 0x0f, 0x74, 0x2c, 0x73, 0x43, 0x3a, + 0x96, 0xd3, 0x27, 0x74, 0xfe, 0x7c, 0xdd, 0xf1, 0x27, 0x70, 0x67, 0x8c, 0xc5, 0xbd, 0xb5, 0x72, + 0x4f, 0x04, 0x19, 0xe9, 0x78, 0x6d, 0x62, 0x11, 0xab, 0xbc, 0xdb, 0x2b, 0x64, 0xdf, 0x69, 0x73, + 0x9d, 0x61, 0x67, 0x2f, 0x58, 0xa5, 0x0c, 0x74, 0x57, 0xd6, 0x52, 0x93, 0xe2, 0x1e, 0x6c, 0x4d, + 0xda, 0x6e, 0x4a, 0xcd, 0x2b, 0xff, 0x5d, 0x82, 0x4b, 0x35, 0xee, 0x93, 0xdf, 0x18, 0x40, 0x86, + 0xb4, 0x47, 0x1f, 0x4c, 0x88, 0xbf, 0xa1, 0x1d, 0x86, 0xf9, 0x83, 0x59, 0x50, 0x89, 0xc6, 0xbf, + 0x36, 0xe0, 0xea, 0xe0, 0x07, 0x82, 0x87, 0x53, 0xc9, 0xec, 0x07, 0x99, 0x1f, 0xcd, 0x00, 0x4a, + 0xf4, 0xf8, 0x9d, 0x01, 0xd7, 0x87, 0xb7, 0x3f, 0xdf, 0x9b, 0x2c, 0x76, 0x28, 0xd0, 0xfc, 0x78, + 0x46, 0x60, 0xa2, 0x53, 0x07, 0x16, 0xfa, 0xba, 0xa0, 0xd2, 0x64, 0x81, 0xbd, 0xfc, 0xe6, 0xa3, + 0xb3, 0xf1, 0xa7, 0xf7, 0x4d, 0x3a, 0x94, 0x29, 0xf7, 0x8d, 0xf9, 0xa7, 0xdd, 0x37, 0x5d, 0xda, + 0x11, 0x0e, 0xf9, 0xde, 0xb2, 0x6e, 0x7b, 0x3a, 0x31, 0x9a, 0xdd, 0xfc, 0xee, 0x99, 0xd8, 0x93, + 0x4d, 0x7f, 0x0e, 0x4b, 0xa9, 0xef, 0x2b, 0x0f, 0x26, 0x0b, 0xea, 0x47, 0x98, 0x1f, 0x9e, 0x15, + 0x91, 0xec, 0xfe, 0x2b, 0x03, 0x96, 0x07, 0xbe, 0xc7, 0x55, 0x26, 0x8b, 0x4b, 0x63, 0xcc, 0xc7, + 0x67, 0xc7, 0x24, 0x4a, 0xfc, 0x02, 0xae, 0xa4, 0xbf, 0x62, 0x7e, 0x67, 0xb2, 0xb8, 0x14, 0xc4, + 0xfc, 0xfe, 0x99, 0x21, 0xbd, 0x67, 0x90, 0x2a, 0x26, 0xa6, 0x38, 0x83, 0x7e, 0xc4, 0x34, 0x67, + 0x30, 0xbc, 0xc4, 0xc0, 0x27, 0x68, 0xb0, 0xc0, 0x78, 0x38, 0xcd, 0xed, 0x4d, 0x81, 0xa6, 0x79, + 0x82, 0x46, 0x96, 0x14, 0xe4, 0x0f, 0x06, 0xdc, 0x18, 0x51, 0x4f, 0x7c, 0x38, 0xed, 0xe9, 0xa6, + 0x91, 0xe6, 0x8f, 0x66, 0x45, 0x26, 0x6a, 0x7d, 0x65, 0x40, 0x61, 0x64, 0x91, 0xf0, 0x78, 0xea, + 0x43, 0x1f, 0xc0, 0x9a, 0x3b, 0xb3, 0x63, 0x13, 0xe5, 0xfe, 0x6c, 0xc0, 0xfa, 0xf8, 0x4c, 0xfc, + 0xf1, 0xb4, 0x0e, 0x18, 0x21, 0xc0, 0xdc, 0x3d, 0xa7, 0x80, 0x58, 0xd7, 0x9d, 0xdd, 0xaf, 0xdf, + 0x6e, 0x18, 0xaf, 0xdf, 0x6e, 0x18, 0xff, 0x78, 0xbb, 0x61, 0xfc, 0xf6, 0xdd, 0xc6, 0x85, 0xd7, + 0xef, 0x36, 0x2e, 0xfc, 0xed, 0xdd, 0xc6, 0x85, 0x9f, 0x6d, 0xf7, 0x14, 0x32, 0x72, 0x8b, 0x6d, + 0xf5, 0x6f, 0x87, 0x90, 0x79, 0xb4, 0xdc, 0xed, 0xfb, 0xef, 0x8c, 0xac, 0x69, 0xea, 0x19, 0x6c, + 0x45, 0x1e, 0xfe, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x5c, 0xd9, 0x42, 0xd4, 0xcb, 0x19, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3103,6 +3113,18 @@ func (m *MsgVoteInbound) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.IsCrossChainCall { + i-- + if m.IsCrossChainCall { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x98 + } if m.CallOptions != nil { { size, err := m.CallOptions.MarshalToSizedBuffer(dAtA[:i]) @@ -3993,6 +4015,9 @@ func (m *MsgVoteInbound) Size() (n int) { l = m.CallOptions.Size() n += 2 + l + sovTx(uint64(l)) } + if m.IsCrossChainCall { + n += 3 + } return n } @@ -6754,6 +6779,26 @@ func (m *MsgVoteInbound) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 19: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsCrossChainCall", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsCrossChainCall = bool(v != 0) default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/fungible/keeper/deposits.go b/x/fungible/keeper/deposits.go index 48c1deb771..b6a0c72c4e 100644 --- a/x/fungible/keeper/deposits.go +++ b/x/fungible/keeper/deposits.go @@ -35,6 +35,7 @@ func (k Keeper) ZRC20DepositAndCallContract( coinType coin.CoinType, asset string, protocolContractVersion crosschaintypes.ProtocolContractVersion, + isCrossChainCall bool, ) (*evmtypes.MsgEthereumTxResponse, bool, error) { // get ZRC20 contract zrc20Contract, _, err := k.getAndCheckZRC20(ctx, amount, senderChainID, coinType, asset) @@ -44,7 +45,17 @@ func (k Keeper) ZRC20DepositAndCallContract( // handle the deposit for protocol contract version 2 if protocolContractVersion == crosschaintypes.ProtocolContractVersion_V2 { - return k.ProcessV2Deposit(ctx, from, senderChainID, zrc20Contract, to, amount, message, coinType) + return k.ProcessV2Deposit( + ctx, + from, + senderChainID, + zrc20Contract, + to, + amount, + message, + coinType, + isCrossChainCall, + ) } // check if the receiver is a contract diff --git a/x/fungible/keeper/deposits_test.go b/x/fungible/keeper/deposits_test.go index f636ca19bd..3958ae191e 100644 --- a/x/fungible/keeper/deposits_test.go +++ b/x/fungible/keeper/deposits_test.go @@ -45,6 +45,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_Gas, sample.EthAddress().String(), crosschaintypes.ProtocolContractVersion_V1, + false, ) require.NoError(t, err) require.False(t, contractCall) @@ -78,6 +79,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_ERC20, assetAddress, crosschaintypes.ProtocolContractVersion_V1, + false, ) require.NoError(t, err) require.False(t, contractCall) @@ -111,6 +113,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_ERC20, assetAddress, crosschaintypes.ProtocolContractVersion_V1, + false, ) require.ErrorIs(t, err, types.ErrCallNonContract) }) @@ -153,6 +156,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_Gas, sample.EthAddress().String(), crosschaintypes.ProtocolContractVersion_V1, + false, ) require.NoError(t, err) require.False(t, contractCall) @@ -191,6 +195,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_Gas, sample.EthAddress().String(), crosschaintypes.ProtocolContractVersion_V1, + false, ) require.ErrorIs(t, err, types.ErrPausedZRC20) }) @@ -233,6 +238,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_Gas, sample.EthAddress().String(), crosschaintypes.ProtocolContractVersion_V1, + false, ) require.ErrorIs(t, err, types.ErrForeignCoinCapReached) }) @@ -260,6 +266,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_Gas, sample.EthAddress().String(), crosschaintypes.ProtocolContractVersion_V1, + false, ) require.ErrorIs(t, err, crosschaintypes.ErrGasCoinNotFound) }) @@ -287,6 +294,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_ERC20, assetAddress, crosschaintypes.ProtocolContractVersion_V1, + false, ) require.ErrorIs(t, err, crosschaintypes.ErrForeignCoinNotFound) }) @@ -318,6 +326,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_Gas, sample.EthAddress().String(), crosschaintypes.ProtocolContractVersion_V1, + false, ) require.NoError(t, err) require.True(t, contractCall) @@ -357,6 +366,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_Gas, sample.EthAddress().String(), crosschaintypes.ProtocolContractVersion_V1, + false, ) require.Error(t, err) require.True(t, contractCall) @@ -390,6 +400,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { coin.CoinType_Gas, sample.EthAddress().String(), crosschaintypes.ProtocolContractVersion_V2, + false, ) require.NoError(t, err) require.False(t, contractCall) diff --git a/x/fungible/keeper/v2_deposits.go b/x/fungible/keeper/v2_deposits.go index 812f2c0b81..16486dcbff 100644 --- a/x/fungible/keeper/v2_deposits.go +++ b/x/fungible/keeper/v2_deposits.go @@ -25,25 +25,27 @@ func (k Keeper) ProcessV2Deposit( amount *big.Int, message []byte, coinType coin.CoinType, + isCrossChainCall bool, ) (*evmtypes.MsgEthereumTxResponse, bool, error) { context := systemcontract.ZContext{ - Origin: from, - Sender: ethcommon.Address{}, + Origin: []byte{}, + Sender: ethcommon.BytesToAddress(from), ChainID: big.NewInt(senderChainID), } - if len(message) == 0 { - // simple deposit - res, err := k.DepositZRC20(ctx, zrc20Addr, to, amount) - return res, false, err - } else if coinType == coin.CoinType_NoAssetCall { + if coinType == coin.CoinType_NoAssetCall { // simple call res, err := k.CallExecute(ctx, context, zrc20Addr, amount, to, message) return res, true, err + } else if isCrossChainCall { + // call with asset + res, err := k.CallDepositAndCallZRC20(ctx, context, zrc20Addr, amount, to, message) + return res, true, err } - // deposit and call - res, err := k.CallDepositAndCallZRC20(ctx, context, zrc20Addr, amount, to, message) - return res, true, err + + // simple deposit + res, err := k.DepositZRC20(ctx, zrc20Addr, to, amount) + return res, false, err } // ProcessV2RevertDeposit handles a revert deposit from an inbound tx with protocol version 2 diff --git a/x/fungible/keeper/v2_deposits_test.go b/x/fungible/keeper/v2_deposits_test.go index e470480776..7b13eeef89 100644 --- a/x/fungible/keeper/v2_deposits_test.go +++ b/x/fungible/keeper/v2_deposits_test.go @@ -15,6 +15,40 @@ import ( "testing" ) +// getTestDAppNoMessageIndex queries the no message index of the test dapp v2 contract +func getTestDAppNoMessageIndex( + t *testing.T, + ctx sdk.Context, + k fungiblekeeper.Keeper, + contract, + account common.Address, +) string { + testDAppABI, err := testdappv2.TestDAppV2MetaData.GetAbi() + require.NoError(t, err) + res, err := k.CallEVM( + ctx, + *testDAppABI, + types.ModuleAddressEVM, + contract, + fungiblekeeper.BigIntZero, + nil, + false, + false, + "getNoMessageIndex", + account, + ) + require.NoError(t, err) + + unpacked, err := testDAppABI.Unpack("getNoMessageIndex", res.Ret) + require.NoError(t, err) + require.Len(t, unpacked, 1) + + index, ok := unpacked[0].(string) + require.True(t, ok) + + return index +} + // deployTestDAppV2 deploys the test dapp v2 contract and returns its address func deployTestDAppV2(t *testing.T, ctx sdk.Context, k *fungiblekeeper.Keeper, evmk types.EVMKeeper) common.Address { testDAppV2, err := k.DeployContract(ctx, testdappv2.TestDAppV2MetaData) @@ -105,6 +139,41 @@ func TestKeeper_ProcessV2Deposit(t *testing.T) { big.NewInt(42), []byte{}, coin.CoinType_Gas, + false, + ) + + // ASSERT + require.NoError(t, err) + require.False(t, contractCall) + + balance, err := k.BalanceOfZRC4(ctx, zrc20, receiver) + require.NoError(t, err) + require.Equal(t, big.NewInt(42), balance) + }) + + t.Run("should process no-call deposit, message should be ignored", func(t *testing.T) { + // ARRANGE + k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) + _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + chainID := chains.DefaultChainsList()[0].ChainId + receiver := sample.EthAddress() + + // deploy the system contracts + deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chainID, "foobar", "foobar") + + // ACT + _, contractCall, err := k.ProcessV2Deposit( + ctx, + sample.EthAddress().Bytes(), + chainID, + zrc20, + receiver, + big.NewInt(42), + []byte("foo"), + coin.CoinType_Gas, + false, ) // ASSERT @@ -140,6 +209,7 @@ func TestKeeper_ProcessV2Deposit(t *testing.T) { big.NewInt(82), []byte("foo"), coin.CoinType_Gas, + true, ) // ASSERT @@ -150,4 +220,52 @@ func TestKeeper_ProcessV2Deposit(t *testing.T) { require.Equal(t, big.NewInt(82), balance) assertTestDAppV2MessageAndAmount(t, ctx, k, testDapp, "foo", 82) }) + + t.Run("should process deposit and call with no message", func(t *testing.T) { + // ARRANGE + k, ctx, sdkk, _ := keepertest.FungibleKeeper(t) + _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) + + chainID := chains.DefaultChainsList()[0].ChainId + + // deploy test dapp + testDapp := deployTestDAppV2(t, ctx, k, sdkk.EvmKeeper) + + // deploy the system contracts + deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chainID, "foobar", "foobar") + + sender := sample.EthAddress() + + // ACT + _, contractCall, err := k.ProcessV2Deposit( + ctx, + sender.Bytes(), + chainID, + zrc20, + testDapp, + big.NewInt(82), + []byte{}, + coin.CoinType_Gas, + true, + ) + + // ASSERT + require.NoError(t, err) + require.True(t, contractCall) + balance, err := k.BalanceOfZRC4(ctx, zrc20, testDapp) + require.NoError(t, err) + require.Equal(t, big.NewInt(82), balance) + + messageIndex := getTestDAppNoMessageIndex(t, ctx, *k, testDapp, sender) + + assertTestDAppV2MessageAndAmount( + t, + ctx, + k, + testDapp, + messageIndex, + 82, + ) + }) } diff --git a/zetaclient/chains/evm/cctx.go b/zetaclient/chains/evm/cctx.go index 019dbfe3a0..597347a0a5 100644 --- a/zetaclient/chains/evm/cctx.go +++ b/zetaclient/chains/evm/cctx.go @@ -47,10 +47,10 @@ func ParseOutboundTypeFromCCTX(cctx types.CrossChainTx) OutboundType { case coin.CoinType_Gas: switch cctx.CctxStatus.Status { case types.CctxStatus_PendingOutbound: - if len(cctx.RelayedMessage) == 0 { - return OutboundTypeGasWithdraw - } else { + if cctx.InboundParams.IsCrossChainCall { return OutboundTypeGasWithdrawAndCall + } else { + return OutboundTypeGasWithdraw } case types.CctxStatus_PendingRevert: if cctx.RevertOptions.CallOnRevert { @@ -62,10 +62,10 @@ func ParseOutboundTypeFromCCTX(cctx types.CrossChainTx) OutboundType { case coin.CoinType_ERC20: switch cctx.CctxStatus.Status { case types.CctxStatus_PendingOutbound: - if len(cctx.RelayedMessage) == 0 { - return OutboundTypeERC20Withdraw - } else { + if cctx.InboundParams.IsCrossChainCall { return OutboundTypeERC20WithdrawAndCall + } else { + return OutboundTypeERC20Withdraw } case types.CctxStatus_PendingRevert: if cctx.RevertOptions.CallOnRevert { diff --git a/zetaclient/chains/evm/cctx_test.go b/zetaclient/chains/evm/cctx_test.go new file mode 100644 index 0000000000..e61202fd13 --- /dev/null +++ b/zetaclient/chains/evm/cctx_test.go @@ -0,0 +1,105 @@ +package evm_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/zeta-chain/node/pkg/coin" + "github.com/zeta-chain/node/x/crosschain/types" + "github.com/zeta-chain/node/zetaclient/chains/evm" +) + +func TestParseOutboundTypeFromCCTX(t *testing.T) { + tests := []struct { + name string + cctx types.CrossChainTx + expected evm.OutboundType + }{ + { + name: "Gas withdraw and call", + cctx: types.CrossChainTx{ + InboundParams: &types.InboundParams{ + CoinType: coin.CoinType_Gas, + IsCrossChainCall: true, + }, + CctxStatus: &types.Status{ + Status: types.CctxStatus_PendingOutbound, + }, + }, + expected: evm.OutboundTypeGasWithdrawAndCall, + }, + { + name: "Gas withdraw", + cctx: types.CrossChainTx{ + InboundParams: &types.InboundParams{ + CoinType: coin.CoinType_Gas, + IsCrossChainCall: false, + }, + CctxStatus: &types.Status{ + Status: types.CctxStatus_PendingOutbound, + }, + }, + expected: evm.OutboundTypeGasWithdraw, + }, + { + name: "ERC20 withdraw and call", + cctx: types.CrossChainTx{ + InboundParams: &types.InboundParams{ + CoinType: coin.CoinType_ERC20, + IsCrossChainCall: true, + }, + CctxStatus: &types.Status{ + Status: types.CctxStatus_PendingOutbound, + }, + }, + expected: evm.OutboundTypeERC20WithdrawAndCall, + }, + { + name: "ERC20 withdraw revert and call on revert", + cctx: types.CrossChainTx{ + InboundParams: &types.InboundParams{ + CoinType: coin.CoinType_ERC20, + }, + CctxStatus: &types.Status{ + Status: types.CctxStatus_PendingRevert, + }, + RevertOptions: types.RevertOptions{ + CallOnRevert: true, + }, + }, + expected: evm.OutboundTypeERC20WithdrawRevertAndCallOnRevert, + }, + { + name: "No asset call", + cctx: types.CrossChainTx{ + InboundParams: &types.InboundParams{ + CoinType: coin.CoinType_NoAssetCall, + }, + CctxStatus: &types.Status{ + Status: types.CctxStatus_PendingOutbound, + }, + }, + expected: evm.OutboundTypeCall, + }, + { + name: "ZETA gives Uuknown outbound type", + cctx: types.CrossChainTx{ + InboundParams: &types.InboundParams{ + CoinType: coin.CoinType_Zeta, + }, + CctxStatus: &types.Status{ + Status: types.CctxStatus_PendingOutbound, + }, + }, + expected: evm.OutboundTypeUnknown, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := evm.ParseOutboundTypeFromCCTX(tt.cctx) + require.Equal(t, tt.expected, result) + }) + } +} diff --git a/zetaclient/chains/evm/constant.go b/zetaclient/chains/evm/constant.go index 65398b3013..01b229591a 100644 --- a/zetaclient/chains/evm/constant.go +++ b/zetaclient/chains/evm/constant.go @@ -47,6 +47,10 @@ const ( // [signature, sender, receiver] TopicsGatewayDeposit = 3 + // TopicsGatewayDepositAndCall is the number of topics for a gateway deposit and call event + // [signature, sender, receiver] + TopicsGatewayDepositAndCall = 3 + // TopicsGatewayCall is the number of topics for a gateway call event // [signature, sender, receiver] TopicsGatewayCall = 3 diff --git a/zetaclient/chains/evm/observer/inbound.go b/zetaclient/chains/evm/observer/inbound.go index aebd661ae3..02ab1a0b6f 100644 --- a/zetaclient/chains/evm/observer/inbound.go +++ b/zetaclient/chains/evm/observer/inbound.go @@ -239,6 +239,12 @@ func (ob *Observer) ObserveInbound(ctx context.Context, sampledLogger zerolog.Lo Err(err). Msgf("ObserveInbound: error observing call events from Gateway contract") } + lastScannedGatewayDepositAndCall, err := ob.ObserveGatewayDepositAndCall(ctx, startBlock, toBlock) + if err != nil { + ob.Logger().Inbound.Error(). + Err(err). + Msgf("ObserveInbound: error observing depositAndCall events from Gateway contract") + } // note: using lowest height for all 3 events is not perfect, but it's simple and good enough lastScannedLowest := lastScannedZetaSent @@ -254,6 +260,9 @@ func (ob *Observer) ObserveInbound(ctx context.Context, sampledLogger zerolog.Lo if lastScannedGatewayCall < lastScannedLowest { lastScannedLowest = lastScannedGatewayCall } + if lastScannedGatewayDepositAndCall < lastScannedLowest { + lastScannedLowest = lastScannedGatewayDepositAndCall + } // update last scanned block height for all 3 events (ZetaSent, Deposited, TssRecvd), ignore db error if lastScannedLowest > lastScanned { diff --git a/zetaclient/chains/evm/observer/v2_inbound.go b/zetaclient/chains/evm/observer/v2_inbound.go index 246dda603a..b19f0e9f85 100644 --- a/zetaclient/chains/evm/observer/v2_inbound.go +++ b/zetaclient/chains/evm/observer/v2_inbound.go @@ -175,6 +175,12 @@ func (ob *Observer) newDepositInboundVote(event *gatewayevm.GatewayEVMDeposited) coinType = coin.CoinType_Gas } + // to maintain compatibility with previous gateway version, deposit event with a non-empty payload is considered as a call + isCrossChainCall := false + if len(event.Payload) > 0 { + isCrossChainCall = true + } + return *types.NewMsgVoteInbound( ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), event.Sender.Hex(), @@ -193,6 +199,7 @@ func (ob *Observer) newDepositInboundVote(event *gatewayevm.GatewayEVMDeposited) types.ProtocolContractVersion_V2, false, // currently not relevant since calls are not arbitrary types.WithEVMRevertOptions(event.RevertOptions), + types.WithCrossChainCall(isCrossChainCall), ) } @@ -330,3 +337,141 @@ func (ob *Observer) newCallInboundVote(event *gatewayevm.GatewayEVMCalled) types types.WithEVMRevertOptions(event.RevertOptions), ) } + +// ObserveGatewayDepositAndCall queries the gateway contract for deposit and call events +// returns the last block successfully scanned +func (ob *Observer) ObserveGatewayDepositAndCall(ctx context.Context, startBlock, toBlock uint64) (uint64, error) { + gatewayAddr, gatewayContract, err := ob.GetGatewayContract() + if err != nil { + // lastScanned is startBlock - 1 + return startBlock - 1, errors.Wrap(err, "can't get gateway contract") + } + + // get iterator for the events for the block range + eventIterator, err := gatewayContract.FilterDepositedAndCalled(&bind.FilterOpts{ + Start: startBlock, + End: &toBlock, + Context: ctx, + }, []ethcommon.Address{}, []ethcommon.Address{}) + if err != nil { + return startBlock - 1, errors.Wrapf( + err, + "error filtering deposits from block %d to %d for chain %d", + startBlock, + toBlock, + ob.Chain().ChainId, + ) + } + + // parse and validate events + events := ob.parseAndValidateDepositAndCallEvents(eventIterator, gatewayAddr) + + // increment prom counter + metrics.GetFilterLogsPerChain.WithLabelValues(ob.Chain().Name).Inc() + + // post to zetacore + lastScanned := uint64(0) + for _, event := range events { + // remember which block we are scanning (there could be multiple events in the same block) + if event.Raw.BlockNumber > lastScanned { + lastScanned = event.Raw.BlockNumber + } + + // check if the event is processable + if !ob.checkEventProcessability(event.Sender, event.Receiver, event.Raw.TxHash, event.Payload) { + continue + } + + msg := ob.newDepositAndCallInboundVote(event) + + ob.Logger().Inbound.Info(). + Msgf("ObserveGateway: DepositAndCall inbound detected on chain %d tx %s block %d from %s value %s message %s", + ob.Chain(). + ChainId, event.Raw.TxHash.Hex(), event.Raw.BlockNumber, event.Sender.Hex(), event.Amount.String(), hex.EncodeToString(event.Payload)) + + _, err = ob.PostVoteInbound(ctx, &msg, zetacore.PostVoteInboundExecutionGasLimit) + if err != nil { + // decrement the last scanned block so we have to re-scan from this block next time + return lastScanned - 1, errors.Wrap(err, "error posting vote inbound") + } + } + + // successfully processed all events in [startBlock, toBlock] + return toBlock, nil +} + +// parseAndValidateDepositAndCallEvents collects and sorts events by block number, tx index, and log index +func (ob *Observer) parseAndValidateDepositAndCallEvents( + iterator *gatewayevm.GatewayEVMDepositedAndCalledIterator, + gatewayAddr ethcommon.Address, +) []*gatewayevm.GatewayEVMDepositedAndCalled { + // collect and sort events by block number, then tx index, then log index (ascending) + events := make([]*gatewayevm.GatewayEVMDepositedAndCalled, 0) + for iterator.Next() { + events = append(events, iterator.Event) + err := evm.ValidateEvmTxLog(&iterator.Event.Raw, gatewayAddr, "", evm.TopicsGatewayDepositAndCall) + if err == nil { + events = append(events, iterator.Event) + continue + } + ob.Logger().Inbound.Warn(). + Err(err). + Msgf("ObserveGateway: invalid DepositedAndCalled event in tx %s on chain %d at height %d", + iterator.Event.Raw.TxHash.Hex(), ob.Chain().ChainId, iterator.Event.Raw.BlockNumber) + } + sort.SliceStable(events, func(i, j int) bool { + if events[i].Raw.BlockNumber == events[j].Raw.BlockNumber { + if events[i].Raw.TxIndex == events[j].Raw.TxIndex { + return events[i].Raw.Index < events[j].Raw.Index + } + return events[i].Raw.TxIndex < events[j].Raw.TxIndex + } + return events[i].Raw.BlockNumber < events[j].Raw.BlockNumber + }) + + // filter events from same tx + filtered := make([]*gatewayevm.GatewayEVMDepositedAndCalled, 0) + guard := make(map[string]bool) + for _, event := range events { + // guard against multiple events in the same tx + if guard[event.Raw.TxHash.Hex()] { + ob.Logger().Inbound.Warn(). + Msgf("ObserveGateway: multiple remote call events detected in same tx %s", event.Raw.TxHash) + continue + } + guard[event.Raw.TxHash.Hex()] = true + filtered = append(filtered, event) + } + + return filtered +} + +// newDepositInboundVote creates a MsgVoteInbound message for a Deposit event +func (ob *Observer) newDepositAndCallInboundVote(event *gatewayevm.GatewayEVMDepositedAndCalled) types.MsgVoteInbound { + // if event.Asset is zero, it's a native token + coinType := coin.CoinType_ERC20 + if crypto.IsEmptyAddress(event.Asset) { + coinType = coin.CoinType_Gas + } + + return *types.NewMsgVoteInbound( + ob.ZetacoreClient().GetKeys().GetOperatorAddress().String(), + event.Sender.Hex(), + ob.Chain().ChainId, + "", + event.Receiver.Hex(), + ob.ZetacoreClient().Chain().ChainId, + sdkmath.NewUintFromBigInt(event.Amount), + hex.EncodeToString(event.Payload), + event.Raw.TxHash.Hex(), + event.Raw.BlockNumber, + 1_500_000, + coinType, + event.Asset.Hex(), + event.Raw.Index, + types.ProtocolContractVersion_V2, + false, // currently not relevant since calls are not arbitrary + types.WithEVMRevertOptions(event.RevertOptions), + types.WithCrossChainCall(true), + ) +} From 3aa68fe19f5b7123a7e61feba6a8d9c16887f2fd Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Tue, 22 Oct 2024 04:34:26 -0500 Subject: [PATCH 36/36] docs(rfc): non-evm chain memo design standard (#2963) * upload non-evm chain memo design doc * add changelog entry and proposal date * change field name abortMessage to abortAddress * reorgs * reorgs 2 * better format doc and table; change terminology 'lite-data' to 'compact' * extend header to 4 bytes for extension purpose; update doc and diagram; add example code * correct the flag positions of CallOnRevert and AbortAddress * make receiver optional * rename --------- Co-authored-by: lumtis --- docs/rfc/001_standard_memo_format.md | 220 +++++++++++++++++++++++++++ docs/rfc/images/001_layout.png | Bin 0 -> 116471 bytes 2 files changed, 220 insertions(+) create mode 100644 docs/rfc/001_standard_memo_format.md create mode 100644 docs/rfc/images/001_layout.png diff --git a/docs/rfc/001_standard_memo_format.md b/docs/rfc/001_standard_memo_format.md new file mode 100644 index 0000000000..35604f12c9 --- /dev/null +++ b/docs/rfc/001_standard_memo_format.md @@ -0,0 +1,220 @@ +# A proposed standard memo format for non-EVM chains +
+ +## The goal + +This doc is aimed to introduce a standard format of ZetaChain inbound `memo` across non-EVM chains. The `memo` in an inbound transaction is to carry both instructions and data, by which the cross-chain transaction to be processed as expected in the `zetacore`. A standard memo format helps to ensure consistent developer experience across EVM and non-EVM chains. +

+ + +## The EVM gateway inbound events + +We want to mimic below `Deposit` and `Called` events in the EVM `gateway` contract for non-EVM chains. Typically, we at least want the following 3 pieces at the time of writing. + +- The `receiver` address in ZEVM. +- The `payload` of the call. +- The `RevertOptions`. + +``` +event Deposited( + address indexed sender, + address indexed receiver, + uint256 amount, + address asset, + bytes payload, + RevertOptions revertOptions +); + +event Called( + address indexed sender, + address indexed receiver, + bytes payload, + RevertOptions revertOptions +); +``` +

+ + +## 1. The Memo Diagram + +![](images/001_layout.png)

+ + +## 2. The memo structure + +The raw-byte representation of a standard non-EVM memo contains `9` sections (2 mandatory + 7 optional). + +`Section 0` is the `header`, which controls how the memo should be interpreted. + +`Section 1~8` are data sections that carry actual data attached to the memo. + + +| | Section 0 | Section 1 | Section 2 | Section 3 | Section 4 | Section 5 | Section 6 | Section 7 | Section 8 | +|-----------------|------------|-------------|-------------|----------------|--------------|--------------|---------------|-------------|-------------| +| **Name** | Header | Receiver | Payload | RevertAddress | CallOnRevert | AbortAddress | RevertMessage | reserved | reserved | +| **Size (byte)** | 4 | 20 | variable | variable | 1 | 20 | variable | -- | -- | +| **Type** | [4]byte | ZEVM address| bytes | non-EVM address| bool | ZEVM address | bytes | -- | -- | +| **Optional** | No | Yes | Yes | Yes | Yes | Yes | Yes | -- | -- | +

+ + +## 3. The header + +The `4-byte` header is a self-contained declaration of the memo properties and rules. The proposed header structure is designed in a flexible manner. The data fields are all declared as optional. With `reserved` flags, new features and fields can be added in the future without breaking compatibility. + +### `byte-0`: Memo Identifier + +The ASCII code `0x5A` of letter `'Z'` is used as the identifier of the standard ZetaChain memo format. Once legacy memo is phased out, zetaclient will only accept memos beginning with `0x5A`. + + +### `byte-1`: Control Byte + +| | bit 4 ~ 7 | bit 0 ~ 3 | +|-----------------|------------------------------------------------|--------------------------------------| +| **Name** | version # | encoding format | +| **Optional** | No (0b0000 for now) | No (0b0000 or 0b0001 or 0b0010) | +
+ + +### `byte-2`: Control Byte + +| | bit 4 ~ 7 | bit 0 ~ 3 | +|-----------------|------------------------------------------------|--------------------------------| +| **Name** | operation code | control bytes reserved | +| **Optional** | No (0b0000 or 0001 or 0010 for now) | -- | +
+ + + +### `byte-3`: Data Flags + +| | bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 | +|-----------------|---------------|--------------|---------------|-------------------|------------------|-------------------|-----------------|------------------| +| **Name** | flag reserved | flag reserved| flag reserved | flag CallOnRevert | flag AbortAddress| flag RevertAddress| flag Payload | flag Receiver | +| **Optional** | -- | -- | -- | -- | Yes | Yes | Yes | Yes | +
+ +Supported `operation codes` : + +The `operation code` is designed for the developers to explicitly specify the intention of an inbound transaction in non-contract chains (e.g. Bitcoin, Doge, …). +The operation code is not necessary for non-contract chains, because the method name tells the intention of the transaction. + +A 4-bit operation code would allow `16` operation codes at maximum. + +| 0b0000 | 0b0001 | 0b0010 | +|-------------|-------------------|-------------| +| deposit | deposit_and_call | call | +
+ + +Supported `encoding flags`: +This flag is to tell `zetaclient` how the memo fields should be decoded. A 2-bit weight flag seems good enough and won’t change in future.
+Note: the `compact *` encoding is to minimizes length of memo data (compared to ABI) and will be explained in following sections. + +| 0b00 00 | 0b000 | 0b0010 | +|--------------|----------------|--------------| +| ABI encoded | compact short | compact long | +

+ + +## 4. The types + +To decode/encode the memo fields with `compact *` format, we've defined a few types below. +To decode/encode the memo fields with `ABI encoded` format, just follow the [ABI Spec](https://docs.soliditylang.org/en/develop/abi-spec.html). + + +| Field | Size (byte) | Description | +|-----------------------------|--------------|---------------------------------------------------------------------------------------------------------------------------------| +| **ZEVM address** | fixed, 20 | The raw bytes representation of a ZEVM address. ZEVM address is the same as standard Ethereum address. | +| **non-EVM address** | variable | The raw bytes representation of a non-EVM external chain address. Different addresses have different lengths, e.g., Bitcoin vs Solana; Bitcoin Segwit vs Legacy. | +| **bytes** | variable | The raw bytes of arbitrary data. | +

+ + +## 5. Byte layout of variable-length types + +There are two ways to encode your the memo fields into raw bytes. The `ABI encoded` and `compact *` encoded. + +| Decoding flag | Format | Layout | Description | Rule | +|---------------|---------------|-----------------------------------------|-----------------------------------------------|----------------------------------------------------------| +| 0b0000 | ABI encoded | ABI encoded types | Types are packed/unpacked with ABI standard | [ABI Spec](https://docs.soliditylang.org/en/develop/abi-spec.html) | +| 0b0001 | compact short | [1-byte length] + [data] | Carry up to 255 bytes of data. | A valid length (>= 0) must match data length. | +| 0b0010 | compact long | [2-byte length, little-endian] + [data] | Carry up to 65535 bytes (64KB) of data. | A valid length (>= 0) must match data length. | +| + + +## 6. How to pack your inbound memo + +### Step-1: prepare your memo header + +```go +func MakeHead() []byte { + header := make([]byte, 4) + header[0] = 'Z' + header[1] = 0<<4 | 0b0010 // version + encoding format (e.g. compact long) + header[2] = 0b0001 << 4 // operation code (e.g. DepositAndCall) + header[3] = 0b00000111 // receiver, payload and revertAddress are set + return header +} +``` + + +### Step-2: pack your memo data + +For use cases that requires compact transaction data, choose encoding format of `compact short` or `compact long`. + +```go +func CompactPack(receiver common.Address, payload []byte, revertAddress string) []byte { + data := make([]byte, 0) + + // pack receiver (fixed 20 bytes) + data = append(data, receiver.Bytes()...) + + // pack payload (dynamic) + // encode length with 1 byte if 'compact short' is your choice + lenthPayload := make([]byte, 2) + binary.LittleEndian.PutUint16(lenthPayload, uint16(len(payload))) + + data = append(data, lenthPayload...) // write length + data = append(data, payload...) // write payload + + // pack revert address (dynamic). + // encode length with 1 byte if 'compact short' is your choice + lengthRevertAddr := make([]byte, 2) + binary.LittleEndian.PutUint16(lengthRevertAddr, uint16(len([]byte(revertAddress)))) + + data = append(data, lengthRevertAddr...) // write length + data = append(data, []byte(revertAddress)...) // write revert address + + return data +} +``` + + +Also, ABI encoding format is another option to consider. + +```go +func ABIPack(receiver common.Address, payload []byte, revertAddress string) ([]byte, error) { + // define the ABI for encoding the types: address, bytes, string + abiString := `[{"type":"function","name":"encode","inputs":[ + {"type":"address"}, + {"type":"bytes"}, + {"type":"string"}], + "outputs":[]}]` + + // parse the ABI + parsedABI, err := abi.JSON(strings.NewReader(abiString)) + if err != nil { + return nil, err + } + + // pack the values using the ABI + data, err := parsedABI.Pack("encode", receiver, payload, revertAddress) + if err != nil { + return nil, err + } + + // remove the 4-byte selector + return data[4:], nil +} +``` diff --git a/docs/rfc/images/001_layout.png b/docs/rfc/images/001_layout.png new file mode 100644 index 0000000000000000000000000000000000000000..05ddaf06e9a85e84dff6c301635f8df9ce554aed GIT binary patch literal 116471 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 YORKWJG_SFqBnCW4XOvT|!Hq)$ literal 0 HcmV?d00001