From c324c47edbc2290255d03ed1c2dcfd02022ffed3 Mon Sep 17 00:00:00 2001 From: Artur Troian Date: Mon, 3 Nov 2025 12:17:55 -0600 Subject: [PATCH] feat: cosmwasm Signed-off-by: Artur Troian --- .env | 1 + .envrc | 2 +- .github/actions/setup-ubuntu/action.yaml | 2 +- .github/workflows/tests.yaml | 2 +- .goreleaser-docker.yaml | 20 +- .goreleaser-test-bins.yaml | 36 +- .goreleaser.yaml | 40 +- Makefile | 62 +- _build/{Dockerfile.akash => akash.Dockerfile} | 0 _build/{Dockerfile.test => test.Dockerfile} | 0 _run/.env | 7 + _run/.envrc | 11 + _run/.envrc_run | 8 + _run/common-base.mk | 29 + _run/common-commands.mk | 47 + _run/common.mk | 143 ++ _run/node/.envrc | 1 + _run/node/.gitignore | 1 + _run/node/Makefile | 5 + app/app.go | 49 +- app/app_configure.go | 22 +- app/config.go | 2 + app/modules.go | 56 +- app/sim/sim_utils.go | 2 +- app/sim_test.go | 119 +- app/testnet.go | 2 +- app/types/app.go | 117 +- app/upgrades.go | 11 +- cmd/akash/cmd/app_creator.go | 2 +- cmd/akash/cmd/config.go | 31 + cmd/akash/cmd/root.go | 46 +- cmd/akash/cmd/testnetify/config.go | 2 +- cmd/akash/cmd/testnetify/testnetify.go | 4 +- cmd/akash/cmd/testnetify/utils.go | 2 +- cmd/akash/main.go | 2 +- contracts/price-oracle/Cargo.lock | 1442 +++++++++++++++++ contracts/price-oracle/Cargo.toml | 41 + .../price-oracle/artifacts/checksums.txt | 1 + .../price-oracle/artifacts/price_oracle.wasm | Bin 0 -> 293652 bytes contracts/price-oracle/src/bin/schema.rs | 10 + contracts/price-oracle/src/contract.rs | 382 +++++ contracts/price-oracle/src/error.rs | 32 + contracts/price-oracle/src/lib.rs | 7 + contracts/price-oracle/src/msg.rs | 81 + contracts/price-oracle/src/querier.rs | 35 + contracts/price-oracle/src/state.rs | 54 + docgen/main.go | 2 +- go.mod | 80 +- go.sum | 148 +- make/cosmwasm.mk | 10 + make/init.mk | 29 +- make/releasing.mk | 42 +- make/setup-cache.mk | 21 + make/test-integration.mk | 22 +- make/test-upgrade.mk | 5 +- meta.json | 5 + pubsub/bus_test.go | 2 +- tests/e2e/certs_cli_test.go | 2 +- tests/e2e/certs_grpc_test.go | 2 +- tests/e2e/cli_test.go | 2 +- tests/e2e/deployment_cli_test.go | 2 +- tests/e2e/deployment_grpc_test.go | 2 +- tests/e2e/grpc_test.go | 2 +- tests/e2e/market_cli_test.go | 2 +- tests/e2e/market_grpc_test.go | 2 +- tests/e2e/provider_cli_test.go | 2 +- tests/e2e/provider_grpc_test.go | 2 +- tests/upgrade/config-v0.24.0.tmpl.json | 41 - tests/upgrade/test-cases.json | 8 + tests/upgrade/testdata/hackatom.wasm | Bin 0 -> 180690 bytes tests/upgrade/upgrade_test.go | 6 +- tests/upgrade/workers_test.go | 127 +- testutil/network/network.go | 2 +- testutil/network_suite.go | 2 +- testutil/sims/simulation_helpers.go | 8 +- testutil/state/suite.go | 19 +- testutil/types.go | 4 +- tools/upgrade-info/main.go | 2 +- upgrades/software/v1.0.0/audit.go | 56 - upgrades/software/v1.0.0/cert.go | 54 - upgrades/software/v1.0.0/deployment.go | 123 -- upgrades/software/v1.0.0/escrow.go | 120 -- upgrades/software/v1.0.0/init.go | 27 - upgrades/software/v1.0.0/market.go | 198 --- upgrades/software/v1.0.0/provider.go | 65 - upgrades/software/v1.0.0/take.go | 27 - upgrades/software/v1.0.0/upgrade.go | 346 ---- upgrades/software/v1.1.0/upgrade.go | 466 ------ upgrades/software/{v1.1.0 => v2.0.0}/init.go | 6 +- upgrades/software/v2.0.0/upgrade.go | 88 + upgrades/types/types.go | 2 +- upgrades/upgrades.go | 2 +- upgrades/upgrades_test.go | 2 +- util/partialord/internal/dag/dag_test.go | 2 +- util/partialord/partialord.go | 2 +- util/partialord/partialord_test.go | 2 +- util/query/pagination.go | 2 +- wasmvm.go | 3 + x/audit/alias.go | 2 +- x/audit/genesis.go | 2 +- x/audit/handler/handler.go | 2 +- x/audit/handler/handler_test.go | 4 +- x/audit/handler/msg_server.go | 2 +- x/audit/keeper/grpc_query_test.go | 6 +- x/audit/keeper/keeper_test.go | 2 +- x/audit/keeper/key.go | 2 +- x/audit/module.go | 17 +- x/cert/alias.go | 2 +- x/cert/genesis.go | 2 +- x/cert/handler/handler.go | 2 +- x/cert/handler/handler_test.go | 4 +- x/cert/handler/msg_server.go | 2 +- x/cert/keeper/grpc_query.go | 2 +- x/cert/keeper/grpc_query_test.go | 4 +- x/cert/keeper/keeper_test.go | 2 +- x/cert/keeper/key.go | 2 +- x/cert/module.go | 21 +- x/cert/utils/key_pair_manager.go | 2 +- x/cert/utils/utils.go | 2 +- x/deployment/alias.go | 2 +- x/deployment/genesis.go | 2 +- x/deployment/handler/handler.go | 2 +- x/deployment/handler/handler_test.go | 12 +- x/deployment/handler/server.go | 2 +- x/deployment/keeper/grpc_query.go | 2 +- x/deployment/keeper/grpc_query_test.go | 8 +- x/deployment/keeper/keeper_test.go | 4 +- x/deployment/module.go | 6 +- x/deployment/simulation/operations.go | 6 +- x/escrow/genesis.go | 2 +- x/escrow/handler/handler.go | 2 +- x/escrow/handler/server.go | 2 +- x/escrow/keeper/grpc_query.go | 2 +- x/escrow/keeper/grpc_query_test.go | 6 +- x/escrow/keeper/keeper_test.go | 2 +- x/escrow/module.go | 19 +- x/escrow/query/querier.go | 2 +- x/market/alias.go | 2 +- x/market/client/rest/params.go | 2 +- x/market/client/rest/rest.go | 2 +- x/market/genesis.go | 4 +- x/market/handler/handler_test.go | 8 +- x/market/handler/keepers.go | 2 +- x/market/keeper/grpc_query.go | 4 +- x/market/keeper/grpc_query_test.go | 4 +- x/market/keeper/keeper.go | 2 +- x/market/keeper/keeper_test.go | 4 +- x/market/module.go | 12 +- x/market/query/path.go | 2 +- x/market/simulation/operations.go | 6 +- x/market/simulation/utils.go | 2 +- x/oracle/alias.go | 12 + x/oracle/genesis.go | 39 + x/oracle/handler/server.go | 39 + x/oracle/keeper/grpc_query.go | 35 + x/oracle/keeper/keeper.go | 98 ++ x/oracle/module.go | 182 +++ x/oracle/simulation/decoder.go | 17 + x/oracle/simulation/genesis.go | 16 + x/oracle/simulation/proposals.go | 42 + x/provider/alias.go | 2 +- x/provider/genesis.go | 2 +- x/provider/handler/handler.go | 4 +- x/provider/handler/handler_test.go | 8 +- x/provider/handler/server.go | 4 +- x/provider/keeper/grpc_query_test.go | 6 +- x/provider/keeper/keeper_test.go | 4 +- x/provider/module.go | 13 +- x/provider/simulation/operations.go | 8 +- x/take/genesis.go | 2 +- x/take/handler/server.go | 2 +- x/take/module.go | 19 +- x/wasm/alias.go | 12 + x/wasm/genesis.go | 50 + x/wasm/handler/server.go | 39 + x/wasm/keeper/grpc_query.go | 30 + x/wasm/keeper/keeper.go | 102 ++ x/wasm/keeper/msg_filter.go | 209 +++ x/wasm/module.go | 182 +++ x/wasm/simulation/decoder.go | 17 + x/wasm/simulation/genesis.go | 16 + x/wasm/simulation/proposals.go | 42 + 182 files changed, 4572 insertions(+), 2075 deletions(-) rename _build/{Dockerfile.akash => akash.Dockerfile} (100%) rename _build/{Dockerfile.test => test.Dockerfile} (100%) create mode 100644 _run/.env create mode 100644 _run/.envrc create mode 100644 _run/.envrc_run create mode 100644 _run/common-base.mk create mode 100644 _run/common-commands.mk create mode 100644 _run/common.mk create mode 120000 _run/node/.envrc create mode 100644 _run/node/.gitignore create mode 100644 _run/node/Makefile create mode 100644 cmd/akash/cmd/config.go create mode 100644 contracts/price-oracle/Cargo.lock create mode 100644 contracts/price-oracle/Cargo.toml create mode 100644 contracts/price-oracle/artifacts/checksums.txt create mode 100644 contracts/price-oracle/artifacts/price_oracle.wasm create mode 100644 contracts/price-oracle/src/bin/schema.rs create mode 100644 contracts/price-oracle/src/contract.rs create mode 100644 contracts/price-oracle/src/error.rs create mode 100644 contracts/price-oracle/src/lib.rs create mode 100644 contracts/price-oracle/src/msg.rs create mode 100644 contracts/price-oracle/src/querier.rs create mode 100644 contracts/price-oracle/src/state.rs create mode 100644 make/cosmwasm.mk delete mode 100644 tests/upgrade/config-v0.24.0.tmpl.json create mode 100644 tests/upgrade/testdata/hackatom.wasm delete mode 100644 upgrades/software/v1.0.0/audit.go delete mode 100644 upgrades/software/v1.0.0/cert.go delete mode 100644 upgrades/software/v1.0.0/deployment.go delete mode 100644 upgrades/software/v1.0.0/escrow.go delete mode 100644 upgrades/software/v1.0.0/init.go delete mode 100644 upgrades/software/v1.0.0/market.go delete mode 100644 upgrades/software/v1.0.0/provider.go delete mode 100644 upgrades/software/v1.0.0/take.go delete mode 100644 upgrades/software/v1.0.0/upgrade.go delete mode 100644 upgrades/software/v1.1.0/upgrade.go rename upgrades/software/{v1.1.0 => v2.0.0}/init.go (55%) create mode 100644 upgrades/software/v2.0.0/upgrade.go create mode 100644 wasmvm.go create mode 100644 x/oracle/alias.go create mode 100644 x/oracle/genesis.go create mode 100644 x/oracle/handler/server.go create mode 100644 x/oracle/keeper/grpc_query.go create mode 100644 x/oracle/keeper/keeper.go create mode 100644 x/oracle/module.go create mode 100644 x/oracle/simulation/decoder.go create mode 100644 x/oracle/simulation/genesis.go create mode 100644 x/oracle/simulation/proposals.go create mode 100644 x/wasm/alias.go create mode 100644 x/wasm/genesis.go create mode 100644 x/wasm/handler/server.go create mode 100644 x/wasm/keeper/grpc_query.go create mode 100644 x/wasm/keeper/keeper.go create mode 100644 x/wasm/keeper/msg_filter.go create mode 100644 x/wasm/module.go create mode 100644 x/wasm/simulation/decoder.go create mode 100644 x/wasm/simulation/genesis.go create mode 100644 x/wasm/simulation/proposals.go diff --git a/.env b/.env index da7aa6deaf..399b76c9eb 100644 --- a/.env +++ b/.env @@ -6,6 +6,7 @@ ROOT_DIR=${AKASH_ROOT} AKASH_DEVCACHE_BASE=${AKASH_ROOT}/.cache AKASH_DEVCACHE=${AKASH_DEVCACHE_BASE} AKASH_DEVCACHE_BIN=${AKASH_DEVCACHE}/bin +AKASH_DEVCACHE_LIB=${AKASH_DEVCACHE}/lib AKASH_DEVCACHE_INCLUDE=${AKASH_DEVCACHE}/include AKASH_DEVCACHE_VERSIONS=${AKASH_DEVCACHE}/versions AKASH_DEVCACHE_NODE_MODULES=${AKASH_DEVCACHE} diff --git a/.envrc b/.envrc index 9ea99da26f..32a57a9a33 100644 --- a/.envrc +++ b/.envrc @@ -99,8 +99,8 @@ export GOTOOLCHAIN export GOTOOLCHAIN_SEMVER export GOWORK -PATH_add "$AKASH_DEVCACHE_NODE_BIN" PATH_add "$AKASH_DEVCACHE_BIN" +PATH_add "$AKASH_DEVCACHE_NODE_BIN" AKASH_DIRENV_SET=1 AKASH=$AKASH_DEVCACHE_BIN/akash diff --git a/.github/actions/setup-ubuntu/action.yaml b/.github/actions/setup-ubuntu/action.yaml index da66e929c4..fe28e200a3 100644 --- a/.github/actions/setup-ubuntu/action.yaml +++ b/.github/actions/setup-ubuntu/action.yaml @@ -14,7 +14,7 @@ runs: - name: Install dependencies # Shell must explicitly specify the shell for each step. https://github.com/orgs/community/discussions/18597 shell: bash - run: sudo apt install -y make direnv unzip lz4 wget curl npm jq pv coreutils libudev-dev + run: sudo apt install -y make direnv unzip lz4 wget curl npm jq pv coreutils musl-tools libudev-dev - name: Setup npm uses: actions/setup-node@v4 with: diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 55cf9ada74..0aa878676f 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -47,7 +47,7 @@ jobs: uses: actions/checkout@v4 - name: Setup environment uses: ./.github/actions/setup-ubuntu - - run: make bins + - run: BUILD_OPTIONS=static-link make bins - run: make docker-image tests: diff --git a/.goreleaser-docker.yaml b/.goreleaser-docker.yaml index 673e28e108..3516eb8d8d 100644 --- a/.goreleaser-docker.yaml +++ b/.goreleaser-docker.yaml @@ -24,10 +24,10 @@ builds: - "-tags={{ .Env.BUILD_TAGS }}" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" - - -extldflags "-lc -lrt -lpthread" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external + - -extldflags "-L./.cache/lib -lwasmvm_muslc.x86_64 -Wl,-z,muldefs -lm -lrt -lc" - id: akash-linux-arm64 binary: akash main: ./cmd/akash @@ -43,12 +43,12 @@ builds: - "-tags={{ .Env.BUILD_TAGS }}" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" - - -extldflags "-lc -lrt -lpthread" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external + - -extldflags "-L./.cache/lib -lwasmvm_muslc.aarch64 -Wl,-z,muldefs -lm -lrt -lc" dockers: - - dockerfile: _build/Dockerfile.akash + - dockerfile: _build/akash.Dockerfile use: buildx goarch: amd64 goos: linux @@ -63,7 +63,7 @@ dockers: - --label=org.opencontainers.image.revision={{ .FullCommit }} image_templates: - '{{ .Env.DOCKER_IMAGE }}:latest-amd64' - - dockerfile: _build/Dockerfile.akash + - dockerfile: _build/akash.Dockerfile use: buildx goarch: arm64 goos: linux diff --git a/.goreleaser-test-bins.yaml b/.goreleaser-test-bins.yaml index c7c8aef50a..f4520e76a0 100644 --- a/.goreleaser-test-bins.yaml +++ b/.goreleaser-test-bins.yaml @@ -20,14 +20,16 @@ builds: env: - CC=o64-clang - CXX=o64-clang++ + - CGO_CFLAGS=-mmacosx-version-min=10.12 + - CGO_LDFLAGS=-L./.cache/lib -mmacosx-version-min=10.12 flags: - "-mod={{ .Env.MOD }}" - - "-tags={{ .Env.BUILD_TAGS }}" + - "-tags={{ .Env.BUILD_TAGS }} static_wasm" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external - id: akash-darwin-arm64 binary: akash main: ./cmd/akash @@ -38,14 +40,16 @@ builds: env: - CC=oa64-clang - CXX=oa64-clang++ + - CGO_CFLAGS=-mmacosx-version-min=10.12 + - CGO_LDFLAGS=-L./.cache/lib -mmacosx-version-min=10.12 flags: - "-mod={{ .Env.MOD }}" - - "-tags={{ .Env.BUILD_TAGS }}" + - "-tags={{ .Env.BUILD_TAGS }} static_wasm" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external - id: akash-linux-amd64 binary: akash main: ./cmd/akash @@ -61,10 +65,10 @@ builds: - "-tags={{ .Env.BUILD_TAGS }}" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" - - -extldflags "-lc -lrt -lpthread" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external + - -extldflags "-L./.cache/lib -lwasmvm_muslc.x86_64 -Wl,-z,muldefs -lm -lrt -lc" - id: akash-linux-arm64 binary: akash main: ./cmd/akash @@ -80,10 +84,10 @@ builds: - "-tags={{ .Env.BUILD_TAGS }}" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" - - -extldflags "-lc -lrt -lpthread" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external + - -extldflags "-L./.cache/lib -lwasmvm_muslc.aarch64 -Wl,-z,muldefs -lm -lrt -lc" universal_binaries: - id: akash-darwin-universal ids: diff --git a/.goreleaser.yaml b/.goreleaser.yaml index eae4a1f73f..46af3213ef 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -20,14 +20,16 @@ builds: env: - CC=o64-clang - CXX=o64-clang++ + - CGO_CFLAGS=-mmacosx-version-min=10.12 flags: - "-mod={{ .Env.MOD }}" - - "-tags={{ .Env.BUILD_TAGS }}" + - "-tags={{ .Env.BUILD_TAGS }} static_wasm" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external + - -extldflags "-L./.cache/lib -mmacosx-version-min=10.12" - id: akash-darwin-arm64 binary: akash main: ./cmd/akash @@ -38,14 +40,16 @@ builds: env: - CC=oa64-clang - CXX=oa64-clang++ + - CGO_CFLAGS=-mmacosx-version-min=10.12 flags: - "-mod={{ .Env.MOD }}" - - "-tags={{ .Env.BUILD_TAGS }}" + - "-tags={{ .Env.BUILD_TAGS }} static_wasm" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external + - -extldflags "-L./.cache/lib -mmacosx-version-min=10.12" - id: akash-linux-amd64 binary: akash main: ./cmd/akash @@ -61,10 +65,10 @@ builds: - "-tags={{ .Env.BUILD_TAGS }}" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" - - -extldflags "-lc -lrt -lpthread" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external + - -extldflags "-L./.cache/lib -lwasmvm_muslc.x86_64 -Wl,-z,muldefs -lm -lrt -lc" - id: akash-linux-arm64 binary: akash main: ./cmd/akash @@ -80,10 +84,10 @@ builds: - "-tags={{ .Env.BUILD_TAGS }}" - -trimpath ldflags: - - "{{ .Env.BUILD_VARS }}" - - "{{ .Env.STRIP_FLAGS }}" - - "-linkmode={{ .Env.LINKMODE }}" - - -extldflags "-lc -lrt -lpthread" + - "{{ .Env.BUILD_LDFLAGS }}" + - -s -w + - -linkmode=external + - -extldflags "-L./.cache/lib -lwasmvm_muslc.aarch64 -Wl,-z,muldefs -lm -lrt -lc" universal_binaries: - id: akash-darwin-universal ids: @@ -121,7 +125,7 @@ checksum: name_template: "akash_{{ .Version }}_checksums.txt" dockers: - - dockerfile: _build/Dockerfile.akash + - dockerfile: _build/akash.Dockerfile use: buildx goarch: amd64 goos: linux @@ -138,7 +142,7 @@ dockers: - '{{ .Env.DOCKER_IMAGE }}:{{ .ShortCommit }}-amd64' - '{{ .Env.DOCKER_IMAGE }}:{{ replace .Version "+" "-" }}-amd64' - '{{ .Env.DOCKER_IMAGE }}:{{if eq .Env.STABLE "true"}}stable{{else}}latest{{end}}-amd64' - - dockerfile: _build/Dockerfile.akash + - dockerfile: _build/akash.Dockerfile use: buildx goarch: arm64 goos: linux diff --git a/Makefile b/Makefile index ac69d70412..48199894b4 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,6 @@ APP_DIR := ./app GOBIN ?= $(shell go env GOPATH)/bin -KIND_APP_IP ?= $(shell make -sC _run/kube kind-k8s-ip) -KIND_APP_PORT ?= $(shell make -sC _run/kube app-http-port) -KIND_VARS ?= KUBE_INGRESS_IP="$(KIND_APP_IP)" KUBE_INGRESS_PORT="$(KIND_APP_PORT)" - include make/init.mk .DEFAULT_GOAL := bins @@ -29,39 +25,70 @@ GOMOD ?= readonly BUILD_TAGS ?= osusergo,netgo,hidraw,ledger GORELEASER_STRIP_FLAGS ?= + ifeq ($(IS_MAINNET), true) ifeq ($(IS_PREREL), false) IS_STABLE := true endif endif +GOMOD ?= readonly + +ifneq ($(UNAME_OS),Darwin) +BUILD_OPTIONS ?= static-link +endif + +BUILD_TAGS := osusergo netgo ledger muslc gcc +DB_BACKEND := goleveldb +BUILD_FLAGS := + +GORELEASER_STRIP_FLAGS ?= + +ifeq (cleveldb,$(findstring cleveldb,$(BUILD_OPTIONS))) + DB_BACKEND=cleveldb +else ifeq (rocksdb,$(findstring rocksdb,$(BUILD_OPTIONS))) + DB_BACKEND=rocksdb +else ifeq (goleveldb,$(findstring goleveldb,$(BUILD_OPTIONS))) + DB_BACKEND=goleveldb +endif + ifneq (,$(findstring cgotrace,$(BUILD_OPTIONS))) - BUILD_TAGS := $(BUILD_TAGS),cgotrace + BUILD_TAGS += cgotrace endif -GORELEASER_BUILD_VARS := \ --X github.com/cosmos/cosmos-sdk/version.Name=akash \ --X github.com/cosmos/cosmos-sdk/version.AppName=akash \ --X github.com/cosmos/cosmos-sdk/version.BuildTags=\"$(BUILD_TAGS)\" \ --X github.com/cosmos/cosmos-sdk/version.Version=$(RELEASE_TAG) \ --X github.com/cosmos/cosmos-sdk/version.Commit=$(GIT_HEAD_COMMIT_LONG) +build_tags := $(strip $(BUILD_TAGS)) +build_tags_cs := $(subst $(WHITESPACE),$(COMMA),$(build_tags)) -ldflags = -linkmode=$(GO_LINKMODE) -X github.com/cosmos/cosmos-sdk/version.Name=akash \ +ldflags := -X github.com/cosmos/cosmos-sdk/version.Name=akash \ -X github.com/cosmos/cosmos-sdk/version.AppName=akash \ --X github.com/cosmos/cosmos-sdk/version.BuildTags="$(BUILD_TAGS)" \ +-X github.com/cosmos/cosmos-sdk/version.BuildTags="$(build_tags_cs)" \ -X github.com/cosmos/cosmos-sdk/version.Version=$(shell git describe --tags | sed 's/^v//') \ --X github.com/cosmos/cosmos-sdk/version.Commit=$(GIT_HEAD_COMMIT_LONG) +-X github.com/cosmos/cosmos-sdk/version.Commit=$(GIT_HEAD_COMMIT_LONG) \ +-X github.com/cosmos/cosmos-sdk/types.DBBackend=$(DB_BACKEND) + +GORELEASER_LDFLAGS := $(ldflags) + +ldflags += -linkmode=external + +ifeq (static-link,$(findstring static-link,$(BUILD_OPTIONS))) + ldflags += -extldflags "-L$(AKASH_DEVCACHE_LIB) -lm -Wl,-z,muldefs -static" +else + ldflags += -extldflags "-L$(AKASH_DEVCACHE_LIB)" +endif # check for nostrip option ifeq (,$(findstring nostrip,$(BUILD_OPTIONS))) - ldflags += -s -w - GORELEASER_STRIP_FLAGS += -s -w + ldflags += -s -w + BUILD_FLAGS += -trimpath endif ldflags += $(LDFLAGS) ldflags := $(strip $(ldflags)) -BUILD_FLAGS := -mod=$(GOMOD) -tags='$(BUILD_TAGS)' -ldflags '$(ldflags)' +GORELEASER_TAGS := $(BUILD_TAGS) +GORELEASER_FLAGS := $(BUILD_FLAGS) -mod=$(GOMOD) -tags='$(build_tags)' + +BUILD_FLAGS += -mod=$(GOMOD) -tags='$(build_tags_cs)' -ldflags '$(ldflags)' .PHONY: all all: build bins @@ -70,6 +97,7 @@ all: build bins clean: cache-clean rm -f $(BINS) +include make/cosmwasm.mk include make/releasing.mk include make/mod.mk include make/lint.mk diff --git a/_build/Dockerfile.akash b/_build/akash.Dockerfile similarity index 100% rename from _build/Dockerfile.akash rename to _build/akash.Dockerfile diff --git a/_build/Dockerfile.test b/_build/test.Dockerfile similarity index 100% rename from _build/Dockerfile.test rename to _build/test.Dockerfile diff --git a/_run/.env b/_run/.env new file mode 100644 index 0000000000..2ce77d5898 --- /dev/null +++ b/_run/.env @@ -0,0 +1,7 @@ +AKASH_KEYRING_BACKEND=test +AKASH_GAS_ADJUSTMENT=2 +AKASH_CHAIN_ID=local +AKASH_YES=true +AKASH_GAS_PRICES=0.025uakt +AKASH_GAS=auto +AKASH_NODE=http://localhost:26657 diff --git a/_run/.envrc b/_run/.envrc new file mode 100644 index 0000000000..5d87c0e683 --- /dev/null +++ b/_run/.envrc @@ -0,0 +1,11 @@ +source_up .envrc + +if ! has grpcurl ; then + echo -e "\033[31mgrpcurl is not installed"; exit 1 +fi + +if ! has tqdm ; then + echo -e "\033[31mtqdm is not installed. https://github.com/tqdm/tqdm"; exit 1 +fi + +dotenv .env diff --git a/_run/.envrc_run b/_run/.envrc_run new file mode 100644 index 0000000000..3c3ace4a66 --- /dev/null +++ b/_run/.envrc_run @@ -0,0 +1,8 @@ +source_up .envrc + +AKASH_RUN_NAME=$(basename "$(pwd)") +AKASH_RUN_DIR="${AKASH_RUN}/${AKASH_RUN_NAME}" + +export AKASH_HOME="${AKASH_RUN_DIR}/.akash" +export AKASH_RUN_NAME +export AKASH_RUN_DIR diff --git a/_run/common-base.mk b/_run/common-base.mk new file mode 100644 index 0000000000..521103c216 --- /dev/null +++ b/_run/common-base.mk @@ -0,0 +1,29 @@ +include $(abspath $(CURDIR)/../../make/init.mk) + +ifeq ($(AKASH_RUN_NAME),) +$(error "AKASH_RUN_NAME is not set") +endif + +ifeq ($(AKASH_RUN_DIR),) +$(error "AKASH_RUN_DIR is not set") +endif + +ifneq ($(AKASH_HOME),) +ifneq ($(DIRENV_FILE),$(CURDIR)/.envrc) +$(error "AKASH_HOME is set by the upper dir (probably in ~/.bashrc|~/.zshrc), \ +but direnv does not seem to be configured. \ +Ensure direnv is installed and hooked to your shell profile. Refer to the documentation for details. \ +") +endif +else +$(error "AKASH_HOME is not set") +endif + +.PHONY: akash +akash: +ifneq ($(SKIP_BUILD), true) + make -C $(AKASH_ROOT) akash +endif + +.PHONY: bins +bins: akash diff --git a/_run/common-commands.mk b/_run/common-commands.mk new file mode 100644 index 0000000000..5166f723f5 --- /dev/null +++ b/_run/common-commands.mk @@ -0,0 +1,47 @@ +KEY_NAME ?= main + +.PHONY: multisig-send +multisig-send: + $(AKASH) tx send \ + "$(shell $(AKASH) $(KEY_OPTS) keys show "$(MULTISIG_KEY)" -a)" \ + "$(shell $(AKASH) $(KEY_OPTS) keys show "$(KEY_NAME)" -a)" \ + 1000000uakt \ + --generate-only \ + > "$(AKASH_HOME)/multisig-tx.json" + $(AKASH) tx sign \ + "$(AKASH_HOME)/multisig-tx.json" \ + --multisig "$(shell $(AKASH) $(KEY_OPTS) keys show "$(MULTISIG_KEY)" -a)" \ + --from "main" \ + > "$(AKASH_HOME)/multisig-sig-main.json" + $(AKASH) tx sign \ + "$(AKASH_HOME)/multisig-tx.json" \ + --multisig "$(shell $(AKASH) $(KEY_OPTS) keys show "$(MULTISIG_KEY)" -a)" \ + --from "other" \ + > "$(AKASH_HOME)/multisig-sig-other.json" + $(AKASH) tx multisign \ + "$(AKASH_HOME)/multisig-tx.json" \ + "$(MULTISIG_KEY)" \ + "$(AKASH_HOME)/multisig-sig-main.json" \ + "$(AKASH_HOME)/multisig-sig-other.json" \ + > "$(AKASH_HOME)/multisig-final.json" + $(AKASH) $(CHAIN_OPTS) tx broadcast "$(AKASH_HOME)/multisig-final.json" + +.PHONY: akash-node-ready +akash-node-ready: SHELL=$(BASH_PATH) +akash-node-ready: + @( \ + max_retry=15; \ + counter=0; \ + while [[ $$counter -lt $$max_retry ]]; do \ + read block < <(curl -s $(AKASH_NODE)/status | jq -r '.result.sync_info.latest_block_height' 2> /dev/null); \ + if [[ $$? -ne 0 || $$block -lt 1 ]]; then \ + echo "unable to get node status. sleep for 1s"; \ + ((counter++)); \ + sleep 1; \ + else \ + echo "latest block height: $${block}"; \ + exit 0; \ + fi \ + done; \ + exit 1 \ + ) diff --git a/_run/common.mk b/_run/common.mk new file mode 100644 index 0000000000..d7422131fa --- /dev/null +++ b/_run/common.mk @@ -0,0 +1,143 @@ +OPTIONS ?= + +SKIP_BUILD := false + +# check for nostrip option +ifneq (,$(findstring nobuild,$(OPTIONS))) + SKIP_BUILD := true +endif + +include ../common-base.mk + +# https://stackoverflow.com/a/7531247 +# https://www.gnu.org/software/make/manual/make.html#Flavors +null := +space := $(null) # +comma := , + +export AKASH_KEYRING_BACKEND = test +export AKASH_GAS_ADJUSTMENT = 2 +export AKASH_CHAIN_ID = local +export AKASH_YES = true +export AKASH_GAS_PRICES = 0.025uakt +export AKASH_GAS = auto +export AKASH_NODE = http://localhost:26657 + +AKASH_INIT := $(AKASH_RUN_DIR)/.akash-init + +KEY_OPTS := --keyring-backend=$(AKASH_KEYRING_BACKEND) +GENESIS_PATH := $(AKASH_HOME)/config/genesis.json + +CHAIN_MIN_DEPOSIT := 10000000000000 +CHAIN_ACCOUNT_DEPOSIT := $(shell echo $$(($(CHAIN_MIN_DEPOSIT) * 10))) +CHAIN_VALIDATOR_DELEGATE := $(shell echo $$(($(CHAIN_MIN_DEPOSIT) / 2))) +CHAIN_TOKEN_DENOM := uakt + +KEY_NAMES := main provider validator other + +MULTISIG_KEY := msig +MULTISIG_SIGNERS := main other + +GENESIS_ACCOUNTS := $(KEY_NAMES) $(MULTISIG_KEY) + +CLIENT_CERTS := main validator other +SERVER_CERTS := provider + +.PHONY: init +init: bins akash-init + +$(AP_RUN_DIR): + mkdir -p $@ + +$(AKASH_HOME): + mkdir -p $@ + +$(AKASH_INIT): $(AKASH_HOME) client-init node-init + touch $@ + +.INTERMEDIATE: akash-init +akash-init: $(AKASH_INIT) + +.INTERMEDIATE: client-init +client-init: client-init-keys + +.INTERMEDIATE: client-init-keys +client-init-keys: $(patsubst %,client-init-key-%,$(KEY_NAMES)) client-init-key-multisig + +.INTERMEDIATE: $(patsubst %,client-init-key-%,$(KEY_NAMES)) +client-init-key-%: + $(AKASH) keys add "$(@:client-init-key-%=%)" + +.INTERMEDIATE: client-init-key-multisig +client-init-key-multisig: + $(AKASH) keys add \ + "$(MULTISIG_KEY)" \ + --multisig "$(subst $(space),$(comma),$(strip $(MULTISIG_SIGNERS)))" \ + --multisig-threshold 2 + +.NOTPARALLEL: node-init +.INTERMEDIATE: node-init +node-init: node-init-genesis node-init-genesis-accounts node-init-genesis-certs node-init-gentx node-init-finalize + +.INTERMEDIATE: node-init-genesis +node-init-genesis: + $(AKASH) genesis init node0 + cp "$(GENESIS_PATH)" "$(GENESIS_PATH).orig" + cat "$(GENESIS_PATH).orig" | \ + jq -M '.app_state.gov.voting_params.voting_period = "30s"' | \ + jq -rM '(..|objects|select(has("denom"))).denom |= "$(CHAIN_TOKEN_DENOM)"' | \ + jq -rM '(..|objects|select(has("bond_denom"))).bond_denom |= "$(CHAIN_TOKEN_DENOM)"' | \ + jq -rM '(..|objects|select(has("mint_denom"))).mint_denom |= "$(CHAIN_TOKEN_DENOM)"' > \ + "$(GENESIS_PATH)" + +.INTERMEDIATE: node-init-genesis-certs +node-init-genesis-certs: $(patsubst %,node-init-genesis-client-cert-%,$(CLIENT_CERTS)) $(patsubst %,node-init-genesis-server-cert-%,$(SERVER_CERTS)) + +.INTERMEDIATE: $(patsubst %,node-init-genesis-client-cert-%,$(CLIENT_CERTS)) +node-init-genesis-client-cert-%: + $(AKASH) tx cert generate client --from=$* + $(AKASH) tx cert publish client --to-genesis=true --from=$* + +.INTERMEDIATE: $(patsubst %,node-init-genesis-server-cert-%,$(SERVER_CERTS)) +node-init-genesis-server-cert-%: + $(AKASH) tx cert generate server localhost akash-provider.localhost --from=$* + $(AKASH) tx cert publish server --to-genesis=true --from=$* + +.INTERMEDIATE: node-init-genesis-accounts +node-init-genesis-accounts: $(patsubst %,node-init-genesis-account-%,$(GENESIS_ACCOUNTS)) + $(AKASH) genesis validate + +.INTERMEDIATE: $(patsubst %,node-init-genesis-account-%,$(GENESIS_ACCOUNTS)) +node-init-genesis-account-%: + $(AKASH) genesis add-account \ + "$(shell $(AKASH) $(KEY_OPTS) keys show "$(@:node-init-genesis-account-%=%)" -a)" \ + "$(CHAIN_MIN_DEPOSIT)$(CHAIN_TOKEN_DENOM)" + +.INTERMEDIATE: node-init-gentx +node-init-gentx: + $(AKASH) genesis gentx validator "$(CHAIN_VALIDATOR_DELEGATE)$(CHAIN_TOKEN_DENOM)" --min-self-delegation=1 --gas=auto --gas-prices=0.025uakt + +.INTERMEDIATE: node-init-finalize +node-init-finalize: + $(AKASH) genesis collect + $(AKASH) genesis validate + +.PHONY: node-run +node-run: + $(AKASH) start --minimum-gas-prices=$(AKASH_GAS_PRICES) + +.PHONY: node-status +node-status: + $(AKASH) status + +.PHONY: rest-server-run +rest-server-run: + $(AKASH) rest-server + +.PHONY: clean +clean: clean-$(AKASH_RUN_NAME) + rm -rf "$(AKASH_RUN)/$(AKASH_RUN_NAME)" + +.PHONY: rosetta-run +rosetta-run: + $(AKASH) rosetta --addr localhost:8080 --grpc localhost:9090 --network=$(AKASH_CHAIN_ID) --blockchain=akash diff --git a/_run/node/.envrc b/_run/node/.envrc new file mode 120000 index 0000000000..a4526206d7 --- /dev/null +++ b/_run/node/.envrc @@ -0,0 +1 @@ +../.envrc_run \ No newline at end of file diff --git a/_run/node/.gitignore b/_run/node/.gitignore new file mode 100644 index 0000000000..e934adfd1b --- /dev/null +++ b/_run/node/.gitignore @@ -0,0 +1 @@ +cache/ diff --git a/_run/node/Makefile b/_run/node/Makefile new file mode 100644 index 0000000000..bce7e8a5a7 --- /dev/null +++ b/_run/node/Makefile @@ -0,0 +1,5 @@ +include ../common.mk +include ../common-commands.mk + +.PHONY: clean-node +clean-node: diff --git a/app/app.go b/app/app.go index 55873de283..22595bca9d 100644 --- a/app/app.go +++ b/app/app.go @@ -11,8 +11,6 @@ import ( "github.com/gorilla/mux" "github.com/rakyll/statik/fs" "github.com/spf13/cast" - emodule "pkg.akt.dev/go/node/escrow/module" - "pkg.akt.dev/go/sdkutil" abci "github.com/cometbft/cometbft/abci/types" tmjson "github.com/cometbft/cometbft/libs/json" @@ -27,6 +25,9 @@ import ( evidencetypes "cosmossdk.io/x/evidence/types" "cosmossdk.io/x/feegrant" upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/CosmWasm/wasmd/x/wasm" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -64,14 +65,17 @@ import ( audittypes "pkg.akt.dev/go/node/audit/v1" certtypes "pkg.akt.dev/go/node/cert/v1" deploymenttypes "pkg.akt.dev/go/node/deployment/v1" + emodule "pkg.akt.dev/go/node/escrow/module" markettypes "pkg.akt.dev/go/node/market/v1" providertypes "pkg.akt.dev/go/node/provider/v1beta4" taketypes "pkg.akt.dev/go/node/take/v1" + "pkg.akt.dev/go/sdkutil" - apptypes "pkg.akt.dev/node/app/types" - utypes "pkg.akt.dev/node/upgrades/types" + apptypes "pkg.akt.dev/node/v2/app/types" + utypes "pkg.akt.dev/node/v2/upgrades/types" + awasm "pkg.akt.dev/node/v2/x/wasm" // unnamed import of statik for swagger UI support - _ "pkg.akt.dev/node/client/docs/statik" + _ "pkg.akt.dev/node/v2/client/docs/statik" ) const ( @@ -130,6 +134,14 @@ func NewApp( homePath = DefaultHome } + var wasmOpts []wasmkeeper.Option + + if val := appOpts.Get("wasm"); val != nil { + if vl, valid := val.([]wasmkeeper.Option); valid { + wasmOpts = append(wasmOpts, vl...) + } + } + app := &AkashApp{ BaseApp: bapp, App: &apptypes.App{ @@ -143,6 +155,20 @@ func NewApp( invCheckPeriod: invCheckPeriod, } + wasmDir := filepath.Join(homePath, "wasm") + wasmConfig, err := wasm.ReadNodeConfig(appOpts) + if err != nil { + panic(fmt.Sprintf("error while reading wasm config: %s", err)) + } + + // Memory limits - prevent DoS + wasmConfig.MemoryCacheSize = 100 // 100 MB max + // Query gas limit - prevent expensive queries + wasmConfig.SmartQueryGasLimit = 3_000_000 + // Debug mode - MUST be false in production + // Uncomment this for debugging contracts. In the future this could be made into a param passed by the tests + wasmConfig.ContractDebugMode = false + app.InitSpecialKeepers( app.cdc, aminoCdc, @@ -156,6 +182,9 @@ func NewApp( encodingConfig, app.BaseApp, ModuleAccountPerms(), + wasmDir, + wasmConfig, + wasmOpts, app.BlockedAddrs(), invCheckPeriod, ) @@ -197,7 +226,7 @@ func NewApp( app.MM.SetOrderInitGenesis(OrderInitGenesis(app.MM.ModuleNames())...) app.Configurator = module.NewConfigurator(app.AppCodec(), app.MsgServiceRouter(), app.GRPCQueryRouter()) - err := app.MM.RegisterServices(app.Configurator) + err = app.MM.RegisterServices(app.Configurator) if err != nil { panic(err) } @@ -289,6 +318,10 @@ func orderBeginBlockers(_ []string) []string { ibctm.ModuleName, ibchost.ModuleName, feegrant.ModuleName, + // akash wasm module must be prior wasm + awasm.ModuleName, + // wasm after ibc transfer + wasmtypes.ModuleName, } } @@ -318,6 +351,10 @@ func OrderEndBlockers(_ []string) []string { transfertypes.ModuleName, ibchost.ModuleName, feegrant.ModuleName, + // akash wasm module must be prior wasm + awasm.ModuleName, + // wasm after ibc transfer + wasmtypes.ModuleName, } } diff --git a/app/app_configure.go b/app/app_configure.go index f59ebcabde..2452babbcb 100644 --- a/app/app_configure.go +++ b/app/app_configure.go @@ -4,6 +4,7 @@ import ( evidencetypes "cosmossdk.io/x/evidence/types" "cosmossdk.io/x/feegrant" upgradetypes "cosmossdk.io/x/upgrade/types" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/cosmos/cosmos-sdk/types/module" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" @@ -24,13 +25,15 @@ import ( audittypes "pkg.akt.dev/go/node/audit/v1" taketypes "pkg.akt.dev/go/node/take/v1" - "pkg.akt.dev/node/x/audit" - "pkg.akt.dev/node/x/cert" - "pkg.akt.dev/node/x/deployment" - "pkg.akt.dev/node/x/escrow" - "pkg.akt.dev/node/x/market" - "pkg.akt.dev/node/x/provider" - "pkg.akt.dev/node/x/take" + "pkg.akt.dev/node/v2/x/audit" + "pkg.akt.dev/node/v2/x/cert" + "pkg.akt.dev/node/v2/x/deployment" + "pkg.akt.dev/node/v2/x/escrow" + "pkg.akt.dev/node/v2/x/market" + oracle "pkg.akt.dev/node/v2/x/oracle" + "pkg.akt.dev/node/v2/x/provider" + "pkg.akt.dev/node/v2/x/take" + awasm "pkg.akt.dev/node/v2/x/wasm" ) func akashModuleBasics() []module.AppModuleBasic { @@ -42,6 +45,8 @@ func akashModuleBasics() []module.AppModuleBasic { provider.AppModuleBasic{}, audit.AppModuleBasic{}, cert.AppModuleBasic{}, + oracle.AppModuleBasic{}, + awasm.AppModuleBasic{}, } } @@ -78,5 +83,8 @@ func OrderInitGenesis(_ []string) []string { provider.ModuleName, market.ModuleName, genutiltypes.ModuleName, + oracle.ModuleName, + awasm.ModuleName, + wasmtypes.ModuleName, } } diff --git a/app/config.go b/app/config.go index 527ff0aa96..3784d9fc48 100644 --- a/app/config.go +++ b/app/config.go @@ -4,6 +4,7 @@ import ( "cosmossdk.io/x/evidence" feegrantmodule "cosmossdk.io/x/feegrant/module" "cosmossdk.io/x/upgrade" + "github.com/CosmWasm/wasmd/x/wasm" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth/vesting" @@ -60,6 +61,7 @@ var mbasics = module.NewBasicManager( transfer.AppModuleBasic{}, vesting.AppModuleBasic{}, feegrantmodule.AppModuleBasic{}, + wasm.AppModuleBasic{}, }, // akash akashModuleBasics()..., diff --git a/app/modules.go b/app/modules.go index a2287bf49a..99547a5b04 100644 --- a/app/modules.go +++ b/app/modules.go @@ -4,6 +4,8 @@ import ( "cosmossdk.io/x/evidence" feegrantmodule "cosmossdk.io/x/feegrant/module" "cosmossdk.io/x/upgrade" + "github.com/CosmWasm/wasmd/x/wasm" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" addresscodec "github.com/cosmos/cosmos-sdk/codec/address" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" @@ -32,13 +34,15 @@ import ( "pkg.akt.dev/go/sdkutil" - "pkg.akt.dev/node/x/audit" - "pkg.akt.dev/node/x/cert" - "pkg.akt.dev/node/x/deployment" - "pkg.akt.dev/node/x/escrow" - "pkg.akt.dev/node/x/market" - "pkg.akt.dev/node/x/provider" - "pkg.akt.dev/node/x/take" + "pkg.akt.dev/node/v2/x/audit" + "pkg.akt.dev/node/v2/x/cert" + "pkg.akt.dev/node/v2/x/deployment" + "pkg.akt.dev/node/v2/x/escrow" + "pkg.akt.dev/node/v2/x/market" + oracle "pkg.akt.dev/node/v2/x/oracle" + "pkg.akt.dev/node/v2/x/provider" + "pkg.akt.dev/node/v2/x/take" + awasm "pkg.akt.dev/node/v2/x/wasm" ) func appModules( @@ -190,6 +194,23 @@ func appModules( app.cdc, app.Keepers.Akash.Cert, ), + awasm.NewAppModule( + app.cdc, + app.Keepers.Akash.Wasm, + ), + oracle.NewAppModule( + app.cdc, + app.Keepers.Akash.Oracle, + ), + wasm.NewAppModule( + app.cdc, + app.Keepers.Cosmos.Wasm, + app.Keepers.Cosmos.Staking, + app.Keepers.Cosmos.Acct, + app.Keepers.Cosmos.Bank, + app.MsgServiceRouter(), + app.GetSubspace(wasmtypes.ModuleName), + ), } } @@ -286,7 +307,6 @@ func appSimModules( app.cdc, app.Keepers.Akash.Take, ), - deployment.NewAppModule( app.cdc, app.Keepers.Akash.Deployment, @@ -296,7 +316,6 @@ func appSimModules( app.Keepers.Cosmos.Bank, app.Keepers.Cosmos.Authz, ), - market.NewAppModule( app.cdc, app.Keepers.Akash.Market, @@ -308,7 +327,6 @@ func appSimModules( app.Keepers.Cosmos.Authz, app.Keepers.Cosmos.Bank, ), - provider.NewAppModule( app.cdc, app.Keepers.Akash.Provider, @@ -316,10 +334,26 @@ func appSimModules( app.Keepers.Cosmos.Bank, app.Keepers.Akash.Market, ), - cert.NewAppModule( app.cdc, app.Keepers.Akash.Cert, ), + oracle.NewAppModule( + app.cdc, + app.Keepers.Akash.Oracle, + ), + awasm.NewAppModule( + app.cdc, + app.Keepers.Akash.Wasm, + ), + wasm.NewAppModule( + app.cdc, + app.Keepers.Cosmos.Wasm, + app.Keepers.Cosmos.Staking, + app.Keepers.Cosmos.Acct, + app.Keepers.Cosmos.Bank, + app.MsgServiceRouter(), + app.GetSubspace(wasmtypes.ModuleName), + ), } } diff --git a/app/sim/sim_utils.go b/app/sim/sim_utils.go index 92baa1d74d..85e6927a99 100644 --- a/app/sim/sim_utils.go +++ b/app/sim/sim_utils.go @@ -14,7 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - akash "pkg.akt.dev/node/app" + akash "pkg.akt.dev/node/v2/app" ) // SetupSimulation creates the config, db (levelDB), temporary directory and logger for diff --git a/app/sim_test.go b/app/sim_test.go index b51ab4ecef..4a08b34808 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -5,12 +5,17 @@ import ( "fmt" "math/rand" "os" + "runtime/debug" + "strings" "testing" "time" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/spf13/viper" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + cflags "pkg.akt.dev/go/cli/flags" abci "github.com/cometbft/cometbft/abci/types" @@ -23,6 +28,7 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/baseapp" sdksim "github.com/cosmos/cosmos-sdk/types/simulation" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" authzkeys "github.com/cosmos/cosmos-sdk/x/authz/keeper/keys" @@ -46,9 +52,9 @@ import ( taketypes "pkg.akt.dev/go/node/take/v1" "pkg.akt.dev/go/sdkutil" - akash "pkg.akt.dev/node/app" - "pkg.akt.dev/node/app/sim" - simtestutil "pkg.akt.dev/node/testutil/sims" + akash "pkg.akt.dev/node/v2/app" + "pkg.akt.dev/node/v2/app/sim" + simtestutil "pkg.akt.dev/node/v2/testutil/sims" ) // AppChainID hardcoded chainID for simulation @@ -141,37 +147,14 @@ func TestFullAppSimulation(t *testing.T) { } func TestAppImportExport(t *testing.T) { - config, db, dir, logger, skip, err := sim.SetupSimulation("leveldb-app-sim", "Simulation") - if skip { - t.Skip("skipping application import/export simulation") - } - require.NoError(t, err, "simulation setup failed") - - defer func() { - _ = db.Close() - require.NoError(t, os.RemoveAll(dir)) - }() - - encodingConfig := sdkutil.MakeEncodingConfig() - - akash.ModuleBasics().RegisterInterfaces(encodingConfig.InterfaceRegistry) - - appOpts := viper.New() - appOpts.Set("home", akash.DefaultHome) - - r := rand.New(rand.NewSource(config.Seed)) // nolint: gosec - genTime := sdksim.RandTimestamp(r) - - appOpts.Set("GenesisTime", genTime) - - appA := akash.NewApp(logger, db, nil, true, sim.FlagPeriodValue, map[int64]bool{}, encodingConfig, appOpts, fauxMerkleModeOpt, baseapp.SetChainID(AppChainID)) - require.Equal(t, akash.AppName, appA.Name()) + config, encodingConfig, db, appOpts, logger, appA := setupSimulationApp(t, "skipping application import/export simulation") // Run randomized simulation _, simParams, simErr := simulateFromSeedFunc(t, appA, config) + require.Equal(t, akash.AppName, appA.Name()) // export state and simParams before the simulation error is checked - err = simtestutil.CheckExportSimulation(appA, config, simParams) + err := simtestutil.CheckExportSimulation(appA, config, simParams) require.NoError(t, err) require.NoError(t, simErr) @@ -179,38 +162,48 @@ func TestAppImportExport(t *testing.T) { sim.PrintStats(db) } - fmt.Printf("exporting genesis...\n") - + t.Log("exporting genesis...\n") exported, err := appA.ExportAppStateAndValidators(false, []string{}, []string{}) require.NoError(t, err) - fmt.Printf("importing genesis...\n") + t.Log("importing genesis...\n") - _, newDB, newDir, _, _, err := sim.SetupSimulation("leveldb-app-sim-2", "Simulation-2") + newDB, newDir, _, skip, err := simtestutil.SetupSimulation(config, "leveldb-app-sim-2", "Simulation-2", sim.FlagVerboseValue, sim.FlagEnabledValue) require.NoError(t, err, "simulation setup failed") + if skip { + t.Skip("skipping application import/export simulation") + } defer func() { - _ = newDB.Close() + require.NoError(t, newDB.Close()) require.NoError(t, os.RemoveAll(newDir)) }() + appOpts[cflags.FlagHome] = t.TempDir() // ensure a unique folder for the new app appB := akash.NewApp(logger, newDB, nil, true, sim.FlagPeriodValue, map[int64]bool{}, encodingConfig, appOpts, fauxMerkleModeOpt, baseapp.SetChainID(AppChainID)) require.Equal(t, akash.AppName, appB.Name()) - var genesisState akash.GenesisState - err = json.Unmarshal(exported.AppState, &genesisState) - require.NoError(t, err) + ctxA := appA.NewContextLegacy(true, cmtproto.Header{Height: appA.LastBlockHeight()}) + ctxB := appB.NewContextLegacy(true, cmtproto.Header{Height: appA.LastBlockHeight()}) - ctxA := appA.NewContext(true) - ctxB := appB.NewContext(true) + initReq := &abci.RequestInitChain{ + AppStateBytes: exported.AppState, + } - _, err = appB.MM.InitGenesis(ctxB, appA.AppCodec(), genesisState) - require.NoError(t, err) + _, err = appB.InitChainer(ctxB, initReq) + if err != nil { + if strings.Contains(err.Error(), "validator set is empty after InitGenesis") { + t.Log("Skipping simulation as all validators have been unbonded") + t.Logf("err: %s stacktrace: %s\n", err, string(debug.Stack())) + return + } + } + require.NoError(t, err) err = appB.StoreConsensusParams(ctxB, exported.ConsensusParams) require.NoError(t, err) - fmt.Printf("comparing stores...\n") + t.Log("comparing stores...") storeKeysPrefixes := []StoreKeysPrefixes{ { @@ -360,6 +353,14 @@ func TestAppImportExport(t *testing.T) { appB, [][]byte{}, }, + { + wasmtypes.StoreKey, + appA, + appB, + [][]byte{ + wasmtypes.TXCounterPrefix, + }, + }, } for _, skp := range storeKeysPrefixes { @@ -399,8 +400,7 @@ func TestAppSimulationAfterImport(t *testing.T) { akash.ModuleBasics().RegisterInterfaces(encodingConfig.InterfaceRegistry) appOpts := viper.New() - - appOpts.Set("home", akash.DefaultHome) + appOpts.Set("home", t.TempDir()) // ensure a unique folder per run r := rand.New(rand.NewSource(config.Seed)) // nolint: gosec genTime := sdksim.RandTimestamp(r) @@ -442,6 +442,7 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() + appOpts.Set("home", t.TempDir()) // ensure a unique folder per run newApp := akash.NewApp(log.NewNopLogger(), newDB, nil, true, sim.FlagPeriodValue, map[int64]bool{}, encodingConfig, appOpts, fauxMerkleModeOpt, baseapp.SetChainID(AppChainID)) require.Equal(t, akash.AppName, newApp.Name()) @@ -487,7 +488,7 @@ func TestAppStateDeterminism(t *testing.T) { db := dbm.NewMemDB() appOpts := viper.New() - appOpts.Set("home", akash.DefaultHome) + appOpts.Set("home", t.TempDir()) // ensure a unique folder per run r := rand.New(rand.NewSource(config.Seed)) // nolint: gosec genTime := sdksim.RandTimestamp(r) @@ -521,3 +522,31 @@ func TestAppStateDeterminism(t *testing.T) { } } } + +func setupSimulationApp(t *testing.T, msg string) (simtypes.Config, sdkutil.EncodingConfig, dbm.DB, simtestutil.AppOptionsMap, log.Logger, *akash.AkashApp) { + config := sim.NewConfigFromFlags() + config.ChainID = AppChainID + + encodingConfig := sdkutil.MakeEncodingConfig() + + akash.ModuleBasics().RegisterInterfaces(encodingConfig.InterfaceRegistry) + + db, dir, logger, skip, err := simtestutil.SetupSimulation(config, "leveldb-app-sim", "Simulation", sim.FlagVerboseValue, sim.FlagEnabledValue) + if skip { + t.Skip(msg) + } + require.NoError(t, err, "simulation setup failed") + + t.Cleanup(func() { + require.NoError(t, db.Close()) + require.NoError(t, os.RemoveAll(dir)) + }) + + appOpts := make(simtestutil.AppOptionsMap) + appOpts[cflags.FlagHome] = dir // ensure a unique folder + appOpts[cflags.FlagInvCheckPeriod] = sim.FlagPeriodValue + app := akash.NewApp(logger, db, nil, true, sim.FlagPeriodValue, map[int64]bool{}, encodingConfig, appOpts, fauxMerkleModeOpt, baseapp.SetChainID(AppChainID)) + + require.Equal(t, akash.AppName, app.Name()) + return config, encodingConfig, db, appOpts, logger, app +} diff --git a/app/testnet.go b/app/testnet.go index 4b2fe5e6cc..f2f318b15a 100644 --- a/app/testnet.go +++ b/app/testnet.go @@ -24,7 +24,7 @@ import ( "pkg.akt.dev/go/sdkutil" - utypes "pkg.akt.dev/node/upgrades/types" + utypes "pkg.akt.dev/node/v2/upgrades/types" ) type TestnetDelegation struct { diff --git a/app/types/app.go b/app/types/app.go index 7f4633c13e..16bab62b57 100644 --- a/app/types/app.go +++ b/app/types/app.go @@ -14,6 +14,9 @@ import ( feegrantkeeper "cosmossdk.io/x/feegrant/keeper" upgradekeeper "cosmossdk.io/x/upgrade/keeper" upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/CosmWasm/wasmd/x/wasm" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" addresscodec "github.com/cosmos/cosmos-sdk/codec/address" @@ -45,38 +48,43 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - icacontrollertypes "github.com/cosmos/ibc-go/v10/modules/apps/27-interchain-accounts/controller/types" - icahosttypes "github.com/cosmos/ibc-go/v10/modules/apps/27-interchain-accounts/host/types" "github.com/cosmos/ibc-go/v10/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v10/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" + transferv2 "github.com/cosmos/ibc-go/v10/modules/apps/transfer/v2" ibcclienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types" ibcconnectiontypes "github.com/cosmos/ibc-go/v10/modules/core/03-connection/types" porttypes "github.com/cosmos/ibc-go/v10/modules/core/05-port/types" + ibcapi "github.com/cosmos/ibc-go/v10/modules/core/api" ibcexported "github.com/cosmos/ibc-go/v10/modules/core/exported" ibckeeper "github.com/cosmos/ibc-go/v10/modules/core/keeper" ibctm "github.com/cosmos/ibc-go/v10/modules/light-clients/07-tendermint" - emodule "pkg.akt.dev/go/node/escrow/module" atypes "pkg.akt.dev/go/node/audit/v1" ctypes "pkg.akt.dev/go/node/cert/v1" dtypes "pkg.akt.dev/go/node/deployment/v1" dv1beta "pkg.akt.dev/go/node/deployment/v1beta3" + emodule "pkg.akt.dev/go/node/escrow/module" agovtypes "pkg.akt.dev/go/node/gov/v1beta3" mtypes "pkg.akt.dev/go/node/market/v1beta4" + otypes "pkg.akt.dev/go/node/oracle/v1" ptypes "pkg.akt.dev/go/node/provider/v1beta4" astakingtypes "pkg.akt.dev/go/node/staking/v1beta3" ttypes "pkg.akt.dev/go/node/take/v1" + wtypes "pkg.akt.dev/go/node/wasm/v1" "pkg.akt.dev/go/sdkutil" - akeeper "pkg.akt.dev/node/x/audit/keeper" - ckeeper "pkg.akt.dev/node/x/cert/keeper" - dkeeper "pkg.akt.dev/node/x/deployment/keeper" - ekeeper "pkg.akt.dev/node/x/escrow/keeper" - mhooks "pkg.akt.dev/node/x/market/hooks" - mkeeper "pkg.akt.dev/node/x/market/keeper" - pkeeper "pkg.akt.dev/node/x/provider/keeper" - tkeeper "pkg.akt.dev/node/x/take/keeper" + akeeper "pkg.akt.dev/node/v2/x/audit/keeper" + ckeeper "pkg.akt.dev/node/v2/x/cert/keeper" + dkeeper "pkg.akt.dev/node/v2/x/deployment/keeper" + ekeeper "pkg.akt.dev/node/v2/x/escrow/keeper" + mhooks "pkg.akt.dev/node/v2/x/market/hooks" + mkeeper "pkg.akt.dev/node/v2/x/market/keeper" + okeeper "pkg.akt.dev/node/v2/x/oracle/keeper" + pkeeper "pkg.akt.dev/node/v2/x/provider/keeper" + tkeeper "pkg.akt.dev/node/v2/x/take/keeper" + awasm "pkg.akt.dev/node/v2/x/wasm" + wkeeper "pkg.akt.dev/node/v2/x/wasm/keeper" ) const ( @@ -103,9 +111,11 @@ type AppKeepers struct { IBC *ibckeeper.Keeper Evidence *evidencekeeper.Keeper Transfer ibctransferkeeper.Keeper + Wasm *wasmkeeper.Keeper } Akash struct { + Oracle okeeper.Keeper Escrow ekeeper.Keeper Deployment dkeeper.IKeeper Take tkeeper.IKeeper @@ -113,6 +123,7 @@ type AppKeepers struct { Provider pkeeper.IKeeper Audit akeeper.Keeper Cert ckeeper.Keeper + Wasm wkeeper.Keeper } Modules struct { @@ -243,6 +254,9 @@ func (app *App) InitNormalKeepers( encodingConfig sdkutil.EncodingConfig, bApp *baseapp.BaseApp, maccPerms map[string][]string, + wasmDir string, + wasmConfig wasmtypes.NodeConfig, + wasmOpts []wasmkeeper.Option, blockedAddresses map[string]bool, invCheckPeriod uint, ) { @@ -391,14 +405,6 @@ func (app *App) InitNormalKeepers( authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) - transferIBCModule := transfer.NewIBCModule(app.Keepers.Cosmos.Transfer) - - // Create static IBC router, add transfer route, then set and seal it - ibcRouter := porttypes.NewRouter() - ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferIBCModule) - - app.Keepers.Cosmos.IBC.SetRouter(ibcRouter) - /// Light client modules clientKeeper := app.Keepers.Cosmos.IBC.ClientKeeper storeProvider := app.Keepers.Cosmos.IBC.ClientKeeper.GetStoreProvider() @@ -449,6 +455,72 @@ func (app *App) InitNormalKeepers( cdc, app.keys[ctypes.StoreKey], ) + + app.Keepers.Akash.Oracle = okeeper.NewKeeper( + cdc, + app.keys[otypes.StoreKey], + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + + app.Keepers.Akash.Wasm = wkeeper.NewKeeper( + cdc, + app.keys[wtypes.StoreKey], + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + + wOpts := make([]wasmkeeper.Option, 0, len(wasmOpts)+1) + + wOpts = append(wOpts, wasmkeeper.WithMessageHandlerDecorator( + app.Keepers.Akash.Wasm.NewMsgFilterDecorator(), + )) + + wOpts = append(wOpts, wasmOpts...) + + // The last arguments can contain custom message handlers and custom query handlers + // if we want to allow any custom callbacks + wasmCapabilities := wasmkeeper.BuiltInCapabilities() + wasmCapabilities = append(wasmCapabilities, "akash") + + wasmKeeper := wasmkeeper.NewKeeper( + cdc, + runtime.NewKVStoreService(app.keys[wasmtypes.StoreKey]), + app.Keepers.Cosmos.Acct, + app.Keepers.Cosmos.Bank, + *app.Keepers.Cosmos.Staking, + distrkeeper.NewQuerier(app.Keepers.Cosmos.Distr), + app.Keepers.Cosmos.IBC.ChannelKeeper, + app.Keepers.Cosmos.IBC.ChannelKeeper, + app.Keepers.Cosmos.IBC.ChannelKeeperV2, + app.Keepers.Cosmos.Transfer, + bApp.MsgServiceRouter(), + bApp.GRPCQueryRouter(), + wasmDir, + wasmConfig, + wasmtypes.VMConfig{}, + wasmCapabilities, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wOpts..., + ) + app.Keepers.Cosmos.Wasm = &wasmKeeper + + // Create fee enabled wasm ibc Stack + wasmStackIBCHandler := wasm.NewIBCHandler(app.Keepers.Cosmos.Wasm, app.Keepers.Cosmos.IBC.ChannelKeeper, app.Keepers.Cosmos.Transfer, app.Keepers.Cosmos.IBC.ChannelKeeper) + + transferIBCModule := transfer.NewIBCModule(app.Keepers.Cosmos.Transfer) + + // Create static IBC router, add transfer route, then set and seal it + ibcRouter := porttypes.NewRouter() + ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferIBCModule) + ibcRouter.AddRoute(wasmtypes.ModuleName, wasmStackIBCHandler) + + app.Keepers.Cosmos.IBC.SetRouter(ibcRouter) + + ibcRouterV2 := ibcapi.NewRouter() + ibcRouterV2 = ibcRouterV2. + AddRoute(ibctransfertypes.PortID, transferv2.NewIBCModule(app.Keepers.Cosmos.Transfer)). + AddPrefixRoute(wasmkeeper.PortIDPrefixV2, wasmkeeper.NewIBC2Handler(app.Keepers.Cosmos.Wasm)) + + app.Keepers.Cosmos.IBC.SetRouterV2(ibcRouterV2) } func (app *App) SetupHooks() { @@ -459,7 +531,6 @@ func (app *App) SetupHooks() { app.Keepers.Cosmos.Slashing.Hooks(), ), ) - app.Keepers.Cosmos.Gov.SetHooks( govtypes.NewMultiGovHooks( // insert governance hooks receivers here @@ -492,8 +563,6 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(crisistypes.ModuleName).WithKeyTable(crisistypes.ParamKeyTable()) // nolint: staticcheck // SA1019 paramsKeeper.Subspace(ibctransfertypes.ModuleName).WithKeyTable(ibctransfertypes.ParamKeyTable()) paramsKeeper.Subspace(ibcexported.ModuleName).WithKeyTable(ibctable) - paramsKeeper.Subspace(icacontrollertypes.SubModuleName) - paramsKeeper.Subspace(icahosttypes.SubModuleName) // akash params subspaces paramsKeeper.Subspace(dtypes.ModuleName).WithKeyTable(dv1beta.ParamKeyTable()) @@ -522,6 +591,8 @@ func kvStoreKeys() []string { upgradetypes.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, + // wasm after ibc transfer + wasmtypes.ModuleName, } keys = append(keys, akashKVStoreKeys()...) @@ -538,6 +609,8 @@ func akashKVStoreKeys() []string { ptypes.StoreKey, atypes.StoreKey, ctypes.StoreKey, + awasm.StoreKey, + otypes.StoreKey, } } diff --git a/app/upgrades.go b/app/upgrades.go index 4ef4974195..74e23dee1a 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -5,9 +5,9 @@ import ( upgradetypes "cosmossdk.io/x/upgrade/types" - utypes "pkg.akt.dev/node/upgrades/types" + utypes "pkg.akt.dev/node/v2/upgrades/types" // nolint: revive - _ "pkg.akt.dev/node/upgrades" + _ "pkg.akt.dev/node/v2/upgrades" ) func (app *AkashApp) registerUpgradeHandlers() error { @@ -20,7 +20,12 @@ func (app *AkashApp) registerUpgradeHandlers() error { return nil } - currentHeight := app.CommitMultiStore().LastCommitID().Version + cms := app.CommitMultiStore() + if cms == nil { + return fmt.Errorf("unable to get CommitMultiStore") + } + + currentHeight := cms.LastCommitID().Version if upgradeInfo.Height == currentHeight+1 { app.customPreUpgradeHandler(upgradeInfo) diff --git a/cmd/akash/cmd/app_creator.go b/cmd/akash/cmd/app_creator.go index 8a8f923be4..449b4794c9 100644 --- a/cmd/akash/cmd/app_creator.go +++ b/cmd/akash/cmd/app_creator.go @@ -22,7 +22,7 @@ import ( cflags "pkg.akt.dev/go/cli/flags" "pkg.akt.dev/go/sdkutil" - akash "pkg.akt.dev/node/app" + akash "pkg.akt.dev/node/v2/app" ) type appCreator struct { diff --git a/cmd/akash/cmd/config.go b/cmd/akash/cmd/config.go new file mode 100644 index 0000000000..bf50660bfc --- /dev/null +++ b/cmd/akash/cmd/config.go @@ -0,0 +1,31 @@ +package cmd + +import ( + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + serverconfig "github.com/cosmos/cosmos-sdk/server/config" +) + +type AppConfig struct { + serverconfig.Config + + WasmConfig wasmtypes.NodeConfig `mapstructure:"wasm"` +} + +var AppTemplate = serverconfig.DefaultConfigTemplate + ` +############################################################################### +### Wasm Configuration ### +############################################################################### +` + wasmtypes.DefaultConfigTemplate() + +func InitAppConfig() (string, interface{}) { + appCfg := AppConfig{ + Config: *serverconfig.DefaultConfig(), + WasmConfig: wasmtypes.DefaultNodeConfig(), + } + + appCfg.MinGasPrices = "0.0025uakt" + appCfg.API.Enable = true + appCfg.API.Address = "tcp://localhost:1317" + + return AppTemplate, appCfg +} diff --git a/cmd/akash/cmd/root.go b/cmd/akash/cmd/root.go index bcb9967fef..a6991800f0 100644 --- a/cmd/akash/cmd/root.go +++ b/cmd/akash/cmd/root.go @@ -3,14 +3,12 @@ package cmd import ( "context" + "github.com/CosmWasm/wasmd/x/wasm" "github.com/cosmos/cosmos-sdk/x/crisis" - "github.com/rs/zerolog" "github.com/spf13/cobra" - cmtcfg "github.com/cometbft/cometbft/config" cmtcli "github.com/cometbft/cometbft/libs/cli" - sdkclient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/debug" "github.com/cosmos/cosmos-sdk/client/pruning" "github.com/cosmos/cosmos-sdk/client/snapshot" @@ -19,11 +17,10 @@ import ( rosettaCmd "github.com/cosmos/rosetta/cmd" "pkg.akt.dev/go/cli" - cflags "pkg.akt.dev/go/cli/flags" "pkg.akt.dev/go/sdkutil" - "pkg.akt.dev/node/app" - "pkg.akt.dev/node/cmd/akash/cmd/testnetify" + "pkg.akt.dev/node/v2/app" + "pkg.akt.dev/node/v2/cmd/akash/cmd/testnetify" ) // NewRootCmd creates a new root command for akash. It is called once in the @@ -33,11 +30,15 @@ func NewRootCmd() (*cobra.Command, sdkutil.EncodingConfig) { app.ModuleBasics().RegisterInterfaces(encodingConfig.InterfaceRegistry) rootCmd := &cobra.Command{ - Use: "akash", - Short: "Akash Blockchain Application", - Long: "Akash CLI Utility.\n\nAkash is a peer-to-peer marketplace for computing resources and \na deployment platform for heavily distributed applications. \nFind out more at https://akash.network", + Use: "akash", + Short: "Akash Blockchain Application", + Long: `Akash CLI Utility. + +Akash is a peer-to-peer marketplace for computing resources and +a deployment platform for heavily distributed applications. +Find out more at https://akash.network`, SilenceUsage: true, - PersistentPreRunE: cli.GetPersistentPreRunE(encodingConfig, []string{"AKASH"}, cli.DefaultHome), + PersistentPreRunE: cli.GetPersistentPreRunE(encodingConfig, []string{"AKASH"}, cli.DefaultHome, cli.WithPreRunAppConfig(InitAppConfig())), } initRootCmd(rootCmd, encodingConfig) @@ -54,29 +55,7 @@ func Execute(rootCmd *cobra.Command, envPrefix string) error { // getting and setting the client.Context. Ideally, we utilize // https://github.com/spf13/cobra/pull/1118. - return ExecuteWithCtx(context.Background(), rootCmd, envPrefix) -} - -// ExecuteWithCtx executes the root command. -func ExecuteWithCtx(ctx context.Context, rootCmd *cobra.Command, envPrefix string) error { - // Create and set a client.Context on the command's Context. During the pre-run - // of the root command, a default initialized client.Context is provided to - // seed child command execution with values such as AccountRetriver, Keyring, - // and a Tendermint RPC. This requires the use of a pointer reference when - // getting and setting the client.Context. Ideally, we utilize - // https://github.com/spf13/cobra/pull/1118. - srvCtx := sdkserver.NewDefaultContext() - - ctx = context.WithValue(ctx, sdkclient.ClientContextKey, &sdkclient.Context{}) - ctx = context.WithValue(ctx, sdkserver.ServerContextKey, srvCtx) - - rootCmd.PersistentFlags().String(cflags.FlagLogLevel, zerolog.InfoLevel.String(), "The logging level (trace|debug|info|warn|error|fatal|panic)") - rootCmd.PersistentFlags().String(cflags.FlagLogFormat, cmtcfg.LogFormatPlain, "The logging format (json|plain)") - rootCmd.PersistentFlags().Bool(cflags.FlagLogColor, false, "Pretty logging output. Applied only when log_format=plain") - rootCmd.PersistentFlags().String(cflags.FlagLogTimestamp, "", "Add timestamp prefix to the logs (rfc3339|rfc3339nano|kitchen)") - - executor := cmtcli.PrepareBaseCmd(rootCmd, envPrefix, app.DefaultHome) - return executor.ExecuteContext(ctx) + return cli.ExecuteWithCtx(context.Background(), rootCmd, envPrefix) } func initRootCmd(rootCmd *cobra.Command, encodingConfig sdkutil.EncodingConfig) { @@ -113,6 +92,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig sdkutil.EncodingConfig) func addModuleInitFlags(startCmd *cobra.Command) { crisis.AddModuleInitFlags(startCmd) //nolint: staticcheck + wasm.AddModuleInitFlags(startCmd) } // genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter diff --git a/cmd/akash/cmd/testnetify/config.go b/cmd/akash/cmd/testnetify/config.go index 251bda818c..3b616e449a 100644 --- a/cmd/akash/cmd/testnetify/config.go +++ b/cmd/akash/cmd/testnetify/config.go @@ -12,7 +12,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - akash "pkg.akt.dev/node/app" + akash "pkg.akt.dev/node/v2/app" ) type PrivValidatorKey struct { diff --git a/cmd/akash/cmd/testnetify/testnetify.go b/cmd/akash/cmd/testnetify/testnetify.go index 0ec2a2ba52..60b3843e68 100644 --- a/cmd/akash/cmd/testnetify/testnetify.go +++ b/cmd/akash/cmd/testnetify/testnetify.go @@ -39,8 +39,8 @@ import ( cflags "pkg.akt.dev/go/cli/flags" - akash "pkg.akt.dev/node/app" - "pkg.akt.dev/node/util/server" + akash "pkg.akt.dev/node/v2/app" + "pkg.akt.dev/node/v2/util/server" ) // GetCmd uses the provided chainID and operatorAddress as well as the local private validator key to diff --git a/cmd/akash/cmd/testnetify/utils.go b/cmd/akash/cmd/testnetify/utils.go index 150256a4fe..ccf332cc4a 100644 --- a/cmd/akash/cmd/testnetify/utils.go +++ b/cmd/akash/cmd/testnetify/utils.go @@ -11,7 +11,7 @@ import ( "golang.org/x/sync/errgroup" cflags "pkg.akt.dev/go/cli/flags" - "pkg.akt.dev/node/util/server" + "pkg.akt.dev/node/v2/util/server" ) func openDB(rootDir string, backendType dbm.BackendType) (dbm.DB, error) { diff --git a/cmd/akash/main.go b/cmd/akash/main.go index 6e6b39237d..67e514a614 100644 --- a/cmd/akash/main.go +++ b/cmd/akash/main.go @@ -5,7 +5,7 @@ import ( _ "pkg.akt.dev/go/sdkutil" - "pkg.akt.dev/node/cmd/akash/cmd" + "pkg.akt.dev/node/v2/cmd/akash/cmd" ) // In main we call the rootCmd diff --git a/contracts/price-oracle/Cargo.lock b/contracts/price-oracle/Cargo.lock new file mode 100644 index 0000000000..3f2f360132 --- /dev/null +++ b/contracts/price-oracle/Cargo.lock @@ -0,0 +1,1442 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "arrayvec", + "digest", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.5", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "arrayvec", + "digest", + "num-bigint", + "rayon", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand", + "rayon", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bnum" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e31ea183f6ee62ac8b8a8cf7feddd766317adfb13ff469de57ce033efd6a790" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cosmwasm-core" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b0a718b13ffe224e32a8c1f68527354868f47d6cc84afe8c66cb05fbb3ced6e" + +[[package]] +name = "cosmwasm-crypto" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c08dd7585b5c48fbcb947ada7a3fb49465fb735481ed295b54ca98add6dc17f" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-serialize", + "cosmwasm-core", + "curve25519-dalek", + "digest", + "ecdsa", + "ed25519-zebra", + "k256", + "num-bigint", + "num-traits", + "p256", + "rand_core", + "rayon", + "sha2", + "thiserror 1.0.69", +] + +[[package]] +name = "cosmwasm-derive" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5677eed823a61eeb615b1ad4915a42336b70b0fe3f87bf3da4b59f3dcf9034af" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cosmwasm-schema" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d8808bf9fb8f4d5ee62e808b3e1dcdf6a116e9e1fe934507a4e0a4135ae941" +dependencies = [ + "cosmwasm-schema-derive", + "cw-schema", + "schemars 0.8.22", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "cosmwasm-schema-derive" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9718a856ff5edb6537ac889ff695abc576304bc25cb7b16ef4c762e10a0149ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cosmwasm-std" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4881104f54871bcea6f30757bee13b7f09c0998d1b0de133cce5a52336a2ada" +dependencies = [ + "base64", + "bech32", + "bnum", + "cosmwasm-core", + "cosmwasm-crypto", + "cosmwasm-derive", + "cw-schema", + "derive_more", + "hex", + "rand_core", + "rmp-serde", + "schemars 0.8.22", + "serde", + "serde_json", + "sha2", + "static_assertions", + "thiserror 1.0.69", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cw-multi-test" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9875e88f5b67dbaf729da99a7de4acd593d18d6d8ee83c8006e09dd865745e" +dependencies = [ + "bech32", + "cosmwasm-schema", + "cosmwasm-std", + "cw-storage-plus", + "cw-utils", + "itertools 0.14.0", + "prost", + "schemars 0.8.22", + "serde", + "sha2", +] + +[[package]] +name = "cw-schema" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f335d3f51e10260f4dfb0840f0526c1d25c6b42a9489c04ce41ed9aa54dd6d" +dependencies = [ + "cw-schema-derive", + "indexmap", + "schemars 1.1.0", + "serde", + "serde_with", + "siphasher", + "typeid", +] + +[[package]] +name = "cw-schema-derive" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba2eb93f854caeacc5eda13d15663b7605395514fd378bfba8e7532f1fc5865" +dependencies = [ + "heck", + "itertools 0.13.0", + "owo-colors", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cw-storage-plus" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75d840d773b4ffd60ff005375e5e15e4be4fda54620574e861bfbb61a074f353" +dependencies = [ + "cosmwasm-std", + "schemars 0.8.22", + "serde", +] + +[[package]] +name = "cw-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8667e96f2c65cf7f4c6c66bfd6ee46909c40827bc1caea0409234e34f03cf061" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "schemars 0.8.22", + "serde", + "thiserror 2.0.17", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-zebra" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "hashbrown 0.14.5", + "hex", + "rand_core", + "sha2", + "zeroize", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +dependencies = [ + "equivalent", + "hashbrown 0.16.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "is_ci" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "sha2", +] + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "owo-colors" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" +dependencies = [ + "supports-color 2.1.0", + "supports-color 3.0.2", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "price-oracle" +version = "1.0.0" +dependencies = [ + "cosmwasm-schema", + "cosmwasm-std", + "cw-multi-test", + "cw-storage-plus", + "schemars 0.8.22", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prost" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive 0.8.22", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" +dependencies = [ + "dyn-clone", + "ref-cast", + "schemars_derive 1.1.0", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "schemars_derive" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301858a4023d78debd2353c7426dc486001bddc91ae31a76fb1f55132f7e2633" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_with" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1" +dependencies = [ + "serde_core", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "supports-color" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" +dependencies = [ + "is-terminal", + "is_ci", +] + +[[package]] +name = "supports-color" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" +dependencies = [ + "is_ci", +] + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/contracts/price-oracle/Cargo.toml b/contracts/price-oracle/Cargo.toml new file mode 100644 index 0000000000..454c9a2561 --- /dev/null +++ b/contracts/price-oracle/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "price-oracle" +version = "1.0.0" +authors = ["Artur Troian"] +edition = "2021" +description = "Pyth price oracle consumer contract for Akash Network" +license = "Apache-2.0" + +[lib] +crate-type = ["cdylib", "rlib"] + +[profile.release] +opt-level = 3 +debug = false +rpath = false +lto = true +debug-assertions = false +codegen-units = 1 +panic = 'abort' +incremental = false +overflow-checks = true + +[features] +default = [] +#backtraces = ["cosmwasm-std/backtraces"] +library = [] + +[dependencies] +cosmwasm-schema = "3.0.2" +cosmwasm-std = "3.0.2" +cw-storage-plus = "3.0.1" +schemars = "0.8" +serde = { version = "1.0", default-features = false, features = ["derive"] } +thiserror = "1.0" + +[dev-dependencies] +cw-multi-test = "3.0.1" + +[[bin]] +name = "schema" +required-features = [] diff --git a/contracts/price-oracle/artifacts/checksums.txt b/contracts/price-oracle/artifacts/checksums.txt new file mode 100644 index 0000000000..f935f2a691 --- /dev/null +++ b/contracts/price-oracle/artifacts/checksums.txt @@ -0,0 +1 @@ +7f0ea92d24051c4823067fab1245f17342c283f1fb482835cbf6ce92189b05ab price_oracle.wasm diff --git a/contracts/price-oracle/artifacts/price_oracle.wasm b/contracts/price-oracle/artifacts/price_oracle.wasm new file mode 100644 index 0000000000000000000000000000000000000000..bfb23bbd747383c95ecf07a87f513c636e6ddb2c GIT binary patch literal 293652 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

oTLQ?yA%Dasg%KG!>KU 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

0UC+9OI>Cw=PU* z3Y6I;^2Q8!45TCXkaLVe$+9<9aU@9}B48Y|O?xTE!Y0BvD~wz!P9%>@tz?-|nF*+& zO^QY4vo?A|LB3A3Jt(rR5z=y_(0Nyt7-fl(PZXPu2s)(`3Q49n^hukCML5PxeL5dv z9Ca{J-WfAXsWoN^mh%2;`!NL!0x$tXlqkS@n6#e&&}}EC5(K@DV<>@oS6t|wy+MST z|CPNVR%wAZKtv%vH3Al0*bDB*F);;$4M4-d|E-U(?F6@WJFYd$^(cH|nbWrM!)RN^4YW*1@w#f37dDGtOe-!qYHeydsKSLR!5+DeRk^IL|g z#+^l@8)2d(ywJSzHp>`ki?C3zEq0+W!!xvm47KG0%s=pG~w1`?aIxVFQ`9f+!QDQ)6VV7pK{>O#9oS|ox9VJf( zvU;RpUTtV9Az1l~5Q*eG^Md;vM1b*u3|&^Own*_AAu;}YYZ$Z9Tv=9w{;-Jx zjiLGW8kosrOLHPH6c@FKR8h9F4)#8mh!Z&xhbv-_#2d}-mF9I9c^l;F{&*2 zf1U*w@=Ze51M%$L|Ij-SrqLGqtAYkj^1O){(O72$wgqBW1{^8m*4}m&ir@Ig4CkD=!QNHCz(DLpAjK?pmlh zBhZ?HVF5;<-`53iz8lY| zenCU^D`^ddEQK7SiP0j{`%qu31k8h^I@M2i9T-`*(j3`s(-xr-VF1o7tK56l4@H}9 zMWSjBM|39?`FblF$OUb0UQ=LT6N2CXFFAW`TlwQfw`Yh0sz63*Ozae(DLCcavJkB% zs45L)n+MtC>;LgQ1u3>R)3kHI^@U-u)%OSu-w~XfA?wWCmjL5j+b#m;9QGI_%^Q%P zIC9)D^mG5ArL+H^^$4;8*5n#+p&l)U4k&9L9isAPD4l4~%H&~LfkWNLp2pF0Q3>$a zHrM4MmA<^(VIUX-kjQIZY|YsX48Ae8zZNSiVc#`*;Z;4EwfFbi!X@4p;Jh;3AQwz@ zWvw%*=_aoAP+n~bXyl?}ZZWc%RBPD>i7;@wT=+xmVk!h&1yLe==s9PR_ zT>P!TITJn=?xxGNn-uB$<>00%peA<$va3lPJailuhwPGY(N3efkT~FK=F%)nMR&Sa zJ6$9~pjv=bvWy2thfE{mm^(CH$Gpc7dDF6eUZ{N=$HTKu4vELI9yJApmgv}c%UVh< zn?ZVcH8>VGedRtw2FAT&`dUHaV&$83ls3XrWYQL^<#wt5Eb+b*rC}_hS2ebK3(0KT zXCqI`;>v|xqm7{;b~@SWz0PE4OZK5f%2vWKsL3p$gOU)(8d+fr)F7?42p>KiGi=?p zlBh5vleLUOa6w5L(TJ)ng_v1GYjP14an)GUDa1Z5>f}BNcXJ_H4@MTJ^Y+9KH&I+Huc90hw{iFl?z^;FP+Phn==g(0*Wo zp6-JTC=v`)bY+G?PX$C2QQaywj|_TZGWl=VcP(uMdzlazXpJz?qD<2FF@vk|Hl((i zL9uF^!W)z9F8@vkF(a(MkSoJEt;{e-ZzbC8YW$B&3Y{^FRG54uLjFu>`}$zcbS^E3 z;^AA;%HE4r$kx7_157S2d3q9?yE zH49gnUTF)tXt(j2!frdEn?BwOO^t3eaJfUf5!DzIMmPtk6|fdrr_rS3H)9BDkS@tPvb}ExQbIO&xoyl{<<;D+ zB2WoEd-Vx0?T^+o+|CP~eEAFVE8-#@ENzdzhaBQ|Iltl|OG>?K=4!mxl6rlvbMkN9 zZAq(q(o;&>V@atOOgqNhqR3ZT0y4F&aEryjEnMNrqraOr0)O5Djc~;`HNq92Ho_IJ z&_Z+(h%?64PiYrF%oDDLuQN4VH*w=FP=o7JQw^@tZr>->;Ob1>impzXh!K20Lk}ts zs>-6l*-Uw2z(PGgM34LjeBFgv$e?3bve6m%n|E? z4^8yL)_(DTmk-Mu^vGtayod^RQpAjkFpJT+tWnN^C_YhR_bu4qbggZS8RpViDI&c) zOKo*3LM9<@Fr*H76X|JOk{8Z3llE9M#kLTttWRMx%)G?^|fgN=D2plwYY<-Rf=qUxdOc2wuXZtx<>Y>cFE*PDZ-Q!>fk6VSb!iqE^Z^W$2vkryp!gYN%V*=h7PR3tjd&@jvH>cxC2wV z(26{9=L%3+j2XiR+gh57JKt)dQ`YJw!kN}q(;wgJ&M}8{;_mtRkV80PnAGadrdA8v z=C|6WoSzK7)jesedsfT;F3`2u5j(ud zqJw^=(sG`<6{19VgU&I6hdFPJ%(S0||GFSw=tAxZmv(YS@4f;#1qn*Y!+J7KDrR9% z_D+V-&t#=&cYtTJr{;I6A$uqP5BtF*CWV#93+4YDvD=2olw)XK2E@^Hn3;pX^i9?j zcAQ|co6uJ60sUk|uXfWmiF+)(K(aL{4tKi{2g9BO>JAi5tYWgmikn&S;IyPm&J@sI z05+dP3dC(}s<48oC^Mi2=5!eMXzqgsozmH~)adJ(P$3Z7lYt_u%MlA3Zl)7~ooY6| zw5qBxN)bfdNMwziX6;EVOiFDh7BhsaD{#64*;95R`e!?{{*CHBD}ja_tY33Mp`A%M zt?*Sis38x}$I5>lSu8V35es$DiIU}NNUd}5m3H||JF8vR8f|I_>ql{b*maqEm^|2% zk2|RKOEP+P|@nRl)Nr(7V(& z*N?$Y?W{q+4kzWqapz;mHMv!w&ECtFT1OGg63VC zxAQSMI2T(Cs`3C>!g>}9nUsx`kjbfUCw!09zJ=Exy?5bFOddHe$r|s+yiH6l{N1zP z;diet`rS_FLI4SaRm^&cV~{4d*-DT+f{j+~3|u>9ZBAZ%?P<5)%1_P|-gf_0r^8tZ z+H5_2jJXh8R|u-_Wd4u@yG0N~ItZElJa<@%~z{ zqPlu88VuR}xw7xSTzER4N^P)Jpdiy3JOsLREkXeI|iLK3xN)Zdnlr_7=OyypY|zQet*w7j323w;J?stV|smm#eI z>ZuIHc^OS2;qv{~(YO5F|y#mOuAPtP4_)*BHt# zeW13Mwyz$%|6`!SgY+OiTkAc|B#6((YxDpjpPr4^ki|`c+UnDM%XW|PI-kP#YfoEB zTIQ_5p<`BwwbhA;dXzk`nsE&uhCyLXd9t?l>|>yMl>BG^g89xQiPt_@>mB5L#&yh7 z<`(Rw>((ArA+4$Ua=L9L?qO+ya)rvP3^JT~yY^8+d?5ZuhQ5x3>66So{MTPD?AA7` zZT7|`u-mG3MIsbeS)TlhqR&Ag_Ne#B!-~#VQ3`qsa1r}lFYDfANf5Mo)p;v(3yC55 z$$$5ZB3~Y&nSOg6?vho>`7FV2!1H{Xz}J5eBxnBvAN(!im${{b|{Q#0}a0*iKL3ZJe;vh88^m(;NYQ70UG8rcPHn#dv6${~b|RePY7Q2|KBg$cwg zvl7xPMg||YhJl^d5WxFvJEiMW zLbhsV1iR+q!jp_*+*|p-?SvfvJ#zn;#=UwiS^^9$fCxq z8SDbnVz9)wilR?fSA&Y{9)P@J#F8QrNeFT+AW1C%VdK@R8Y7C(<`K11ux-i}SQFQ< zD`2CoSO#TBdc5(0H4O3V>FRQz&JF>eu#ML`lk-IVTnR|KU_a;C4XU&%Fyg}CH2;rt zxNVgIyJTGS>{^Swu#>hs*$!7?iIBkte#eqG_0l02&;U&Sc)G8 z9IX7k*^(@~EIgQzNaFimss}-_H4+HtN;~I{1}Mc#`lHVwN+Q=;1R6RBaiw8_HuUlW zk#*heJzdmjUJ32MSH-Sx@*!1%22`WEadX(3uhqVmK+ERiKwMRh6xuIt&epbt!N8DE zyCK%-)3(S!`rsK6aS@HV+8S-`hzx44Ku1eHeF|#dnu(!H--4h7WUw6N9_C7p6l2@BZZjOhQHv2|L;)yf3Ic`#Fb6<~gzQxyL9XLi8k9k6+0CdaYXuaM zO_Actty6rVoNe)&l)%0P)PW6Eil4@rnwCLFBb>3KOc1q{DSZ0LlqozXE^&48nJnQo z$2OkL62ANdIr@{&{!;qM!%EnmJf0=|H|@T-BDecuH@HB(S}$!~R^*R*=v5tj4m?5qBt*X3qZ<;Dj20l2DtJQEUibhtS}IsB)g5wrYf~K2p(%Xj%YbY-LQ)o) z5hIXFA8MqW8p}NcC5BKcfK>YU@oQi_EYhg;fy@$vp98amfG6 zj1s|+uAsB6Xdl1LupO66Isvdr2;&PkYsxK%@iaht!^^pwgl5F`O_s@W|KRL->ifPTGrJ<%PMh? zXqlPCL{`~V`hF$BjjT?rK*jPZKLATa9^hg~k`;E*s8-7H zo50NomL?X<09>{ZVpnYhaHq~60S)lNq&x+1!vj~6}#qeeT3&Rbe z^B4|*7sl{r0AB>d-Jfk_n_2q3t)R6&KyB;6)qwFjg_(-!lLmpIsNNd@fi%Dxs62IyBeAv3?T$02l*iw?k zUl@`vVfuTKO%Bnjkqnez6!axfs<0tjiyk;qAt39&V~Z?~X^>)oWyAx{@A$H2Z73N# zgfKhd#oTF-1h+pO9=aP5`QeiiFL5Gjm)Zcs%Z5Ni&{ka-C&gM!Dk4fTHWQQ$2ZkXr z0u7!B5b~)uqzv?}+nyZtzzQ;Z623v1tKv3ih(!17)5ne>BkPbffval&)s>`hVT9!OMKkMErJ4?GN#FvO4(;7iYx`Rr4Z+OHJ>T zvhfAlExGPFU03$22c7X-`qdxqWHGD!2>aCItr3(N1$4~@?3RKBNMX|11AZZPwRC$7 z+&XI(aqBpJ2$jg(I%`cka!=;garS7)Pm5b;O|x5PP3G1y8@{=9*5=(hLFU$3dr`Lz zre^2X;byIO>lE-i5SO*v3rFLkoH~bi!l!dD7q%YwFq7PSbeLS3KPSlf zbJi^6&$%+e`sqA6ICqj}k50kwovk>6qIc-5;tqFA3?1iN2C|5QQ`mxs*yVH1oHU<% z&m>bm>>fG~v9_ez!C>`40=x}0b4I1~ihM6&dgx{g_(JMx;kH8-P-u>9p;$#_3tclS zOOvyPu9Y=38(?{4w4yLDUyNq2ET(Hu)c_*224srIxOfG5Z!KC;V^Pf*vVe?B7==kl z3zO@_-s7Ipd)zZk@6A198F0@i1MZoY4A^2VL*z0P=Vfqp@Gb5c`?hy5_&|-Io@ngp z8vd?ZdN3Oe-XC{9Sz9M3%i0IF7b@hW*XUrv5bL2jXQp9$4S??I;Rq9UUtQSE(+(VP z^RRC}(tx>nu1(!GGR>_UeCGqT)eqLLgIm_Novy9dbyIw;F6&|vHsjTauS-9<_O#2{ zKU>`ruTQ-_YvOC2wjuL_#wAw#stxAwF?Y}U2WwdVPgSp1FJoF^ zzNWROYa1FR=bTJp=xXw5@=1VL`oL`M9l3h8Qpmc~)d6Gu)gAE$KB(@b+RUBQNnd*7 z@{_)%8&220hpM@(Rev|Ct7*}4YV|6$Zx)}Zt4`?XI@+5x;O&hD%npXLwGHuljOMLw zD9GT#ZYX@N9C(d`%DbVW72O!V@@^>0k-4FGk90TR4Q08U8_KdY+)(8e?EaQo93PQa z$xeCj7RSf41aEQtY?k0HjxTaPg!{x>9G}Y)ULic;R@xmyV+Tu zw=wRUosGX|wz_sOigyTTx%n|056ElVs}5f`JIk~i4B}03|7@I_tg}phru-V0V>2z^ zq*<{ozTp%;-;Jl@zEkmrQ`L2VTBX!B#_RXeEJr0~@3EB&`nb9pmK~`_OEFg<4GR2L zJ43rRzJ9jKM2R;lyr(x_Hw%av1-?=jPgVI7Z@625hq}27D7Z4cs>b-lk$jK*nW$>3 z#&YtAkkEXO8YF70mg8&ZcaN6Jlq*2xVJD!GeoCHgTDDGkplSjV&0KS;x^XbDPAd`k z(dl(D^kPlC!F5_fidtt*9Z0%*yN+(w`WWacj-+_KxYfG&T7Va?1_;;2eZmbiC3ZSp zmOQTZdjWD;^4atWjKwK>4*?md3)dQuz$x9GQUg!z#esyVE1QwLo2%okgN0LfgNczp zZzy|3e5E)DNDP7_VO7zI0P^N%8yh1`=K~1_60fCtMKp{a2&FBZ7+_-=tc%1ppy^ZGxh?|Y8cx@k<((;E&^7LEh#K5_QG>g@sKNBh zi5lJOgR82S$KB5ViYMEf)ARn<2zTo_Q4Pizc0uS22{@hAhs^&<2*W#~PaAFFTPKv7 zynsv$mEv15AouO#%7)Q9|1}EbbIOPQ4f!#Hzod=+=oMMrCF7)De?i$WmFK=rUM=X+ z`+g~;Kl&Rp*7rvbVRn6jQC!UT8$B&o0mERv-;jOJ@bXf@r)87z_s>QC-fT_D->9;@ zLzplFTa`m4J;;N{_3AHQA7Zd~@Qj?e3ZfSVM z2>F#FhzNzSs)J>M+VWUIz1%4UKiO_jeCclNw&p^^sJxq~g5}t46%I}X3c0m<>;OI= zOP-4i`7EBkCYJn4mf%_P!@rp3@GSXZDWb;3Jxl(=6FwpC#FD1Cn40=U|KzDO-=*fg zLD@B(uF@3io4SCCEOUIR3@rsd=0|eimf78V`~aU;X~6}t6a#q1uon~}V4oNX*%V~P zL{OD&A~2hTY`fa2+C1E@Jp!Sug*M7&plG|9@7wskBk%Vk1P*n$Bfeb7qp)`DN|7dh zc5g@wnPfq_`ZaqOtG#H*2$i5DmE2|OoPnRTbhSxSr_D=0FMX?A_Kmc?>h^ zu^^T;-YgETMeymL1Ew+Wkjgc6IQZ2;O9TWX&xm>bt7H}t@}eTkbS z-l&Z!Xbxhwv=iMxs$*+zNUTUkmJ`zQf)=uxgZS!P&KI>VwI%0k+LF>7z;87cPr0vk zK%u#w3!zKx5Mu3*)O#D936qELlwQO2DT4B2t}n2Zr|PR%s_Rp2c#OHe&|bZYIa6TV z3RPs7c@!;no-gUNj_xlRRgl(N_qi|inYIdg-!;p#H(Va{B*g}8_L62(0Ttj9VmkqB2VE8MH?&}{b~m##*{yL9Dp7jJ3i z6yD*ban8XN4uLUwLAWwcfvEho?RkH#11$I^=a2Dw2UyUp8L&Vu1uUTo4QB7T=4DNQ z)iORsJUYNy|7n*5fXgllSlZGISU+@hHNINdV?$?vH9-QH3b1V{TgDp@itnD2-4zcl zfNpqb3*x+x{`v4U|1UB?6Fl2*rpe;i^YOF+&&X}bfa@q>-%&%?;Mt6*mk3YV(hSecWf;UO7lfxFYBM|;LW3vrAMn)H+681eQ4HX@Y=L>7N-{{O zHsei_u{&Vuq@WAIwBX`sE|`JGIjcf&&G7bF0N zr$zw4Q`iG=MZp#O!1X7`hxfsnbfWE|Br$v0QCTI%fUT{BAq70L$zp)V4$uf2LwuB^ z+Nv?ouuNm?<)>@UiK{NPN%mTs z38W}=0B#Xcb&)rSstdl6;$K}0beg4nZ>@5AvS~`d#v~Jw4MjROffcy13Qj`ND+OFB zsRE^}tX<&(@4`%?OfUVmVT(R|_q;;{`#2R7jD%OuU`9BgKHdRfY)*`2_O zhVyNnfSrdN`0u-%Q&8GSbC!urz(!>-8hTjf58BV6R%TkWNoVw zmuVww7a!v9hInnt-y%aiUlF+|oKh%(?cGjf>DF}g>J<=?cx~{qh{ROiHkCvN1T!&g z=`xXJ7XzJ0lr)q1pv&I;{}OZ{PFD&usU!+=_Amn~tQnT9M9||a1^nsE*h~w+-dbiR zzzmmY{R)oi zWxpjVRQAP+mPd%xp6inD9LuvlIwL!f#U1pfli8+rlV5#)OhVDlIUuM(BwWQ33cW6h z*;)m^t}Ly4^k;8e+!)@SIG3;j5J)RldE_It+BuH7U|^I(*+m@4Q5<@C` z{oPy$1faa7~w+2OG3$-Z!{5EaaX4X1bTyo9vS~QIhlv_54 zz2-!$1CK!iw%;}vGlXF9oj*`3d@L@U;x_mI8CZD!tuP8tN7^|m4J}ZK7>cWG2OjMb zxn2&HcBd)_cB(S12<>CcQOw0axI8Hp ztHWsbJ~_+28+f(AptvwwE8O*D9L?&3LfpOAzTu|vjXZtXXHYd8HA?H&zVMP8J756; zXLncrXF-P3uNqCY2n#irfRf}jYbTvlzIBDUP{qz-H|X5^B(Kkg>PB3irFpZ1}%{1vrga0Xa$ z;WWusgQx=X8fnl33UaRfS~ORq`EL1A%tM!AM8eeZPXRIRL0kAlm2j&czYf$=Vr*MqeM|$UO@lI8{BH<~!urfkA zXu}Xr9|W^_AbP+lt%-%93Tp!#vo-!O%HUbIh7%+dZnARxly#vCz=+uL zQ3G$4DBm4(S_fotViw|C%+w}8E-q^yk)mQ2@!qx34ghX9#IT8V8X;(-vy0M~jHm$O zl-59B1W%Dh*BqlkXWgi^(wB!ywqZPTyP|1~sg7@eQ$WdVb*X*prD^G)8oi7|f)dfX zWsibh1LF+=TR#b&uzR-*kX*KxbGw8D$*NJ%em>rMAt}zDelB%ATNn zj42gLK{>Ww*y@MD@{H4?Yi7y`BJ)a@GKQAMkm8UBooJ_w6PVcu`lQ^X{aCGNZV<-D z0|17oMhec1hXO)toK(knL`~z7X1DRsHyQjG51gcpXU0Q2tY_~T4*?>3W<0`{@nCED z#(TyiY>bDzy4E}!k2VE7gPG++A#uNqeo9Laanjq;X@o_Lk)QbN83H;)WoE@z-xU@ll_=tYv6X0AqdZ+oH)$FOY|K9g zM1ia(WtydQRLf3_5X3_H;Q~9_sgOmd4yGMswRGx~D7a+D!81$_scmpHL;Pk%T29`W zEIyMU=dy$2{!Y-&=7qo02)Q(kU0OkUXMnbi>C^`-g>(t@lq;ZUt8{W((y^_Q`e_2J zu$*}FLplgYkjU z`uIqE@4Z1#36=%{ze*5t9i2EaG(I{KkJl#-&K!!@$Mp{#tq;%CN8%vBF>iS{axIg0 z4J z8nPrvKASyog5Go4Lj^B}9=_3~e5!2Y@#(3JFY-)H*DImb;t05f#LrB+xBnUw*A1y>H5@2ec$2f$%ze{uJ5~k z)7EYF-AMiVDPT2IpPCpNkLy!YlT$n6x}Jf?@rkMW(D0$5{p0m`cygp3yhI1SpSGMU zGH1A^&p*cVn%wiMCMo>%kSlY9PqI(1#{d6@T?^Zds2k*?FpXTwVHLF)L0jv#mw z*OB_fL>SuUt=UrOp{J4(=3PTqX!So%#0qXgAJn-`$k8m>mc0Jf#VY+ zU=OHwXlR9KDz~!!AA>~V3dB{&hJWo!kun@pkc7Q<@pMq_I19| zxC_?$M)z;w_x|JcsnPlr2=2g7bEQgfi28nwpW2i@ ztH1f@UxntpEBF4_cz$>8`QO|7*u$f-vGZIM0cy8ueGZr7-iP(-)(8<@3%ZZ zLf(A89%*_1NuKlldbH*J+o>@BJsX5I!DWMg){LK-G-3hq*nfO#qW+=!@bQ`Y=*094 zTyGTCGcm+o-reD7&?NVwBS&cS(82mN&7PQiN$2h8T*yGyVtiw~_yAT-z7>ZjTDPsa_vJU^qTJ6TfS6bRxcQ6yaxcTz8~PeY(E0 zVtkw1Y|h`nz5nXQi4*RlExC_I_(pWV=NS|W**$S!vNh*f^2LpOw>fY%a^@TI6nSfn zy!6^QRU`AJv;jfzWuJE_o~|D|UY{7QzfLT0lG52j;HD~ntmf<`!;2e)KU?4{N%X7#R%N2lYF`q8Pn_$Z`!kR+qV8~+qVsD+tJ_Gzo~z7|Cau({oDHc`?vQG^zYc-w|&$0&D*zZ-@1L<_WteL zw-0RJG0-=#X<+lfmVvDU+Xngvwhs&p?ASpQcThc|GzIM-(~cdl6SqcZCWoB-?Zj_j z@2JVq?n-bc@cc4AjsJIH5K&tksd|yJ-$R){%TJW*Mp0R=>DYd}hXXo{Tv7Jx+c9g8Ft+pQIf9OYwA&`#WYvtlKF~-aj;5@87yJ z?psnpr-9>5ojf`-39~wS=;V!JVN8JCj()!zQhvLa*7poaTRM0LoCyu`!!{jnpE*>Y z%1c6$D)dj|sNcKwz`wLTH*&vwVxm4}E!sb1BKL583_*HS$@#oD@sL(-*(Z|t+^yrze3g5RE8y?4XngimQZ*0(%wx98-u=hAjz6?iUtxQhz2hwr1p?BQ-I%pN{K z$3B%7a1R~J9=@NBWe*>uW7)&Mpq}jEUs6x@u#bAOhkL0fdl;ggpH1u8Pd(YgF!f{) zBh-^U)Tt+XI6ysm_~Rvl(?P*Xj6Oa9r;m5P+r$g>8bpTU(&yp%roY8Uho**(Oy4v# zDvfexGKOzXos6BV;a|oFrY4WL>^tKicxYM0HBt#)$qQlJ`f+G$epPE7hYtHx1%bdw(4_689zE&C~*^~>dpO`*S_u{A$O+-y@ z-MjJ5JKo)B9g?kJt$%k;3>~KjQ==cQk9b-UTgF(@-_H0&>XJ6Pdt&$BvI`Ox7c|ko;BhN~>CSxs&4d*f^>j^$_U~Au#Ki^?ZGE2l=*_Z);rN!&UH4 z+a%p+f=V##q;{?i1MB01fGrp&@7u`h>Kh)K5HR=G;}6%TCf_B@!At@|nS}^x7G#-> z4`B?TF}#f_aad9%kViT`G&!yze!`de`&?zY@U#Rlq`rso;sY z{0Z77P3@w!QPHL3aWynV+t(<6%Z1A~i4&|%q)uI+j;4IA^?dM(is_*T>ofZdf3q7+ zj1fI)utyIzr!y0R;8DI6zx_F`8joM)s`2>^uAaPP^%)z4i)L70l$uI0 zEKSiV9ml2|*WO`M>f#%5o6}ZlpCg6)9G!H3eV*G*Awv#;fPSx6 z2ruxe71m#TlcS?UV;rg7t51)sz?~|Dl77`y{Wi)%ixW#%IgG z)B5bb?9VX%QND}$?jMnvzQHd*CMfW00<08YDnop$(VY1#MFmUBgCXG@<`JAC@whcql{E`3hz^67JGmrtLs zA%C39pW5lu_oC}-G0@4eKthC z`ZZemd6S}O=<6Nh{S(KJY{18Yqs8>;{qh2AJThsz%6VF#vHK-pC&;``d|J4!siBe4 z4>`?f{R*cU{p=fA-|(UO@L1jY_bB!4qhD`%W9l0jJvcg}o^`LR1m8zJr}+tv`p0yz z--ozfs%7H!YrWH%ru_tMnx|=hrxnNoW#}`CH*O>HDIS20L&L+zkJ!NWT+2rs>@(~QV;w~VgF(7z2rG~a;ENY-)pYc^kHav<__b;K4A|oDAekv za{d)hcg`FbFs;`Nsr!x}-8VB?m-S*Fyny$!{8GAe%D!&2LwIo$I!so^ep&LzxH!kpqgQ~Qjc#V3$!R^w# z%<#XwS}~jPcS=fdo;t(sNgSysCx$oT+O2P#nA|6|ZD_=7+ILgO_XC%0{Bl}bW&wJZ z_mc4SPg0&>d;>pJW%(o0;D_LE$VVu{L(jrd%`)^6Hc!YNJ{lxX`guo{bpL>87j;kK1PMv!-Gh3*~1S6$rrMRvqAD@J^bbsqNV>6 zKj*t~c0wW|G*w3!4Ozz10ZNUC!MAG8ipaOg;Je;^<4rf;vim)^zW28G-M;7j-+Ra2 zJMa3wyFYNx(Ej0(`hkOoMh}mTADNgudTeTX=J<*GK6LWKeVaCK*}AQN`@oLtHY%R- z692t}eD8GM?Y!Z8-tNB&!l+OzwY7J2c9pw(mMpC-yX^AiSG?)XSH8t%xN619tKWJ} zT&=xr)#^2Cd)Hli-TDpJZ&VX5vD!B_TkwOxUNWoj>tFNBKR@KtKDeq9e4P7~_G`}P zpReFqX=ljyLtKBDpUTwzC-}+Kx>IpK;s!h8;5_+c$@(p>(q{h+Kh>|_EiKQfCG{op zzK3@|!tdYmdzhcf*1vRqh&StB`ut8c!GDD|`RH{@6OMzBRCwxFxyguAG$u|A=SS>o~XLECw;CFqyZ{#YT^ED>5 zV09-1oIJPs`ZJy~;?R6Yj;Y-NV%HqQ@fz(rM14p2ec%nR7q{;J z%if#7Q}w<7;s?#dam>ebl8Q2iN)%BcQ^tfiIEKvgJXAyxDy5=AX+o)JP*NHYq6ukG zGNqCRl``CCt$mJs`g}g$`@P@K?|1Kg{r~s8Job9_UejKC?=?K@{X7pUAKn&AqosQ0 z8Z>JJqN4f0HY%1agE*9UUqF6t5e%XsceEkT06A$0K!1E`J|J&|Ib#qbh!)`&0wG_# z^EnIkz~-(UqAn$6Pu+-QCwflv+;&4&YSbO2MJIw8TXt0$UGAxSB0(1MsZ zI1J?9G&ho^v>$=X<<9@3+JgLU6XmW29A7Ow-m@dSP~^ZH6O=E75gfj|Xt3xE-T z{s|r~WBggsKy;$^_XR_qnsR`TosjoIX5P&CzCM5vSNR3PQ1I&`{-50rX&>adbV8no ze!HKF-}r04@!i1x_xDvk(3b>8pf#hIJV;WZzGx>G&2?Bj+QBu1N$*pb&0gk*mywhM zbdX8oqG3|F8WYW_4I#E%f@Mm+hB`ot4A_13K~RsG-4p zbIgf37qgZAjhKXt{1?Wj1L}oF&wnciqM`m5qW)eQU;`A1xAtFUV&Z234?>su9RB^7 zL}|bFqpm?&Oa3SK#wrV>Z^VYiU$)_|SihGsSBZ>Qp#Lg0b9VZ#ql^!g|HdPoFtugI z{=HhHGN_jpaqlpS$g|diXov*?2AUhfwAaszB%(|vK}SG301_QED`Qp?kaNrs-iag7 z)d(ZTJUfn>WAYQwam+KU$A=O@zUW&(tBSwcYpI5w;UUmdpl+akpg|yZcsD1^#{Kas zgLwzUoP!v%p+vaHe;t#Eg9lr>r!N{3_;h$r%B{xOk1^c#<6EEBIM0gt5Ktnv{*X9AxLVKm0Ft|NZI z1YR4$Xm-rHz5>GN`Ap<#=-fZkSNW@NY5b$9Q70t&NP30d1?K#MMgR~%^yKH}hL(`% z`%zs)%z1R-h~gT-5zX6JX^2@qvHPt-gZqH%ND{=l?hV^1tc;W48k!CMU0(h$AA;W6 z)7MQN$b@bJaSMQ0lC)zGJ`QvOoPd9T8Ds?(;huyu|2OR3DlY!x?(IMBd0`k+^hbkL zpf8$Jr$YXwaIcF&7>HVNB0p;aFZbJZ#G~u~X?-R@ugCWi#g_cVULq=k*#@kAK6(&r zMPOLC8^-f#fV9WkO~EtB5wL!Nj?PHC0N~v+2+{`ckSr_xb(o%@ukN4M`4{T93F>SF zdHxrneqpiW;t?pXqOeFo9q(Vz16@22PF<0>f*u)3PJ@hlYy_J}_rrQ-mtmnUP13nA z2ygK#(ShY~34YSr_&~BHj@s$OG5IEO-1r?I;}aBgNbqZ-xZq<#OBOyd8XC}%=9tTl zI+fl~{YB`QpGozBqjp!0Qa&6rByL@8hNJ4-K`$;{QvAzB5jS;oNx7|wHmaezq#6@< zpBsg`B(0rJo$FrdYNwWki=PqDGyBld+(})dx9hR-l*WO0y|0F^s@dhs^hystiO>!2 z)7!}|BR4;Vwo;8l<>HrO%a!a2qn!aywyoSmkyPxNcYWoomhK-fmA|a)OU+$kyG(YK zbjh^j4?7%J3HeSgE4#FNRZi_Hsn^G9R&hkP_GLGXuG(x|9Y|lXaP@0iMB@;}W3{NK zjqW9(L#xl`3C@3b@4;$u!<;Wko2Tj**x&pp>!PLKBSKyD!y!iLUe4l%Jmkt=-tL0BldL_L^XINz88;C?x-gplR7<1HKd^ zBU4^}?sv^+Hkk_U=RIC8dco9g>~T|N{#(=im5Ch}SI#nvQ=Ip7PL`FK|7 zQ%^6m;EJ(%FC-siVQOF8>+t=!h0FO?=a8?@EhPM_9j2F4Eaw<4DNFHKZK-fLDgX3} z7|WQOnRAK_&RN=j8S)i=)@>OSaA~{5ZZWIgRp$jiKV55;FYNT}gZWmgyAt6K3wy3u zE$3U{TIc`Kin~=!YqWljHN|90y_U9}bshP^;knaxT90PlS*>Jv+geNGlI_);AJ%Tt ze3u6Elx*VP3(XC>>uU3|_uvPfk^MHQXR8Kfmo?dZa99{rYCLJ3ml`Q!7JbRO+bc+4 zJTLpLyCNIExZ~lGb@Nqo@3hslu2a*|59j^KZF@sT{%xPVuI*%YW-#zR-Hp8j-={DaPwn#Fd8h!#1yvm5yE{DsXZAA$hyW&Ta43 zZysK!8#7JH?#NQb%$)7kcBwO#Ue=XQwaeZt6aUD8LhqR3lRJGwVYIQd-X!e}%}<@=ttJO=sHa>GKQ-m#hB%uZK`Z_C z4QKY6DX8t>bF{nK8L`=4-!bs5gYc2mSjTziH9m9+op=1`INhuLd5`1!i*+k)9*aAD zF+ZGQU108Xc3zS~kx3GK9Woj=QWZ|@S+)tGYM-2L4*Sh{R5h3W*S&KW>XU8U(l3(B|=NXftqL-JnJ=Z(8 zvycvl(v!=&X2oew{*CEgkq<=@3^oQ$vDK$_#ciB+bdkL3 zhw~d}>_}Y9_O^GU(ZI2-H|9usDOt;W*%xNvb;V0XInFBC>(rFEkrx}UdChnA+fc{; z*-K4}Q$6ihJs@2|$E`86K%|7BiJ1ASjdX|dM zThkS_g(uy7x?k_QB50Z8<9~0dT3YFSAFitHRcB{S@l6kuUnp^EsqcRG;dXPw0N=Px zKeKvr3Vhq?KVoK0dg?0|bG1LSgX|ZY<27GHbfsVBmMLY^oFo0TDAEBdV@mw$1$`R! z=5+eS+1JEhy(!|~xFn{@ifZPso1CNfmX_dedFrOXT-nS1Z!%T0{enLD^FAltm~&!w zfHl94vf{3F0baH{N6Igx1-x#Fe4(mxGvL_{5y7g_Zvhq`4`&CC$_GCBs+%{p(m8P3 zm&|RozFC2V%0J#l88!rRIz|WWFkugB2(@cc>QE2bWEnWA;(&KhQ*gD^g_n6jlguLu zU$1Kp+Iq}puh<99VE&q~&jUhqf`uc4t?oSt2|l#%e&43mg~2XkRVrt>UIlAb2E{!$ z6$s%xW7huYh+&Ak&n`~JvG|bd)51(f8%skz-sSHY;phu#9yKZk??j=g%W~IASXhQC zn$+}nxo-=-LXX_oexou}ASN|`!IRIS>vI%SLK|hm{I~p+x8!gPo2ych!|%L1tR(i` z&HWlRVfKf5RJ9F8!-lHJvufU}gkSn>DXVePJ-k5a)cNGy2gBVr82YP4KL}_0YG1!X zbZW%rg~4%r9hwo!xhE8jW(G!R)$Ce&IOAA^ab(zxYSm{E{zco}hI4r%Q*Gqqmrh?5 z=~ukiX?sdkB*S}lwECj6k#Vc#L?!0nF=lBN^}5$CmzWt^vr49f?Tax=m9?+QycbjQZU2%HF^<@r5K^*c z=b~7S-K0}%p8Ldh*l8P@p30AH3v3d5ZP^l=kv^$YbpFh^@+X^p*J`YYlg*fYx2q;J zZeehdresu6TyD+V#LxAw;{M@k>~HWmc;5x)i7QQ4At?{+HX%V0l2_4bpj;CC7w5q? zgY!n%sQQabuselBV}Er8Z<3AcS2$@n{R+#0iH1O$lf$1+#r!&j1=!Yw3=q_B7sK}HV8Mz|6pz6MPeuJNxXuq9MDqPS9UoB>BU zII_W!)qDh+;*W-7%peXo#MuBxB-27IJk@a(wZqx?^5^H0H2-c3piKc9Nr|Kl3dv4j(<>g}et%4x zODZ8B`S;E|-0m3}sJEMf6;nPUlye*S9~ z`?B0`cgP!O@3_uwek{pG|IF0`pIWHNrY&v-U{RobNvcvuT7&uIbyp5UM$>~;orxWy&!LEc7mYpjab>2$3D->7O?I)bcTbn zNKKiip(W9C!PRZ8S?3;z4P~rf-qOBk*0#NmR;?Q37WxsSU%#^3u_w1s_rZOKK#IfG znUR`WZUw4E4=$M2ZV^9ws3p@SOJc3V>=nDX@^XZ3tciHOxjnWm#x$FIM(JycN0FWL z{e763)28RNQR?J@H!e08U9X;%qn9P8U}^yn>jEsy3W^#k|#;%D&QEVhU^ zt0UrMcI|74r2DjB_LOJxH{4gBKQ_8yy@+|PteRhmwCdKwRc}Yv=<`1n>CgCNE1q#E z&SM*+c?sE3wxm@2=1-$6mE$KK&;BZMuH4q)tlD0!B0I_Qus65(Wt?Bd%-c|yWo=;e zb63(q^2~!CwXL;ATJz`}XXdVQ2WMgFhFGPRi4{@pf0tpzjuWtFwyL0vx68?%P6KZ>`I*37a?9 zoA<%Hg4UE9l`tmC$D>>Jx~ z9RG2}=$vet(=iF&mV_kPVe>t;N75`gsfoheMNJRNYfqe-x}`PL@AN^w*F{u`4bR%1 z7u>&YbFRc$(saB2nl&Z*v1@e>6s27k6?u~P@bP0?pSre&SJnj!1^J^kJqzQFveE2l z=_%~1;w8^-bh6#N;nN-UxyOo5O}Zd*r67K_hwz}+?X_>Mtq$(w-hcd@|cZt{kNHt~^@ZsBdz0on71WV~m{wG_Nh*PaX!i6nDH5l9bTl zZQwmzEVEVYu>K^D&#o@nqMT2KuUUANbWJ&^mM;EAKrmlmbsf*P&wXBoI|Dmug}jTd z280_uy`;D5lxTtv+e$GWxuGMt zD&OUX^}2O|+*xNoiQRKAyuV3|tv!NoFo2RKBUJFtO6Q)SY8?Gp#trV)trXwY)@m`* zGzNQhk4I;$U#5w-To6k5Avg57Wd9Y_*>q!}qVJR?-&V_5nAkg7 zF7^=kRJ2|~LGIz@5YCu5T_+1YyY2eI>t;Wz{`OdDf1}7r_2{KOd~+WR1*UE*O*@y) z{c&i4faE0|h4dp+=LgChnmt48ARifE`N>(S|*KbPGMXEOBv?vYy zXqJ8?`Q35-RDO>xgNPk-72CIjia2$@noOpx^{t*^UfI>SfuEYV={{F{+sDa%-1`%r ztRW9R^4QEzx@Fqj`T9%lAceXh>^<pDd&bq+dpdTc|yAn&1y zn)_~p3l3f)pH-<_Xd@cu>Z4uQYC%r9yA_U!`o7q+`U^&Gj|t#z~2BqolxeS28o zZ63wK7RAYFoeE>3@sD@eO$z#yT$H+TnRq2b&`ocJL6gkjLu)OoeTHLwyhn05Rv7Cf zU$)tE*2SH17c3MOLy+?ki)}ukdma^6C;Qq8SkAi5s z&|m>;JMjm{3|}qVNn1N2aQo|Xy=WnB$$aXVw(;@1dW&|QZK|ah)_Hz&y?2_E*LR(n zX(^AyQqBI`X00ij$3I2{EzjT*uC4vJs4Zgp-NY}|RVvzAd{0-rsr*`X;-p_W*P)AU zH4?A0%j*|3TFjce$3IriJXd(L!5;r@fhVb#p3h|r1fS=gPg0_! z(1zToK=qxDGv@A_^6u~=k@ilJy>{QVMII-tnmiCE$8XfPy70^$(kt?!$@f$D&nB;a zzI>(8QTKa2(vM45r#}#xa<=|p^BeP4$&1f#9u7Rgzj)q^H7om{Mu^D8dWuwSCEK>1 zn>fEvkn<@hGC^W_CzpIciu%o9*Nx#!)1*D}s)x1|@qT=R}B6!PKa zx5eBCd%2Cy94O)wjhJss-7Vi*ViDLpr^EWBfP&R(eV%I(JD%NmadFd1OWx=!oNcjt z(*-hfvQitTm5XL6HuI119t#UCX>ShnQ4owseW5#ceC^QA&*#DiE3WaT6^}d^T`pE7 z_U__(DHm6<*6pqv)^3QhWYuc+$C zF!d2dd`phJQIY3{z=~|KyZX8-gmPYQZ{B7pJUG%JIBlwDHs#Lb!U`VC9sP=4AGunC zZ;OM8M0WhhoBmm#(doj%|&iI7Ukt z(?^G7YiCZss9Zd(6Xzm4V^dw`tVb=mx93UURjuF57j`e)vhi}IyC0X2?yTZPl0yOV z&kHi^C2jq;HyYav30Hrqh*|r*IWF>Z-tuKdKlnKN6>EDHu8rNil%p~d@lCQ>`g1O= zQrS)YhhWu6^)8WcaeFGYe%_@GKMUFFyhHe%I-{dbPq)}DTzl0$f53sfKR5Gs$%?lU zUxG82Z|qT|zUmI0G>?5-m;L6}h#&o$hDIW?O1# z61=d!iCS#b-81KL!%NxxWf|$sK>{C}*KS=K7GT_8TK6O{T$Z=j=1p_&wce-_%cAsz z9U-DLzFF-SD&@nr&$n@HJo-%_enpS4u1t-~X+vNC{x`dL-8Qz)TRd~-6d_(is*tXP z*xOmf@8phZc~OFWqbNDCg4QNB6$4_U$xrRq4ePuf<(+Lf$GJ3fuZ|;qhm-o`IQRnkJO=T!?mMmi1+o%dRa$K|Yj%J*jRBJZD$+-O%_{^)5Gu2tGVEAik2V2n#itT6Dh}N9srI{a-7OC?oOS~G~QoYL1 zXZYFrDR*|Rm?unKz%k{puZ@z>nM3!FXPfh7ytuDf7c+-CM_5_x*seYa?XKfWnxo?S z7bDicPB?Kzn6!55^;+dM4{ukW-h9xaman1oNW+RZyynx73Ei(rJRx~BLu?uQtf#?K zFSToH9I_BGn`v0bRx0pqvXhAW&(0P6$7f8No-O<0`=axa=EGam$Su#gPV8KvlxBNr z{>9x(K8WzGnL*=b-?8k~Q2+N8^h$mn&1vz=vb7jJ)$4v_Q}>fQ&;! zNT-`__TGXC@y~ajF@5zX-Npa5>v6C8K zH&2gP&G9O0PQmtfje_MrZ+Sd&@@|ZeNa*t&SWcNgG?hC^HL~l#;6w5n>Oyg;%q5)O z847DV=Igdi6R;O5J6Zks>amozO;(Ms9+FEaNjy)a6av~aa;&=8EjD$Fdvo!drmQz= z6MP}wc;diYq3uUb7UV}AIUOE*wt&_l#dmV@$^4Cu4`SwJmE|8$KO|v!pSC$U?rD}} z(Ki!;U9rMp$K&r!af^;HntiABdGJ2IkDP3sGyLV#i@lD_+iSUAa(y$&EZ)MAh z$#AlOh``DNPd4$3`;UJ5c5dhinLlh}6o0m^(DhNfJ2DDUGs&NHcfG$g`BVK}xf$Fs z3(kmC<#1nXT4XoFuOcttu2d@jz1Pd?f`;^`rDm1Rdo1ctE;;NP{?3lOt!R!Vm(`FF z^?IC{)4-W!Q56?YHk0Wy1Qxn!$A7M@+mj{N|00O`m~8If;AZYt^kLoV64%Qa{nV$n zM=xwew%q+p%{S}leA9c3pHnCrXNOnXIk+5qmcZS5=4YQ+%?>56GlpV` zB~8otK08YZJ!+YI^^@=Grnzl(AyvJbC|gsH-suxMT-qYLYTLo%IpSXaW|Kd(3(sHG zKPgXWYl+ad&rc4{IsekqE9IbZ#G%iWVDqoees3F+!dEIr%Ve2LIGot9xl)Sr;hl|@ zwOc7GggY;<@u(No3aJrO%G;G;HVFe#YyB+q}5-PP6EFn@`nA=2w2W{5DZVz_`@7H2aF5 zh{^s``nLONr?fJTe(i9!<>z|UOwBvq+JE=Sg$1UYSCdy}OK->yoEOXcb$k0+4le2> z194%4!Nk#--iCndr#zm8P6v>;Z5lzwj^hM5g=F9pgm%oYX?%Dfv_{+_K zms;ojUsXE_a_~|FvmDgdQ|kujZd%gKJE>P}Kzi6ZBjbe>r&{_Ev8H#gQ^l3qpB!7W zIp1OV8^N~OTeQyF#=Ux*f6wHsiY3K<$zsK_sydH|`!Ss+2^Qk7<((=W)S4|akGq-$ za)b(rrF1jS&JRBs`tHK9w8mSMA9^i*WvAxyeB?`Mi8(h_!g*tR<$Njg<@0p?ido1LFOC2_$q{30P#3o@e%&a5fm|UG1;!A+LQ;s!3`SqUfJ|c*ii5OSG+mlZy0q zGq1-xj|iM`Z7`~sGTC7J;nyFYA2;PatI-izGh^Bb-Lb{pipS20eo^TCxg>vyh3D9A ziO&f#f)1bFDgG?24oMp0IXB2r&a2S3x_jrWCsNDD;x0%%v={qiIVDkNQ)C%qY;0%m zi4ws<-NlR8*qm=&R9X0R>-)Ks{==U?vU#X$*e1N)c~pQ?JVoT|yzI*xe!ld)8f?a^ zDbyUfVQa^aSjC2=q-)-v@F@;Xxr&z*X1M!;UovT z%$WDHH>cP6nAPu(;XAs=Vq`qW5!MaeCC@3k&oJ72yfAon!A z)AQ+^QPq$i|0!|G(0OH1!^<-1{@Izfxy0AVwB5O__kD}7W^T%tcn>Gj-(2Fh_KUw$r zdzGZGK=vBFsheisX(@g=xLd7Tns-6b!)4i%wQLPkt+z^P`HEiM_N-3e(8x=lo4k`Z z-~A}ylK0w=S9tWiw5QIZ?4@bE_p=|wmD##%of@Jx=k{$uG49vg3wQFrx&I*Jo7tj6 z;ewoE%hTIJ%Y#E^-qDs5{=pl5N4YCQ`rG>}`bXSf+TIkCpKNzgTU;)s_FhL#X@i z8si7?q}37G@9vrvJfY<4Md*v)Beka8F4o&LO;%!ale~{m>q5Te_iYXyct{hzcT8G3 zV%66ZjN?Uy0-?ryF-J9W)3hpr{R$$(lC3)=T+Q}$FH?4PNWJ*;_7qB)@Wo@N-q!87 zVCXNm_r4eREk2v0rzm`a(!A8w1HBZXT*>w~{oK#=wzTnkf3{fBZX^;vtFkrvAbW@I zY*}58I4%B#n^Yo4VmwUL#b6q(qD;PY&n#n4t+rvsoy%)v*Y=9s;XHmU?9sw$$`7jj zlG-lwdrf~QaVJzZcL(>w$_J-2$?Z>zT#wkSAQ=c<8WWFAqKdqp-B;Gm){ska+J9Dg ziNNVHvE-db_xz1Rx{K$f{UCQ(WgaUleoZ}d#ovG{X1-`|m~P@Nn>SIPoOevs%DN(u zG^93ZV?1SN0f zU6qiyd!y1WllExJlUhOU7=wVI z*R=F=wARqc{7Wg(3Ot(=Cuhg@HQ0V!YOz54?zIB8LyOMT^|!44qWH{8C~sea>YAZ- z(<_U-Z>9|M-Zuq#At!(0u5yo!=^`Y?xquMl$x zaZ{Q2SCY=QM#K^@SctnHv6)5$92RY0<6k@hi$(jV_(vn)v1q>$|1vW$Om;l}WmOE9 zMPP39)9zuzuvxT!iGImS1bmhi|5P*qqh-dAfAsVXhSM_R=hm7Nuv$qX`J`*-1u?u9 z?U%wYvDk@#*$QJ;ySp`348Z`e86tTZZsfbl~7qk~gi^V((-a9%M| z{8rn97e`Oj*kM>NFNxOcH%IW^gYrNO?-d})bkv>B-jw9Yg!z(eeU=-uo&A!xAH#il zwa@6M=juEUm_fjP1;|gS=cnzmf+_UogB__(O$Eb!~6VT3!NXEKwF3Ar^bK z|A8R^H>Nm0$~yAg;Z%}10Xr6os*T~Y8q9p-O2CiB-ygg;&q`#3_pl3wAyYh7Rt21L zjBehliQ&jXRn02gd%{FhPjF&bve=S4?J^bfciI>b@MKEOMWGVkft2ehCb|7HOyb-dD-ojGXsbvBfzAV@h6x-4KO3OfsfH8}@O-nbP zTYSf7a36*<^Tyx(^wMwL;#w5~)+|7aQGAl(yESTT1BN$KRZmyA3r$unb|hfVCqUGc{7XYxGG*_1`3e#5?M41?w$ zXeeyfi$D3iGXle*MJ_lkn6hAC+YChl7ESJ4e4$#+TdqNafJgI-S07oTn-ms5oq$P; zbY9|`#_zf30KH2Mmr0l?SgrKO4iRh10#Cr625FE0SA; zVbl^&ZoY|dR({CS$%*0Ae2uEE!dFJB`JS6#ShWzxikKI&BbV1@I%9aX_zDB=1scnO zFXo67Fza1U@0ZmWukGR>;MPK6=Br+7d3l}M$$m&cU>A|pU-n)AfwRTmAza7rQ@NB`D;qLmc za$R$x37EF%JqNNjRr5^Nj%66G&ATFmzlp|~J)%Uwwgq*tqcS;G-8)K635z zC*b1}&uZ?Ne-oVM=tjWEDST1k^UB2TevMnz#CNH+;`l z#_)2A(utJbX-;h4*a?`qkmjz_Qk<7=lx{hQ;pSot(c-}=d_!h|1niu$+*$a1jm@Gi zZUTNT*ckbuy<9%=(1R2VLl?Wj^|mfklkbQN0Y~Tk*w{6CnG?j)1T0;!U-xkA3GRER zQ;aY?T{L9-Y*X1#&CA(HlJ6TmH zb@$9$9dDlnV|Y9NrnP?G$steY@)Iz3k&nApX3v*3*k?q*-O0t@1XqLv*GDVX^IufHT90Az z!o_R8*Kw_BRy+`Z;qekiicw=d{ap?u0w&KV`O|hRZ=++#^#Kf*7wU;niZfh!ao4~* z0yeK?6q|06a?VbWfX`Dj+Z`54DIESJO2FuaIBnFfpBh^A!I^;5i@RITx-`Q+^|1p1 ztEaFP$-2!9`d~O%h2iyrY(k}#O{Rqh&wa))doic9rmzm)lzdYHZqGY(_LhKMvwVsR z0lOCrd!hF9?MTshnG+ z@?M>Q?UN}g4Sq^CaVHX#F?^ptEB1QIu-xGXT_YIAFCt;Ou0=fh$dNOL2snSYvx4y) zyVO)W0@lxe_-90Jf4~{PPhl9|FOn3wPk*CHHs=Q`4D*-FG;;J|=hbm9Q^Rn7zH-Tn z({!zPZ%8p=|0jAn@9sWj74Vi1!~Z2}$&DLwwm+U5M5qDq{d}}JRQLV%f%G1%4j`yQ^i`FZ#-Fq)dvJCOJ@p*G;}C8C1N!Kv2PhN#fsPECG#I* zbpl?svcP>ym4=ROPsVBmf}5SwV-2G(nicn9^#ZY-2Sw6P7YCXbQLvf;@7GB$Rj9T+ z?ly$FfxyBk`zoCjA8N}JY6qe(IV!_)Mz-i{66y!Mt+!6^;TSo(ehs09Aiy0;jndOJ zQGQW^)e)$*+Xm`Sbv3=%ej2MKke3$8#S2I#?v*Fh6Zj2V7QJk9n>&1I0IMlb)4HYV z^-22<1`+BCWR=_nW9vzy31p_)!m{MA*8<|Tj`0)f3nC`-OBK>y);B&0#A*zZ{s)wv zuj6_-t7a-zXW*N8BbwijXWjhr=~%5n*z9BW6GOiKQW>Ut!-G(^8t!`jfc=VC&4F+0 zBeqD&m~BHGq3$4j!eFy-OKiz?M?&pEV!H2Izg4Ebtx<&f17Aw*98Tfa+wM^bH3*^p zr5|R#u#?+NC)6RtLlVnsHeR;-7)_`}P#$!5MBYArPX5_#tR5k>H8=aog|(7PEC@9T zaZ5cmeai0h9GOyBU4r7dhpnwSEO*ipLTy6u=8sJo^?PboP9@YQ#L6|-wjFjjm~zVx zt5NXwrgSw;ElW6E#);J_1Yh?{+&1W#Lp_p))ha}dtrm*<7TXNWA=E2)^X8NCYxnth z`w?mu0tRaFGloZ#SFa(|EksRbWo&ggT*j5YfKa>0lU40io%*^lkWjx6n4zj8#a{b# z3lE`&LEU=Y!z$0g^V~K~td2oGK2UXPdKrggQ5{yx;J;rKBw&<(Yi?F7p`O8Eg!NxfKoL$bC> zyol0u^QM9}k?$My$@mx~CAk;*7*`@ll#BU{W#}Voxf}2md?vO5%eQ+odtBr{6?Ay?) z&bwZB3m;Y=;Z-jPO-tCL#P3R|kqB%t;Xl_^t|<~jsFR3N&KjjRez~p4O{kUdT0fTz z;t0HW<^EDay`<<-k7?SKP3=33;xB&jy=0YwvF))K2(I z7}L~?eG3v32eA4HHEsEA9XUo)kOiTJLJmk*HxFCpY1W&9)lv9O7T%gGkhaCOLjkL$ zh)8LN_#X&3I&z>KtEWf`=o@S$Rd0Qf%a7Gm_^1b-9={$gBUo#T)m4P^;vd`}*n7@y zDWSF^>6$Tni}fK>kvW9=3SVsSyV>s&k2sz_gVk7s5AN)db9Ybuw%-n`vq-RCAxGz4 zzo?;2sI^dTzTwZVDPb67T*T@vLJOtaZu}6dva+FbS^)Lkh0-hn+w zU_WUEq4pxQeyZs!qx^k&yEkF=7qNY=_qqHTV|v3%SPh19tzt5{e%W&CrGz?+po08V z{y6T&1>23VT8x-hbb>dJC*7{uk5G>>$}U)KadXM1x)iJ?BPhw9E+V5^(|^qutILR5 z(1&>T)3mG>5o$BMCoX@psPsskpBRhPX9OrG24y~MRt%ZTRHNbCwm;(WS*_`BXw;u%eG_JmQ zbOTnm;jic}w2!(szh!$|Y?sUx z-sC%29Y*B-OQ`Ee@O_|U9idJwxp)Sv?eMjpYKb;_H7%zg8>{aKrR|xSb6A9vBb^ClxuBk3GR^Jwh|}7%wKbd_NIKsP~8`8;+fF*_vHzN~rlz z=8ISE8FpvC`dS97`v?YiDqQ)=#!)CnsQrl5nv7U#y?WL6@i12Z;f>1IJe6vDfYD!F z?&hwfEl91ad-UN0Y3xmer}iezCeeWnW1WM0oR+J+)2V5iv;=SY9xlol)i7%v*-a*GnrVJi-Nt#e!obyJWVG54@tIpm>IA85-%U(l4BjX^d=v9%TXs^ z~!rLKxZ3n8<^nfN|ai z!n1(>pFcP3Rrxp2FxWB*4vxUiNRh)G0QP>5A_G{QuTtiw~tZRhI9F1fN z=Miuml<|VWOg5PKG{p`Ri7?B4HpB+coGc%fKA`0XN^{I4*sVA#BGaN;FgPY3x4KOv zh757cfA~-dRm#6|fJs;iYJmH3g!_?(2Z996tovmh33bO`=Z)eB4LH_yq|XNmcycsI zi`pOk6qGy{s(7lahAdPGQCDTTq-5DG_Xp#ZF35Z*ywOB_^t=&W0s7|_On!NAxC(Ve z?`l2}68ira(uI$nh^(&9ty zR{?Yls1gX*2P}X22PwLGBjaj*F33`t!Xj*Yg>?$<Wm?!!KWzaGyiqwK zqy8SCwn>__iHz-8oqz(-H~e?WLAHgnf#me?U&+VQpN90P57nGtH*%S#t7i~$Q180z z_m^heu_9{wn@|VTUt9#51GIwWb&)piP!Zeu9XA_D*t7+^r{I7!7>u*}fOiDQLk7}H z1Az`4NqRFGzUf~n#tURsi8g*_y!`F(Akb#bbs)6qgr30-pei8N^MaAX6RcAs>$=!C zFnD~#E|Ne&6}+5zGF(B2*OzJ0IgsIoEU5nB4A_TnY#Lg`8o&sd4VZme@}m~D2%I5 z_eQFc5ui;AYSux&S~<)w#2ak=AveJ|H!v6o3b@D`GBz?h&W#6fLtx8 z2AbSVem6BY7H$5)1-;I4p-W`TmQ7g*r+^Owa= z_P~)K(NZWE8n_d5^&VHIChTy5{x}^x7lH>+rV=)C(uX|qfmU%ya9AMHVn*Kce8EB? z(}Z)7KQhA1V0fXI3f>q9q4vXff%Kv2<0{9v)Nvb$@BqM=vI`hi4hf1Nyls!C!{=O~ zK~O`w1o{O9$-6Q_k@H7Evf~iF?HV8(akuE%F zYZJzZe?2TTGzJESfMG({32*wJm8nsFO#O4hLM^;DVDH%-y+YWeGGPEY#20x62JdRv zu?W`9r^)yQF`XF8PWT2Q5{a=i0gmXq&;Y%CGzJh_*%~vLwi=nL+sH8qjqZY7DuRA` zFeAJK($OH@@0|j?G=v8X9P5uRFj^rE(oRP6GSpA~IW2h30L|(kKVR%X1NAHXTM7S( z*$`jl@6veFBO@Hqb3!S=qX49t1;_h9s4VEu;8O_mUG|}}f@nP&?tHPES2R+BWlYeS zrxEtOVAC4XqYdzba76v#@Abrqp{T2H9c?VTKm(%tVYV3z;+}4VsZHFbG!H*NFT(yO zo!QDT(t;^Y^tp9H9;%Qw4aP;(f2IMUyk-DR97k>fkAAGV*e!w`=Whdl2dEmT2B;Q@ z)&Jdva2-%RPy^8K_oJYo2!G>!Dbte)a^wfE5z~iFY7$XTceq!Wc8>R@x$sO;Uyam40H{}oePBWLUS4f9zbzf&k^N^&Y`%7P@eoi z=vksQ13HJ|AP@n{7nOm+C>{zULS>}Fc$foJ3{(l!2-FVr324$5@WBTp38V_74YUTx z2`B_80caOc0Z<(fM*_TWKnsDE1L*^q133dl03`wK0m=uu0CWxL2~ZEvH=vpD+@*lz zfpme)fb4+WfMjH$vhYJ=FCz3E{-<-XaT~6FFlz$eu6T?=pZRtu6Y@O}1Xe3h@rs&v|xBQQNclAP6I%5{nOpF!~-fpkUUySl}n-Q3^czc3IcUAUrY8?Z6vMxSj%G zv~Fg_N4z4C?u2s(A*==@Co8i|bMAa?R@}|#+=O@u5S|01FyUMh^Bf#-e~R9p79dt0 z=$`d~939R7t>+S|M2v|RJBYqg1=6CvgvFz}PvjS1UguJF6^ZlU3{-k6kdvDaytDXy zasqG39>f$AY{YXS>)DOMINS=bEA5gmIVozmtV*Tz3 zX3#y+DlTMkh_X7dnnxaiu$w)%g(`09s^}&lFhHK37c`(#!E(7_4or8u(l#90? z7!?BN)t){YvuV(5Xab4WK`A!dF~7VylBJbhsG;=0NwScfo1 z4wliOL0~!SLJtJ@XX9mBKw%nmykRi|pAYUL950MU#70|nF;Jui6ZZ#b3fP8>(?*rwv0ioFys>f5HXF$(^ zT=dN=yu z#sSOwvH*I?M>A0?ya1vjCo^Cj3p*S_HnPBbkq-zF(E^ZIYk>GVB+wVFv3!|pGVBi% znac+&!i+%g2(&VQ@)&dYro&lDm08T-2-N z1EDbymO>=f-LT|kva%Dpb`Tc95|$(Ogyy-(xqMeS9d_TMjY?2#)hm4ZgmhDlPzQ3JgWU&B`VrTH|cY}=&r#+i=tF5Hr zsz}_zV;plO-`r&wBD zKz#kf6`I_ZV=mW&tm=h63^6{*T($aE{Ve|3d*3hjK0I^$W-)pE8T{e)+`NNTz~H|k zJXo|mk5F_4&r{g=$)B6bRRQfT(3a7ZNbjH>(D)n*guc|jjO+;>esFBkczpEc|6P24 zZz4J?@9@8k>m1^y0B-;ccktMZb=Emr7_4^GGgxh4X#r_i>7$tGS$q}n=$WzjpAbeP zI*UgJPbk3u<-Nd-D=p?)Y|7SHt?k3M#E9sO8w0^ywW1U?LS^xRn26M#qe%;MdEpV%fw zz)MZI&IA0!Iv}^%h;Ls>)#7NRcHj6}KME}A?wteGLZkkL&wf6_yy>&6*M`rAjeY(3 z4D(#gUOFFkT3_QG?!>(2a9l>QWYZ40;dhwda==Pi#(wR?Rl{E}UsijpIK3#~Abofk z^K~ixv%{ov`l5y>jiK^;RhiY$xHVUFL>2R0Me~LB%~1WIHlm67 zv~z0nf4VO|XEvgT`K8P6JZOJZli)RCg!%G@htzp`&u=G=SYm!}?VKz34twp+9kIuJ zLVFP491>ep8GCo z%cruW5tp$}%)h1b?sA>hbv1VE9p>wk&HSd0CPx zgWF{7oO@%Fz>zCrvINNmk9vE@(CCYP&PBK1h8J_-^)dJYou2tUe97`n5_mL)okD@B zwNdx7t}n*l2F&U0`=ait#HL%|H4u1Nh<{Ufbn%17K3M(*CjO)j2+f^mdN>(-;)Rvp z&s&d_^IhKOlk{+DCyHxQ7c*XzRN#FW82cH8)U;{UTUxPUC-4X)9S)`_57;uTXG6+ZowJzF&9 z!-StlhOs4JzUp?i-L9>6TX(UgVqVK(Z_RBBwVEQfOw6Cp&H7XSoNUB?3-blx_7Ah~(dymU>oMPMF)Qlxdcl30*dJkDLrF60Sy^sJHv2Qo z?>+z8-s1j~6BpP!F|Vn2{OFVD?4M2S?=Vl+J9^y6DD=u(_Ai*H=4fB|kXD#7g<}}= zatSua$R8w|XdIKE{{fFF$~)h59VKTk%U^PRGH#AL}j51AAlcugLJ0brwzvYJ(*=T*mDj$t7 zXar^P+Q0F|zokcS6RQ88>oW@t;V^XKy&Wu+W99h_^8D*G%<0F3s?T}+{Qmm>p~>u&9AHA_JWpvJi4`Axk$)W@cB{a% z>G(WJ75X)185PVl3Q7v{3&7$onA%nP^E3LxEDN?}Aty-3$|Dx;4b2poI}1=4_$_9^ zDX@=E{A|&R0TvFd1v>T+#xyew`$WV=riI|~y)R@s*bUF?UfY2upC=+AL|K{yG!hJTD14)G+RZ71XjG72~FxQhL-{vmQM#FhT5xZVs%@Q0|R zdWefwC$b6(e-a9#Zw3AASmIy;sPelwnC4^xdm2n}Fi4reXAL|lyqQEIY3C6(i;1Ne zb5qb6d7%l?!2aFPvJF;kSPDfrVnb^-I0N4hq=f@19FAy4ihh%rghmN1tyx;IfQ32u z1Pp=`zDc54oS2(rGib0nbOYbnGl=sVG}1-L6YXMD!x60pU%(N4*MCfiQZSRkHC7r@ zK9QCTN0f$@7P7@FN;pN*glq6Q;2#(KNA>Ok>IUioqM=_DNS$a=GvsE(&|+j{;OOwD zZUI)$itw7ln4lE?{}q(opZk^hU~)SUx-sP?anNp}&^{{Ac&HEi%LXC(M`Wh_pZvx} za~Vg7GEdGR`fe6~4tOMmV19ET2!URRc#)x(qJ{V)9(qAfpAa8_MS%1Rc3+MXlIuU! z8&WVgC)xfF|42FocVT|Kko{l&IDY$0LO+tuYn1f6@L%5E1lL(4mja@{@`s0rzTJsD zlA*JBmnp>jhQ;svjo-!O?LbQG;LLzgg9fr5WVBrd1!Tc8J#-*Qa)e}2PEJptTqIrU zfg}3n-og=m=Re_y`ZJ6GB%UG5mo^;>ziGHr0@qkeX=t25P?sR&o}MN{Y`4pzt#>Dq z*f9c$Fb|G%AwOd{qMcDII6_s&%RxE(p|>NFkEc(7_(;yrs+T^zH|V`T3YCz7a*~Ab+ew#=xn`|KDl!OFh0z!yDAOR9Apd_4t=ckm}B+AJz zpq^S#Ab1>K0kITML^w}~;++KU_=%?w3k$2xf_RErAmn;B#=1Ja+M1nt``+t*-P8TL zd;0CXpE3ByclQSuqU~I4t^0_&iOLa#GZfofa%yF$2FobA(dWa80HDAKmy)QeMs#i? z4(0+kiQz-Mu@Fb%Nuu4$eQFA%!#p;h?4|q2LDEA`l2gWM?F>0f&cj9COD?l7$dy1J z`<`59H^3NHT2@=vwQ=K%kFI#;xtCr&@Z>%rwW3jFlfOQ3lEo$zg(f#F-MMG)+rPRP zv+SwW8=2kVju~E17_O+S9#>n}(z<-*s;>R-ynCekuV)(fzme>fs&0#oFDeOd-*N6E zEwpCscBz+^&6(Tvw7ae8@Rh4mXMOWS|HMh_*5?I>W!7)lwD}KPwr$^i;NTHqGva*V z(G?T6Zu{GZn`B~A+R(Dmm%qH)f3%wgZX24BIifgRHLhm-#QMqiPHmjgJiB$y{6!Bv zwsiTHoqJ#T^NBrs7qory=`%CZ9_5tf(m51@d1kwh7C5~uUGwv7K8886%$*{grL#=6 z&{j(ejYvrI=xRb~MG2j)YWW_XN|QO17qh!~km*vB<$+<$(28i7CrM_=@ztRb_7O5q z)kOyNsl+^SkBf$K)GSX@hBr1|t3^~}?1@qrRq8NpiS3TEEK$mJF+l)#QEr=}65lL; zm8zRtXQWlwbYUM77P^S_=CFA4&5C)%r}ZthQW=%P~h(XrJb>Oia| zQjZiR%2Mj92j}hfj`eev*vuo#Yi8R!^IaajYdvotyY9{KlilqlGK)2e482m%13JY^-5+jlF6nB_IE~VNLgf(;iEb)mR_Mr^LnRHfO0MbkwTT4Tld-$jU>CvVK|wK#>5QK@Q<4; z0TOAFOa?DW@dRi#&9&u0J}V%%!#1{q>}0#t>*NN%Np8`8ZTCYDuUPd`e#5;hR<7}W z;&9$obK{4+;ONHbO`mnHTD|t^9s3Tvb+r4~2cKU0ykB8a1qg*pM^%rT-nkkpUpw$t z_Xo#&E`6^2q#mV~e#~fT?OeNl!?EK%cK7gbX+?Fzw8j}tEv>88?!Ycbk6pO*d7s@~ zQQgvNcD{P>(Bac(`@ZUUV#SuNhYlZoujl;7RWH2#VfXQ#>e{-7DKna$THUp8{~L$j z>3;95+Y>*n@!Rii^_%zq=F) zv+t{G4=n0hyyUrzyx_LIZybKF=j?@bO8N6IRJQ=^7Tia&LCD%Px>c;AxukDWMq?xV}M`f+!>wDt?EeTN426Rh*m78sz?Y)Dj8(w`^BZ*}b<#3k ztY-7}es_Wzbm!7kXR6a&$=cU>Y;nJPmIrw$3R;3@9!gtmm}inAE^hW}|K3PLTBI@7 z{F7>a5?4xfQLI*~hFEO#)2VEVW_Bcab&poV%;jR&79*Y&Y-W-38Ped~-0F&4lMu)f zSi6duhiEc&+W+r_|Kr5pWGyTlnDbwMd0^$~-8jcvwsf#O1+Oie@-t9Y(qh)!`v&|- zY_QuE&DZTjTVvV8pZjAA+Hei%18tb@``_IpqtV(Td{|KU3*q6w+CEGM{8yCHGWS8t zjLv#Ex(rfjN8DCMC%P{U274Hg{^(K-n#+M2D?W?ngDks=F~WTqHf_PamM^g%&uKrw zuzZ05gZ>5nZrS?5`hos~4x1JFT6?%eBMs~nEhy@q0Xyu+vlY8qNy82nP}cHhW%`g! zN=$qp#RxQ~T+In&XXS6oZrj?NL$+Vc@!zTZ|}IT{k^s2g`4m3&+MJpH*e;oy0+d)8xGE_S9)enZaukqvT{DPLAkj3-aVhC zPW|#y@3a$N%xnxOR~q|Z>2zfw{z)JgJw<{asIuk9xu6vlfDmA}fj@bgEv#vfz(7Ou z&a-K$mX!bjd^H#_6$M@D#0O!kJ5#ZVPLhC-67&NYLB#?;pz zBhW+%L$<&MplV!{w*&XVAt}ETkVTd_P=>@gNWE$i8E, +) -> Result { + let response = querier + .query_oracle_params() + .map_err(|e| ContractError::InvalidPriceData { + reason: format!("Failed to query oracle params from chain: {}", e), + })?; + + // Validate the price feed ID is not empty + if response.params.akt_price_feed_id.is_empty() { + return Err(ContractError::InvalidPriceData { + reason: "Price feed ID not configured in chain params".to_string(), + }); + } + + Ok(response.params.akt_price_feed_id) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn instantiate( + deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: InstantiateMsg, +) -> Result { + // Validate admin address + let admin = deps.api.addr_validate(&msg.admin)?; + + // Fetch price feed ID from chain params at startup using custom query + let price_feed_id = if msg.price_feed_id.is_empty() { + // If not provided in msg, fetch from chain params + fetch_price_feed_id_from_chain(&deps.querier.into())? + } else { + // Use provided value + msg.price_feed_id.clone() + }; + + // Initialize config with price feed ID + let config = Config { + admin, + update_fee: msg.update_fee, + price_feed_id: price_feed_id.clone(), + }; + CONFIG.save(deps.storage, &config)?; + + // Initialize price feed with default values + let price_feed = PriceFeed::new(); + PRICE_FEED.save(deps.storage, &price_feed)?; + + Ok(Response::new() + .add_attribute("method", "instantiate") + .add_attribute("admin", msg.admin) + .add_attribute("update_fee", msg.update_fee) + .add_attribute("price_feed_id", price_feed_id)) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, +) -> Result { + match msg { + ExecuteMsg::UpdatePriceFeed { + price, + conf, + expo, + publish_time, + } => execute_update_price_feed(deps, env, info, price, conf, expo, publish_time), + ExecuteMsg::UpdateFee { new_fee } => execute_update_fee(deps, info, new_fee), + ExecuteMsg::TransferAdmin { new_admin } => execute_transfer_admin(deps, info, new_admin), + } +} + +pub fn execute_update_price_feed( + deps: DepsMut, + env: Env, + info: MessageInfo, + price: Uint128, + conf: Uint128, + expo: i32, + publish_time: i64, +) -> Result { + let config = CONFIG.load(deps.storage)?; + + // Check if sufficient fee was paid (CosmWasm 3.x uses Uint256 for coin amounts) + let sent_amount = info + .funds + .iter() + .find(|coin| coin.denom == "uakt") + .map(|coin| coin.amount) + .unwrap_or_else(Uint256::zero); + + if sent_amount < config.update_fee { + return Err(ContractError::InsufficientFunds { + required: config.update_fee.to_string(), + sent: sent_amount.to_string(), + }); + } + + // Validate price data + if price.is_zero() { + return Err(ContractError::ZeroPrice {}); + } + + // Validate exponent + if expo != EXPECTED_EXPO { + return Err(ContractError::InvalidExponent { expo }); + } + + // Check staleness + let current_time = env.block.time.seconds() as i64; + if current_time - publish_time > MAX_STALENESS { + return Err(ContractError::StalePriceData { + current_time, + publish_time, + }); + } + + // Validate confidence interval (should not exceed 5% of price) + let max_conf = price.multiply_ratio(5u128, 100u128); + if conf > max_conf { + return Err(ContractError::HighConfidence { + conf: conf.to_string(), + }); + } + + // Load existing price feed to get previous publish time + let mut price_feed = PRICE_FEED.load(deps.storage)?; + + // Ensure new price is not older than current price + if publish_time <= price_feed.publish_time { + return Err(ContractError::InvalidPriceData { + reason: format!( + "New publish time {} is not newer than current publish time {}", + publish_time, price_feed.publish_time + ), + }); + } + + // Update price feed + price_feed.prev_publish_time = price_feed.publish_time; + price_feed.price = price; + price_feed.conf = conf; + price_feed.expo = expo; + price_feed.publish_time = publish_time; + + PRICE_FEED.save(deps.storage, &price_feed)?; + + Ok(Response::new() + .add_attribute("method", "update_price_feed") + .add_attribute("price", price.to_string()) + .add_attribute("conf", conf.to_string()) + .add_attribute("publish_time", publish_time.to_string()) + .add_attribute("updater", info.sender)) +} + +pub fn execute_update_fee( + deps: DepsMut, + info: MessageInfo, + new_fee: Uint256, +) -> Result { + let mut config = CONFIG.load(deps.storage)?; + + // Only admin can update fee + if info.sender != config.admin { + return Err(ContractError::Unauthorized {}); + } + + config.update_fee = new_fee; + CONFIG.save(deps.storage, &config)?; + + Ok(Response::new() + .add_attribute("method", "update_fee") + .add_attribute("new_fee", new_fee.to_string())) +} + +pub fn execute_transfer_admin( + deps: DepsMut, + info: MessageInfo, + new_admin: String, +) -> Result { + let mut config = CONFIG.load(deps.storage)?; + + // Only current admin can transfer admin rights + if info.sender != config.admin { + return Err(ContractError::Unauthorized {}); + } + + let new_admin_addr = deps.api.addr_validate(&new_admin)?; + config.admin = new_admin_addr; + CONFIG.save(deps.storage, &config)?; + + Ok(Response::new() + .add_attribute("method", "transfer_admin") + .add_attribute("new_admin", new_admin)) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { + match msg { + QueryMsg::GetPrice {} => to_json_binary(&query_price(deps, env)?), + QueryMsg::GetPriceFeed {} => to_json_binary(&query_price_feed(deps)?), + QueryMsg::GetConfig {} => to_json_binary(&query_config(deps)?), + QueryMsg::GetPriceFeedId {} => to_json_binary(&query_price_feed_id(deps)?), + } +} + +fn query_price(deps: Deps, _env: Env) -> StdResult { + let price_feed = PRICE_FEED.load(deps.storage)?; + + Ok(PriceResponse { + price: price_feed.price, + conf: price_feed.conf, + expo: price_feed.expo, + publish_time: price_feed.publish_time, + }) +} + +fn query_price_feed(deps: Deps) -> StdResult { + let price_feed = PRICE_FEED.load(deps.storage)?; + + Ok(PriceFeedResponse { + symbol: price_feed.symbol, + price: price_feed.price, + conf: price_feed.conf, + expo: price_feed.expo, + publish_time: price_feed.publish_time, + prev_publish_time: price_feed.prev_publish_time, + }) +} + +fn query_config(deps: Deps) -> StdResult { + let config = CONFIG.load(deps.storage)?; + + Ok(ConfigResponse { + admin: config.admin.to_string(), + update_fee: config.update_fee, + price_feed_id: config.price_feed_id, + }) +} + +fn query_price_feed_id(deps: Deps) -> StdResult { + let config = CONFIG.load(deps.storage)?; + + Ok(PriceFeedIdResponse { + price_feed_id: config.price_feed_id, + }) +} + +#[cfg_attr(not(feature = "library"), entry_point)] +pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result { + Ok(Response::default()) +} + +#[cfg(test)] +mod tests { + use super::*; + use cosmwasm_std::testing::{message_info, mock_dependencies, mock_env}; + use cosmwasm_std::{coin, from_json}; + + #[test] + fn test_instantiate_with_provided_id() { + let mut deps = mock_dependencies(); + let msg = InstantiateMsg { + admin: "admin".to_string(), + update_fee: Uint256::from(1000u128), + price_feed_id: "0xabc123def456".to_string(), + }; + let info = message_info(&deps.api.addr_make("creator"), &[]); + let env = mock_env(); + + let res = instantiate(deps.as_mut(), env.clone(), info, msg).unwrap(); + assert_eq!(4, res.attributes.len()); + + let config: ConfigResponse = + from_json(&query(deps.as_ref(), env, QueryMsg::GetConfig {}).unwrap()).unwrap(); + assert_eq!("admin", config.admin); + assert_eq!("0xabc123def456", config.price_feed_id); + } + + #[test] + fn test_update_price_feed() { + let mut deps = mock_dependencies(); + + let config = Config { + admin: deps.api.addr_make("admin"), + update_fee: Uint256::from(1000u128), + price_feed_id: "0xtest123".to_string(), + }; + CONFIG.save(&mut deps.storage, &config).unwrap(); + + let price_feed = PriceFeed::new(); + PRICE_FEED.save(&mut deps.storage, &price_feed).unwrap(); + + let env = mock_env(); + + let update_msg = ExecuteMsg::UpdatePriceFeed { + price: Uint128::new(123000000), + conf: Uint128::new(1000000), + expo: -8, + publish_time: env.block.time.seconds() as i64, + }; + let info = message_info(&deps.api.addr_make("updater"), &[coin(1000, "uakt")]); + let res = execute(deps.as_mut(), env.clone(), info, update_msg).unwrap(); + assert_eq!(5, res.attributes.len()); + + let price: PriceResponse = + from_json(&query(deps.as_ref(), env, QueryMsg::GetPrice {}).unwrap()).unwrap(); + assert_eq!(Uint128::new(123000000), price.price); + } + + #[test] + fn test_update_fee() { + let mut deps = mock_dependencies(); + + let config = Config { + admin: deps.api.addr_make("admin"), + update_fee: Uint256::from(1000u128), + price_feed_id: "0xtest123".to_string(), + }; + CONFIG.save(&mut deps.storage, &config).unwrap(); + + let msg = ExecuteMsg::UpdateFee { + new_fee: Uint256::from(2000u128), + }; + let info = message_info(&deps.api.addr_make("admin"), &[]); + let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap(); + assert_eq!(2, res.attributes.len()); + + let config: ConfigResponse = + from_json(&query(deps.as_ref(), mock_env(), QueryMsg::GetConfig {}).unwrap()) + .unwrap(); + assert_eq!(Uint256::from(2000u128), config.update_fee); + } + + #[test] + fn test_query_price_feed_id() { + let mut deps = mock_dependencies(); + + let config = Config { + admin: deps.api.addr_make("admin"), + update_fee: Uint256::from(1000u128), + price_feed_id: "0xabc123def456".to_string(), + }; + CONFIG.save(&mut deps.storage, &config).unwrap(); + + let response: PriceFeedIdResponse = from_json( + &query( + deps.as_ref(), + mock_env(), + QueryMsg::GetPriceFeedId {}, + ) + .unwrap(), + ) + .unwrap(); + + assert_eq!("0xabc123def456", response.price_feed_id); + } +} diff --git a/contracts/price-oracle/src/error.rs b/contracts/price-oracle/src/error.rs new file mode 100644 index 0000000000..bdfd9cd456 --- /dev/null +++ b/contracts/price-oracle/src/error.rs @@ -0,0 +1,32 @@ +use cosmwasm_std::StdError; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ContractError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("Unauthorized")] + Unauthorized {}, + + #[error("Invalid price data: {reason}")] + InvalidPriceData { reason: String }, + + #[error("Insufficient funds: required {required}, sent {sent}")] + InsufficientFunds { required: String, sent: String }, + + #[error("Price data is stale: current time {current_time}, publish time {publish_time}")] + StalePriceData { + current_time: i64, + publish_time: i64, + }, + + #[error("Invalid exponent: expected -8, got {expo}")] + InvalidExponent { expo: i32 }, + + #[error("Price cannot be zero")] + ZeroPrice {}, + + #[error("Confidence interval too high: conf {conf} exceeds threshold")] + HighConfidence { conf: String }, +} diff --git a/contracts/price-oracle/src/lib.rs b/contracts/price-oracle/src/lib.rs new file mode 100644 index 0000000000..55fc147fef --- /dev/null +++ b/contracts/price-oracle/src/lib.rs @@ -0,0 +1,7 @@ +pub mod contract; +pub mod error; +pub mod msg; +pub mod querier; +pub mod state; + +pub use crate::error::ContractError; diff --git a/contracts/price-oracle/src/msg.rs b/contracts/price-oracle/src/msg.rs new file mode 100644 index 0000000000..8f415eff76 --- /dev/null +++ b/contracts/price-oracle/src/msg.rs @@ -0,0 +1,81 @@ +use cosmwasm_schema::{cw_serde, QueryResponses}; +use cosmwasm_std::{Uint128, Uint256}; + +#[cw_serde] +pub struct InstantiateMsg { + /// Address of the contract admin + pub admin: String, + /// Initial update fee in uakt (Uint256 for CosmWasm 3.x) + pub update_fee: Uint256, + /// Pyth price feed ID for AKT/USD + /// If empty, will be fetched from chain oracle params + pub price_feed_id: String, +} + +#[cw_serde] +pub enum ExecuteMsg { + /// Update the AKT/USD price feed + UpdatePriceFeed { + price: Uint128, + conf: Uint128, + expo: i32, + publish_time: i64, + }, + /// Update the update fee (admin only) + UpdateFee { new_fee: Uint256 }, + /// Transfer admin rights (admin only) + TransferAdmin { new_admin: String }, +} + +#[cw_serde] +#[derive(QueryResponses)] +pub enum QueryMsg { + /// Get the current AKT/USD price + #[returns(PriceResponse)] + GetPrice {}, + + /// Get the current AKT/USD price with metadata + #[returns(PriceFeedResponse)] + GetPriceFeed {}, + + /// Get contract configuration + #[returns(ConfigResponse)] + GetConfig {}, + + /// Get the Pyth price feed ID + #[returns(PriceFeedIdResponse)] + GetPriceFeedId {}, +} + +#[cw_serde] +pub struct PriceResponse { + pub price: Uint128, + pub conf: Uint128, + pub expo: i32, + pub publish_time: i64, +} + +#[cw_serde] +pub struct PriceFeedResponse { + pub symbol: String, + pub price: Uint128, + pub conf: Uint128, + pub expo: i32, + pub publish_time: i64, + pub prev_publish_time: i64, +} + +#[cw_serde] +pub struct ConfigResponse { + pub admin: String, + pub update_fee: Uint256, + pub price_feed_id: String, +} + +#[cw_serde] +pub struct PriceFeedIdResponse { + pub price_feed_id: String, +} + +#[cw_serde] +pub struct MigrateMsg {} diff --git a/contracts/price-oracle/src/querier.rs b/contracts/price-oracle/src/querier.rs new file mode 100644 index 0000000000..d0f5528049 --- /dev/null +++ b/contracts/price-oracle/src/querier.rs @@ -0,0 +1,35 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{CustomQuery, QuerierWrapper, StdResult}; + +/// Custom query type for Akash chain queries +#[cw_serde] +pub enum AkashQuery { + /// Query oracle module parameters + OracleParams {}, +} + +impl CustomQuery for AkashQuery {} + +/// Response for oracle params query +#[cw_serde] +pub struct OracleParamsResponse { + pub params: OracleParams, +} + +/// Oracle module parameters +#[cw_serde] +pub struct OracleParams { + /// Pyth price feed ID for AKT/USD + pub akt_price_feed_id: String, +} + +/// Extension trait for querying Akash-specific data +pub trait AkashQuerier { + fn query_oracle_params(&self) -> StdResult; +} + +impl<'a> AkashQuerier for QuerierWrapper<'a, AkashQuery> { + fn query_oracle_params(&self) -> StdResult { + self.query(&AkashQuery::OracleParams {}.into()) + } +} diff --git a/contracts/price-oracle/src/state.rs b/contracts/price-oracle/src/state.rs new file mode 100644 index 0000000000..6cfced3948 --- /dev/null +++ b/contracts/price-oracle/src/state.rs @@ -0,0 +1,54 @@ +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{Addr, Uint128, Uint256}; +use cw_storage_plus::Item; + +#[cw_serde] +pub struct Config { + /// Admin address that can update contract settings + pub admin: Addr, + /// Fee required to update the price feed (in Uint256 for CosmWasm 3.x) + pub update_fee: Uint256, + /// Pyth price feed ID for AKT/USD + pub price_feed_id: String, +} + +#[cw_serde] +pub struct PriceFeed { + /// Symbol for the price feed (always "AKT/USD") + pub symbol: String, + /// Current price with decimals based on expo + pub price: Uint128, + /// Confidence interval + pub conf: Uint128, + /// Price exponent (typically -8 for 8 decimal places) + pub expo: i32, + /// Unix timestamp of current price publication + pub publish_time: i64, + /// Unix timestamp of previous price publication + pub prev_publish_time: i64, +} + +impl PriceFeed { + pub fn new() -> Self { + Self { + symbol: "AKT/USD".to_string(), + price: Uint128::zero(), + conf: Uint128::zero(), + expo: -8, + publish_time: 0, + prev_publish_time: 0, + } + } +} + +impl Default for PriceFeed { + fn default() -> Self { + Self::new() + } +} + +/// Contract configuration storage +pub const CONFIG: Item = Item::new("config"); + +/// AKT/USD price feed storage +pub const PRICE_FEED: Item = Item::new("price_feed"); diff --git a/docgen/main.go b/docgen/main.go index c6567f060a..05492e9bf7 100644 --- a/docgen/main.go +++ b/docgen/main.go @@ -5,7 +5,7 @@ import ( "os" "github.com/spf13/cobra/doc" - root "pkg.akt.dev/node/cmd/akash/cmd" + root "pkg.akt.dev/node/v2/cmd/akash/cmd" ) func main() { diff --git a/go.mod b/go.mod index 7c939f7b32..ce34bd97bb 100644 --- a/go.mod +++ b/go.mod @@ -1,25 +1,27 @@ -module pkg.akt.dev/node +module pkg.akt.dev/node/v2 go 1.25.4 require ( cosmossdk.io/api v0.9.2 - cosmossdk.io/collections v1.2.1 + cosmossdk.io/collections v1.3.1 cosmossdk.io/core v0.11.3 cosmossdk.io/depinject v1.2.1 cosmossdk.io/errors v1.0.2 - cosmossdk.io/log v1.6.0 + cosmossdk.io/log v1.6.1 cosmossdk.io/math v1.5.3 cosmossdk.io/store v1.1.2 cosmossdk.io/x/evidence v0.2.0 cosmossdk.io/x/feegrant v0.2.0 cosmossdk.io/x/upgrade v0.2.0 + github.com/CosmWasm/wasmd v0.61.6 + github.com/CosmWasm/wasmvm/v3 v3.0.2 github.com/boz/go-lifecycle v0.1.1 github.com/cometbft/cometbft v0.38.17 - github.com/cosmos/cosmos-db v1.1.1 - github.com/cosmos/cosmos-sdk v0.53.3 + github.com/cosmos/cosmos-db v1.1.3 + github.com/cosmos/cosmos-sdk v0.53.4 github.com/cosmos/gogoproto v1.7.0 - github.com/cosmos/ibc-go/v10 v10.3.0 + github.com/cosmos/ibc-go/v10 v10.4.0 github.com/cosmos/rosetta v0.50.12 github.com/golang-jwt/jwt/v5 v5.2.3 github.com/google/go-github/v62 v62.0.0 @@ -29,24 +31,24 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/ianlancetaylor/cgosymbolizer v0.0.0-20250410214317-b8ecc8b6bbe6 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.23.0 + github.com/prometheus/client_golang v1.23.2 github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.3.1 github.com/rs/zerolog v1.34.0 - github.com/spf13/cast v1.9.2 - github.com/spf13/cobra v1.9.1 - github.com/spf13/pflag v1.0.7 - github.com/spf13/viper v1.20.1 + github.com/spf13/cast v1.10.0 + github.com/spf13/cobra v1.10.1 + github.com/spf13/pflag v1.0.10 + github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 go.step.sm/crypto v0.45.1 - golang.org/x/mod v0.26.0 + golang.org/x/mod v0.29.0 golang.org/x/oauth2 v0.30.0 - golang.org/x/sync v0.16.0 - google.golang.org/grpc v1.75.0 + golang.org/x/sync v0.18.0 + google.golang.org/grpc v1.76.0 gopkg.in/yaml.v3 v3.0.1 gotest.tools/v3 v3.5.2 - pkg.akt.dev/go v0.1.6 - pkg.akt.dev/go/cli v0.1.4 + pkg.akt.dev/go v0.2.0-b1 + pkg.akt.dev/go/cli v0.2.0-b1 pkg.akt.dev/go/sdl v0.1.1 ) @@ -59,7 +61,7 @@ replace ( // use akash fork of cometbft github.com/cometbft/cometbft => github.com/akash-network/cometbft v0.38.19-akash.1 // use akash fork of cosmos sdk - github.com/cosmos/cosmos-sdk => github.com/akash-network/cosmos-sdk v0.53.4-akash.b.10 + github.com/cosmos/cosmos-sdk => github.com/akash-network/cosmos-sdk v0.53.4-akash.10 github.com/cosmos/gogoproto => github.com/akash-network/gogoproto v1.7.0-akash.2 @@ -112,7 +114,7 @@ require ( github.com/bits-and-blooms/bitset v1.22.0 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/bytedance/gopkg v0.1.3 // indirect - github.com/bytedance/sonic v1.13.2 // indirect + github.com/bytedance/sonic v1.14.0 // indirect github.com/bytedance/sonic/loader v0.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -132,7 +134,7 @@ require ( 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 v1.2.2 // indirect + github.com/cosmos/iavl v1.2.6 // indirect github.com/cosmos/ics23/go v0.11.0 // indirect github.com/cosmos/ledger-cosmos-go v0.14.0 // indirect github.com/cosmos/rosetta-sdk-go v0.10.0 // indirect @@ -143,6 +145,7 @@ require ( github.com/desertbit/timer v1.0.1 // indirect github.com/dgraph-io/badger/v4 v4.6.0 // indirect github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect + github.com/distribution/reference v0.6.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.8.0 // indirect github.com/edwingeng/deque/v2 v2.1.1 // indirect @@ -154,9 +157,9 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/getsentry/sentry-go v0.35.0 // indirect + github.com/getsentry/sentry-go v0.36.0 // indirect github.com/go-errors/errors v1.5.1 // indirect - github.com/go-jose/go-jose/v4 v4.1.1 // indirect + github.com/go-jose/go-jose/v4 v4.1.2 // indirect github.com/go-kit/kit v0.13.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect @@ -172,6 +175,7 @@ require ( github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect @@ -182,7 +186,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.8 // indirect + github.com/hashicorp/go-getter v1.7.9 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.4 // indirect @@ -213,7 +217,6 @@ require ( github.com/mdp/qrterminal/v3 v3.2.1 // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -221,21 +224,23 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/common v0.66.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sagikazarmark/locafero v0.9.0 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.14.0 // indirect + github.com/shamaton/msgpack/v2 v2.2.3 // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect @@ -243,13 +248,13 @@ require ( github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.7.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ulikunitz/xz v0.5.11 // indirect + github.com/ulikunitz/xz v0.5.14 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/zeebo/errs v1.4.0 // indirect - github.com/zondax/golem v0.27.0 // indirect + github.com/zondax/golem v0.28.0 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.15.0 // indirect go.etcd.io/bbolt v1.4.0 // indirect @@ -266,17 +271,18 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/arch v0.15.0 // indirect - golang.org/x/crypto v0.41.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/arch v0.17.0 // indirect + golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/term v0.34.0 // indirect - golang.org/x/text v0.28.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect + golang.org/x/text v0.31.0 // indirect golang.org/x/time v0.12.0 // indirect google.golang.org/api v0.247.0 // indirect google.golang.org/genproto v0.0.0-20250728155136-f173205681a0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a // indirect google.golang.org/protobuf v1.36.8 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -285,7 +291,7 @@ require ( k8s.io/apimachinery v0.33.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect - nhooyr.io/websocket v1.8.11 // indirect + nhooyr.io/websocket v1.8.17 // indirect pgregory.net/rapid v1.2.0 // indirect pkg.akt.dev/specs v0.0.1 // indirect rsc.io/qr v0.2.0 // indirect diff --git a/go.sum b/go.sum index db778c74fa..a223e2553a 100644 --- a/go.sum +++ b/go.sum @@ -1209,16 +1209,16 @@ cloud.google.com/go/workflows v1.12.2/go.mod h1:+OmBIgNqYJPVggnMo9nqmizW0qEXHhmn cloud.google.com/go/workflows v1.12.3/go.mod h1:fmOUeeqEwPzIU81foMjTRQIdwQHADi/vEr1cx9R1m5g= cosmossdk.io/api v0.9.2 h1:9i9ptOBdmoIEVEVWLtYYHjxZonlF/aOVODLFaxpmNtg= cosmossdk.io/api v0.9.2/go.mod h1:CWt31nVohvoPMTlPv+mMNCtC0a7BqRdESjCsstHcTkU= -cosmossdk.io/collections v1.2.1 h1:mAlNMs5vJwkda4TA+k5q/43p24RVAQ/qyDrjANu3BXE= -cosmossdk.io/collections v1.2.1/go.mod h1:PSsEJ/fqny0VPsHLFT6gXDj/2C1tBOTS9eByK0+PBFU= +cosmossdk.io/collections v1.3.1 h1:09e+DUId2brWsNOQ4nrk+bprVmMUaDH9xvtZkeqIjVw= +cosmossdk.io/collections v1.3.1/go.mod h1:ynvkP0r5ruAjbmedE+vQ07MT6OtJ0ZIDKrtJHK7Q/4c= cosmossdk.io/core v0.11.3 h1:mei+MVDJOwIjIniaKelE3jPDqShCc/F4LkNNHh+4yfo= cosmossdk.io/core v0.11.3/go.mod h1:9rL4RE1uDt5AJ4Tg55sYyHWXA16VmpHgbe0PbJc6N2Y= cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= -cosmossdk.io/log v1.6.0 h1:SJIOmJ059wi1piyRgNRXKXhlDXGqnB5eQwhcZKv2tOk= -cosmossdk.io/log v1.6.0/go.mod h1:5cXXBvfBkR2/BcXmosdCSLXllvgSjphrrDVdfVRmBGM= +cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= +cosmossdk.io/log v1.6.1/go.mod h1:gMwsWyyDBjpdG9u2avCFdysXqxq28WJapJvu+vF1y+E= cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U= cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ= cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE= @@ -1244,6 +1244,10 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/CosmWasm/wasmd v0.61.6 h1:wa1rY/mZi8OYnf0f6a02N7o3vBockOfL3P37hSH0XtY= +github.com/CosmWasm/wasmd v0.61.6/go.mod h1:Wg2gfY2qrjjFY8UvpkTCRdy8t67qebOQn7UvRiGRzDw= +github.com/CosmWasm/wasmvm/v3 v3.0.2 h1:+MLkOX+IdklITLqfG26PCFv5OXdZvNb8z5Wq5JFXTRM= +github.com/CosmWasm/wasmvm/v3 v3.0.2/go.mod h1:oknpb1bFERvvKcY7vHRp1F/Y/z66xVrsl7n9uWkOAlM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v4.8.3+incompatible h1:fNGaYSuObuQb5nzeTQqowRAd9bpDIRRV4/gUtIBjh8Q= github.com/DataDog/datadog-go v4.8.3+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= @@ -1281,8 +1285,8 @@ github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3 github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/akash-network/cometbft v0.38.19-akash.1 h1:am45M/0vjs1FEwh1WiLv/cp92Yskj2Dls997phjnxso= github.com/akash-network/cometbft v0.38.19-akash.1/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo= -github.com/akash-network/cosmos-sdk v0.53.4-akash.b.10 h1:zPQVFSuBQKE3orKGgePPLU6eWn7kTAMCfuqFFa1Gc3Y= -github.com/akash-network/cosmos-sdk v0.53.4-akash.b.10/go.mod h1:gZcyUJu6h94FfxgJbuBpiW7RPCFEV/+GJdy4UAJ3Y1Q= +github.com/akash-network/cosmos-sdk v0.53.4-akash.10 h1:8XyxL+VfqkdVYaDudk4lrNX9vH/n3JxRizcLQlUiC/o= +github.com/akash-network/cosmos-sdk v0.53.4-akash.10/go.mod h1:gZcyUJu6h94FfxgJbuBpiW7RPCFEV/+GJdy4UAJ3Y1Q= github.com/akash-network/gogoproto v1.7.0-akash.2 h1:zY5seM6kBOLMBWn15t8vrY1ao4J1HjrhNaEeO/Soro0= github.com/akash-network/gogoproto v1.7.0-akash.2/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/akash-network/ledger-go v0.16.0 h1:75oasauaV0dNGOgMB3jr/rUuxJC0gHDdYYnQW+a4bvg= @@ -1422,18 +1426,18 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= -github.com/cosmos/cosmos-db v1.1.1 h1:FezFSU37AlBC8S98NlSagL76oqBRWq/prTPvFcEJNCM= -github.com/cosmos/cosmos-db v1.1.1/go.mod h1:AghjcIPqdhSLP/2Z0yha5xPH3nLnskz81pBx3tcVSAw= +github.com/cosmos/cosmos-db v1.1.3 h1:7QNT77+vkefostcKkhrzDK9uoIEryzFrU9eoMeaQOPY= +github.com/cosmos/cosmos-db v1.1.3/go.mod h1:kN+wGsnwUJZYn8Sy5Q2O0vCYA99MJllkKASbs6Unb9U= 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/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= -github.com/cosmos/iavl v1.2.2 h1:qHhKW3I70w+04g5KdsdVSHRbFLgt3yY3qTMd4Xa4rC8= -github.com/cosmos/iavl v1.2.2/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= -github.com/cosmos/ibc-go/v10 v10.3.0 h1:w5DkHih8qn15deAeFoTk778WJU+xC1krJ5kDnicfUBc= -github.com/cosmos/ibc-go/v10 v10.3.0/go.mod h1:CthaR7n4d23PJJ7wZHegmNgbVcLXCQql7EwHrAXnMtw= +github.com/cosmos/iavl v1.2.6 h1:Hs3LndJbkIB+rEvToKJFXZvKo6Vy0Ex1SJ54hhtioIs= +github.com/cosmos/iavl v1.2.6/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw= +github.com/cosmos/ibc-go/v10 v10.4.0 h1:dPMtBw1vb/CdXQuiue+JfGwS/BYbbEFJaeSVFx86nMw= +github.com/cosmos/ibc-go/v10 v10.4.0/go.mod h1:a74pAPUSJ7NewvmvELU74hUClJhwnmm5MGbEaiTw/kE= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= @@ -1467,6 +1471,8 @@ github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4Typ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -1539,8 +1545,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/getsentry/sentry-go v0.35.0 h1:+FJNlnjJsZMG3g0/rmmP7GiKjQoUF5EXfEtBwtPtkzY= -github.com/getsentry/sentry-go v0.35.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE= +github.com/getsentry/sentry-go v0.36.0 h1:UkCk0zV28PiGf+2YIONSSYiYhxwlERE5Li3JPpZqEns= +github.com/getsentry/sentry-go v0.36.0/go.mod h1:p5Im24mJBeruET8Q4bbcMfCQ+F+Iadc4L48tB1apo2c= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= @@ -1551,8 +1557,8 @@ github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3 github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= -github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -1785,8 +1791,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.8 h1:mshVHx1Fto0/MydBekWan5zUipGq7jO0novchgMmSiY= -github.com/hashicorp/go-getter v1.7.8/go.mod h1:2c6CboOEb9jG6YvmC9xdD+tyAFsrUaJPedwXDGr0TM4= +github.com/hashicorp/go-getter v1.7.9 h1:G9gcjrDixz7glqJ+ll5IWvggSBR+R0B54DSRt4qfdC4= +github.com/hashicorp/go-getter v1.7.9/go.mod h1:dyFCmT1AQkDfOIt9NH8pw9XBDqNrIKJT5ylbpi7zPNE= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -1950,8 +1956,6 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= -github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -2058,8 +2062,8 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= -github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -2078,8 +2082,8 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= -github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -2119,12 +2123,14 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= -github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shamaton/msgpack/v2 v2.2.3 h1:uDOHmxQySlvlUYfQwdjxyybAOzjlQsD1Vjy+4jmO9NM= +github.com/shamaton/msgpack/v2 v2.2.3/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -2138,27 +2144,27 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= -github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= -github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= -github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= -github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -2202,8 +2208,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2 github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= -github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.14 h1:uv/0Bq533iFdnMHZdRBTOlaNMdb1+ZxXIlHDZHIHcvg= +github.com/ulikunitz/xz v0.5.14/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -2226,8 +2232,8 @@ github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -github.com/zondax/golem v0.27.0 h1:IbBjGIXF3SoGOZHsILJvIM/F/ylwJzMcHAcggiqniPw= -github.com/zondax/golem v0.27.0/go.mod h1:AmorCgJPt00L8xN1VrMBe13PSifoZksnQ1Ge906bu4A= +github.com/zondax/golem v0.28.0 h1:0OByPaZyiv6il6bFmkVeLA7tccovg+wZT9kvZXzIbiI= +github.com/zondax/golem v0.28.0/go.mod h1:/Iku0p+mKx3XGOahtJhYsO+N9EBPY4XLBP5hbI2UogQ= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= @@ -2300,10 +2306,10 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= -go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= -golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= -golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= +golang.org/x/arch v0.17.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -2334,8 +2340,8 @@ golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1m golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= @@ -2380,8 +2386,8 @@ golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= -golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2466,8 +2472,8 @@ golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2528,8 +2534,8 @@ golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2646,8 +2652,8 @@ 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/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -2670,8 +2676,8 @@ golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2695,8 +2701,8 @@ 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.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= 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= @@ -3063,8 +3069,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go. google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0 h1:0UOBWO4dC+e51ui0NFKSPbkHHiQ4TmrEfEZMLDyRmY8= -google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0/go.mod h1:8ytArBbtOy2xfht+y2fqKd5DRDJRUQhqbyEnQ4bDChs= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= 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= @@ -3152,8 +3158,8 @@ google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9Y google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= -google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= +google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= 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= @@ -3280,14 +3286,14 @@ modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= -nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= -nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= +nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= +nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= -pkg.akt.dev/go v0.1.6 h1:3wkDfEMWwe4ziUfNq6wUxRFSgYsL/uYF/uZgVfdet/U= -pkg.akt.dev/go v0.1.6/go.mod h1:GUDt3iohVNbt8yW4P5Q0D05zoMs2NXaojF2ZBZgfWUQ= -pkg.akt.dev/go/cli v0.1.4 h1:wFPegnPwimWHi0v5LN6AnWZnwtwpnD6mb7Dp1HSuzlw= -pkg.akt.dev/go/cli v0.1.4/go.mod h1:ZLqHZcq+D/8a27WTPYhmfCm2iGbNicWV1AwOhdspJ4Y= +pkg.akt.dev/go v0.2.0-b1 h1:50s1/4e+aTFtZLcd3U7rOn3tmLEHdG/roYYIycYEMrw= +pkg.akt.dev/go v0.2.0-b1/go.mod h1:ji2QJSAJyN0pDHMOJSDDdMNBlW3TEX3hOmDtH3sW+nA= +pkg.akt.dev/go/cli v0.2.0-b1 h1:xzQrxM7kw1p63A+E3cJSicaHVXq3q6hSwuh6Kr+N7Ak= +pkg.akt.dev/go/cli v0.2.0-b1/go.mod h1:GMEP/0aYxwYbtuHsNDrsuZtRmZO5aAQ/leu0ANpq2Vs= pkg.akt.dev/go/sdl v0.1.1 h1:3CcAqWeKouFlvUSjQMktWLDqftOjn4cBX37TRFT7BRM= pkg.akt.dev/go/sdl v0.1.1/go.mod h1:ADsH8/kh61tWTax8nV0utelOaKWfU3qbG+OT3v9nmeY= pkg.akt.dev/specs v0.0.1 h1:OP0zil3Fr4kcCuybFqQ8LWgSlSP2Yn7306meWpu6/S4= diff --git a/make/cosmwasm.mk b/make/cosmwasm.mk new file mode 100644 index 0000000000..edd906a920 --- /dev/null +++ b/make/cosmwasm.mk @@ -0,0 +1,10 @@ +.PHONY: build-contract-% +build-contract-%: + mkdir -p $(AKASH_DEVCACHE)/cosmwasm/$* + docker run --rm -v "$(ROOT_DIR)/contracts/$*":/code \ + -v "$(AKASH_DEVCACHE)/cosmwasm/$*":/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + $(COSMWASM_OPTIMIZER_IMAGE) + +.PHONY: build-contract +build-contract: build-contract-price-oracle diff --git a/make/init.mk b/make/init.mk index 52c0bf4f9c..29b4778099 100644 --- a/make/init.mk +++ b/make/init.mk @@ -25,7 +25,8 @@ $(error "GOTOOLCHAIN is not set") endif NULL := -SPACE := $(NULL) # +SPACE := $(NULL) +WHITESPACE := $(NULL) $(NULL) COMMA := , BINS := $(AKASH) @@ -36,12 +37,6 @@ else endif ifneq ($(GOWORK),off) -# ifeq ($(shell test -e $(AKASH_ROOT)/go.work && echo -n yes),yes) -# GOWORK=${AKASH_ROOT}/go.work -# else -# GOWORK=off -# endif - ifeq ($(GOMOD),$(filter $(GOMOD),mod "")) $(error '-mod may only be set to readonly or vendor when in workspace mode, but it is set to ""') endif @@ -72,6 +67,18 @@ STATIK_VERSION ?= v0.1.7 GIT_CHGLOG_VERSION ?= v0.15.1 MOCKERY_VERSION ?= 3.5.0 COSMOVISOR_VERSION ?= v1.7.1 +COSMWASM_OPTIMIZER_VERSION ?= 0.17.0 + +WASMVM_MOD := $(shell $(GO) list -m -f '{{ .Path }}' all | grep github.com/CosmWasm/wasmvm) +WASMVM_VERSION := $(shell $(GO) list -mod=readonly -m -f '{{ .Version }}' $(WASMVM_MOD)) + +COSMWASM_OPTIMIZER_IMAGE := cosmwasm/rust-optimizer + +ifeq (arm64,$(UNAME_ARCH)) + COSMWASM_OPTIMIZER_IMAGE := $(COSMWASM_OPTIMIZER_IMAGE)-arm64 +endif + +COSMWASM_OPTIMIZER_IMAGE := $(COSMWASM_OPTIMIZER_IMAGE):$(COSMWASM_OPTIMIZER_VERSION) # ==== Build tools version tracking ==== # _VERSION_FILE points to the marker file for the installed version. @@ -92,7 +99,13 @@ STATIK := $(AKASH_DEVCACHE_BIN)/statik COSMOVISOR := $(AKASH_DEVCACHE_BIN)/cosmovisor COSMOVISOR_DEBUG := $(AKASH_RUN_BIN)/cosmovisor +RELEASE_TAG ?= $(shell git describe --tags --abbrev=0) -RELEASE_TAG ?= $(shell git describe --tags --abbrev=0) +WASMVM_LIBS := libwasmvm_muslc.x86_64.a \ +libwasmvm_muslc.aarch64.a \ +libwasmvmstatic_darwin.a \ +libwasmvm.aarch64.so \ +libwasmvm.dylib \ +libwasmvm.x86_64.so include $(AKASH_ROOT)/make/setup-cache.mk diff --git a/make/releasing.mk b/make/releasing.mk index 7a5f8c31c2..60ba53de7f 100644 --- a/make/releasing.mk +++ b/make/releasing.mk @@ -34,22 +34,22 @@ ifeq ($(GORELEASER_MOUNT_CONFIG),true) endif .PHONY: bins -bins: $(BINS) +bins: $(AKASH) .PHONY: build -build: - $(GO_BUILD) -a ./... +build: wasmvm-libs + $(GO_BUILD) -a $(BUILD_FLAGS) ./... .PHONY: $(AKASH) -$(AKASH): - $(GO_BUILD) -o $@ $(BUILD_FLAGS) ./cmd/akash +$(AKASH): wasmvm-libs + $(GO_BUILD) -v $(BUILD_FLAGS) -o $@ ./cmd/akash .PHONY: akash akash: $(AKASH) .PHONY: akash_docgen akash_docgen: $(AKASH_DEVCACHE) - $(GO_BUILD) -o $(AKASH_DEVCACHE_BIN)/akash_docgen $(BUILD_FLAGS) ./docgen + $(GO_BUILD) $(BUILD_FLAGS) -o $(AKASH_DEVCACHE_BIN)/akash_docgen ./docgen .PHONY: install install: @@ -61,15 +61,13 @@ image-minikube: eval $$(minikube docker-env) && docker-image .PHONY: test-bins -test-bins: +test-bins: wasmvm-libs docker run \ --rm \ - -e STABLE=$(IS_STABLE) \ -e MOD="$(GOMOD)" \ - -e BUILD_TAGS="$(BUILD_TAGS)" \ - -e BUILD_VARS="$(GORELEASER_BUILD_VARS)" \ - -e STRIP_FLAGS="$(GORELEASER_STRIP_FLAGS)" \ - -e LINKMODE="$(GO_LINKMODE)" \ + -e STABLE=$(IS_STABLE) \ + -e BUILD_TAGS="$(GORELEASER_TAGS)" \ + -e BUILD_LDFLAGS="$(GORELEASER_LDFLAGS)" \ -e DOCKER_IMAGE=$(RELEASE_DOCKER_IMAGE) \ -e GOPATH=/go \ -e GOTOOLCHAIN="$(GOTOOLCHAIN)" \ @@ -86,15 +84,13 @@ test-bins: --snapshot .PHONY: docker-image -docker-image: +docker-image: wasmvm-libs docker run \ --rm \ - -e STABLE=$(IS_STABLE) \ -e MOD="$(GOMOD)" \ - -e BUILD_TAGS="$(BUILD_TAGS)" \ - -e BUILD_VARS="$(GORELEASER_BUILD_VARS)" \ - -e STRIP_FLAGS="$(GORELEASER_STRIP_FLAGS)" \ - -e LINKMODE="$(GO_LINKMODE)" \ + -e STABLE=$(IS_STABLE) \ + -e BUILD_TAGS="$(GORELEASER_TAGS)" \ + -e BUILD_LDFLAGS="$(GORELEASER_LDFLAGS)" \ -e DOCKER_IMAGE=$(RELEASE_DOCKER_IMAGE) \ -e GOPATH=/go \ -e GOTOOLCHAIN="$(GOTOOLCHAIN)" \ @@ -116,15 +112,13 @@ gen-changelog: $(GIT_CHGLOG) ./script/genchangelog.sh "$(RELEASE_TAG)" .cache/changelog.md .PHONY: release -release: gen-changelog +release: wasmvm-libs gen-changelog docker run \ --rm \ - -e STABLE=$(IS_STABLE) \ -e MOD="$(GOMOD)" \ - -e BUILD_TAGS="$(BUILD_TAGS)" \ - -e BUILD_VARS="$(GORELEASER_BUILD_VARS)" \ - -e STRIP_FLAGS="$(GORELEASER_STRIP_FLAGS)" \ - -e LINKMODE="$(GO_LINKMODE)" \ + -e STABLE=$(IS_STABLE) \ + -e BUILD_TAGS="$(GORELEASER_TAGS)" \ + -e BUILD_LDFLAGS="$(GORELEASER_LDFLAGS)" \ -e GITHUB_TOKEN="$(GITHUB_TOKEN)" \ -e GORELEASER_CURRENT_TAG="$(RELEASE_TAG)" \ -e DOCKER_IMAGE=$(RELEASE_DOCKER_IMAGE) \ diff --git a/make/setup-cache.mk b/make/setup-cache.mk index cfabcd2f31..2a2b019102 100644 --- a/make/setup-cache.mk +++ b/make/setup-cache.mk @@ -2,6 +2,7 @@ $(AKASH_DEVCACHE): @echo "creating .cache dir structure..." mkdir -p $@ mkdir -p $(AKASH_DEVCACHE_BIN) + mkdir -p $(AKASH_DEVCACHE_LIB) mkdir -p $(AKASH_DEVCACHE_INCLUDE) mkdir -p $(AKASH_DEVCACHE_VERSIONS) mkdir -p $(AKASH_DEVCACHE_NODE_MODULES) @@ -57,3 +58,23 @@ $(COSMOVISOR): $(COSMOVISOR_VERSION_FILE) cache-clean: rm -rf $(AKASH_DEVCACHE) + +$(AKASH_DEVCACHE_LIB)/%: + wget -q --show-progress https://github.com/CosmWasm/wasmvm/releases/download/$(WASMVM_VERSION)/$* -O $@ + @rm -f $(AKASH_DEVCACHE_LIB)/.wasmvm_verified + +$(AKASH_DEVCACHE_LIB)/wasmvm_checksums.txt: + wget -q --show-progress https://github.com/CosmWasm/wasmvm/releases/download/$(WASMVM_VERSION)/checksums.txt -O $@ + @rm -f $(AKASH_DEVCACHE_LIB)/.wasmvm_verified + +$(AKASH_DEVCACHE_LIB)/.wasmvm_verified: $(patsubst %, $(AKASH_DEVCACHE_LIB)/%,$(WASMVM_LIBS)) $(AKASH_DEVCACHE_LIB)/wasmvm_checksums.txt + cd $(AKASH_DEVCACHE_LIB) && sha256sum -c --ignore-missing wasmvm_checksums.txt + @touch $@ + +.PHONY: wasmvm-libs-verify +wasmvm-libs-verify: + @$(MAKE) -s $(AKASH_DEVCACHE_LIB)/.wasmvm_verified + +.NOTPARALLEL: wasmvm-libs +.PHONY: wasmvm-libs +wasmvm-libs: $(AKASH_DEVCACHE) $(patsubst %, $(AKASH_DEVCACHE_LIB)/%,$(WASMVM_LIBS)) $(AKASH_DEVCACHE_LIB)/wasmvm_checksums.txt wasmvm-libs-verify diff --git a/make/test-integration.mk b/make/test-integration.mk index ee4b63bddb..23df9ecac4 100644 --- a/make/test-integration.mk +++ b/make/test-integration.mk @@ -7,28 +7,28 @@ TEST_MODULES ?= $(shell $(GO) list ./... | grep -v '/mocks') ############################################################################### .PHONY: test -test: - $(GO_TEST) -v -timeout 600s $(TEST_MODULES) +test: wasmvm-libs + $(GO_TEST) $(BUILD_FLAGS) -v -timeout 600s $(TEST_MODULES) .PHONY: test-nocache -test-nocache: - $(GO_TEST) -count=1 $(TEST_MODULES) +test-nocache: wasmvm-libs + $(GO_TEST) $(BUILD_FLAGS) -count=1 $(TEST_MODULES) .PHONY: test-full -test-full: - $(GO_TEST) -v -tags=$(BUILD_TAGS) $(TEST_MODULES) +test-full: wasmvm-libs + $(GO_TEST) -v $(BUILD_FLAGS) $(TEST_MODULES) .PHONY: test-integration test-integration: - $(GO_TEST) -v -tags="e2e.integration" $(TEST_MODULES) + $(GO_TEST) -v -tags="e2e.integration" -ldflags '$(ldflags)' $(TEST_MODULES) .PHONY: test-coverage -test-coverage: - $(GO_TEST) -tags=$(BUILD_MAINNET) -coverprofile=coverage.txt \ +test-coverage: wasmvm-libs + $(GO_TEST) $(BUILD_FLAGS) -coverprofile=coverage.txt \ -covermode=count \ -coverpkg="$(COVER_PACKAGES)" \ ./... .PHONY: test-vet -test-vet: - $(GO_VET) ./... +test-vet: wasmvm-libs + $(GO_VET) $(BUILD_FLAGS) ./... diff --git a/make/test-upgrade.mk b/make/test-upgrade.mk index 487dc7c7e8..04faf20390 100644 --- a/make/test-upgrade.mk +++ b/make/test-upgrade.mk @@ -21,7 +21,7 @@ UPGRADE_FROM := $(shell cat $(ROOT_DIR)/meta.json | jq -r --arg name GENESIS_BINARY_VERSION := $(shell cat $(ROOT_DIR)/meta.json | jq -r --arg name $(UPGRADE_TO) '.upgrades[$$name].from_binary' | tr -d '\n') UPGRADE_BINARY_VERSION ?= local -SNAPSHOT_SOURCE ?= sandbox-2 +SNAPSHOT_SOURCE ?= sandbox ifeq ($(SNAPSHOT_SOURCE),mainnet) SNAPSHOT_NETWORK := akashnet-2 @@ -29,9 +29,6 @@ ifeq ($(SNAPSHOT_SOURCE),mainnet) else ifeq ($(SNAPSHOT_SOURCE),sandbox) SNAPSHOT_NETWORK := sandbox-2 CHAIN_METADATA_URL := https://raw.githubusercontent.com/akash-network/net/master/sandbox-2/meta.json -else ifeq ($(SNAPSHOT_SOURCE),sandbox1) - SNAPSHOT_NETWORK := sandbox-01 - CHAIN_METADATA_URL := https://raw.githubusercontent.com/akash-network/net/master/sandbox/meta.json else $(error "invalid snapshot source $(SNAPSHOT_SOURCE)") endif diff --git a/meta.json b/meta.json index d80c0038d2..245dcdb2db 100644 --- a/meta.json +++ b/meta.json @@ -49,6 +49,11 @@ "skipped": false, "from_binary": "v1.0.4", "from_version": "v1.0.0" + }, + "v2.0.0": { + "skipped": false, + "from_binary": "v1.1.0", + "from_version": "v1.1.0" } } } diff --git a/pubsub/bus_test.go b/pubsub/bus_test.go index 747c400102..1187d70926 100644 --- a/pubsub/bus_test.go +++ b/pubsub/bus_test.go @@ -6,7 +6,7 @@ import ( "github.com/cometbft/cometbft/crypto/ed25519" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "pkg.akt.dev/node/pubsub" + "pkg.akt.dev/node/v2/pubsub" ) func TestBus(t *testing.T) { diff --git a/tests/e2e/certs_cli_test.go b/tests/e2e/certs_cli_test.go index 57e607159d..c6c017ae97 100644 --- a/tests/e2e/certs_cli_test.go +++ b/tests/e2e/certs_cli_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" clitestutil "pkg.akt.dev/go/cli/testutil" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" "pkg.akt.dev/go/cli" utiltls "pkg.akt.dev/go/util/tls" diff --git a/tests/e2e/certs_grpc_test.go b/tests/e2e/certs_grpc_test.go index 8140092baf..db43d65849 100644 --- a/tests/e2e/certs_grpc_test.go +++ b/tests/e2e/certs_grpc_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" types "pkg.akt.dev/go/node/cert/v1" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" ) type certsGRPCRestTestSuite struct { diff --git a/tests/e2e/cli_test.go b/tests/e2e/cli_test.go index 647769fffa..20bf3e5d0d 100644 --- a/tests/e2e/cli_test.go +++ b/tests/e2e/cli_test.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/suite" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" ) var DefaultDeposit = sdk.NewCoin("uakt", sdk.NewInt(5000000)) diff --git a/tests/e2e/deployment_cli_test.go b/tests/e2e/deployment_cli_test.go index 9f314a992a..6fef619745 100644 --- a/tests/e2e/deployment_cli_test.go +++ b/tests/e2e/deployment_cli_test.go @@ -22,7 +22,7 @@ import ( "pkg.akt.dev/go/cli" clitestutil "pkg.akt.dev/go/cli/testutil" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" ) type deploymentIntegrationTestSuite struct { diff --git a/tests/e2e/deployment_grpc_test.go b/tests/e2e/deployment_grpc_test.go index 6373d1004c..dcebbd231c 100644 --- a/tests/e2e/deployment_grpc_test.go +++ b/tests/e2e/deployment_grpc_test.go @@ -14,7 +14,7 @@ import ( v1 "pkg.akt.dev/go/node/deployment/v1" "pkg.akt.dev/go/node/deployment/v1beta4" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" ) type deploymentGRPCRestTestSuite struct { diff --git a/tests/e2e/grpc_test.go b/tests/e2e/grpc_test.go index 57768a574a..0810d5af11 100644 --- a/tests/e2e/grpc_test.go +++ b/tests/e2e/grpc_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/suite" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" ) func TestIntegrationGRPC(t *testing.T) { diff --git a/tests/e2e/market_cli_test.go b/tests/e2e/market_cli_test.go index 73346ae86d..d799a1d9e1 100644 --- a/tests/e2e/market_cli_test.go +++ b/tests/e2e/market_cli_test.go @@ -17,7 +17,7 @@ import ( "pkg.akt.dev/go/cli" clitestutil "pkg.akt.dev/go/cli/testutil" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" ) type marketIntegrationTestSuite struct { diff --git a/tests/e2e/market_grpc_test.go b/tests/e2e/market_grpc_test.go index e7009120e0..d75cba641e 100644 --- a/tests/e2e/market_grpc_test.go +++ b/tests/e2e/market_grpc_test.go @@ -19,7 +19,7 @@ import ( "pkg.akt.dev/go/cli" clitestutil "pkg.akt.dev/go/cli/testutil" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" ) type marketGRPCRestTestSuite struct { diff --git a/tests/e2e/provider_cli_test.go b/tests/e2e/provider_cli_test.go index 93a6b122b9..db32075bbe 100644 --- a/tests/e2e/provider_cli_test.go +++ b/tests/e2e/provider_cli_test.go @@ -11,7 +11,7 @@ import ( types "pkg.akt.dev/go/node/provider/v1beta4" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" ) type providerIntegrationTestSuite struct { diff --git a/tests/e2e/provider_grpc_test.go b/tests/e2e/provider_grpc_test.go index ef26357ddd..8d595e53eb 100644 --- a/tests/e2e/provider_grpc_test.go +++ b/tests/e2e/provider_grpc_test.go @@ -13,7 +13,7 @@ import ( sdktestutil "github.com/cosmos/cosmos-sdk/testutil" types "pkg.akt.dev/go/node/provider/v1beta4" - "pkg.akt.dev/node/testutil" + "pkg.akt.dev/node/v2/testutil" ) type providerGRPCRestTestSuite struct { diff --git a/tests/upgrade/config-v0.24.0.tmpl.json b/tests/upgrade/config-v0.24.0.tmpl.json deleted file mode 100644 index 6a67ae1dbc..0000000000 --- a/tests/upgrade/config-v0.24.0.tmpl.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "chain_id": "localakash", - "accounts": { - "add": [ - { - "address": "{{ (ds "account_address") }}", - "pubkey": {{ (ds "account_pubkey") }}, - "coins": [ - "2000000000000000uakt" - ] - } - ] - }, - "validators": { - "add": [ - { - "name": "upgrade-tester", - "pubkey": {{ (ds "validator_pubkey") }}, - "rates": { - "rate": "0.05", - "maxRate": "0.8", - "maxChangeRate": "0.1" - }, - "bonded": true, - "delegators": [ - { - "address": "{{ (ds "account_address") }}", - "coins": [ - "1950000000000000uakt" - ] - } - ] - } - ] - }, - "gov": { - "voting_params": { - "voting_period": "60s" - } - } -} diff --git a/tests/upgrade/test-cases.json b/tests/upgrade/test-cases.json index 3d86cdca02..1259beca0a 100644 --- a/tests/upgrade/test-cases.json +++ b/tests/upgrade/test-cases.json @@ -5,6 +5,14 @@ "migrations": { } }, + "v2.0.0": { + "modules": { + "added": [ + "wasm", + "awasm" + ] + } + }, "v1.0.0": { "modules": { "added": [ diff --git a/tests/upgrade/testdata/hackatom.wasm b/tests/upgrade/testdata/hackatom.wasm new file mode 100644 index 0000000000000000000000000000000000000000..5333788263dd98ea1769251ecfe1b9977269713c GIT binary patch literal 180690 zcmeFa4ZL4hS?9ao{x9b>|DnEwtJu z1V+q6zU7vg8}GXLj@xg!nKD*otv!3q&98g?>u!GyZ~o=2 zNus)5_O>^@_U6~s&w6jX^)+{X<2P;F`{En#x^?FE?|pNUs_2H{G5Rbj#O}Eax`Nr4W zcJuA81KuCc4rQGzA1y|UUY=)pR@mRH@PF-OG-ImU{HGbu(jx10yhIKS@V~V@U*W$j zYbVsq^G=pz8SUyHIBd0xPCix?`S`l=@w`Y{YM$r(uT44qmjgmOzW@NTqD$o@?{+8D zeJg8c6YXqFg*r*g|Fasrv;Pc`G%vEToO-mG=V_kvG)?jmU6Z7frt3!x@;n*oq*R=| z@S>5l)nY8Pl}siVt5}+*8;VwXXL{FNEk?SweMx>_TFuTLPsZ*`s=2@S>p@*R`_r-Z zYj1t+>u27aC1bb0?v49ye%-#?MGi0Py!Q6*o6+5_;*D>*<@L$SJGb6_>ucV`gIBa{ z9+GRiH{Wr`>tCZXZyvqn*80c4yx{iN?Ynj6dvAWtt(wX=-v0X6-MAyUcl5>^A+(!s zy!CarYLwqYo3k#T$(0TI`*c^|1_OT@7lcONcscm75~RQ|L1+P z>08pbrf*C4r*BX1Pv4PFZQXI@KmLhq+duiHccll?@BG#q|JUm;zvF-3{N4ZC_uQ~` z$M@ZI#kO0%_f_BVnkUnnU%mU=|Cj&y+rI0cUw8Qrrhk^cJNsh#q4e@Aem4D?^l%Zp5N7G+Qe>wfPNQ951S9~`8z4SBbr_0hJ| zWLJD7{Zjh(>1_5>*;}%=W^c=WGMmpv-!nUUDEl0feP4R-i;}9`JLqgm%5*AA`mJob zOt&OOFQ zRZ>{Bvh5Yyv0~d=Ez0(uYCvIHY1ggfp~~J@T4(Jt@2&CfhPBF!rys~JrD9Gab@xfx z-dm;L>J_VOdBy7eUr1gWI?VP6=uXw!Lo-G1eJO+QOl7@YR8Oj8Tb5|_ovOQsKO6Tj z{6WgYvQu_8XX^(e+w+8S<9kYbnv^5kvw{curE2A#P083N(=@-&k(_NxvT5O0BTaWr zP+3jpRl09blqvs;YcCt5RhJUoSL*J*H&$PJSHGZ64oI0=-k_0h%hq#AszNYr%X$Jc z6Tlm|svUmy_Viv-W>Zpqn-qyQZ|%dOVcb2C67a)vy8#KG7bh9pLsADpfG9;2G}$h`dc)ZJPanc!Q?)eT!Ufs zO9w*>Hkf>s!GNj8U~(VK=bPl;jpW}3)q(umBL9vstGmI7E=K2*CV_vM>L%s zQ4-IJa%2hlt6JF+`M1kXtk|(ui?S2QpI3D&(6d!B^5=z-zjZgPRg*u=K_hkd^c2Wn zEsFe?RE*?ruZ{e>B7eBFZ1>hO`tCCN?~4ArP5SSaUD5yOQu-fl(tp?S{JGJrbzdPd zb1>aIC_r>kEhKvw)CW_#E2grWM43f(I@z-&N&3052&Ja7TL$eC83p;Z_Vq!-E+*e9 zSH(=fn;S#CL3q{tWQH|Ia~9DIh0_F>t!F2Tv*S>-dq2Ghin7>}+;&xRIS3H|+p?(u zZc$C`seTP*RJGvF^o32dOCYTKd9{LlEHqy;aMFXkN9W5FOSUWYtMtl}bxm z3nDomisWHyktPx4m5XFx-hYU`eIY-h6buReC_6F>Qrzx4RK z@9RB;V1Z)o@qhfopZUE%efX2__?yHZ(jdx+W(w5uR4(K z>3vyrPtpCmCGM*)g4L}Otp}j)y}kFLS@UYWV~_UeW<=c#M(d6S>V8>2D8Z%uP(1*5 zopts3MptR*svLW`+B$Ppax1+u^#@F!J@gsa4d4V6Q*Y4kslL9<_V)g(CiP&7f}O~r z2_^!ro64@!pX+-+fd-t)b~Dp@*82ro<7QgFou3|G%ug??S!M&4K$Y|!v<5azpi7~N zJ_;MrgF?qpnn=c~1WFyN{yu#}mAs<&lc{r?q$sV!if$wrr*4#x?4sO;MnXeK!r|2; zkaD%1s&na{>M8v=@eYXl@1%F(Xk+$hRCqfLaUd=?ER6j>UsY!=I!v9lrO+S)Nc@G? zXYavbbF+Et-a$Ls4KmS!-2kO^`z>*&?gkxQ%x*y2BY*8Rikx2(xh+Y3o|!4I$ZS@% zvL(T-v4n~(Yn2B( zjqXxIquVqz+DLN@?LWd*4%TTWPD^VzE&spsX5KIAe-_?Mu@uQg6Uo7w`IU9)8X;M> zoNL&vkPJq8*85S3pbb zor?_A8FtI%^aj~~S-nDRJeuHj0Kx}>KP|I1v^41r zq{CVPl(XpaqW4}RN{y5GUUwiLlJ8Kb- zNdcv^IZ1Z@&8I&3Yo9;zdmsDDVY2}h+EdhMl+XH_Dt*={tAl9k2VZZw=!8FIAB$G~*Qz_)(zRDK~X z1qkKS>Oy&~9q6Y`(LSQJqgiDd6L4X8AM0m@+uUXkBWqYUpnO=@oZ)-=n355YHNz$#=)9cVhEarxv@P4s1(*9(Tqd?<*Ki?Z z^D-`@+kmmXYvMwxVn~Svd+#x-ng%&w*C^>_ureUM%IWHwezzP2GnxtJfV;x(h$q~| zWR35dxCk%#7t-;IMC7uc4KbL(k}|o>+q<{t03mDdW#eP#Qwrjp7`1-JN6%TFiHC*8 zCsoLq67myn6i7eXLoQ1nr@Q<&*hZTp_g)Are8D zo?+xdTDp@Ww>wc+0khL~V>0d<xf+-^3S}=qVD+m0dm=Y|d@HTh~FtN`6w2{wmr zanT`khC+vKY&GbFuK*n)EusiQJ~wpmzvKoIK|spqY~W7v(ji-1YzUc6y+h{6GQ8R3 z2fRhvHR%#nVcLiIup>1mf<@HcUo6NEpA<1kl=D^o*pKnUUBWvuC|s08(aE`o@_V z3U=+GwJK*Vh%BQUiE^Z!`qr%x;5B`8pqVP@n(n@tzK~cF?~^2jxDa9@EJ;#eoHpXG z-gV%3QX!`isJ%-8)raJ++Ha+4DjVud5^N|{XTn66qREYWs(|}Vdn}gBv&U)A!lj~# z9uFvcIaOqFZOcl#>vA{66H4qTb6j%^o#5011ZKG8dJLTKLtNYYB9c3LpeF2=d!R__ zt!@Ys4G?R??SjP^o~wGlkA;*QISr7uhsu+rFi5N9_*bQ%aZutxJ9jPjQ=WC!?MyK2=3PQTlq93 zD048cE`K?7e?NKo3>U1mnTc^g#{7gT1iV)s!ThAA>@qr&lq6V}jIZIY%(cWp@LCVh zIGL=}IOt0hdUvCAm$Ya#c*R6JwvWHhE#@1+`MDHb!S#UbGg`Z_ZtVfHCTJGgfh5Db zT@w>hu4tJ|CU@*_v-dY;Y$)RRO!5lFFnmCz3Sv)Z3N>IF(O>BU+e8HmoZ-@XgjR77 z+3_hY63x7%-_0~9+{(g+-Ew~VKSIN1Q+I{N3F6a427sp?W&=* zuosuwe75@3yMPLCTp|6_LiOTymV=I4dBqjU*QwIiS3MZfLOz#c_)=u5KcW|#XjDBG zW0=?$dMz}OvCk3j(pi}>4BhqkKT zT~}#&t1!RQrw>XpgV1mbntu#5Yg%P*NX3OIwF!e^m;;|!MST;3`PpX0xW=~Uw^39a zrpHM+W}Ij0b$ncteX7Ay-|e$~JrhC?d4(f2F%lNvt2-9s|oM^x}r|py84vtjEoTy^_0h!L1=GNNpQ@mClSo5U_!2N0Pv#rh=2iD=_*3NnjXxiB?Zmss>@D3O7_U`4jMz zFVmTwh1Mg=FJieH-jkRTv2;Z&wq9uy$lxwkOScVZ2nUH?rm}rv_o?ho4R=d&hsffJ z|u{<_Ap_L zEu2&`tmMcqZWim#8tChV!D*``gk>FP*jJ${w#nkE2%<1gn4I{)Y9I416qhA{!!tHW zB{_(gNpc`2BspR`(Mm>gq)~EY)x1L2W6#ABcg95U8ZVIS0o%reM!DjSElvS|xwprs12B_98`4O()$Qpo>W zyzU7m6i=F#Kaf$a5r!Av1R)DCNrRgnpu9A=df}N$#8+N9xIBUBq^IIMy9HoWVpIr~ zKy>4S>PV)I z)G65EcQ!3w0!Q##t?CfL-leO*HVa$JGMkb$F^2$PHPUEq7D(?U*5>|~WM6Y%OH0M` zMGP;_l3jpF7UPR&5r*S3ObDRK-Ddd#qJWm*JfIxgr-kD-e zEj-}kSpfJ5_8$Vaz+G@;7+=sHdZ5;=>c|3i~fS0P@)6=^V8KYM;#EDXt5-yQiPchr!8Hxm0B%I$2b$y^~5g z%RD?eUd_MtIE(L!H$ve3aq-@G^+7$XBa`DYJH{1j{GX*Vnp#tCe-E- z50+6l`p5b`C*tN`h`u*7=xJiGA{Rv`nTs)c!?6xgF3=rEAgA**D?53$kZakw4p5!S zx91C)&}KAR9TnCPa%?m6?qJwNv>pqV_hG%t8|uRGTyF!~z@+^ub~g&~vOxEQmc3Nwb71C)UUwR761l zk|+^Ip`e%*aUU#uIkL?Q1PZAO(8h!c34vZB5Z1C1&9T-KW9tl4nUC9pSBeov=DS@a zP6~+|p+!Rk!D@jwx=~cNx?%53j&u}FZ9Ch_Ylu*MheNSjP{@AtE&}5> zmNz<*7rwj^EOaezbjEE`<#fabuNAusJHg+mWr(%l>l;=r0E0}WuFH@^1^yjKdZ6fA zQ0*W-fPNpKC(VuS=Pb&ubpoHQa{$=5_@CA{@g*PewhlP@tmu$<< zAP7n<=cjZfz<65MP4Km@<@Wqk?ivSqMZ+ry018|z(IX}MD-EgT!b3s!b5$iJ^4tY3 z3~fVfQLN1sL$S8s#2UiQ%^qN8q2K_EqfZNdET*%$+ZUJvG+|=xEb{c_6Se^1pv^88 zYiE(gjB351DM-~gv<>AN)?#>P*sfAvu5e~J1WHBda_W5jX?kzXUzO|qX_q~4ms>xD zwUmNqkCBQj&07Tb|OKD z3~bKJ!Hb3s-ZLo67hPvjLCk9Fj8;9m#yk*n3mqt?Q(c9TJ?3okcVd$*$qy9-p+t;V zBtKBRG!>q=BtCbJN=4mV(+8&BKqQ8V8Ig#iv}QgqC-(=7L1a;zg29T6Dy}A+lb7oe zW!v);n%v6}blZ~O&@E#;0c9Vv`zfAnOa84rJ(Kqb4h)*l*A^R=1ND;Mr`}Ak;)n|@m~W&4?6m6z)aS9f?q=H9o*xSRe}pnWg^1Z%&OJ;c<-`3;$~FCq zY)!Jn-P;eP@hc6 zXLY45xO;qTXWD;}DHL%lleIaYE&7{yI*^q2pU~A5JtM+t+}NSfAi!CJ07ZkgN)-ix zNn@%GMHPOC3#O#J)ZE*uDYTXeDqC%HL1pgIxdfFK8d;hvKpWW~A|H@HAX`49!fajj*dT}TyIbRu)B_W(XDcs^*FX+lzi=l>vm{TB=MV~c_ z(Q)Ups7a!7!In{}Q=3z1gVY$`sl0C(c}f#L1sy8Ml|GHSlFtpzQJ}dhd6M6vq6G$v zafW?4w$xHK#cax1=!5cQ^_o~E4piHY?<4$}O^fE|-E||G+ho*STyz)ELZr6-#9(hZYaT zU2>`+dkYbC7!|7VxLva#Fk{vTV+|%GJQq>WZg1rICX1S zSvVT7txK3!O~zV3(;P*MI1`h`b&DS3*L%hs1iB)yk-*;q41!?RA%ITYF3yJDwUUbz zxwckNFNZ>(+ePLx;hijI+CPpQbZVl`u8z7^k zSs_fKq0S7_k;Min7Ng0jq4`;5nhVVuZLO`9Oys$gB*jkVe;%uq+i=ig5s|XFqi?-fS5nWtvuqa(pUM%^!p$>I9gE!sR zVCMx3RE>JCD_F1e3fFnGD8RlU1f*66)cEY_oa|BXaMlC{i#wM_=o?B@a{xvST`ZH~ z4QTc^qmcT2Sz?NAbv|77EgE>|+x8EPUm*;um=v<%WT51xNs_P6J!C2G-yiU<(> zH0d~lULeO{VpI&fqRZ|i2&l}o@|lFK>SRM!{bnlVyCpd(p5|>@yX`GS3WA6_(GXFO zOIaUx0d>L!6!e!`^JmgKkz2y@>@5ihjdUrU)$#8mtjSJZqhdWrMCwsziIT3pJI ziA7vlvv=ma8-PJ39BYWFpAS$RtHo68qz(cqN`RPZNf27gOqvA&aS(ZG*gV>3@}pqM zWz^9cPu7@HH)#XG7%Q$Uq}GaD5K>0dkf#YN%)3@oNVTGn>Qo&GsWsJayagfESt_K~ zR<@<8v*h)dOhtU>Af(nHq%4Ik!SJ)iDjO;JCP{y-i!Eq%27N4_z(f-oP@;(t6GT>> zMc@PgHk1=AyKAJQ6H3&REDEod$|43y0L>zuqs}8l&&*Uhmu#Zt7hX1*=sA~cLcI)o z6|l}F?p?a1G^1~&F*S=Dy&P`P%ZCC99u~C_s4P^%2w*vGh-^S}kdOx%O{z>Nl`zsw zT}5>1bBI7e#YU2aKWM&O8?1V)LK83u3llI{i)WGjqq~?yvl2(6$BI#FjU#Sst}tpX z{|upPl!K~sNMs{K`BJ+u6d6ii(u0;moQZ4@P@+gC!`o6zXqXr^B=cADrwgK3y+S!i zy^abU8q)>%$P#$iUnT$< zau*@F-S!9J9Y?r%4)pZz=}AS^|8aV<7I^+~ora1+1RBC}$zN{?ZWhI>psmKydF9RVmHsq z=ndX6dh3~n4L*)7IzYyX`Zy2ad0hlg(Sfs6oF$w1Aucre8ipo1qF)4{X+cubcf^%p z<=k@f(@&g zRv{NwO3>qZ&o}-Qg-(F1TcxPodhLGff5rsk;jl2^6ZEwzbMS8yOw5gE%6U5-?wU@C;u*=p$ zY-ev2|D&Tm=}EqLI!3#T8bjb(?`7-5bT@kMJ!D7K>1gx zC`%q!>6qdn+V!I~Yt5tY?9qI0@cnNw%gQ)n?N!OwmwELVc}CzK>Q*}A)taX2>-TI^ z3*0H4aR*mQ+~5}y*{dTzr1S@J*%d2M>ZJmK+AFF|NZepcr5Se zFtW5o$ZWTK#$+cM0Nqfs0VKko*1U7#2j2>Ttz1^Uf#z(z=a5?RsGX$Xa!u1OWLxsX zFRV$&l^8n<$vUdp3{;fNWWBja3CGxOCM(!nq`_v4yt%c=78w^O0EBhNRkjwP1M96t zBVhtBk*yp5seJ`zS^JlDD1$Yd&g-K05lVXSgR_?PjVVqg@DMc8xbmcZe~Eae=j|3AAu^5mOTX&x|w2qk?n>APJ4w4QON!z8V343kmc4^}! zi9!>I2n-LImA18Iq>h5zR$E!slT5ztj{$I#&f?!Ywo3{t&Uw8AKZdZ8h^=;AFGQPl zto37)oXyU!AMT7PJMO1<42>)f$AN~mpqF_d(aG;?MQFC`MiShcUSV9S(yiMI(-PaG z!;xm2h;7?HVZ(K-dS~Y2?DLts6Fn#z=lBUhV3^U)lQv;&85?2-o8nk-xPRgq_nlZQ zNDVNH%EXK_NV7Hfr!L=Ig3De|Fb0sM@?OS>Y~|Wab8YRy)zQ{2_Gr9{3jjzfGEXn# zVjB|JHpM`eZS5Kcj_R#lHtcI)^p>dKbfk6+jq3aj%nY*F`YDQrY?QswhRSfUVkr_F zs9V}1-$EIP_v215GO|Tlw?ZIRxa($`Fj3nynz4q=Xtqs96h_w>r8YLMU`F#)Gjff|0KCwM zQvwyjX$DR)Rsv4RZFHPw!l^7oaH>rX9?N4$b$p{DxQBT1?JaD1LB&7A<`z*AoJ1Fn z=W7&~Tei7{bU)D&gAgsDqeV-MV;WTa+&hmaRcTY%vv?%YaqOhOzA(G!zFb!GaT%Pp z{{v=)iexE;e=$EHUKut#5LZK%X15ngOjZ&M=qhY016Y)*M0Z%r+RH$8yBgVzywAiR zx0RViI%m`E`As}R#^9LPPKI%nzLs%wxyGy`i^{E`6mbh>?DeWHjGa|1WDt3o2@P$AU1@Jh z&CnNHF)-s{Kr>%P^?PU1-=LA56vXqItuS12S*yotZbS z@r@`x$4ki}S^>PigIC%p(Iy_7%!lTU?Zr`S5(;zkrVjKdHhGCA8)lB}vCoD%V!&pl zNki9xNs(v>Oj0X=qSdC3%o~t4&jN$452h>;b0wo6l4o(8@Rb_X3Y4_I1tv3XD(C5> z**HmRO3zOP8rnGRXyd?YvoMRypUXH%&1@X2PYdfp3*z5!u28duVB<_KYJs7M`IQ}H zIvDB-!A)gdFg&9b3vRL}#u9_-;N~EAn~fS2)VmQ0m*B+pKypwVdZXQKV=y_}re~$r{we26B%XfKDn? zT_(bODMK_+T0AYQ9^s9(fvA!IjcsH{m^I~PA2u8q>(Yenbs*A+A!1CWy_{J^_&OLO zs-7Pf2*^xJC))6^ym2|a3R(&X4fAknAP_&wq!}WCt<^~5UM2Yp1ED8Slh=1@I-H_w zY3GqZMMrBYI$~7hL&h-deY2*}e;U0VOMBle6AfKq8rATj>A8?0u-L^!9VFRLHTl@TcIV7uRaM@vbxpajx!^(*gBb&MAusrMz z(g}4*gm_{wqC8GYla~ym%B2!O?crg0?3&vW@{gZ zVhQzVVNHUGLlldXlMAOq_b{qkw%xc|Wdz7{$2{IFt*5;V4hoV}gSv_FKNwBJJ zx2DtKKk?losRA6vK1aBvASNuzZ8MytH^h&{D)3v)X>b?C7_bvp5Mm+`khY(24@72M zHe_G$ZUj3ZJxl6=Q5eh90ZMf#E0fEyn0+B{@t%>~kbG8RU(4?`{xY!ye~qZ_k+gq- zGn8{akfG2~*c=MRiD(i+4!n54p12@zLv_gLOLlr{L7A{gBUHn4fMQcRBbPF~*BLEk!zmin0}qOtIU00FuIY3)XGfJ}!`l z!8=x7unWFN516s%Tb_;E;IqLcJ2%`9Z26soOLtDq?T0-t;R>@}Y8g=N^3sRLNIAb` zXZQYc!_FOZ`yU2*$iePDHZE+~xq&Px#EL-8Su(VKj*m(j85#rXq znRBDx%=QN8qt6O-+f`$sd1Ny?%C#-qV(W^4IcVlAXaKDKV)lNXQ*S*y$c`PidI<{W zy?OB^W?F9N3rec#p9Z_tRIcu>)F5F@0+{f%Xw0gxea{XWk((u+Q`DdZDJ*eI)9R-HXa?1UDB|(Q6b9E3LkE9RcN@5~))mw5?&-Z#hcJ}HO~g-2 znlK)T71e}QOsikzx`{fX5NnaU%egDkVWd_{MC~mu}8PClpR}-dp~c5g6wTCY&(3 zC})wn*(GqUxdYw4Xc@zxWV!!KmiMVBo1Z9(^M1YpnOeL` z3n$AOL};kb1&%(DfMC%avsCVP;BmQ6+OUS$0CZ$=7yDnnh`O}+i46h|o-Rjf{2uIP35ho2UHczB`g9<$qvGFUA7f+1r{8&H- zYQzt$HR>=;BH};+V_|X%umU4;7cjrHUvWqrvR>7xO?@B^9pY`MP-M<+&LMGxL%iLl z;*=zaCvNG@#xG`{a?!4Ds=Fpp;zft zqQF(LyR13MMp#WDQb8vlGcacL>HXIB!?A5dwNw06iA)q1ncIlvgc=sot3IPzqcmug z%yoQd2_b7~B*=68))3Dqbxfz9@(fQ!k!;z6{8IZ{=&|=xsh^!-Vx#)4CD7poo(FX9 zW-Ws*bZfl6a=-Xu64K9go{lV;CzjNo%RFU)m?TKpZ<9ki5ObWcr-YKRUOi#R#fXwe z8WVPOIAJ({)!QNXYGN5m%n%MrHljo|wIh@Y{CKz|zh+hkMtqKg7U$#8@($G!e&B)|w?pFih>J zp2y8lUctb8ES2zDy=4<3=c;WqB@1Om`}H1=M`D8stfrJu!+M5ojT$|ywK&rUSeNs!GoP|;LKC>J`jTMVu_+0XH&>e#2hxEtagEdJk#>p2aRt)tsRCR zd0h@pqtG&T#%gH3KR1c8CebW>L_JD^S~!5~)S@)fKL%XLZ(veajWbpO$$<5oq#dvSAU6JzWPgOZPl0JHyrtsAx^sjeN($0V1w>? zIz=_v6AeAja)$eX;xvs9BK2{%Opn5)=Nd-@X643NM|h^j0k&yu58aNe0-_oioYKc| zO798wj=79qHm6)xbg;*zP+0bLKd3|eMt7D-zOo%FzJp)nWxX(FeK-25BP*KqzYJY& zX8SDN>G-bd-whd6qZoP4X1z1&TJ7d{KHv*U4Mxq)39>1|+ST?Ma(IvszT|NZ%lrjL z&^ev?zx>oE{^-a4{L>%*vlqsh&l*mSEK_oEbG({>pz04KB-*`)0)@Jc|2>l&dT6mq zfB0K^*wI7dEPwbPV#$D3L;X3Fky)QwqF@0kL{smcKx5#+PnKg^3>%EGRhWby!tRYv zOo(Z(CzmD4x9PovTNVd&zs}{ZL9lwb1^^V*gQJK|q~y%%j)=!pHm#`AmgHqL5I$TZ z;pDCW7t?hBg~qbiCi9Hvh)jhK*90zVa_A5VfZBqMT9^Eh%M-Kjvrln#A^5E3(2wKVkWf z%axF?BAiThkOIzipV$1^45}M0my& zGPt$n87cmhPj2{3!NF766X^hZhK*cl2)>~0iK%-&AJ5Ih(t;0_R+zObwOVOwMm3eXNvyFG&m@dPHsWA@r`KqJk!GBB=mdqtVBE8^$|Z{6Py&ya`b z>G8CEq|V}1tdrze zEC{Wq-T`m_A(pFH*jKX7*plT!7MCoQtLa}#k;Ktrm?RD!3KPpOlQ{ee5=ZnYJISMb zoPtZwRnV0B(hfoo8n=xfs{AZkv_%ka5V4huYSj|VaL$I3uo$)sLL)+Pj~VJMN2Svq zKCC_{)7Fw;lk_;0QF)#sL{05;s;FwVkKw_3QJB>{EehK(NM5WlEY{IOv5u0PU8eKI z;{7p>%F=6E9aVU)4Nin%!!pxf%6xy8t@=_E5F!bDeTjA4)F_QVW)jrown+;=CVp71 z3onPv%U69^itQ~zV9`JzgYqRIzW>ABl#I+ENVFWJx3S%u%xQx zdID|ncuZ>L!}{1biemm zeht+=ut$pC2Lr(=E@4}Nis&vluNStG%jeYwXgJIpG`SrpEb~Tdfn>Gl3jqGTKCOgd z;*dHd6GsR{#%Z*UoHSxptfx|@5N*KNM~>477o;nQ@L!NdI&5O@piRO9bwYhg}@o3rb-XIFb7 z52*wcrS~n#t3>Gh*rD`E88=y#f(Ecdep@hZNbUqX?1L6fgGb<^xcok~5l$z82+Q;}!W>C%+>Z9fR!F ziMla@lxyH_wg@!>MtCBe9YB-58kIIzqeR}#vf;y{sF1K2Wy=7&E#L+5(b+XJ_g|%j zD9g;NLHoZ2T3qAUEtCHFg61nxEA}cj$r@~8_K?_wrx4E$&n0-qQsyK-V=0UKK4U4_ zk>@$%i?cfxQPH9`vfZ%j`L?+t6=6}?4mne>^-P`BOihFZiQN((=P^@n_Z700iD>1S zI)A(kx#&kslt$PPiJ6JSbI!Fe|9nSq{yha)#aNR2FiKn#+O4IX^MKa^zx8Y!(uiBn zZp3QgA7;c2ST$k`n=cx%l+QErhJ|6!7b{KUM)v~E{6mgo$4O6hJ(cGfTQ=A98B3X+ zxN85_#!@k3#^aKQ#^F1R*v084;=8Y4mz?pJwGSvkvrXcJPc@srKoV=X|wU*R8y3+n{_-r$3__wUtvZ_% zQlI5zS@?m7v?Hx>SC~zN(90%sRW>jboa@1;_Nnpo5<=o!w5tp;Q6+t%_5xjgOuwVw zxw+)VD~q?wEjbOqjw%b=i_AkS9VBfaNabu?egd@E8c#?P>p%nLqy+6}AgI(qopNJ54Wxg@{_-B!N;gA5^ z9iX_xa3??BwKj$z6%n-su*|Q*Of_NFc$DvO+I8-|Iu*%g9BoF z-2}^kb3+7dq3`DK*PE}MGWOda0O3lbo-+kwl7nfuSU_?9B^VJCiSzh-u-<7UuPvV= z3V2i)=t_;pLNMNP*f1qbG{r%0FqgKb751-*QV5ONfv)1V(B+AhWHz1h<%U}7Ao7M% z=N?`m0VOCAu-urOyqg;YB!9t{#AH+8FenSsnZRMdQDZ2rLq{8c7xKSg zedf_E-0Pu*d%DmNt9s-(B?a%4QlFOOzt^oLzjK<3m2UiP{XH{ zg=d7XHQbove8W*kVlTldyM;y{Nnsv8HTjdwe|p#Pq}mb)O}mU)U)B6^y}_o?zA34%?1|!!TjcylvjjN7*RYON}#P0+L28?ek;JjZxHUkJN}!f zpZ{+AZ%ktU-SXe82~5ht96X8C-P&O#yAqQmEl*mDH{ic65K zz;~qW*audgzHN}H5RMFm*bIuWgDwe7Qi#b!c@HqC*^DVedV@r?Vk4-HZ_tCX5AI0X zu}~rqmZ^o%1S=#Wce(y;>lnS^ZyHfc^?MnZSefB>Ty@uKt`=%+<0j;9n{o6DV_hVu z^OUu3)PJep5=YA$iJwFg0_@{Y8l-N1C#^qWPXtX!qiY$xqD-)#3msbWG^iG zof6s$3&?jEUVi6ie)}I?TfvMiYFnHNlyA60`%AHhwXa7LY7?fD;F#7-LRj0eg zIKRr@+H~cU1qN>c?^70Lk(n1cQ^8$5HByZa?U8n-h0vmLu&CS8GdvpWY=cH(3lH=0 z%tAkx&{wqCTHh#Ppo+AOoda0}mtXeQ_pc4|eA+KjyL@bmE*-Lwf<@;(C%2UAx+Vugqe#Qz$SRkMYafVHn zhz&D%G0s`MGys`=n@GznZMOJaCQ`x|Q5idiTa_wga(Ntxbe2tgCvl@OxNh);HuzgY zt6yjwywo6E5QK3UkoI)gkl2u8<%_zf4c3#jXw?#5It)EcS+AIk)>BGPTIHb%-vp|G z(^4p@s*cW$=Kr=<7D$G2V1({VbBb5Hr0`X znbZSXt(xt9I|^B2|CTrKZsw{)8(Y$#xxPXY+Umu}5w6VWs4*B_OQ3tLnU=I^$6I0f3EG>Pib%U}>8Z zm3@69HINO`LB98u4mucGGXy?>%t|6~V~B8gXoIwBb3!a+qy2~iy;QZz*ST1iGdaMRp3af-I!KU}%ahHm%G=lIjblmhBZ@WQr{{)fSm@Zpsih zWhNSc;imGS0r~V^eh)_`qio!ww4(Ey%4{d6iOiDdeLcnGnc4bX{pCyqXNY@d)e*w7 zW)|7;8LFPBG~4oRKS5SKicw;orSZ@_%oAF~*=38iOlyT~uh%&oP>yU!vrjEXYgA*N z%(9+BrwhZLsB6vR-4NPR%moM8yXO8u-5>PlIxSTRc#9$70Rvms`!e_l`64BCWI=CA zByWxp$J0M@|M8^S&IA10C13U2Ii%U=O0GYf(ndBdNf+fYq?CLcG^HGN83tVWDi-o7 z)uO1vIl`pPiR>;Z1k786NAG_!#jH_?ViI{z$_IT z&#ag_RIRa7&&P<@9%7lGSn;FR>O`B`iq|(-WxMAxPtBUA!+%&a{=Kj9KzBOwSEd35 zw{iw;V8kh&z}5qtE&Q;W6Fp(9_eJ}REooi(l!u4bo1-ET-SQnD{MJmjsw?+YxMaY+ z7(mS^&(0oL4xkP^z-PLe3$(GrfSdwI2Un~FoYWQI0u#Wm83L}MM8K!_t^jxn6#@A4 za=?*V&i{gYR?&wclL0Dgeou+xPQ2rI()+tK8T(st2pW9FsiBEQGZF?oM91kB=H@Fq zbi&<1WUMrrXGTlJ%Gg{hYu{HaJFOej!aP<#QA4X+I=pGna`91SQb$bJ^F6J*FM~yE zP$7dG1vMJa?Jm${CFktzv=70>gSXq2o#IW5b_1t)lgyjz3~zq+?imn!ylw_xjbG(p zoR|oS=EHo3zF_!5G)+*=b?1OJwFyK1M1HM3o8G~POo<9XmqGVcNs4zn|(qBmc1{YLYMW~ z*uz7Qa`<(q{;`<-1Wu8#1f)ICndm&%ndp!F;IaWrre4o09eK?KakBcE=v!TlUg_@K zs%N6p43QzUejMXHd#p`u4E zv}+(c;1PU+J(KH;PAlnjva}Qa%R8MmvD$Pq$Kn0a!f$`+SO4@gA3wvH{0h^CS%d=$ zTY`M>$Bruj>-{)lget4I$DgobU04TYenTl<`~2re|GaoOAd@^0Q$V{k9d~ zeqL|w``DP3v2HuQ{m4Py>MJ@ry9u16)qha=4QfqP9s25cd5jw{b5ziDdsoW>iUo9R zee<^xUB^DqJS6`sM+q6itQwP3nO6@8dSS|9B1R(Byq=}Kt7Y&xz!vVJTA&%y46S;) ztUBS;VRg{s)uHugLt@P6ViF_qVn|~DuOuc-k4Xu^@Su8 zPHgw5oHJQH;kP;^{iNU87X%+q`#KDBo+EeQC_ea^4(wd?IaYLpDg5=sb8YygTpLP- zTpK)lzL|(nwBGr9YB*f=%#)LiC-lmb29hF5PN*N$H_NkmbO4U(*=g26=+4fKc<_GA z-u)V>5RtHkz;PJ%Mc{mxiQ=dwONC?ItVvA{<$F^~B1kMOu$WREO8q<)k*j93&Ao|Qisk)m>`+4xwyH$nE8Y>B$|h>s?u zgLo!|)dVvd=9NGqoO!p*1h=GvfRVE)tHoTukgAEP>`aQH<@!{rnp4?nbH_3J909O< zm&0KaP8LE#+jrK7-29zHEKx0_SJ=UZCfixcml1>2npRKian^e&%cg2gyW-SVyPYz5 z%OpeFmRp8xVOMjctsFM&rmK=GnQMTyn!$Mu_o z>QCs3-S?QTxTePmX(+8KuS{Txgu{okj%NdXn#N-zk7eT3DVkw9g6j!oAlXWkTYY|5 zKg;gxS(C(|Vk=sEm#T38sGoz`-=p zxdc4GG_Z$Y0^bD=-vw$4F(*_BO2nM7rCSLb5T;wioFDFQV$K{w$J*mILb3_`vqRu> zhrhUz3-0k&X-^}(6f&y`4{cM^5XyzEe70!dJ1YTqtCo)p=_Vau8!CXW8W(Q!%6>2rH+kBOaWF% z97V>ZE(7JPXq%2Cx^+Hl^be^;`mfG1AS1K-3B1b_bXt5O9ytMzoMsYN)Mha2Kooiu z5i!(ej;c97oJ0Av&!o<%fI92gao~`4>8laqc?94tn7&N>Y+>c!Y5HgdSCn;r`<#b$!f&Bc#G_kcV$T#jQ~mjRDQvOU?$#;$*qoJl+hZgxtiyRpI2Tz$SvQ7RJlXk za$2=+A7t-}>#XX`tZp^w)hW9*O(pEn{23ne;;5)U=r*pAGK?bhAwNszLUM4cL$j&z zB)1mWMe1|A!JmGXTXS4#5@1+Lu~ZQ-!>^bRo$Hf_r>tX3TFws(1SW4VDVDF!WLly( zgSDR#FFZ;REwO;1$b@__4tuH&%l24+|P39ljrfcIxav;QSC5@tqp9R6H7Gp+cMdVXTy~4rqDdnD{~NqR{M(N9Bn9@ zX}_*0)>&OIwVYIZT%$G=ltu0obl%e|)qig=;VuaG>pAfI0}47QDB=kf!jJ{F^mY2) z+K%!9d`CowJAD-b8*_@hSAHd0z^YkBM=jbzR+&riL^nYz&|vuiDP(7B1gSnX2(`Do&AkM-W?E%dT@T#>S;*{iJSGoLefUVa-$Gr z*=r=Kd1Q0hP!;+Jv?eGNV_QsCSWf_<;Nl9PL0@zXeL0wHgb_9X!fF{1ml+TOk+%Y| z23r!K2F#KL?VBN@5A$1;kGBX9r8-kr*?PyrM%c2^;9@)sK?r!jiX3)VPsQrAXsIG1 zx;UxJkVhjzYbtgYAjz4aaM(T+a7)~t8b$@ODsyGk!HEJYQBie!LsW(s=d?Ax~Zkb18 zR$2jg+|(7BTQ~sQvJ5YHWLg5z+crdl@!s!0RWSqS3_MZbWC%QEL5?4*2WL3|bc2}| zhGHAU^qpg5x80xM9#Ky-$CY}^6_0CF*Hij}BG=Dmq^+Y^7ZjMHMYCIZe$T*mzs*`? zC=&q%V;TzIlDxQ2qg#@#7}L1I_}RHaLyPz0*rU**uL)Rq=|`;Q<@AL#prfflTvX_j zGe)CjXf*39Z%8p0F%@2)f-V#JbhhXpbEPm#V>^yKVvGI|W?`LzP)kw=gn(6#dj2RZ zRUn@t2z+QtAXwN(Y0KVt;bE3g6Pd{;vL;6O!dK#(D0{;O8Xpoess%Q$JgHG^Nj^&> zlJ}u&(L!7%VTRg5$fKEnAVEJv(QthPMCf{yWdRt%GHriS{5max+xYmuXfcn8?EPQVwb-h8DR($PBo zg093yKC3H&Lm(1KmPZj#tP0uYsbdIQQSvh#g$!q zn3F+t2%w@Tbx>%7?FMu!xlnsjmIQ=2a6dMT>rm}V*|-jB{=7|2E>O@GKX$~nJP*!(8wbhAs3uox;ADrrZZ-P1~8d|0_5e@je;+8=A70kZ6@cSIC;UQ zEQ3%NmU=|JsJf^}IC|KLL4f$AGc0h^q(}-9xsir1?XDg)giZ^Fpmfca7R@()n$ZEq7hs zL>vx7*`Cj$6U2>Dyy9|60r~j-7B20<;L^JNZWJQN78f$QX#6S$?CBX_!8^Ty?Kdb! zGPc->gQ%D9QtYXI73Xe?zFUMFTz!HcCO>7y^T8UM2<_hR*-3Z4gJiCgc<0f~wl!Mz zTtWE`6-)9su)Pa)xt>W+s>hpt#TxVIOf)1~v4coCjhER@bkLeP%X+ld9?9jnX|RsN z)_?{x!YZ3DWK|3Vr*FWhs2)oJ{Mp8XV4n-%#Su8cx-0S)Q-6Yz? zSwFy<@#^wQZt#2;dF7y5i8PkFN3M;M$CwImXrTq40z(231dD|Cl4$;EW`C&?!pRI;Y7I(p-f;xddZ8De^N;n6(eEGmM=U|Im{h%`&?YR*#%wKvJ9JT0706)aSZ7hUhv37pH!QYOS|QQwCGIxukhROPYQfQ5ytr?UW`GAjwH3dd%vg}o^uM)s zF*kd2Q#2=)#~K(5K{*})4@{$;bvJXZUghUr-*+sI`uhH8Sl>5?(bo5gt>GW73qB;B zaiUp#6uduFN_0H?4p=F`gr_(~HZ@w`Pt?I>p$W?xSmbpknqD0s5vMnLotOz*lBZKZ z(a8#7(qM(?bsi1zfFqe3#D{~|`B3me=ar0>gRIQ{0Y{rfc`^eN?6aaeEFW`3i9lg( zzdq}M9s8mt5X$0yQaz%Ajm7;@Z>QZ(Ec#iuLuk~~yXuC_&cqQt3oU77|7itGjS_5W zKi9JJy0En0@uhud*3hQ8qw~0HA9~9W8G6pFl_OL&ao6G{4i5={-cwoZH_3_NC zzK-k;_03JiG<^g><*t&}lF39kqAO;iEK*taM61oxpHH>4uWh@|EdFKQdE>X>t31TS zsiPyoB|OZg{l>C>7g+5Zp6vfbrk{UAI;{5bh2aZJJBWkt&31NKoD!4Tht!mlS{Va; zjKg(M4r&m(Mp~|3RQxk;hZv#sA~RpoM-G8wC{huYnpBk<14j7mk;Zyh9+>WCUttL@TtY5XWLf4O;3qwkdVp*Q!z6U~6q^r!=@)@3>O#gm6HP zLPH9gFb>|I&!LvUm(HDtMsvCXXwP;I7Xf4+!1B<0X6r!EACw~>CORtzxDC#V>`e%f z0x~-G8?rLFMf>HQpp$2H<<-+7Rh-bXX81TaCs=niH=7q0nG;{(X&zX#$ftz?F#dAVk<#Bg>Mb{nhw0&@HZdC=5f(ZS|&tG#NG}c9$OqSUU6tPz|;i zEV559KV-q8@Cjy@JdSpt0jGvNNyrc^Iy(#&Id9DlgEul)&VsPRn9B;~4q>F*{UMq= z8=|}j{B@oLku~B+rV9v%3cthnQSP4hA;7ReL*#p-9Ya?AM08`=h))ER)_rH0MFDhY znVD6NnR^>g7@Euzt#me`N3*mtj2`&_}zJ zd(rYt3-@vi4#rp;KjD+yQRwo@BlO647{&|$`8A$tVV{ULMS_bcu*IdONEpVvh5?GI zv)_-BMPEswc!+2=WLh8z4A0DRoV#kyo**IWCy*PJndSII2$R2Ox|bdo=qXO{DfLQ6 zHp8dr{lWW>Th?X}6Uy3z;-nqhHSLSGt#r6Rp5Fj#+P_F^%KR->e#Q9;S_wHoM@E6*|I1R zw5Ag==)s~obYYUlwn`F^y`Hso(85ZuF4L6O?y_Nmh>q*Qk;?$d4~15IsVJQ%5J zWb`R=C`KlCK`v)qP! z_xTpfo~-xf14{*8$XD|~vuXdQ(#P5NB{L?k=EZz*wobAGbbAEs{d)K^FS*0TGL6w0=*W?K>n^zd{(xJ=jC!t>sh z{}eN=-bUU)Ab8TiTEx*|4F`Uh zBe^aL)LHJU6KtTTf5BP{RL6{^!7I;SsZbkm03@!7!ZlJ0n{u%;#TZ;*u@Nnaq4;99t6DsF+&%!KB4=0&7oStmmdXY@0=N_sLNCgjfD5-K|b{$8Dlrj(j4}-EpCf=@i{*_qpiqcn@{T5#ec2S)PXFpnTU7T4Q>Nj`*-8_L~y zC$>54;7b(0!J~sg1bS$-<#F4V4T@NYi9pUT1uC8P3V=NZ8Gg2dKBRkf4D2Qg-bd%^ zYTm{)p_97Afb2h@9t(fMS6A(DkED}kITV^uwfAa|4%b6oy^UN{NlzK#2+7zhaG3aBHjFOw+IULi`lD1|8=8qvBwQ-o(s-{L_lRSs&jGm{6O~qNL z#i6LGzGxC+hN*o99#~ z%7Q$QY7TNFs~-+La4>^ZuqH$xZwb|B9U29{Rm8?Gyj+Fmky2YkKg3RlR$POA zjBcPGDA(x6G??heXuwdX84|V)>)4Zqb?x-1v2G+IF0o1sU$aW0^$LU|MrcqPa0kL6 z*pj+FhR7gLHPLQ1QEPLh5X2^I#zbXd;!WL>jvp&-&|=O7%#?T*@J?=6F-<0o(l z6l8plu^rl4TUe?`WKK`Ly&x2M!YOi_oTs1V=c8 z)FpP>65A>qt$!BoEa`QT5&9QooWc0iKBL;_HU@A-Ya^6BjWR+B>Iif;u|-4i50%44 zdkfYcO!7R9&{Omf+y33qHfzj+_1wn5$xtyGp}!d_pY+OKH3n8U22R*SyD{*|)Q!*+ zLL1X5W1y&wfsSlU5Gy1@Y%3X|60z0s&|;j7Pf*9{?zm6Kxr|VYvjpeoQKvfv$DzAp zL%REDnBJq--t(tB1#TkUeJHd|DoySIet zowfF!Ki#nbsHVF&yC}W;JgAOP_adsp;uRL}w5ngFxz%Zol_{eTVe57mb+-*EPOE87 zaV=%0FxMvO$U9hp;>-jk+ielW-5dqoO*R$hqBrFV#URfOre06-1aiB+)~?^-)4E%2 zJ%3tLo>G)?*Lus>7?kJMtkZiJky_<7r>*8!No{pfBdf_|ky1FIwwE}yDYMDtTcET; zoB1Q9bylP_3yzZM)D&$m_Gz#kImBR>y49G=A*idAsGvw8OOgUF~o zj3Rp5tHluEf)26z5JQZ~AB^`BZ&ryPY_(W5fGD$)%qG!gv=-KSO=UOnskg<^Lp~=k z^m6_|qlaSm7e0CjrdM(zYz^jI(L<}pP7#rWsB6)QFJ`rAb=hT^eOWwG*pM*fJ?FMG z;0Jevfd7P=UK*=6r`deY<$_Rn!C5>ap9?4Qu&y{z59z8EK(5tc^2?9Bi|_--RVYf} z#{&35kGWR9c;l`W_NK6M%HU%is*e3X$rFxD!TqTgxDAJboK`t<`SJVo=8RQiv8t{% z+ulZU3_H-zavKgC@m&5#1n3#d<=0q3F24QNezj>fff`E&Xci(&OAK_Gw5J zDOw-W#<^#OU7HoO__g9hOvBlJQ-t>gg3A(RD$|U3-(%=h8m~%#TE@6d|mPc$OZ-1vR-Ax zA0rIfd#@dxYO|bxhP3)^c79ZrWVJ~{m?{%C_Uo=>@LV?e!Z>5tncg!P*q3b`$n)zr z_9}$NJ+{ENY~8z>oduAM)dKMJ{!20WI7(^*Bq7*?Qe|(+=aRxu?qbxu` z3BTiuEK<9|adxe~&(fxPi*^+N%l7F+XIy8UkW5>?J0yIcg|#dDJ`2*SRH)0o&tfdq zGL}-n&~^t3{fr7RF+k{O}OO%~-Ej;Ea=@fG8#ghA|3p zIU6^5aPiUnx;+DL8NAYJW#Ht?b>&ev(GZL+0p@!mbN0X zutD!k5)j>XL6T`Jjt~G%>2QpgEW=)rrKvLe0tsu&#|@OGk|r60M)dBTctTIfWApuh zvG+!PoM9GIK32^wlm-67F`W;mOcH20nHm9jjtpl_)$Nhh^90>J7IO70kTJz08X`2c zB}w=qvl=)K@-fS7%K@k$1!!?2kCAk=U?tC3S2|HGWRxhxwP?H70%cFC4VW`1Ndvpr zS5GBV&bA?a4H4@Kp|RCPgGr70pr=gfk2GP20Srt8l2f!f+cZFafCtG)(UQaq={y4^ z>lBKtN1>vw4hB#kh@c`h*o40pod6>we+7#xo;Ajw& zK)$I*0PN&T;|_q&y3SE?pju2(cOR7ZbmtA+ZrC@Y2X|Go|24PYcg@TYt*zMgNu0ML zb+1}yKrjmcvGc7kp;DH$ou;>^dIZY7B1vAFi1XMebcElVlVrR7erWi^6o+YGQyda0 zM41gDl1eSKpU9OO{*h60=IuQ@grtp$4Y^vW97E1<4$Z2b{?P#tmD!8AsvhI)$w?I zxTND(*e9Ap$BwF~jfA8HNn@_kN*x#$OO;csLDPB=A`KQ0qP~F(N%s8Vf`%8Pq$0P$ z=~xRhkF(PNJyQM5-)5qlOrMBtXcm46aLE-x(*&HAvLVdA=Rk%zNM0mXu45{zxgQ1l z|CpD@baRS7cG^1#;MjPZ>`^;HT+=>Y)^jcFmP*M(5_A3=vLe6$$sU*F;HrHETtpHN zF~{O;BTB}?4T4NxqX2S=34MtXmEhcuIH38Hwy(~_go(N!5rgf-*KKv8;#YDu*2dZ3 z0|YyN`qzK_=l4qw z;=ni}4KZ{iu1x287&}M4wH;Gp<@jI;BR3?74t{q5r~~pBiT1LV{&Byi1gaI0@|Mhx z`!$OoL#0BcgE^rjXd4|i>QADoB<&B zxffPBdS0A!^m%iR1}S^N&VRAdY9XBOIIT|F>BleDjqGnccRJSk?vD zKD)@$$dh9(QmI&{;U)eckbEW$L6U))Tr zMVXGdjt`s_i^v92V!8>A!6?Pm=PiRV*w4P1N#S{@pog`E-jUbB6EQv(W@Q=WsXWu& zrCp}I*d~6-c~ZHJJW}W|Kw`V3Ia1CV!zjY0QCnuYn%$xKHmR~v1c`*JA8gWtGmQsM zvh@Qt=2>3-EwqM3Y>a0usW0FDV_U&1eki|eS zKmS+)tt%p7g3Zo{`)|y>4U}A0b?19Os;aBI`lF<7NiDTLZj}{~6AMfp0mmUkw`UA! zc{v0YZ@s*%x7H-H)~p8-!&tJPVAf*A4G2emF(3v*WMVRMaDpHv5y5~>3^c?s!ee3^ zoQV?KK?FlY;(!u74*?E-zyIFn-nvy?-D(T-p|~qMnUqYuQWw z`?w9^p%4T=uGnY^IbH>FShR`u?ZS@@VcR2t8^uPm?h8!>!&RB0DL|t{aE9a|h!c0x zmzp*+YgQiW z?Vk}8cgdRs_?CM~2v-ccbBZE_OO`-4(yAzuvsj(5q;T=fS*`wDw6Z5xmr7o!kSvu6 z=~;VmqNiGjF70p{o7AXs3Amh{X{h1T^46W6KmD1vJoK*XANklnYqo~EZ6+T)hf-i2 zv~^j3um*k*Acjd^-A2Q~n`6hMIHK*ay-UYKv58Y=*ml;KzZPzD2F}4r_6|i3v=_*m zIsQa{+8d#!4Qm)KGgtsLfs0Uh4q@Vg6d-=RKx|eCgHm@!Fw-1Hlcz0QG;7;hzGQ4% zC)-xOVu8(Qx|@}+fL*uK8!14fj?iv(q&a_xj)>znML$9ZLZ>_K_(;E=0s(y1DGGER znr4}13Agv-+HuD7-gFZW z>{m7z2V_%QO(Zm3B-jO}6maypw2-)E#RjgeJd`H}Z{vYOg%SgA#zR)Luqm5H1%I33 z?N$5*?UW6sgh2%ZHka+4hKX0RD2hbRY|z9H+uff012)%aSU@US<2-h9;?a-5V)flH zM+i?vE`c=f_HpMGqYm)9X2N^w*0NYL~%DD zm~m3|^h_`++53u7DOjm&kZKH3N%3Y_shXRP2j%`Yp8#wG&}&V~u948Qz?5wK7bi8% zM|{F=j4Rlkc!J%C=b{|-%*HjBzzrMF7>OH0fMVzFyfT?u|UfDt|Ym8+a*4zESY=*Xs#CpuC zrZu;Q*5rp9zCY5IBPo*+4MGPPQ$Fjcl{c!<_HY$xv~qibrPZVLVt-_6UgQ>w^$7y9 zntiNTC$hEIf&Gz>T%F8a)6ju|3$^P0NVKtHe?x(o z->JmoX|ZvV4We|B?O#O~MI*eyd$@RGKF2AWCGiy2{W0#@Q%o^OQ+F@ECH0Myx2G(+ z^8U_L8z@m?(~bh`pCKGMqo%V;{KTL$;XohhpvA_<2V$lvxCY#Bu4*hpS{Os@&>jXT zF2Vpscco z#gtp#%>P|)m4kh(pY< zaJ#c!0}Wha3>r-HE}Q6N^3T9k1+1$%W-ESY$&gLh!AK9M&*uy_1r182)fZTvcVb}3 zK!6Fj=>=A#@njyaF=^VKj+jtKM*Gyb&1>9-rpmzZVynN{O3_ls9~Jc>Wl!nKlFP%o zvT7;-vX#k>Me%`GhLj-2iA4>SrxB-Q*evwEL_x1c3XTA}7ciYwjcXKn$w|13O=B1# z3K#3srhBmhdOs=NRY2NhKaD#X4#yFGC^n4^r!`ImI|NUaF&|85amJk>sDq*iWt=!N zo{|SG&)~7flL?71U*;nL^*N6H@>!JQf$(Lbo;bl{fJ7Pr9736pm*tq5Podq{AIj13q zcqQn?-9lZvj^;>w3I2!FBfwXJrQ-0x zqdgI4Y=4M|qi2BJ#XK#m?VU_wMJ7!0xBdTu7E`&GlZD!4xI`E_TU|-^*~qPwz+zd-id#s> z|LQ|)8&rZ`2Rrm3mW*8Q2w%uZ9S>MaKp5##31}f1EX07k$;y#2&7%M{domv`bPYEY zK{wJh2E?Z_EiXQ`9a2(OYa4x_2l;FR@c`6w;;yo4SFkBb+%QJ7+8I*F#4ybp&?;E# zn^asBn^X0bZ^NYVr~FCQm?Sl2Jv8cp-I$nsm4o?}P!M9$4Cnjd`LwW1a3%0iq#g58gOskO1-XFu2e1KFI7)!xW@1r9Z1^9y-QBF-T7Zq65nZter+C)Ga+r`vbl5&xjqkIgchZBM(eE%# zRg@3a**{V?^R^%-k~+A@**<5ZN&$#WMjBY*Z=xg-u3ZeL0Neal!Ff<7r3CYP)@BQ(f_4UFwogGL3zj;0cDq@PqeY8&azN~KET$}b ziP`74JE=ErZnoosa2AzDWtt#j_aHZFG@+NFcxSiYJ{=cYn z9>P%_JYm@uD%no*W{b@380okTdlByEHf(J0Z3(vsOuj8ad%+r{oy(Bh8HW>%@c$V9xAfs zup^}J3i?R@S4up^5X;}ytUqb2W%k6Fh0LYJ1_16W8vr=6V@#SAQ7^(SfOvvM_QJN$ z>do;)ak8zLF|Fp@p18;TaX38d;shg0x?2b|O_~RtZOE(ge!o=%2-zoQqNNZ3r&~EB z-sQI}^$FAUHqN%Z50*0lw%BnN?*m;M7N2aB=00?+Nlq>`Ha3iF@57872WD7&=hE)z z0FT3VjKjFE;&<1%amsYPai&Pr(%sb6F+T_e`L||K9=$|{9QtdkQ*cIi1n0ttvPi{x zThxAUvdLdGS(|U4!u7_oXdOhcDQzRd;aJc?>7>s(bdUb99)z=flz%#E-z-*Si_iHH ztw|RvmzWXr!_^l|c=AJ)7h1bJrJ@#!my0oCHO?2KmjWs2S&akT=z}4Z=0939_#oZj zCeC;510VBW+J}XQUZ~IZUJo=>5`sCM4=*D@;-@*O&RsQ@X zhYlX>Yz4NzbX8Y#a5Q7!hdjJlttI8P#?o+`e=@T4*DC*Pczf!X^seboXSTiR;K6L` z!Oj+-#kmjr@=G*7Ps9k|!ro)8YJJeSkv$v2=?$OZ4g!6|Eexf&h1C?dFreZVMpfKG z)ZtbaID}Pr5IAtNJvQ^q z5H`}%djyou>CnvqhdNlP@cW)Hzi(ayzi*z+?^`=4Fk2MKCM_8+LNcB$8FZIT^^#3l zGG2saJX^9h$vAMiC~eG=@ggMS*^-TuOo6q6Px^=@<3&iuvn69MRMze#Yg;m2gk(Hh zGNP8DiIt@_Eg3IDGM+7&+>QKbN}?K@K@QabzgwR6vZu=8Zo-iRt#-B+MB3R_P-iDA zNV3y$eCflDk(PmR=JS4Qgba-=>1OKjj(eqKc06;ryZt5rT$ zlttvt^Ct4H6M4K!BG&}ShP>oHB>uGvQ<#+49QkOwYVUzhHA%2whF3cJIQLOwnj2S zeiy7_jS)950&(-~#Ek&_c$~$kSu9cQ?XG8Xr{HQhu1N{@-Aa;_QTq>#2jep=*&q*T z6Wa*kosn2XETzMulIo6~6kH;)3wBYoC;hX+7l?0|PDn>kP_ofI`9+sTHgh4|Fe>4& zZA-~5siroj!$9cLVdO)CnvWooXC`$?2SKqCh4`&DQknW-AMj;a6phChCY<4m!86D; z7>7yo_A?!;5XE8F3j&JLO%*GY5GiqsXt$D9I)#sgPe1{R7KQvQvm0@jkO3tCH&m>_ z?39uZ%{Z4W<~C}f@6DPsu!}UV>>|xa@CT~PgkRHyb~6{$@L4W6xXf@tt*?~K>^zX!=-jbRewcv(#VOSP$ zEGh~`&osQk9kL5vQ3EP#58=qLH?Ln|c!{rMd&=6^>E-G+EnvSbaY#Pm)%V~+>D8yw z;N*bV(AP?fi_(&%rRBf>xNrF)U&3w|srG^-zFn+B;2|q5MFe%Oz8a2#>QVb9P}hC; z4Myx@H!K~p*Y7Ck7rZyP2Ja2x^1u6S&}AnLg6i8HZ=g@N4ViT& zrhLLc@+xK6UN!QRQ%T!KXZYZxV4k`fO0q4O?{YDq=~<@Dw}B`spBwk8wwY&et}YP( zjT~4p{kj^G7(7EmLrSk~E{&7Ro{q*!yJ%&vx{Sbwc3uWJ$Am~u&ExpW6zMfbx(v3b z>5zr>IbY053S3B+;sVaYZ#zYbCa7 zNQ6YL;MP$bYWi@C{1tqG8N&h32ehL(?N z`sbZE#f;32yxBCGLfe$K#h7MSQ@A}Ei61^2`W?jSYp7IzB9*b-bPY8?mG6umO~ZEP zv!J0Jl*`F1E0h4|SUG{AvU47oWfk^E(FAU@Rc4N^34D~QDoNm)Oo9#9kJi)~f{xUT z#SG!2hpT)vm@WHoUAhIU_G++`N*L z5Z+UD`35adDSK}uv$S)t^#2B;| zVsDHJcmXsWcaYyC(*_xgdnOu{ahYUHdn}po#>>|s=@iEqmgZMwlW|s5%CPMgC@hSN zR(lgUwngDcx{G+s=rAG=?(uHE?utY`D?|W3;;*|Ok)gZE7_F} zuopzKJep#62=D+u__T%PUhRw@r8MNLy>go(9!>VjmU|OZnnPnYdSg6D6VzQ4ZVR?5 zOv=A1dGW+J4owX$wXl@o_@-{G@dDbu+FJxOrrJrz#V7F3kvCAN+BMr70fdIdXPc<> z_ROpk$O!7ns=>DN&+R;@KsELJTVlHnb7*3QOJeu$JL2SrDk%se4FV&z7SY`D`9z!z|pA>n8(c&BZ|GX88D z^~bcTWRAv0c15erW2hMp#)8})2C8l&`Z8!>mLEQAfqNA52uk57mn+z;Ehg)(=;*C3#Q;WJ2F1j{Z zkyDIjA*3sEN^>eYLFZG_v7 z$agR{gR>E!8eU1sAv%`wn8jloH9rEjX0e_;>hvmR?v>(AP^r`&`s%Sppp{S`wq@t9 zauU!;h-~dRbPOz}fHQigZQxXtzxB6a>s!5pZCfXD#4?uyMhP7AeUP%!FbLYMdZn@5 z)3#HAio?DME#TQE9Dz%E95xsEUpc}Vc3HkF-6#dOuzgefg2;?|f!6X>w$sBvexWg_ zE}Xu)i#7e%?H)YuVoxW^ly;>V3DmH)o1uvJA&`${#d0WO(JWbuCYmO@mM)i&!J6fW zToM!&Qi3YvvWv7JY%xJ`A$z{&qo-_5G*JCm%tx*c1oM$?3jH=}KoR*T`@zjenyV-H z2egPNzRPMkc_x%SrIx8(VNv zs5vP}r_b;Ab$DsUzGlx&Sf-bS&zI@dEp!Zqg;!`_l1$D`0&~xOX3ZGNJRqB%5*Ma* z);p2ow8M^4=jt0iZEKdT`co>nz&`V%47ghrm$T1$Q-Y#mjX^t*z7jGTsph8%Uy*Bl zq26W&vntD^LBqNsL!*=q%#0NarJMcEL5PLz27`Mc$|RJqn**+(hOtJDP7|iDh3Sy# z>hn_<(!zF{e2Z@Z^T~O=TH2Kr8|NKzDdHGc4L}e5Y-Wz|JBJZc4N@x8lF!E!%EY6m z(l2X_jLjGsrg*}+<2CJSB=E`pPL!DA(6Pki0zG$!B&~UdE~io;b>II(;e*Q#i*x6^AKvVKe6_-?Td1F^c&W zwiLXB(1h7Fr0ZE*o;J@ZI3N29^hu_DZa733(fz&PeWxV>J7Cz|AuUV()i;9`iP$IU z5BpxHr&9Q(GUEd9UfDKp>9LUzbKwUY;(d$ZxHzdCc_NAzb zU4*tN!xETAKoZ(iU~1vWCf7TSq0m|5Wvth>R+Ot1YI%y6o!nB)Q$PQ!>lm{K>63W} zc9iop3YU>G9%|NN8bw{ME2#whG^MAUmP6eU(BJfzGLY?dUzY+WY3N`!i~LiahnbS$g?gC= z>t1HI4G?TMX3AO{Yl8gYNr$^&Vy}t3NGjryHh1%eiB9c`ecB``3?SqvZTDCa+xF1e zn!o}Ox)|e-<*JHyWpx&f@;3W+wU7!X&>02o&^_nQ?$skWQ_IiLWc#6TvNiVF@=cUK zq4)Yxr81JhH!q)q9`eWaML+t&oSna9x4y`K*GD2l% zQJsaJKk6l^-Q>EWm&Nmvh0dtBB#-y2#mb=lUXj7xJfpQle5$XU-7;|vv<9q_T5u0N z7r@*l(Ay`ls+o;yGe3{(NY-F|KmW~rRNS)RwI~u+nb!<&(R4(x80F4m$=2k1W-Hs{ zgkNN?-$ZidCuyPmkU0NMP#`_vRsl6%cr$=idoO?igf;+!0mUd&_vp&OJ&fx| zVvRiAFmk#(&R>_m-q3VTh=3@}(%p0T{~1#juN+ar%7;yXU5{Ad;5W{X?FZsk>zPpk zE9U_^w18MK)WLU|@^XgVJ$T~QX71I0Hd+V{S&+?SJe;()s4{&R?R`$0I>CENt_0x!J0dO zG89%hMZ0faUsz%?*Go3lGB=tSu*VSqLTC8N8;~0ksRfR`Z0{$A#Au`6qOd+dFuDLiZ>2qgge0eb?`D zf2w%Vhu0gu?yfbUV5i1Le_;rLd6jpHLe}J;*JXqn2zjI$+SixV@>_8=bD?Ny#EeS$ z0fxknNK#{6Z~Tx7ggc9o#`$B%d0ekYL|vSp)Z>gE1+q+y^mg2)4`cZ!?c(h?!9DE| zXpL+?rG{9ooy56Cv_0yzC)uSxBUCl0L4!Cl!P@i?QUe{0T5UJs`#!3=^eELS@3olK zq-u+;11FSsdUywf?ZZ2OlEl~*9T4XNH(u$043tCfft};_=8|}NIOvEjgeH*|K)Z(T z-0T2m5EXYqoE?UW1gpPJZwv{)oAyD93Redy1y6J;Cc=N9;wWDP0%`#PEsTos`&N@= zB@xk5udO5w&3o&)^D+j*>%A55ougg`Y0_CI9`Ec7jYM{YAqh8yNe77${|ppHuirI$aNP2M+y%(X8gH`WtM21 zQ0rALoO-+8fp&gJF=9{8b-s%?Lw*EaV~k3Ju3SH543~t$z84rCDhnve#}{ztJoggr z97~_eo&1RtN6}q-p@rqOzIP<8SN9Q0*##Od#hqGu^l~eV%gG}&l5QX-GM*3)Bz1`C zu7FtLNXr`o*e8+|iKS#Hfx``qoxvo^SAna`;@c{4^(PqLdIImpq$2&k5x4#iA4U8R zgH~r!Pi_u64Ipgd6L06aj4X)yWnU!i5P!EKi@1Z!oB@9rOi-tZbVa`Y$JX&$T$3sS zs>9zvNJD|Bu*>NU2V&H?h;g+KN@_S+3bcje^{b;TzF zsz9@2E@2Y5rWwtj_{gdI?z#4%FJ5=e%b6N5Z}zIc_B2&3D-{)vcLYz!{%*<*Bo%HM z4)rdhZVikpRsRsGr>~MlG)i6OqAs5VfamIR2mDW1vq5C<%FMC|T{qci&85~!^Ktgs z@76>yW^@6i#0!@i7iwY1+xq|Gv2ir!U&?0oF~*caQP>}3keQ9KeQQsCJz8RZnjeo- zro!d#y$+n9R%NG;Kwl-aGy~(F;{Q_~weATDuFpmi+f)f47J}|hN2RJQv|nnoX6=^a z+x|-u0H!%V z9=&>HjSo$h62b>0O0U6ae*-gEsWR~gUCA*S)e%?|1?OnSFlYb zEqEbl7upr4fZZgNo#h=D+4Pg7n)HBvTabwb+8@<`hJ=zDz3>ON+5A2Zmhm{DD9LQJ+EMo@RsK`yp;K9-jA zB^+eI)>0k8B{L3D%^1u&V_FWT#aZqj%(|Q!mJTK-IP4l6%(`Neh0(;GtSNl!Y?9Qj zi4_g85QktF_;MtM!IXc}HDDLP*^AHbh6nD9Ov=arrWkL+JKVe=X?JV1Vs0cISqW|- z^^UqbyZ|G0$2-_P)~#e0f#}Th(3nD;N58C7yJWPi!+P$Yz+yzz9dF z#kepeC;BCR74O|yZPsexol+E^JTn6mGOHMyC1`DN+#zPMfvvTc%qq}~jDjwWRFJaE z?;^@|HlXH{%8Zp&@@mF32=UIWf#(=p)3;iyGhu6wX$u!)uAl_BtRijDDu9Zyw{AMe zv&jM2AP+=qOj;kFOh$dEj)JA8y5y(u@hC>)H%xU{GV$zC0ii@o%`1A%oq4Y)7xY3x&2jqaB9w;>8c)>RRG_ zri8?8GKU}cpUS*r+sR-t5t#GJ-fO#b>=08CQBB96Hf>C}_0B{oL*##Kb+T|?O@Wb> z1oN#jtMDl3#ZI(TC~U!_{6s?mhl1ANeaJ-v1AQvC3;D@6O$P9}hT2N5|11SFV+X9o zma9EG`YC04riBlIhv}5YFWpBwOSng;sBhs#u5?wGmj5Hs$RDmqy^1j*tOZHhf@G@NM&9eHUQ1 zqqc(&Y8X=6AgTCLN$vxyr6P(DiC!OfThC8lX|z?ajh4~8xJTs9%5vB$ue0fPx0$3nx7XDgt7SLpZ-spCe z;l3sew?*EnM(EPI%g6*vhy<^(Fib?d5d#`wFcp20$V)c*3BrOq=gzqn-aIm)jeb#T zm-sCCH0y;8kt1=rJQ^TH0&hrme}|<4-a>n}nV=}|=Q|_LK`!ymjO11lVY*ZRC{g4J zP0=vfiMxP=fD$a?$$w7W7Zo~WG=Q*vg$)|HY(Fx@HiCgF7U|GNo){Dyy9vUX>02aD zOIb5(fe^G-xebVnh5IrdishF4Vq{K030mhV6lPW+4v0e?0&F5t2u+3a5*=Gcnd}K! zUI)=glId+T16d4_-PKQ|LtkErpRCjkquNGQ7J0jW6=)Z`d9H{KS zD1iDLAEb*#E;9C7?|S2)kcVahK7Wkv=buXpv#u>A4|^S{$3cQda!?Ht54ZFFVx?J& zzB>9~lxMCj5`qRZ1bD~_qw3FUW;WvxCQ;>{DW(#VV_-nvJ<#gL;v6Vj;vBFEagL%K z=~)uza1JK$&N&hmy`{XU zTIoe7qBbt|P`3f78+ zlM^pA+i&ksdzcx({$$N|!)1|LmNRd6>x(;+>1&#r``r&b#!$4zK>PFnKiFxa7t;}c zmFQJ!uk!TOnoNylW9C-Xu2KS-sP+g2yP6v zfTWbX7*oWEQC(&><#@2r9BiSJ+oSwlzzlxena*zrcQe)M`tPmL-E^`MX~$n3?G$Se z#Ga3FK}l|LVL@~p6HyLzXTg0c;gsfyJi}%t#sI;vzk#AO!BX%HG>KnSIJ-E1@aSTs zH|QLa3ryId9xlNcz&M0EPAo8M8O2fX-p*RJGv$9&+y>q5*5nR@Tb1l|GQ1u{! z7y;x5-7D9hj4(@kjut+M7khuih@PsT5Us=>6-;PTT3 zeWES`#o$=wXj=5DOf*|2BCuOXln$1(u}qYfiE4w1HkFBLWup3EqPa4W4yE@tH3k!H zE)zA%L?eTV28(9!f~>4>mXM&_AfL`c-k*6is{WgF(7du_IU{?cm?X0!9p z;&&rKxejKV=DYmP&2Q#+^Za@OgKZ!bSDWklzVKWds^PgPrxy~8bY)1e^<_w~^%fHB z;Pa!%#!&{mVWSAqG&^!vLeH0;J35%k26TcYV*5Nc_}PY%&n^4h8vJa7$menUJU;l@ zhL6t^_IYCPvke@dC++j(;Aa~$K2O=_slm@-u!fIPHe#HnZ=j|KA#%P~>|i&XA;!6#@sV#F{Oscs=bJ3| zroqoXK5;&0pXUZY`}oB9X8XK(@UxFkoNuwuTLwS-_{8~E`@D7VvyV@lZ?n(a20v?j zUIxRP%GdrF!Ole47J#_y)eb#0Y|I#Ivs$;YdqUADTlxK;MT~Xw8}2E@*bvsd6rqrp zF7EOh3W3-YuQoeUY!AdB0srKiSkukk?#N5EB=g{>EhjuB@BV)xCE|zDkLy* z*@>DeX*WUT1NjRH%xter7JgDbzkfoubC&%jK+;pc>zMZ{R7#i-!ka zJXXBO+WFXvCZ+*fsp}TxsH&&RT9+vDX8JOu9Tn1UDQmy}^94uSKAJ0S801pSEG-=noB67Xvyc zC-z!w!VK7?on)M|f!O>E>&n?;u?|k>?52`B$To104F}q|;k>4j!o?ea&)GA=HVwGR zK#eZpw3DND1-wzLWFUnLxe-#ZS48JCI*X~);&N`36pbs`;VvdJP=<>-#ikg!g7qMA zkbxA&TI_HW55}6AXd~HrWnJdw?u;S{7+$ zczPw$Gh$kt?!)*o-|TDJ=DotnWe`UX)nL2&h{59EzL)rQ_%||b1p#*j?E{Mj2mS7^13dm5Ty)sE6 zvubZJWW8sgN^5|zbu2^ytL{~g%-&*LW(sa_$)Oh*rK7eXXC-r)5z62#XMNVM;oNiG zQLV*Fa+2ZVkO37A;cG(LGbC9^#`a5D1iW07IQa9hWH?)`hb?(B)HqoFuw*bo*%~|< zid>RS3`>UTWBq(PBoo^LumxiEy4_@}l1X@|8O1q|(d1glvBLeu{oTx;1!9{tzc$&_ z0){?T!fzBhd{|G$b};E>d7|au}@CZe4hgi01n-<^^Coxz^mbYnBPgr1SU2A5l% z6Oiu9>MurPh2LIn%hV&>rmx0CepxZsgxh1SQ;@1LlK^P~Ftxu`DhfM9_hZ{MbSM}! zCWFA1d!yH7*r1*}YbH!JArS9}vNV#kjFqt?6b4<*c;Ed#(@N%K%5oSE&%rT@aZrX$2D5=!i!U|5?Y`ZZPTz@~U zuFkxlxUa{RA#TmjnW&6ih=QEVUvh0Xoxk+Z`|<~Wf6>hHNN&o76{8sRAFyzcl+Pt4 zey072wI80u)pHlv4OuyNfsD@@mJt@6!pVme30F?%yTiU<&7|=1=m@GU?ZmV<934Tw zI69)sUdUFy-n?h~Tg(DCn`(!AfX&0Y56*8MRyERZ43%|7z>Pi?z>S?R;F$g`12`?H z4F}wWSGHQvEdzr|0JI!braa&r&+B zF{{Ka4guP2XhBjtvc)&yr;ptixTDytWYv}3*4{3OWjG-pOxlb&%ymmEdYfC>fbI8VsGBN(r39a2K9^*)U>tL&IDq3C0vFcTZC?;r8 zDqSb5QxF#z;yAKI{h|l`{gMo!=cGg(Q%YKPb$;41?2^?3%rNf?1@T%gk+?(1106 ziYP!nKe!&A{=G$F@8`E1rIN>~#GSgO4w+gjg1U($ZP_F8Tb1~y^OJg^#AscVJ-Aj$DdqI6U<_ikxGo}3{QbW!3p}mpC-F8iOl6>J0T5zFxmER7jnbqdi&|6sz(}r(y}Eat9at>eikhR8u=|GX9FTpUxqD>RRhT63lQjZMaJOz=vPm&d!@6LWSPD+A zCejY#kV3=M#bWrv49x$C{7gZ2ckw3UGyx_p3=17>(n^rKq<3@GW3i*tVA>L>R9|QyfoDaScjo#2Jt5-Qw*q=l= zckBe5QYPQTre_$p5~fyE7kQiX4h^CqSMO(L_q<3@_W6;P8d|Wbqem9yM)dF>z(&l* z9A4adQ}JTq-K6N`_ZBG%X6AGBSHg7)X5-;!Vyt`&5)iX#U`%^;)S&zeaj7acNXnXF zAmzJ23dY$ybE-IOFfdEYA+Gu1n0O~XQ)ddE00w~qxTs_b0fL#>2X8&TR~)!86~V`X zorQ@t)d>to|5!MSamGwVMvI|AKqx=KS2J8Lll$z7xflK<Te2@C$@AqL_ z630P|Ge7!)0Qj=c<;`=8rdW)mVlOT5vo_mBgl%{dwV@*#(@LYbb$!hdZx?n2?{|Uk zxNEYmz50B-e2_>H+<|-NkNrisKZH0c0V~&1Cz2%U``Gs0A00Z4R%H;*%9+&5GIZg8#KJgniV-0Ota-X*1SeZ+-Z-81OCQeAYi&jCMqk z1cu??A)c%Fw@`fs|IU^uNBT46gU|<0WJ4dQ!Q0M7=%WCyponp=5`AbjBfBE{9H;6Z z0{S=-Ekz$2DxpouNDPcWI3nGXmT@0oD}c>ht!-ua>=dgcb(t+V=E(S zvH{jE*ct`^OW{KRn^l$py+CEej=+xifKTcRq$z& z<}#dFjI+VyM~4xC$=4oN*03@b;>x)day~#lRsk|&AsvF20Z>dIeviy#sXF#!3k2Aa zDs&BcgJ}O_(~aMp{$vo%=ns)-?*HIQM01j_D@`&UXS|muxhE>vV5oV1g!XS?7__ZN zf=ClYVw~(BJJ%Fn!X2Naz!J3QY-Lb~=l5YCuVZ0wacGGyA>18Te0y{GVA6==l@p4zksexu6ncp00)5^V-MTC)%Z z)iD@yUs?$4TmRE8-u1l+qpqVp327s2u}h7MO$plV@vdh1^epPm_)V>|PR~u81uVQ$ zO{eg6<7_5duT$)5Ip@{$<=x!wj6RfV60-l zN1SthDXje(O@Gd&+AjX0iS6STpj=obliJ|#2`9@$oZF>6}Sdr_4Vq)adra^?T_t|hwQ91GO`ISlkAZ10p-OL&qUoZ(?#)_7y%{7 z)LR|@$e<}SM84p+^iU_-;$3aQD2kq~QEyb8!co|G&?7}4n5gA)U2ZXAO;)|0E$bYs zE_%Fd;#odteHK0lVCncy;HAPDRXd=F2hQ9oVLN`2;7L@AqSB6|MJB9ZLQkP8T*(YM zKndPX_TKhE>c&_NR(GXgmt7TVgs!HnYFK+nK-v(+M!O)yKYm$LZ2ZhoigqiY4U0w0 zn7~K^DG@LXTYZ$#&+!W&o~~9{}hXomrd*#hJ!y%R~(D}i^I(+ zYsdIA`*E;4+O8%La19HmLjKVqScsn;YaKJwl*2a z?O}MoM{t%4NM_`$z#gND&O++{%fJrjR6BpQI}xbwWx@n~{}n4{>n7+9avY<+6RCyi zSd*5ljUg6)8S&UGBRceuo{Z@wK6Il_-8i-X<~~ZbBj@ZJ2q#}cz&PRU!l#K_C;#05 zp6V4Y1nZly$g3!0cBmR+cEn;Capmm?+P@#_Lk-4+Q+66cTpm(i}Mh(!wLZT zid>;BC*c7TZK5^-meZ*^z9V@w#nR37R4SiE&Rj^n&>hK1BMifO;xdU>u|`+N0WYe> zT2kqSC}1~n9$)Pna+4g2$REFB(RZ-V`TpEc07Z;>5lM{lGcu$IJQ!63{>7Cds7>Zd z$xRUtrO{Wodc2hay=5uVvGA zKwa%Zj=sf_(g|) zZ}cOi#D(cej{MI+(?aS4!%_%`r-GR~$;ls|^QJ9953WNOS9OCEfHm>K$%x%;}aJu z(tz|R1ED^KxE!zIjb}%6+CWkJUT?hxdMPVsScX8T$ZhHbp2hXMLraTu7jLfbGp+VNo8F@(N9?b!3ZX$J@P8rpTq ztA3vD047Bj(w>ii+y z@{wb(e6&m3FVDlv@U^6s$|%>9O2zvrDu04ReiSOG%CVb+CVMnB8NewwVn!BuYNMk` zEk9y;T$0@cH>Q}wBBmY55j3NKZf{3RE!i4yJ*)!dj=`nVLX1`ag0}8zCL54KxG@)L ztx}}bIhZz=*DG;GJpz?|Gm%zTthCfc+96s~wBtI{mUl*nyhAW&XRl2cMG8dKbfH#P zs3R-clkA6GqcAJ(5E@sd$TuK~#7}lc3)U%g)IzRV8EDo;#?T;fp|mI03k?F4@ zo*vMt6Sa0lyod~fEGaYbsuWM$!ze+sesMy!6_jp?go|7xmTQUoQOBg(jS*7c~gH1L~O;Mb{y;}Ts`{tW~y_9Q5rEK7%N zHGA5(voBx+;8EC&Vb#S)Sk!FlC2O*yR1H(I$Dnre*l-?oKh+i$K0t-4?0!{NQM~It z9%W@q@rFmSK1{GYtJ;I*8C9dGREqpuDDp%olH}MQ*dOe*i_989kc3icDm z(u;X#d>N|kemH?mfEi5FYmEmS($p6q5;x4-BtRo`4d!_JMKCyPYb9KsxQ7vWqkobG z5*s7n*C&^yO7;Xg)x$P_abDDL!aQkq6ElhAiN*#xvI_>Dkz1RD$k>A21OQZOuLm)e78a@6pC6MB-(c#lwXQRj_e zSdN7HghwJBn-SuGz@yk#v?-r%(e*lgg75WBF(p(R>M80*rR29$veW8emCX>kBnvam zhRU%wbUG9e+9yeo^rW(hq>5CABu#;BRHbr5b{xfxYUU#nh3tzdrh!Z{*?wq(Su@8G z6U+mjX^Q5Fg=|(q#3vmf%y4hJpb9|TOhjy$++@HzYvf;@u?q`OEiDG;rt( zc&D=`H_S)#W9?fY&dfs=n46I#I|G#HC2@JBSsx}DY(?YP72$jCzP5JK&| zCRxWTMScjUPjM6$RjgA#!b#SbPrUsdBg;&(if=zDldP{u`uu1nSr_<(;evwar&XT+ z6F12UfO$%jEMoSS{Ox9F)ba0Vz`ve;H()RuD<@go97F_+36rd?{$i_OcC3Qk?+*lX zOl8BTU`ue7ALAs;xbczD|AJ5582Ho?CuO*U#-W2)d&M6Ku6`4nNcC94#98@=Ih zTrO-}2Ltn!jYD2k`U5U)pw<`4=aQujL{(T$SfC-r(#9K%ha#c90k9}nKu3CWta5Qf zD`nL=mM>G7PQqyyWs(22P&{8JuDgo@%he4^02ZdLlkI6;-Ka&im6kV{oD)Sjist|I zp3lGO+n;~vj;}^98@|R-i;|TVIaJWd(t-lxTV|z$&Ki!G9{ZEC((#zMWV33DLIW!7 zPCvSpj;@=^Sq@s=O2=B~9)#C-<;1LKOHKZ=3Ah?QQDw#E~O~is|xjM?X+sG~w&_Q??awZjJ!Q7%7S@8Ly)_*}9cF1W(^cBUq}| zzBhAjt>*1z69kcK$$rhXFU`g!xn?W55Mq{Veee}nV>YPLQW03b7ON8(Ufh5=W|k(K ziG+E8W+LWAX3Kym|GDH~>oQP4MofP)L+0AcpyVvQZ2x|(%DP8XWuo9dA}h@kw4fm~ zQDIE^No*pPJU20!I5Wd9>vV;S%VDVgn%=@uR}^5*-vEHSn#(;QyR zri8?3bkHhT)Tk?-a?=H{A)y%z-Dm2ZAa1eHyn?x|KtC{cYH|bw92;X9eE^xvhSi5& zO`%tUQ3e#WjlB)-6M7I3i_S;PSJPQ8c*M?d8J9byZJ8S9!XiSG3pj;iU^XSxTBm&& zGeTy8Znf@NG{m3|x&f*nRW+%^p+>V&4zGa&aRpIN>55z1!@9!G;hs{n@cJ>|2)hrv z3vSlVyF+%6mAETwlJ}Fzb|G`@m+S+AH4%^8<0PC9$&=g4-p)}?g8zx&i@`D~S$>W} zIvWzRol^IVg-4a?>@s;-%5%err6$OoQ5$LNW4Z#Z)2i|ijkeBkRcGc8X|K|n=dgqKpvs8YUv=YnU*5XpNr1(H0joF5y0=VTy`{TzaYy z_HEisf}=Ixe;q;q84?bJ0J?Y7y^e_rrESufPM7<$&4qF#8h4NSk>=N3$XhL`!ohX>lZebr?mvWA!W==qn)YJ?77%-P5+cmi2-@-)c$9fPec(RhF6cMjG= zE)bIxI-GO~jOCz=wR!;Bs1d_^ad@!w)k8*h$Dvs9_@ACPv|(cd@CcZ8=lPcjQ!{AO zv*n>Jd=<2hE?du2fVR1IF}|y+@$83|gVs~15r#W_EFK&z{h|VU&PkyXG(*RCaj?vt zt1c5cF;J$lwj@7Rmg)ZGJ4k0drQ{gOX~#bQyUMwMXo=!AaL5j0Y&*dQx4MEr5_nuB z@Ql2o7AMkM;0QvXi6idHO6O|ZdRT6rwgam}6N~N7kRwXb(! zP)YeArEK@5yep&>i?5`7pHhzHAC@Br4&!CFDN~HQlJeb3IWaV)*fA+X3<~Z#I}YOa+7k8=f_r4h&WLwM7=xc^;ZY| zdR}SJ#a}8ZPYW-``v(1SUMZ!xMkVE7Al!Y+71ks;jBw=1nUyWAcUYx$v~G<19s>Ve!}XK+=Z>< zp-XA#5>zLB8L-nO+Zf9VaM>kiw`G@rpm_B;x|DjCzMZaCYgKove>V2gVrQya?8M|$ zd(GPE8PjIJzbF>IBkzvS2x-0=9yjXr$Rz(4hV)c7Pam>TateRjNqtSH9u$JkE%0_Kt;x z+CHo*+L5AW?dcW`v1l^+I_*1ceI|+POQuy`8N5K1)ym2^`WNbCtFFZ^;}oO4oaKed zoc{*@RbMsWtO6A+fT{#aoG#@(M6(T6HYwwDIy*~Pu52(#+Qu8tB)5)mv>oLboGM@Z zl}aVvnmhq2?Zd^!z|rV|19q^qEf|TGKz_*!YacDAEqLmydEU;}=VF2bB*4c1e$>zt zt1{@xMQ(M_D|)b`kDu;!rLP-li3GKP1b%oxT}be=t3ZN&1WBRg{$WT9l+e+I05)`L zc?5`Z*%60O%$YTDOQDCb8JIxHg5ALTgB3?e-6;Em^H?VVZ7ebp$m2(IHF4>K#+v!V zf+=>yF+&<>GK3CSKx^DWc`vh@BI)K@pyTCLA!(~Xb|N+!vMV^XpMtIpxXpko@-mVT zm1M)wi0$o{gYBtr&Lws$@AoRi9g=AlPeJJdI<#=JpAiT}*L;V%(BF!&xRJ`$GZaI# zDi9{Zdz^S^HgFY(q-QU|gob>@qGc9DtY3TRfeA_N{H3YVC5%VfORZE=?Ti%?S$z9Z z?i+w`Y-beVh>`(Y-qax~?_}?nPecq1yTRq+O4Y1*n;${yxPTNXTQCtP9Ra_rd#{sK#WCOPp zC*!=dM;XMS*KvZ;dE;tV;~z<5%*iXDJy{mca8|~`aobTxLSn4bnT6w@Lg!vMeCIW` zKbBxOHWqZ5fl+xR%NK6vNEIR&6dOV8<&z&1?TVv7TmXy>86W_ADU{>MKjCnjB%d;0 zhy{g=*K58mu;J5_j9tAyNAn@Vo*G3P7Vd(EttHf}rx)#4I1nC)8@>?lzciY*r-nt} zwih~IiC9m)7r2q}V(kH)o_a=E;DUzsA;_O*@U`~gVH8Qawnt{tkq`9CHbILwUSq9c z4pN^}V`Imhg|@EM=9R5E6>6p_mBy~gbqZ=<4sR}L7A;3^6H$t!-Fd9zA7JU;{L8H_ z#KJO-XLiIl?P?~Cw_kY7dQu&2J-;6k$vgR-q7-SXv_krsx+tLl9U>7WPmnMKtUwSN zKX>jg`pjCAcC@8qms+cfpe^K`g6O5_+8l<;X#(?FxX50{J1NX#TK5nlNQ|j~uHrj# zW1*p>TcRFFk)Q+8CAec%V$AQLcL_AjMpjI~SJKsxu%wib)KZT}R8$z}9@$T@SYjTt6&gV7U@nV(> zVdjqT)dG_I=eU9T*{83e3rBi^7)CG`Dse+Igpqv16*(QtMuJj2=YH3QMX|BaLUk$i zbdGq70jXSGTmPHQNcw6+JG2Q33|LcxdRA+B2F7o<^8AuDrpe-$+9U}^MUr4V8V`=V z%U-=E3DVLi4bOGu|NRMODd==<_^zU!kPBASE300X1+NfGW3GYaF%(nZlXoQ@8meR* zNSU#OwxP$RZ2HcUi%?tu?Jo<3#NR;7gffI%oEsm*DLQBj`8It>^Z#%K>FRmo>TE<2 zLlfdPhm;8^;gAhh5|#c+X_-1=0w!t+Q%hLS*Io_npNaOV^t8<5X=;1ezwGL0Rkfhm z3X?iHN3f$2ju9I2Pnbx|XWOg}UxwA8=-93_fNq)}u&I@xk`68?*YICAUtme93gA|g zMHw`U*HAp&HQ1P01?UVvj0*nVJ)qSEq0JAW3y=3|aA-g6K>9|n22Hbn2z~fkuLi`- z52J>E?bSfAdz(pv$C>LY3zz{#(a1$uzaoG8&+~Ir~{QVOh;=6@{3VUo?6ZDsf+jX^L&)xIb}AITLmaHrs^TJ>5gb! z8nWsTP1zHAlPOIcYCuCPs>`IksOVV}xy_KPMU-hw`&m-NM4q-_tu72KT(e}0JYmqr z09#W^2v@N=1OPff-P9RU>}k1-K>v5+!?I8=rISEYiWT@~5G!W6KYtnbi14emAVat{ zIf%)w=IV5&5R~Xs-XoEr$tMpt9qe?4u#_g~8GEdr2|OUsRI%(z8oDAe7^LjQSS9lX zY?6h0i``4-@oc@-NK&DpwBC_=uwBG5rWSCBMH-`(bY79cr47=~vDcv9j=g%X;pS*Q zhT_ZKMw^_l2Oe}AyV5>2&8+{G=nA%~DQo^{^qS%ud%k#adW7kge>*)=e&g&yz8(I{ zsQk!%`ISQu`Fiv%GQ)UQ?#r(n>crQ@gTGjQ<-Yuy+S1&@2mc=1OvtQ<@;j2B+zX%i z>u2}A^H6?AWz_c@{^?;3Un>gG(`%eg^QhIWGxyWzK(x|o5(19fpu0-0cN#VgAL z_0TO&A1w*fWv&R(3I`AQXtC4_Wsua?vzo1|VCxI>jobgCoNweaxjmf*OLxnvUInE` zV2>FCo8J_`>_N`FeR|5~H~#TMUugiSmW;fjF?Qj+CvLqwl)IAtYAZ!O>PiB2$zG=w z0UKRYXdg0Se_D(Do)!6fNs^S~UN5v{$E`trAf5=&`8rIY!q43q+1 zz|>)-1x4~w>#7x9D&WI)9w6cqG@I-6S~CDKn5?x+3O4#L?3?4(pq8##Bw_p)V#aHT z+1Lcn-lFNdADW(&%@!IbqWKdaId$JX*FN;c>#k|7CxeR7kM4kzmRGmfKxtXinBHv< zY68YI(&me;|2=SM?59iz)o=i0=L(3s!v4&U!?vL^omEBvsi|C)_m?!)VkWHAVy=rJ zNHtcVJ|{P876DFE;+w`TpZ!FPYm}e;D>VytoKHFo|IuDVo+j4V3seFn-BSbNEb`MD zD#c{6y;3nC=~23xTkj?X|1;7 z<=3Hvd=@al3EeTn59OaNJ2IqHE!e4CHCe+wSc95s>y9`7Qrxxm#Lby5UdzwA*Ivc%$ZN0KlWom1?)UM#2OGtgj@^JQu1%pG&R)#6?L)cQ#{E@S zL6=)!%g;1f>-iX2_jD)pYQkPk=v6kMJXbMKrr=ENV)65w?IKcMJG(&V{R{`X@e$|k~8iJ$VHd3+VMa-7>}woT`fr`Z&lQ!;Z{<7@d*pV6P_ME=l;V}FV?AJ>R9_jPqbdDHsb z=C`eew5=f=u&zE!ZH(G1kkDriF)A^E`_N}Tsn47nSkEYxz}Hs$lrk@Y_(KODx(5$v z(v7OBQL74tkoIwWQr4!~(`2Mht;|p-48N>XmiK(&`#QnX>)gaa?{?Z(cY=nF1b|Jb z)(PwLg!lPh-h0=5oP15K^=wpq9?jI-y8o&nRUB09v)w7xK2@om`%pWd)ZNDp+GETznl_37f-@f~1yq0L?vbY`ke9fHTMckg!IA6R9?A8gBAow{T{`kkg^G*`c%4Kmo^!d4~!0kE5ZAxoaAl(!_H;tYN z3nCu&#+%;!oe_j~!0nBz!R<>{f!lT*DW{DS6|BVVan(L_G!`c zw9)gl(X+UzaC@WU_6t^l+il@?D(n&i94B*=%%iGx)M_2|TCac4;cqdc+9)iX-q+RX zWYb2^DZi;2l3GJB7m07r<{Mwj&m@d>Hct;+m9Y-a38fSHlz8I=uaT|?uG08Qqs}OI z2Gmjg8n7AFKV$XJc>SNc^}juY+<>2KRAn2jvW?d3jkJH7jGM_=Q@u5-ms2FE7fB5H zv{i50>P4`qUI`2EoAQLRGh`nn`%-9s_sq3#q+ZUvYi1kO@01HYHmNlzI0<*5`Zrkp z8?1h0F~^xsss1Uef6D700p!4ta%T}Cs(;47M!#pR-?QHDyZ`Lk?{iie<5N?=Yu0ZJ z7C;cM4@TPiJ*IlctllxJ7ikO$VZoDd5xh}w)bB(iVZ3aHdS}T#9Nzc-`JWyQ+$5{1 z-_%CGn+PyurJ7O^o|1x_)Phacf=$)}Br+$Yj;IAA)&gXXS^(S`uRTORnX&q3>GuYW z_Xg|t2JiPbPu}uPuYXLHjak3Ptlwj_MN&)SJ*iqJt=37al@m=NBNk|-JgMI(PpUN) zCQJ*@W~q0>vhe=Ebzk@*>LTf;voZC1l#8?jVf!G#fv8yYXhFkTfYS#U$8o^SU&qyg zacjZ2w*a^^UVFNmGUC2a{|1`BN&Vhr{odsLe)x-@`6~RBbd&1$r1g8!`aPMAm3ZD# zt!yHrgDtBSCle8}YE7+H2vPlRW?({1^-^oLiF${_`)}X=wU5C`)%9#r{hst58@3OU z9Q2*7RSVWy3)Wf-kj&UoX4HZiYr%}S0JzJg2V=|ztA7*y=HyucO?qL&`~Am{T>DA5 z8uho-@0RtuW&LKqXNl))RO=e6l~re;4O2l4YO2#YISqoq~?9thWHTGhTbTYpGvw zZ_w|x>i1gf_ge4w?Z?0MBw9H2uTj6(Sijd;zX_h2wa6$uU$0u%TdnJ@R+tKeG^$!h ztyZ*H^?O?GMq?l$@LszDyzf|e_nWDgbYs~Xr|&iDv0?il$$_ZZoLVqvEtsd?0tOXmq1;Cy0+S6S}zt__IwKRX7`n}Hjz0UjnmeWt3K%P+ldi8s~^?SYbdp+%6 z6Z$=&S|_Yl?Cgv;ECoWER;|-kE0RzB-Y84}Q@|hUT^HcpQoSv!x8?QT@yM6IfM&QB z`pVYt>&{Wvdio8-_#GrU2@dLSTm5aTALfF<+NAn7S^b;5ewKoSZ$ZV~;z1F(D*1EkGu&pQG9QmeH?UYqJW!1t_prehdcB55`=u@}bk}fqwTz3uK z7Php=zDC_%W8Gfk-TsF!+;TIj={lkLT6KGpi-ud>UW(>*)nB*z>sG%M;NjvMvLB-n z26l~_(0nP_-~7&pKLI-j&DW{l>#X1Ftl#Sdw$Sep)jMMKat<}a4M%~FhKX-O^YspH z)w^aWxNrZ=V`r$BbTm@^u5no&%@ft1SpA9B4{wgf8wDJeI1^*9GVMH zG~VN?ciie7w|e0y(9tmQ4ZIn==SVq~>wo~r)T>c?mX+~F-8qCP};_o4an zaDVV???2W!H=fU^-WjWR#_CO%72m*{u{#&M|LmQ|K8zS!EuJ@3f79x3TK({r;levx z9iD&TpCA7hrUvK2^CjvrJY^a2y*fPq-XDJKF~sL;@qASM9<_dtTEAf~!-coB=T+eO zm;QL+9}%PH!t*8SF-&C{@x3}c|Hy~m^(pFIEuK%S-_zFbY3n!4Ww`KOC7vJt`UC%r z7=y%Da0Bc^CDr7SA`T-y5yp8?E0k7f5Z0@LnaJ|HGf$_ASKd zx$u06_=c%0BfeLM=MR7DcmD_Vt`^Uqg7{t?o`3I#&wh!6ug-<%PeFdK4$sdle&9{W z@73b@Q;^?<+JdfWT9@Q#P5ML4^oN@35AS;8J3jCAHzdCsCchgdzZ>EYL5{6KWPoX_ zk>J34t@!y`*m|M2ELD#WoqXh9TyJ3|R`Q$Lkl%IxRa5#*r&^Do{?$nEf}ay;)6|a| z{a$LWzV{n9e;oZ`Gx~!n>z{_wq?P6O8tH3mOkYE#m%fIwgEF5{p3WdF)Z?Y_{>XPe z^9NXX!1F}Y&^danY3OoG132ia-%BMp4ysasH4$bqr52zj8$ajhkJ4nl)a>!$8_y7Z zL;W7qiOEfqLcf=h-|JNCI;#~OPqnTWn{TM!g15{(!{L3;gMa`3!A$2gVYg{$Vk6Bm zIK5wLW?DvmuT}kPt$uWC)lbY;BpkB`%uFLIn3?Xo;ad-*H}T(~QcSaH5)IdMY#I5z zUiGfGdYQ_o-Z`;(#!eIQ5i|2>O=YP`@mpWIai^aEm@{QbTirm z@*9F`sQ!l44{fUcS;5^F39xmQW~QZh{*5<(@)qo@K5q1l;R3u7qSWd47!4mL zzagYK)jMbP&Uw9KV)KlhCgRjg_Tgs5Z{GdRzo6b3;raMJ=49CAR>1RN@|y|Jkjb}Z zX(^2`xXW5J9PW?3?eG4^O}R7b_l)%$!v+1;R%9XSB>f&HzagYC^?S_vjcH2oo))|r zJK;IDGP298xD?)JzxS0JT~DNu>Nj>d>-TUxA11$sNWS^9;Pmu6#6|(ej_lJPQRxG?{Vg8z?+(vh4(xE@RN_AuVEg* z?79z|6sBjxbB+2S>M<8sG66TEVoh+b8Qd|20(Zx9N`*mMuj{-^)N4YQ((A-~eckOh z9>VAW!cEXk4X%uEgG;_l0hUa_ZTh{W+tQh#YE8pg#-unQd0W-Ct=hI%`_{L9{9cr` zsXZ)pPq0MF!uL4qvn+#;vPj&y03d9U{?96TJKMU4HFG@f_ppNA%({CzU0f-4v2`Ka zUTje8J}=pvMOh|~gDBgoE#^_S#bY2{pzsS()-mUdY@54|XrCgXi01G3tuJ2pj{pAE zf0cXD{QDpI{$DMA?Mn~b%ih2!KltRL7UM5#b#OIGcCq4bp+N{T6}G_J_IYi2Xnirk z3B|oQ@D}kk{3yYTooqxpwOu5M{2|8mh|??%3EcIZX7yBcn#JQmZUL}-H9@{TIPSG4 z?PUiyQ2F(_qY&R=!z|F^~jCqK?T zd-K=s%RzPpe`s7jm&JQCxl^hOhEqkxI`1!^v+`KV3U4_^YcCDy%9RhN(=WuGC=pJv z0E17B?NW^hEvG#Zu-KeZ_wG}wvSs*5weMEP`6M9j&1#n;^JDJtYsA|oYJW~))A(9z z-@|Ka373yrxdMAfnc2G`-zgF>P!X6$Mi4oscvcbv^wK?7=pD#E=>uPIzl zdGUYq!2jKi_8wrzECt0^@6BI`=W>I=&lkV97`Zc??NJ7k*$*WwT5hn*-KyqfpP%%$ zFhW|c>qZCYOKJmM%TM{YD~KPOPBLg;JCf-z#%Q)F9${)czQ_YGBUT2gnOhTsO28&K5IaScDtGf{q{aKoY$=R0V%%X+}n*V=yZvtmmRpQp5aWXJ^UDuDz@YRFJkDFW6G5C~%=45DaqQgxE5)Nm>_B!os%0UTOUL230mb+Bng zMa6r)Ev>ZD-Kf~2;Qe4r+YYEG*wUKY4wu)UdEeiE?S1N0B|%&8z4v(qCu^_0rvLh{ z|N2jB*yy=zQsYvO$5acW!qU9E=R=#Wtm zqVcPM3YqZ>>fl;PRk4DszU<&Wdj&^R(H!m^|VrmvZSjm5CObI7q>S3Mv98 zw3BO&T-ZwleL%KTfjhPlHr|_j-l;OL*ik%#Hsqexe1bN({ii~cwCiXiu|G_ zMz;u30aT5c)R&$1u5b1hNxbMSyk;U&)QbulbG}k6QsB5}g`or~I}&c2eZeDMqnf=G z`H-51!QN?_iwy*h;H71_v2b~8Be9zyszI33C@2q8I4Q(|I>5;{)yD_KXL!!w0nsx+ zB2d-zuhgLa5!}?Gnl4mN946zZT@v8l4|8ksL}QKr>__?a@IngZjrB@eJeO8-E_LMj zo=R3H`n<+RA#8$g`cb{zdSa6zt+&~~m@}VN6Slp7A<~Sayson88quMta)Tk5D>HU* z6Rm?rKmrj^Q>$*;NFWjc&T3nCnxw6AsyHoA=~^o-;Ud2=uVW;_IE=*3Rv(d( zR0)~qV^Y7L<}~;2Pf~v?u_6y zNb-kzqFyQB;v~F)deiKfznN*BX|^krpo$+BGO$IQCLZNT9L<-6or*+zf$C>Bt>B*+jEK>NKzD5vfcb!BF`i# z3M<)eQOXqm2m*zbY_}`&#w0~yCENQHxiv{qSjqP8>XbVb(Hm90zdCZaB6_2gyQ(9f zRzz=usW=#5gIP~@>B zqOg+kv?7luDGDpuex=A$Ns7Wsw&xT%kfbQAWV;!Xj-N?V6jrj`qLeBA5jYAf*=|?l zjY*2aO1AeYa%+;Ju#)XgMc$pHD6C|=Tao=qio!~^Pb+d)lA^GZ?LI~BNm3M6vOS>4 zy-A9~O16g-xj#u!SjqONA`d1h3M<(jsZKevoOS#yk>fLYp$Tipt4xlYC`OKZ$Z@eo z@wyj*A)=8cT-WJz8C*9nltZFPnv*LE3y<+_8%_zKaKhb#phy3~{2nwl&t$2^Qx{E$ zwnpx-@ezrJr$C}qH9Rf|Y!iN5*%lbjHJw%!qrZOLm!}0^6s;n%P{>jPW42tB0q@M- ztmGmVix?y_@9=U_rbi+dgT^oWQu>kxX(Z@LrAB05S>~v41zsm0YyvzkO3**_L`t72 zPeRDofZC0}o43j*(KIVxB7&;1F|GJpJ7xlafj}AoHXAqusVNGAL^Y5%lB%0Cl8nyS z6bcY+4h6`F!>I;UC~!c7!K!|$V>T284MD1n(7StWOb#!{&_Bs5IcDEknxTv_jAo=` z)iJaYsNtxrf_iXoa?IMx7w*#~k`dUNpPV4}6sb2~GMa(hQMl=KGPgOi$o1C@E$94{ z!fu8{y#@rgwdz*?)fi+HWfnDM&`I?z-2e^Sma9-S(5F=+rZ~PrYbHo5NAbrXVP--Z zcH0Yq!L+#IwQ5#jVVz^sIr?+#6t;pWyj zlo54O6VV1AWfx%WY7NTUKw!U5`$U>KAj}}h!$uQikVggTSB-M*iK3brNR4blLoJdbyYw_mbiT01#%u&AZ&YaOO4((=|)btI+Cw(C?=s6;v#Jb>GEWvyTpA;<{dAVg( zzS-OoLtgU0oN*8zXamBOHOld8Q@+9)walWyb|9v#5g>jqYn0y;vZ}DgL`n(!I^=6o zK%_R!u?uET(^}-)jdaeKVcyQNYQn>L{+S^#`ike@M)<--`1MjO>oL(g4y`hXJ!WYl zY$OpP!7ekuIgtEMjI=7x2{ca@fUS5wSVub4^N~7ml6kZNuH)md>>7#`!M5!IeOE0kB<2l;=7ag3S*(K!9PrXIfn0bIT=Vj#kc;oVC7RNM-#y7xpN?X#(?1Xb3&c@biOtRu1-w}28G%r9o!5_W+b)} z8i~5xIFE*O)kvsIbJ7`0rBHY>tGR4}Olj@3&s`FO4nCMO+7!IPOYZQ{whd4@tq^gi zB-lZQP$niE+*z0_bn(#xkGMBDR;Y6ik+-vO6p!%&CGQ&K-xJp_B31H0o+`GMM6k$A z9N?VXRY~x7vdhFJu)bSZ!m}&EDyTmeYc0-5)coM8$()FV6O<3@;0Vd}Rmpat3VEIP zQJpb@r_1ye9WWE$z(T1ta!8(>)w84E!a)ncZ4wR^7U=#RI@s7OMcHRmnBdH?Lejr_ zmd2+acNq>ywjS;%{7=m_J$p@n)%d2sm`>xHE!3O82JrjTr*cGMtYn!KRH14IENU0OnSp1{LV`5}BGXvu82f!ZH2%_$f9#5T+QM?cy+iK>XUn;If|{0l z4G4yXF-%Uo5~N@^`^&xgtcoTK+>3woJt{Q@0hbjBrpyVrA1cMK0!~faz8fyujJ@*; zzX=2GFTKHaGTqYz22BjXoCQ}hdaCc=X4hxJgU&MR+y@10axr6V69VwtOhXN7s-cY@ z*gDLH{Wd|5uHVcsV+gY8)(B@*!ocTqs@-*v$t(MZK*j8~+4!dp3SBts`pc?-3fc9^ z)7if3&@!D3Q7sco^-x>4cO1ceWRm>`6_^B*mF;tBmv|U&^17?~RIYJhgrjh|7j=7G zdcpwh2v+fgXSt1_wliExknap50?8qnQ8F31EcWhyxnEOYo`-^>v6vtKs{@Va#R<_Q zckhK&nRR;}l3IQ&GWG9>Ca%B$~`r_etvN7Z|j`x9Dku4dkmBBVPFBM10 ztk=L_xjByiYFO|K?Do0pkIK|QAkdJ^S|QRrQ`}yZ(j%iI8aI^%BVU@kcI)stneVZj z09`=3(l|6lATbF8@Wq^!5v1GH1Vk|Xi5%0&Kwi})!x_`P1g^Uz*ScWJ71itL%pp7R zsu85?G7Lc}#^%_I89VWm^3$L7%`J zG80Kjx8iAs7i)!5>|WHZc+flOnz0q{d~sAq9L>|dVvOORG?g(p4qZ25NpKKUtps1Rpb>Kc@;k6dr*3i z>5;OPT)&FOYnLHIdEys1dhryo!A76xQR6s#0NuWU>JsQ2*G7u81r(U4RO1CE1e8#a zhe+0hdZ{UdI__XLjUOA*Q{1JbR)#WEQY1Cdw_pb#*m4vW@gG7NLiE zg$pVhI!$UG)^vFs5)q3<@wKO!rpr^jv)i@5orO)oNe-|MD*YhD4q;%eAB?Zyf%Tsn zF6|84NaP}V{%zaQ`0fC#f{cwe#`=bK7(eFiFeNf6vavJV!dtUr9@oZ>#&_DFp5&xV z1P9Sg-(d1x_I|PBC1N5#ouER74M2c;8$U*pTnv}nsVOxV7N;@LZeoVOC<@2~`dR`y z(#5RcGe3Jt>yk>6(L@0B9$aSxYcY^G*R8GX?&?V#fJCJ-TMsEd7zf%~r1CTtR?0hi zSleuqgU`Z$`+l$0gZG}{Nn_&5(x31Kg{!$nI+d(I&b_#Lh10gq@O&zDIOV#3keZ-0 zRAbMFRNTX13{n%6HnPx9SB_@n2n4ZReQ)qq_1CIj%l=!Y8~jzP!J7O4rUhjOm}u8k z?M9_u9d~v9L0E_?y^m)1TBCDFXHB|-oKwTD>1z!cf7obeh63wV*y!kT!>RR#e5Ef99V?8!&Xre*_fpwvdh2I0b=_ zPA4y!J@!#SF7yyTXB%V&|2Akt0*HXPks1+>CIO~0j#Hu}FvG;;Sf>c7(G7xLYe-b1 z+7K6Gxa8J`m>3#oE~Dg1&CyMjKv8jVaMPLM6&DBd&=f?Owp=XuM#(tc*NKaRDgO-7 zcqK2EqV6%R;z#+X@jqpE@SPhC_YO1V6LmUt!)^703im;4bzHbouco|43pa6 z(G%;a>Vo6buEQ##4sUV{7_-HhyJFrdL}{nc-TtpY*bqM>K+$?gj-S%=Z_^ia@MiMx ziAvFmz@Gzq2hxRM56(=l@I+9N!q$e=RGdEoPN#=xhb5T!R#UE7dx-C(Hb8KyCN@9- zMbfNP0n8i-od=FVXb7470@hb0lHu}cxN=UMNP1BeV8s5xhYd@Tg{lqCX8EDWVv8|* zZCWJ@e{%xQhZI7@DyEwGCWLkSf~&zWE#94b)M&+lLBmfxcE7cdv6T-4JHj4obhmag zb`EF?NppVW`Epy^@#*n?GT9eA(igX;FZQ^BghQC{6Ly&aLJYJkxk@v7!X=nIal57b zu6p^vcZKrglTo^%*g0gGM^L)cdO+<`O)RL=ed+?-1}1o4P|J_~@b|ZDOLdP zKb5)fR=ACz200xN++ws;xn+aCM>M)Yo2_|}58;qjXiX3b@}ygWY)l^pQmbwiEXoNt zoC`p4VH!%r=iCyN#W1UP&}`fTBZMJ}b?3+uE`kBV3H88xKK}-%al*1G2j*c_T9#pO z8ebP6TF7Ji7)z4&%z|K3*7Es$JIIMmI1C~~Ipgb{w6r&fFlL%y_`==`koC(Lp!6xI zJcafog%M2Ju(O#?LJ_V{2WM7d*`SmVJXZ{Nkng@zLcvTERa<~|v9|Et*3wi*FEbtR?S_GJ^ z(==)m?WM<7#qPVI~C&gVd1iE_R-0bcj zy#Q`@vU)Bho9zJ@Nw+?GznyhqfS&tL_t^MveDaF{Uo9jxzAq?zK5*+3@`+}q6+?3z zHACX&_Y2}k-|(xHV!IFCA~(uVNWdsbYffCK-=hBXix#@-vD$}zRW4JSlR9NYb!c;m$Ci88@YudMt%-~Ppvs*)E2@upp{GP%;s46`b%|c> z2q^6K5Hz;RG?kHqE)*H*LrzXUig@ZB@#GT|+`MRY;&O=|q5UIF1tv=qSm%t7<`fet zQOY&z;80T5HS3e<*DRG7>jZU8bPk(fA|-Q4x4`SAyanLdrmGx;kTP$q5xXl}yUxwY zXFN*Qzve0}WG9-069)qP_V5s(n^r*p=bVN>Q;=!P0sRaL1SD!`f|(rcR{0_x?br?c z#yXDog);zNlkd0`$!4bj0-Py;g>nlZ;z|eUtvm4(wq=bT8=>&YGGA;P?%|v*puLew zoU3`dQdhQ8DN7($DPIK?OG_%PNh)O(*yrnjRGM%AwyV!)o4K5S6m-jo36epcFf5s2 zsFiBYdSf=(E8}_-<;*tKplLXJS+;=eU+Poke08`QWG4hG5{fNHY7=XqLQ z=4M3rA1Vr4Icf!}zNO8#di1eE-nMOMsMYtgv+>*ZUeHjdGZWc(%g%WJ-t$O+->`1E z_mT$fnxI$t_(WH%UK&Q81+{ntg~h6^Q(lw<%d0m;dnlRq5!WPLzm$_3Ngv645l2wT z83%ljl5+yn2^YAtbm}ZJK39O7Xk40&pr`iTc=NS8In>I!mraJs3$8AJM4CCa$#Hi! z=2xI#mJ4;jP(dB964VK51UW#cfHTE4Dzs-1W6!x!F^HK^Nk+qt0jPWXwN3#eGm|>z z5(aauXpU)J*n?o9Y}?rq@c~IM>5x<_vvZSywQmp$?ZnjyRY^G%7*%A}4F#yE@P;tp zP`8$>SWeQ~HRniz9tl}3ClO?&nKR9rVG{G9Vz-bajuG3E(D$)QquNDr5JSz}t5eZR zpl{`()A%=Lzl}fQ)@)`Zz{{L=G{CDiH@Ps!>N7d~k9DH|2E`UESNa8m_P0x9BybfxiG_>a9z zy5L?&&BMcC3K?9H990WbJf{m&I>q7^p>W1%5enkAMX17X#m!)Hwpxrj{mqj+ma{|z zz!Umg^0eO^16mW+kPf_OJu?!} zYNzuL@DjJAs40y{?z0@GCi1%K-T*#O;@X;K{A%!MpmOv&SPnW zGw!gCL5CSAiZ7hf8`!*Vyv?N*pfIRWNn`W4ek0&xT&bWCi$W!ne8|(d5h5bkMqNZH zb>3vEB<+0s>n1f~1f_=GIpT!@o#WH~4lCh8rPiVoz zEW6o?O*KzH-|*Vz{JJN+speY#cbcmqlY$7Zy6r^i3N`Oi})(6ENrdk|` zgP_a4$#-NB&Bg@IP#@zPITDBv7flSY)`Jzp5Tf2wV&>3jdV7NCZD04aCdobw%?7Xl z@Z2p2O*&}E0#HME%Tm;hV0X-{OvS7f=D4-&vd+w;7DG$GjOF`sI z=3{%YbeCP!B;L)*Vmy6OUBY8LTQ24W8j6~yN%=4B6b_48@LM@9Yb}HC9G4NdXQ+?n zw8XBkFHNHvR2-H(B@RoT5{D&EiNlhdFgr7~7?zx=+qJY5V%khs0+SH~ARFcrpG&fA zHOK-u794<)MvTMf;PY@#@d6}S!bCk-v-}SbqgF|0zG?{ZxoH&#uRBy4&8U2c9JN3SVhcL%0dvXW)vLyhDav= z!b;I6*^y} z8{Q6w(RQdd#=*$8+oVSzAa_jM)!KRd_N_ z2~XxJ;mJHDJXyr2%@c5}$|4f0G~Ucgnv@NmY+e%#7vsqQ#C}k~$xB+u9Jzic8)lM* zrJBdSz=noX5bUM(#a=pS5K0nrw7`8Q09zT4~JME;QN*hW{G1CO`X&Ae+GC6okCI?T+0E*oI3ydBYYy=w3!G#Z12o;T=EH;*^A(fIp>77QecB| zG!YA2hH0{)!m|w(Dmto_PZ2!Z7AT{BV>j$Dx0zV~cdDKr<=O4GF_)W}x7qjs-X@Rx zf1<@>JZlm~xN0r;MPM=;v!zmdIQ1w`=N5aCAMO?QRL|2!dy?^fzSbw$E}rh`0BqaS zVPKEpoROumzJbqr8{N=3rot3d#?cY+z^O)i#OhXLie1r#CebrAvQ$ODu|DQ&y|7y~ zTrZNxr>nX=8x=pLV?v8i@o&lVum0d(_gfFuYuEp!Jh}d##FOj4b}OBac28C)EUMu~ zGhmjBli8@Ih418X_Tb2`tSnD3HU6-1aIFg>*Sa7&Uz8&I_ueNl$)AQZ7=cLR&NRLO zrNX9Zd^)k8C5adZ$WTk9`8I4wbEYPrz9!AMZsHP} zc|oHxXU3>JJlz{7E7ia(LYG_77?j8-IJeuYWpdCXrl`8p_?)AsEKXYJ2{DY4gqYW= zw6!NjHCYR+1QfHJQC5 z=QlXXj=$7vF2v1poMxIEP#l`)pgOpP3#aWk-5&^cG|i3C6eC;_GQ)u}*PKUwrF;L- z#ob;zb;x#}^ zYFV}6w6tJidRX7+>698nUOH)kqh4B7t`Ogd^x*E)wnNwRfj^w{(i+Cr{(_9}hiRlb z%zAK0WaIhjo4~0P? z{<%W*olph|1`$GBLu~^*LruXW;7zM3wzy!ME~j;f^BN2n)j9+M-4%mH2ZIr#nRw;3 z{f)KbuqUc*Ldk0iumub)-|?F20!A|ZFLJ6R8ZA!;5B{UB^TtcXW#b;uYm>}xDG>$Q zY^eXZ-k-r%mTWG|h6uVGkm*@6$!WzxM*M3%^FG6~niD!SNZ2Y`H)D4b5js<_T_p@) zD%yFR7VSh#v?I;kCVKoDy1}QGW3=o6(=PmAVwZM;@l90rW??p}Zgg{uL$2}x+fB$> z?f5YIMm^J}KoEsPJ*Sl!J~7Tx4ud2V`Wl@0(I3ESBm^0uY6GxZpQPq=pri;hZpjc( zMP&%Ieq+sPrm20?$JGeiuG2<-7TCeXxWH{UaZ^*sFL3iL=!tb4!r#Rlgv5i1c>k|h zGY}UjaQ9A>IZr~1)j^zmT3$n?HGSL0=AgTSM{^Uxqea#M)jyW#th3as6jPqH^x?;m zX{j_rTa|{6*~QE!P4|3!D+_cdN`Lg@rg#ci8lRMM5XN_=aFLx>eW${s4 z_cD}?Z>_+@;LyS5Kt^%|_W}hv*Zm{kqbe_sP#yzpD5wcW>`9g6L9}KwQ;)Vv%dwX) z*AK>zeD?GWq<{58JZCqI*>&L`_*G#r{$WAyfAB3H|8jnkz)qSE9H?8*`wzaK_j8ih z?8JHeYjvVE(N6q{f4|?0m&LFDIl%*d{7=6i{D-jdJscm0cD?wsKd&2%bxW!P>;Z2u zK5)~-1~cj6Tc0BL()e)&f60vfH^NT_N#R0)&I_el;s2V>YSx{KlwW%!?bj9P44k>Zj49K0az{L?Osx6r3$FWMika&dv`@ROdVHDyvCc+0mo^?+O+6#2x|+)+F%yK zkp4sR9Lm~4u{OIhHEasS+O#uP_JPSRh}8**ho;&zS?$AW6Qo;MWW=eNF~BTsaLoq!)lEU zb8}X6hJjD^@`sxC+PyEsBct{1=6td{u9n?#kXtqKKu7+N-EY`!wiEYO)D51p8x~0z z-;X?)g6HUH7d!irk+U+PF(B9Tv9`h?(~xLYTj6joPgkd$EGN1DC^2Ib9G}TeHo;v; z4Lz5Pu}O{DT{FE6j(urjgEh7d4miX~a8YnPaJq?Vh+(AUV29ZAx5!oNcHB(%%P;to)Eu3?Y{#WVN9}g2i@1K&4VF;d#gy zIe>k`vEFGQLf+LYFXM_zEm>olsF4N-MIF(6H}G>}2&}#ZJrxy%g-S_Ii1&BgF_z!e zq{7nY8bZhi^r1gsHKEsmC03Xa0iZCwO{>6elSnK1(#qMBA~9suGu{#^_-pA1fFW^x zDugMB`NQ6sG1McvCnahSw~kRaWE+cC4m^pBG3!+4K`i!DNt{Ys&If8L64skLC?M}; zA~S4(%#>*l-=y0Fn$aduwoS-K5Ng>ARU4fGDL}_jHRTu%b`;<$pcmJiHuVKsFdS!l z2C8hLEhGkVJOvMSHZoau7H;#W_qy8-4Z7D9&?k?6(;&2qZSRzq*_VL8;}CdkFtJNO zq}#YlKo}K?ve;b$5)iA}HD1}#Zk3ZUh8n6b0V#YT2(p#Ck}?>bOH3Mg+HP>Uaahe4 zz{_Z_BQphJ9|Ts*Fx8w>KCQ~b7{P4pmgZ-!97D2bJzASQ(t0$*jh`B>?)FhcIoqAj zC~Ix~N1nDQ2h;)03kuH4@}62NEow`^(BW6QgB~)vW$x-4;B+%KS%@bDV7StRwm55P z8|u@ZW$>0D0JiO}QOUS%Hwz$8DP0fgW)sMwV&L1%B88dt3%~GSz|fn#v@vJL;1sQa za7_i94wRgafN%#MP(pOzA^7;ZgZ@o6H%(4dNClQSlT_$r<@7;HDw?AjFKKD+e5odG zgGwgHiL9$QF40VAt<~xsNRBzurkX&1g+@f zZY=KASY)ckg5iz*CT0(K&>o+9o@~@UJv(RhxlXwv7SLlXb{+53Euh-o`7}nhOn0~x z_IHyn5|i>2TKhFy{CA zq?k&?nmKSVI%26Fx)MN$YS9dJo=TUy>wq;WAxMg{&^DtF=YYGRMFDC%YLOyTZ7{@qhu7h5$B^tOiy$qgzHLt_o)ZuV4ii zz~V7*sz*Uqh6>c1XgdNTut}MiB^WdqD%cc-{~9s>L)DU9fUE;VvMwG9VPpA*F>64U<(1gSMeD4q`4Most0o)wz*v z!ZRaa!jdrqDrr*g%)22m9ax7ub&nMahxmR!dqYG+>|Hx}aPCdQdit2XL0}S(-q@VG zffR73=ll)VH}mrK*Ee$?9jH~uF8{d1?+qX)bNRYutWfyzbvX}J z_kOSN>xSaQL}_?*BAO^i#lF61_rOGdRNhq@+cs3*-CGKbbxTwpiHal9mUG9(wnV#%LzAVm%L5~QrIGS*akxA=GU0i(p8N9&>i8A-)$^-< z-#~m0zq$Mx`Jpd+NAY_JzoYq8=RJn_?&A1x@8tMId3bAaWN;n7mrs_)_5kJPt;M0@ zNN;JJK8%&d$CGG0G_=ko(1p?R$av{0s<1-6<&lZ8V(-M}fst+HN<_uSin|9(d&Y;0 zV-v&U+qVvtdk4umGEU}!@<^JszcjGDe_~=_xYXNU92nU=&^KNJ17q7JNBYKr^kU##_fH`dY`wdRt4^j+VzJ##_b& z<71RB)U5cQ&5D0zR{S?fTqANZD4QGu(<6No<;}@(2=_z6$N=$wJ^(V^m=Xkd7Bs5DIGqG%%;D^1XM zrVNwAnvW(&z<8;5qSQCEX9hhlqMp_8cx+F1cQs8P2?8-Gvf4PFHM16tC|$dlF^ASS*nEBwI=^*b z1Y~!2ud{G=e>Y51C*7LW+YKWSq{Gu;K|Ob5*Q^qoCi}{V)^i!8J~m!T>zY;OTsIRA zEq1Y+OGiStm}htQp}cXrdM4gPsk?iV0%%EmSaU$X#r%%vcLKlRf$?$iB*uLRF|lQB zO{4Mh3kk*dCr1WH%DYD@>C2*YGDO}rN!~$1&9N=ZqKW>}SSc#<8!5XoFsU@(8_6dg z*EcyjG|&rNX|24whcwBK+3oHs!Z$}IqAjF7n&ffq#ZzxZ`u*)uRnl)5@*jYS%oKqG zBQS=6zG!Q4ywtHu3>QyGqe-jQ$?>sPCSq}@wYNC7z1%uh+CIR9++#D-_Tc-nZ& zKzVt`wsxlWimh9V?W^0`+PAfi_ZL?zZ)<69YguUpddp+*!_fgIbK2+?10xe1tD+@K zqUALF&ZONB5o#o=bG5JNik9&1KGKAVG|yV%uOxmJzYc!YadEfpKdIgEx=(EX+}JNi z)^`8;(!bt&*_@Z((w}|r$NuG}6Bm5#@mEa_4Z$(C4QzM9Zw&SeBKnX$ObW3)BM}Lf zl(7IlJ)USmgi`N14B&-4mLSgJLiD78|Z-wwjt{5p!PV|?@2CicSF06C2 zS{y-tNM(}_TM_Wv26_iztX@BPq^*n+N;^#B&`)t_v(uw)PtwLpy#u2I3^n=g;+<$| zBeSrEaGDJsX&6U~Bd`n!O=jcfAtq~Sv!f~z(fF_v9Gi#A($NVezR(Mbzi zp#^DmOS!05urDSQ_nJqjK4g>l&wx=H>rV(pcV8!z2B8an6;H+C_L3CP3A!gf-&Y!) z=-*u)8!U?zraEnkmv>QC8uJ?n1;bPlzBQ@y9faZwvnBB%LS($(=EyI}FZ@*rD?kz6 zOJlsYzbgKCh;`6H4)tAaau&vGnG?Uaxo>W7q zNNUu8X&u4yrjq=(5sKET``StT1g5Nquu?bkqEBRJ2?b{7Z*fS50yr?PxO0UTJ|c+$@-O?+KvI3TGodtJ-Kb0EJWJa zkmwv&T)w`Gviivy*0`_X_b2Ex?7P%DT<)`ee|m1C_Zr%f%#Qe_@!dSjvd|yyuLt&{ zL4BhsASO;2@eBFMdGQDSokhNvty0byXQIq z@9=PXD^tfA97{d#UGp5Lmju6yXU(cq>q`~VPxD^9?23``$x+$%Sf6HAMKX)JqlZYB zU$ zvd@K&>bPLI{Gv0?xvV?7QqHRA5H%FAqfJiUcXyAY-QXP1yWukWYA-79c(kWH$)KDoceJ#;NWf*}JhdtfVc_rLKL`~0iUb69M+gN$nGMM%{Zo2U9($EkC zkd9u_bSs*cU!f)1L>QH~Mdisc+JQBr>$-<+Mcf>MNdwV0ApRj`ShmsD63Qt2sYnAO z%S+dydy*8Pl;fIk?g`n`4yu;uGWoK|x_epLO;w4uzek=vlo2ZIFYX!;41iMIqn7CM zax^+t#z`|_g{_AZW97-ML!}7TD6TiMEJAq%FQbt(Np)&$41K*kW|a@ftA@)31+TZ% z6kSz{`TsaV5yHv@9Afni@JGvjAIxmddi($|I!+?@yGp zVoFuZ)6hvCrga3G!l5(mAA9a-=N~IWKhnGgMn)lviE=p_(l`rzIk+~PiAYapM4W+9 z>SNMuJjTt3Bb8?e%ch~i{H>1a7ghD#PCbi&!}9b`4x`p0k<4zfcJ58uNjxE!m&-9GpHg4=5<=<-ASG2$|q_ZC|ZHnj9J!)FoYf|;~ZfuuRb#Hz_v z&5D0DiC>2O0-cZI!xp)MnGp6pB6K!o}edursqNe8fDO zn6Pa&<=au$@1?vn#I*eQz;>+oNhS=W%rHJfx@1L~-p>FhN#6YVjb@!EATeA9lsRjw zwX(I-q$8ZU#%miw@5j*fr1xFWM7bR~jpK zNB8hvy#7*(XuU%6=|SE};{rhF3A?`HIhQ<)l*RiFc_g2HNhtlr<&`KCzlI3PCOo73 z0*8+@pK+jj+3-6rUO4iJ2@8o%wF^E++4%38jCfW!9Oas#2x*5b5gcd05_K z1HBcjKFxd4QZh)<=;T&OhYHd&3mxq{YZAk`YDi8ZO>j;RRyqRXNQmB2H9ee3J~wXb z_Pml&t4@37f%kchQTaPD98C7ZLYq4k<16YcS?qMemlBHJs>gI1o)K1UOd4Y4nwmEq zbsFMGd9zea*oIRnr{jI4#2B2M)@0LKXzy~`6}|QnYR-=*;Z20H4Btj5ugE(IcLRYGyCU7MKEV9R)Y>JWNfzMK2>pU~&3-QIrJMYW7;slzqRq3tboxDCtWsWQy zW3z0+%b;K(pZLs^)U9#6iSeA`_ga3}@!QRBg5Ry=)87S~F1;jz`68fEe};=uahv3l z^su2K3aO2gIm`gT+r6u15XnFd+68?uR+loWudXRb-ZISHW@_enR_mw)9 zEL+0rxD{OT+9g%xgxKBFc#W2xb9P(X52xO7&ieK1PyMe}4_HfHJ+pRc%rmO*a@DW< z{ne|sZq;__dW|+}dnyWNqV6!s$%r1Nje#dz6{(r!;aa*R!HwYJ* zxh#~HkRMLgx&Es1k56v3%>^?HT>>Eei2Hcc*&8;@?zZRcY;sy*TK9jWPWfB@lvqf8 zK6lafR@yp=pM2|S{IxtwqNMSCJTK$7&UvetaNA5%Ufb-X!=DUR#xiwKT~1rQ!0=su zg7wAmcNY7KqvDILCHRdbt2qH5q^(!cMw_)2-~S~j>%u4_Dtn_DRrT=bLdIp=V8lD{S>h>FEr8mw>KXz97f?4Ue z(w;ojX@4{etMQ?@d{$}t`)8#qj_auw%FXmbOPUBbd zd`wmRYM$Gx;+o;ohAJ*EQ@JpNWTN96m>d}^6_NJxGNpdYyH9EKPNU2QoH*=EAgSAV zCdwl?lW<^_Fow|!x{xvQsE*%0EB;R6>#OoB-cuFVs#A6Och8Co-%6hzd;FKfMQy_v z`_58lul@;eFVZt6{0wcplJ@p$g}7mRbNMu7--_&#HllVIi}c;?-|~TMuh6Q zZJWH%OsZSRr+K!YQ1yI-5SHbgn=0I;Yb$!VQFt-xSiW^Y-rJ=2E#3o^IlT%7(S1bx z8Qu$Lv+KT)ce3#^{4U~mF~90}mk{3~GXY=lxu-e1YgvSi#&ba0IfQ~S4NW87G94c! zU3P7n{sPCv>3Quf_y<>Xr23tse++%hJFsC}0B)sSjnSiYPIGZ1KlM?+m-D-f-zI+A zD*%hxa_Ok->)HEWqb(?MrDQ9H^8rT5<^uUhz)8Yb+-4Q(yYO_k8(<5e@SX1COE+a& zX{cz5bot+|0C^hg#Jr*_1KakP`DfjT`pe}(w~|nF9ZTHbaKyg5sAJV(+OU$!M>|iD zN4_J?VYQRS&tmXSsEVIST(VYtPd2vjbOk@*Ev1hudA^FDc(u}B!B4!rI*)KJElTh7 zC)&7%->dnh_7hm|h8U5JG zJCirgbuc4MvTi*KL-JY4XD~+mzd(b|K#q2oC)tIEH7e(*El$V_U=f+qNiMBku(uh1 zG=gv&Gehow^Q4*2vnrSElR12@R5tbvY^R1NpJ(r~amM|ord^Gw~nIV2@JzKh?%JZqM4p!w&=fW`0;`e2Kk^cUy zZdu(jg6Or;YnRq7T~_xht2?FfQS!YyC7{Z73+Sg6v_nI$r47+oiJy3W+qG?M6>MA4 zwz6$i+v>KCw$8S$wl(c-?d|O=+E=!(YG2*n(canK)xKs$+luxTD^{#rv1-NY6&))& zS9Gmdv$Abv`^pt7SFT*Oa`noNm7OcQR<2pqwyJ&Aid8FDty;BuRmZB%Rb8vrtZrM~ zzIw&#m8(~+UcI_wb?54?)oVK1I@&u{bgb-H)v>yxqocELJ#oq7L&}aL z7})es8t&~M1NXn8d_=x}e$v0$@z4H3=RtB*m(r(8!CM$v6(U)uBSt5+J6h}@Y_8P7 zPWXgw`*|-4P19X@SNrs0kr6wEY~{#%BV`2t2M8rQ{QsB#y!dxdU<9uWp7$@D^_S5f z-x>cgMV~z8RV^(ouQnwl!7LMc#^e`Hw|L&)uWkWTl5!b3ro*npGa|7>t=f!hsVQ3OY=lz{ zq7NAWju1+pN$Wn8)+Q?6i}#UNb6j?-Y^X!>CSK9jQPzYeWZpoW~E z(yz7FB$<}R7xLV}&-247Pbc~{0|2o2|k+nSpGkQXS2Tzeit6B{rI(e-u#viwq5m# zH{WvW;_uFxd*MaTKG)LvvTI(w`G+^Z<*m29{Ue|H?B~AtrLX+c_n!FiK`%4!s8icl zb#|X|=7tMiee+vM{Pbr(_oaXO`omBBnD1cBvDEG}&RxIZg4gtwZocik@BhlzA8wd; zDz7$N^{Q)Lv$?PImfJo;kuQGb`%nD%K*PLqH}sXJZvOB0ef|sI{MLd0ebejSeCLNg z|AjAp`QdN>>-q2gyRUue>kn_Z~XKU<~RT6 zcL%42cYg2tb50y7FFtw?QJLiuSdUr@RCbk`KnxgZsU^HpZ{W{ z+>Q!{Vh-E*csmOZg{-=c6q z-p{mVR%LRbpR38utJ^sDsN5B~FtfO>Hq3{)FkoiXXR=|T#-DRc_LAJ9+*P@t=D7Ne znX|*?p`V#oGq=7wbNtDhqv6bslcyfc-gr;Au;#|!hF9l~t({+cbp6rwJ8J4`7S>#y zJ3YI;ZW$Mv`(b-wS!Q8PA)LCKq}KL}!>K#-Ys0zW+FV!u^z4lX=grTz&RZTf&25@H zbxY>PcP%I!^Tyk=t=Thj!JPTEQ=f01sGs`hh4tB~gW0L?*Z;@+!_L}$*Bm`{Z+_~l z*}C~>gmpDt`Stnwnu)>*;VUy&*G}Cue{tQhwHIZk-c<9kJL`|jwBM20_w7@1_1Wyy zhZ^_&I_F2H)sXs@%+%+@Md92Ak2`zlT#(J>f_%OiMgT>7>TeBdwt?9K0Z=Li4$XJ7xRnp|zinP*-3%SXPEIeLCa=apCO{pcq? z`FE=yKk5yC{?-pvh*7k7$)$azYyRdlix%hdb%mpk>sZr$*GC@vm)g!-Z@Vj3cg9)U z2Hy7edF9Pt`1vnhx%F4i9o%&Jd*0j9x@74U@85sNU)}lPyFUKe`yQw%)E{$v_sh#RMtE*bGS`x?+jq)k7oMI!?bwB&`l@ z=8SAz&C6^2Y-5<6dh^y3&d=9PedsmK=N9T}8eY;}Q`fO9bKKP5uI<}Ye|~M<`g0eZ zpWoE5Ay+r`oAq_ahv#kR4CmzQYS!fH_H``Coe?g+(x1Dc;imU)n=DK{@TQA;8*XlE zJoarLz45#|{`ST-xzjS&)SObczHVvuB{$yls?vp-HMw~`B8hiBlfU_&PpkdlllxZA z^^dQalgaP9<J9tO3tzWx?lCuS zJh7%`>YJx$&ua2Vmxl{8!M>go=XGcOeUF@W<4>mkz>>N3Gi^Uk^G%&C7^TjOW0 z$SztH?3=SJ(^r3G-P9+#j&E3&sbxmgOugr($1?N6hH!Uga}D!rZhfYU&MnP1U$XD= z`s0D6BR_|%wYjOUo?Lfx%@KKc!pk>nAs;rbtz5DltM!`+Shwl?73JTppH7Z$o+z8G zuo>-QrcN|TnOoL0nxAna&r7S~va2L3rP$t-K~K(Z@m~Fs{oYZ>MJLurTTcANvi+x@ z))p-*f9UaL!ChOHpYZIK7Vmda#|I8>>G-YxgATv0sq>_UA9Q|fPH|1^{5#gPEiRt_ z%M}IR{uz|5r{q$qr`9kF3(5rrt5qP;XrTDwU=8r4tsL*4?`PPA>ic>B<$jQ> z&u{gE+Cpwau!#D6zjKaHi`jyIQmwx&ACV_Dmb`tiO~`enoWB54%XDVA!1x zf_I00gP&7_Veq9M&;Q3JFMNx?CGu(p0*}uOM#07aEdbaT1X=%G!NQ{&{8RD^3N2w9 zeG7sm{@GwY;2?J1Z}nGFE0;^q@6&?3|8t?uN4aWjl$qoI(Ep397t+hj(lF!yHT8SJ z#&CV1J@aRN$J|rtXI(zV)9SbPba$OA#fODu#P5B<9yDFR2lV3B}L*RM-%Q7$Lz1I>PhceAp<9t5I zoshXb^g1&u^8OtE*sMR7TIX4f**eR_Zn=;nBO9P Mzs3%IczNUh4Rp$Av;Y7A literal 0 HcmV?d00001 diff --git a/tests/upgrade/upgrade_test.go b/tests/upgrade/upgrade_test.go index 8207f924fb..89f0252fcc 100644 --- a/tests/upgrade/upgrade_test.go +++ b/tests/upgrade/upgrade_test.go @@ -33,9 +33,9 @@ import ( // init sdk config _ "pkg.akt.dev/go/sdkutil" - "pkg.akt.dev/node/pubsub" - uttypes "pkg.akt.dev/node/tests/upgrade/types" - "pkg.akt.dev/node/util/cli" + "pkg.akt.dev/node/v2/pubsub" + uttypes "pkg.akt.dev/node/v2/tests/upgrade/types" + "pkg.akt.dev/node/v2/util/cli" ) const ( diff --git a/tests/upgrade/workers_test.go b/tests/upgrade/workers_test.go index e9e93e4ea0..5769658e6b 100644 --- a/tests/upgrade/workers_test.go +++ b/tests/upgrade/workers_test.go @@ -4,13 +4,34 @@ package upgrade import ( "context" + "fmt" + "os" "testing" - uttypes "pkg.akt.dev/node/tests/upgrade/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/stretchr/testify/require" + + "github.com/CosmWasm/wasmd/x/wasm/ioutils" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdkclient "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + client "pkg.akt.dev/go/node/client/discovery" + cltypes "pkg.akt.dev/go/node/client/types" + clt "pkg.akt.dev/go/node/client/v1beta3" + + cflags "pkg.akt.dev/go/cli/flags" + arpcclient "pkg.akt.dev/go/node/client" + "pkg.akt.dev/go/sdkutil" + + akash "pkg.akt.dev/node/v2/app" + uttypes "pkg.akt.dev/node/v2/tests/upgrade/types" ) func init() { - uttypes.RegisterPostUpgradeWorker("v1.1.0", &postUpgrade{}) + uttypes.RegisterPostUpgradeWorker("v2.0.0", &postUpgrade{}) } type postUpgrade struct{} @@ -18,5 +39,107 @@ type postUpgrade struct{} var _ uttypes.TestWorker = (*postUpgrade)(nil) func (pu *postUpgrade) Run(ctx context.Context, t *testing.T, params uttypes.TestParams) { + encCfg := sdkutil.MakeEncodingConfig() + akash.ModuleBasics().RegisterInterfaces(encCfg.InterfaceRegistry) + rpcClient, err := arpcclient.NewClient(ctx, params.Node) + require.NoError(t, err) + + cctx := sdkclient.Context{}. + WithCodec(encCfg.Codec). + WithInterfaceRegistry(encCfg.InterfaceRegistry). + WithTxConfig(encCfg.TxConfig). + WithLegacyAmino(encCfg.Amino). + WithAccountRetriever(authtypes.AccountRetriever{}). + WithBroadcastMode(cflags.BroadcastBlock). + WithHomeDir(params.Home). + WithChainID(params.ChainID). + WithNodeURI(params.Node). + WithClient(rpcClient). + WithSkipConfirmation(true). + WithFrom(params.From). + WithKeyringDir(params.Home). + WithSignModeStr("direct") + + kr, err := sdkclient.NewKeyringFromBackend(cctx, params.KeyringBackend) + require.NoError(t, err) + + cctx = cctx.WithKeyring(kr) + + info, err := kr.Key(params.From) + require.NoError(t, err) + + mainAddr, err := info.GetAddress() + require.NoError(t, err) + + mainCctx := cctx.WithFromName(info.Name). + WithFromAddress(mainAddr) + + opts := []cltypes.ClientOption{ + cltypes.WithGasPrices("0.025uakt"), + cltypes.WithGas(cltypes.GasSetting{Simulate: false, Gas: 1000000}), + cltypes.WithGasAdjustment(2), + } + + mcl, err := client.DiscoverClient(ctx, mainCctx, opts...) + require.NoError(t, err) + require.NotNil(t, mcl) + + // should not be able to deploy smart contract directly + wasm, err := os.ReadFile(fmt.Sprintf("%s/tests/upgrade/testdata/hackatom.wasm", params.SourceDir)) + require.NoError(t, err) + + // gzip the wasm file + if ioutils.IsWasm(wasm) { + wasm, err = ioutils.GzipIt(wasm) + require.NoError(t, err) + } else { + require.True(t, ioutils.IsGzip(wasm)) + } + + msg := &wasmtypes.MsgStoreCode{ + Sender: mainAddr.String(), + WASMByteCode: wasm, + InstantiatePermission: &wasmtypes.AllowNobody, + } + + err = msg.ValidateBasic() + require.NoError(t, err) + + resp, err := mcl.Tx().BroadcastMsgs(ctx, []sdk.Msg{msg}) + require.Error(t, err) + require.NotNil(t, resp) + require.IsType(t, &sdk.TxResponse{}, resp) + require.ErrorIs(t, err, sdkerrors.ErrUnauthorized) + + govMsg, err := govv1.NewMsgSubmitProposal([]sdk.Msg{msg}, sdk.Coins{sdk.NewInt64Coin("uakt", 1000000000)}, mainCctx.GetFromAddress().String(), "", "test wasm store", "test wasm store", false) + require.NoError(t, err) + + // sending contract via gov with sender not as the gov module account should fail as well + resp, err = mcl.Tx().BroadcastMsgs(ctx, []sdk.Msg{govMsg}) + require.Error(t, err) + require.NotNil(t, resp) + require.IsType(t, &sdk.TxResponse{}, resp) + + qResp, err := mcl.Query().Auth().ModuleAccountByName(ctx, &authtypes.QueryModuleAccountByNameRequest{Name: "gov"}) + require.NoError(t, err) + require.NotNil(t, qResp) + + var acc sdk.AccountI + err = encCfg.InterfaceRegistry.UnpackAny(qResp.Account, &acc) + require.NoError(t, err) + macc, ok := acc.(sdk.ModuleAccountI) + require.True(t, ok) + + err = encCfg.InterfaceRegistry.UnpackAny(qResp.Account, &macc) + require.NoError(t, err) + msg.Sender = macc.GetAddress().String() + + govMsg, err = govv1.NewMsgSubmitProposal([]sdk.Msg{msg}, sdk.Coins{sdk.NewInt64Coin("uakt", 1000000000)}, mainCctx.GetFromAddress().String(), "", "test wasm store", "test wasm store", false) + require.NoError(t, err) + // sending contract via gov with sender as the gov module account shall pass + resp, err = mcl.Tx().BroadcastMsgs(ctx, []sdk.Msg{govMsg}, clt.WithGas(cltypes.GasSetting{Simulate: true})) + require.NoError(t, err) + require.NotNil(t, resp) + require.IsType(t, &sdk.TxResponse{}, resp) } diff --git a/testutil/network/network.go b/testutil/network/network.go index 3c40c510a2..5cd1f9069c 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -49,7 +49,7 @@ import ( cflags "pkg.akt.dev/go/cli/flags" "pkg.akt.dev/go/sdkutil" - "pkg.akt.dev/node/app" + "pkg.akt.dev/node/v2/app" ) const ( diff --git a/testutil/network_suite.go b/testutil/network_suite.go index a4052329be..105de40403 100644 --- a/testutil/network_suite.go +++ b/testutil/network_suite.go @@ -26,7 +26,7 @@ import ( cclient "pkg.akt.dev/go/node/client/v1beta3" sdktestutil "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/testutil/network" + "pkg.akt.dev/node/v2/testutil/network" ) type NetworkTestSuite struct { diff --git a/testutil/sims/simulation_helpers.go b/testutil/sims/simulation_helpers.go index 6876fde201..b9614ffaee 100644 --- a/testutil/sims/simulation_helpers.go +++ b/testutil/sims/simulation_helpers.go @@ -21,7 +21,7 @@ import ( ) // SetupSimulation creates the config, db (levelDB), temporary directory and logger for the simulation tests. -// If `skip` is false it skips the current test. `skip` should be set using the `FlagEnabledValue` flag. +// If `skip` is false, it skips the current test. `skip` should be set using the `FlagEnabledValue` flag. // Returns error on an invalid db instantiation or temp dir creation. func SetupSimulation(config simtypes.Config, dirPrefix, dbName string, verbose, skip bool) (dbm.DB, string, log.Logger, bool, error) { if !skip { @@ -56,7 +56,7 @@ func SimulationOperations(app runtime.AppI, cdc codec.JSONCodec, config simtypes } // BuildSimulationOperations retrieves the simulation params from the provided file path -// and returns all the modules weighted operations +// and returns all the module-weighted operations func BuildSimulationOperations(app runtime.AppI, cdc codec.JSONCodec, config simtypes.Config, txConfig client.TxConfig) []simtypes.WeightedOperation { simState := module.SimulationState{ AppParams: make(simtypes.AppParams), @@ -196,8 +196,8 @@ func getDiffFromKVPair(kvAs, kvBs []kv.Pair) (diffA, diffB []kv.Pair) { } index := make(map[string][]byte, len(kvBs)) - for _, kv := range kvBs { - index[string(kv.Key)] = kv.Value + for _, pair := range kvBs { + index[string(pair.Key)] = pair.Value } for _, kvA := range kvAs { diff --git a/testutil/state/suite.go b/testutil/state/suite.go index cf063291eb..2c23ee0d10 100644 --- a/testutil/state/suite.go +++ b/testutil/state/suite.go @@ -26,15 +26,15 @@ import ( ptypes "pkg.akt.dev/go/node/provider/v1beta4" ttypes "pkg.akt.dev/go/node/take/v1" - "pkg.akt.dev/node/app" - emocks "pkg.akt.dev/node/testutil/cosmos/mocks" - akeeper "pkg.akt.dev/node/x/audit/keeper" - dkeeper "pkg.akt.dev/node/x/deployment/keeper" - ekeeper "pkg.akt.dev/node/x/escrow/keeper" - mhooks "pkg.akt.dev/node/x/market/hooks" - mkeeper "pkg.akt.dev/node/x/market/keeper" - pkeeper "pkg.akt.dev/node/x/provider/keeper" - tkeeper "pkg.akt.dev/node/x/take/keeper" + "pkg.akt.dev/node/v2/app" + emocks "pkg.akt.dev/node/v2/testutil/cosmos/mocks" + akeeper "pkg.akt.dev/node/v2/x/audit/keeper" + dkeeper "pkg.akt.dev/node/v2/x/deployment/keeper" + ekeeper "pkg.akt.dev/node/v2/x/escrow/keeper" + mhooks "pkg.akt.dev/node/v2/x/market/hooks" + mkeeper "pkg.akt.dev/node/v2/x/market/keeper" + pkeeper "pkg.akt.dev/node/v2/x/provider/keeper" + tkeeper "pkg.akt.dev/node/v2/x/take/keeper" ) // TestSuite encapsulates a functional Akash nodes data stores for @@ -98,7 +98,6 @@ func SetupTestSuiteWithKeepers(t testing.TB, keepers Keepers) *TestSuite { ) ctx := app.NewContext(false) - cdc := app.AppCodec() vals, err := app.Keepers.Cosmos.Staking.GetAllValidators(ctx) diff --git a/testutil/types.go b/testutil/types.go index 440853fd95..3429b5559b 100644 --- a/testutil/types.go +++ b/testutil/types.go @@ -14,8 +14,8 @@ import ( cflags "pkg.akt.dev/go/cli/flags" "pkg.akt.dev/go/sdkutil" - "pkg.akt.dev/node/app" - "pkg.akt.dev/node/testutil/network" + "pkg.akt.dev/node/v2/app" + "pkg.akt.dev/node/v2/testutil/network" ) // NewTestNetworkFixture returns a new simapp AppConstructor for network simulation tests diff --git a/tools/upgrade-info/main.go b/tools/upgrade-info/main.go index 2af65403b8..93776c7c5d 100644 --- a/tools/upgrade-info/main.go +++ b/tools/upgrade-info/main.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" - utilcli "pkg.akt.dev/node/util/cli" + utilcli "pkg.akt.dev/node/v2/util/cli" ) func main() { diff --git a/upgrades/software/v1.0.0/audit.go b/upgrades/software/v1.0.0/audit.go deleted file mode 100644 index 27608de207..0000000000 --- a/upgrades/software/v1.0.0/audit.go +++ /dev/null @@ -1,56 +0,0 @@ -// Package v1_0_0 -// nolint revive -package v1_0_0 - -import ( - "cosmossdk.io/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkmodule "github.com/cosmos/cosmos-sdk/types/module" - types "pkg.akt.dev/go/node/audit/v1" - - "pkg.akt.dev/go/node/migrate" - - utypes "pkg.akt.dev/node/upgrades/types" - akeeper "pkg.akt.dev/node/x/audit/keeper" -) - -type auditMigrations struct { - utypes.Migrator -} - -func newAuditMigration(m utypes.Migrator) utypes.Migration { - return auditMigrations{Migrator: m} -} - -func (m auditMigrations) GetHandler() sdkmodule.MigrationHandler { - return m.handler -} - -// handler migrates audit store from version 2 to 3. -func (m auditMigrations) handler(ctx sdk.Context) (err error) { - cdc := m.Codec() - - store := ctx.KVStore(m.StoreKey()) - oStore := prefix.NewStore(store, migrate.AuditedAttributesV1beta3Prefix()) - - iter := oStore.Iterator(nil, nil) - defer func() { - err = iter.Close() - }() - - for ; iter.Valid(); iter.Next() { - val := migrate.AuditedProviderFromV1beta3(cdc, iter.Value()) - - owner := sdk.MustAccAddressFromBech32(val.Owner) - auditor := sdk.MustAccAddressFromBech32(val.Auditor) - - key := akeeper.ProviderKey(types.ProviderID{Owner: owner, Auditor: auditor}) - - bz := cdc.MustMarshal(&types.AuditedAttributesStore{Attributes: val.Attributes}) - - oStore.Delete(iter.Key()) - store.Set(key, bz) - } - - return nil -} diff --git a/upgrades/software/v1.0.0/cert.go b/upgrades/software/v1.0.0/cert.go deleted file mode 100644 index b9ec7eafe2..0000000000 --- a/upgrades/software/v1.0.0/cert.go +++ /dev/null @@ -1,54 +0,0 @@ -// Package v1_0_0 -// nolint revive -package v1_0_0 - -import ( - "cosmossdk.io/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkmodule "github.com/cosmos/cosmos-sdk/types/module" - "pkg.akt.dev/go/node/migrate" - - utypes "pkg.akt.dev/node/upgrades/types" - ckeeper "pkg.akt.dev/node/x/cert/keeper" -) - -type certsMigrations struct { - utypes.Migrator -} - -func newCertsMigration(m utypes.Migrator) utypes.Migration { - return certsMigrations{Migrator: m} -} - -func (m certsMigrations) GetHandler() sdkmodule.MigrationHandler { - return m.handler -} - -// handler migrates certificates store from version 2 to 3. -func (m certsMigrations) handler(ctx sdk.Context) (err error) { - cdc := m.Codec() - - store := ctx.KVStore(m.StoreKey()) - oStore := prefix.NewStore(store, migrate.CertV1beta3Prefix()) - - iter := oStore.Iterator(nil, nil) - defer func() { - err = iter.Close() - }() - - for ; iter.Valid(); iter.Next() { - val := migrate.CertFromV1beta3(cdc, iter.Value()) - - id, err := ckeeper.ParseCertID(nil, iter.Key()) - if err != nil { - return err - } - - bz := cdc.MustMarshal(&val) - key := ckeeper.MustCertificateKey(val.State, id) - oStore.Delete(iter.Key()) - store.Set(key, bz) - } - - return nil -} diff --git a/upgrades/software/v1.0.0/deployment.go b/upgrades/software/v1.0.0/deployment.go deleted file mode 100644 index f3085bd6ed..0000000000 --- a/upgrades/software/v1.0.0/deployment.go +++ /dev/null @@ -1,123 +0,0 @@ -// Package v1_0_0 -// nolint revive -package v1_0_0 - -import ( - "fmt" - - "cosmossdk.io/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkmodule "github.com/cosmos/cosmos-sdk/types/module" - dv1 "pkg.akt.dev/go/node/deployment/v1" - dv1beta "pkg.akt.dev/go/node/deployment/v1beta4" - "pkg.akt.dev/go/node/migrate" - - utypes "pkg.akt.dev/node/upgrades/types" - dkeeper "pkg.akt.dev/node/x/deployment/keeper" -) - -type deploymentsMigrations struct { - utypes.Migrator -} - -func newDeploymentsMigration(m utypes.Migrator) utypes.Migration { - return deploymentsMigrations{Migrator: m} -} - -func (m deploymentsMigrations) GetHandler() sdkmodule.MigrationHandler { - return m.handler -} - -// handler migrates deployment store from version 4 to 5 -func (m deploymentsMigrations) handler(ctx sdk.Context) error { - store := ctx.KVStore(m.StoreKey()) - - // deployment prefix does not change in this upgrade - oStore := prefix.NewStore(store, dkeeper.DeploymentPrefix) - - iter := oStore.Iterator(nil, nil) - defer func() { - _ = iter.Close() - }() - - var deploymentsTotal uint64 - var deploymentsActive uint64 - var deploymentsClosed uint64 - - cdc := m.Codec() - - for ; iter.Valid(); iter.Next() { - nVal := migrate.DeploymentFromV1beta3(cdc, iter.Value()) - bz := cdc.MustMarshal(&nVal) - - switch nVal.State { - case dv1.DeploymentActive: - deploymentsActive++ - case dv1.DeploymentClosed: - deploymentsClosed++ - default: - return fmt.Errorf("unknown order state %d", nVal.State) - } - - deploymentsTotal++ - - key := dkeeper.MustDeploymentKey(dkeeper.DeploymentStateToPrefix(nVal.State), nVal.ID) - - oStore.Delete(iter.Key()) - store.Set(key, bz) - } - - // group prefix does not change in this upgrade - oStore = prefix.NewStore(store, dkeeper.GroupPrefix) - - iter = oStore.Iterator(nil, nil) - defer func() { - _ = iter.Close() - }() - - var groupsTotal uint64 - var groupsOpen uint64 - var groupsPaused uint64 - var groupsInsufficientFunds uint64 - var groupsClosed uint64 - - for ; iter.Valid(); iter.Next() { - nVal := migrate.GroupFromV1Beta3(cdc, iter.Value()) - bz := cdc.MustMarshal(&nVal) - - switch nVal.State { - case dv1beta.GroupOpen: - groupsOpen++ - case dv1beta.GroupPaused: - groupsPaused++ - case dv1beta.GroupInsufficientFunds: - groupsInsufficientFunds++ - case dv1beta.GroupClosed: - groupsClosed++ - default: - return fmt.Errorf("unknown order state %d", nVal.State) - } - - groupsTotal++ - - key := dkeeper.MustGroupKey(dkeeper.GroupStateToPrefix(nVal.State), nVal.ID) - - oStore.Delete(iter.Key()) - store.Set(key, bz) - } - - ctx.Logger().Info(fmt.Sprintf("[upgrade %s]: updated x/deployment store keys:"+ - "\n\tdeployments total: %d"+ - "\n\tdeployments active: %d"+ - "\n\tdeployments closed: %d"+ - "\n\tgroups total: %d"+ - "\n\tgroups open: %d"+ - "\n\tgroups paused: %d"+ - "\n\tgroups insufficient funds: %d"+ - "\n\tgroups closed: %d", - UpgradeName, - deploymentsTotal, deploymentsActive, deploymentsClosed, - groupsTotal, groupsOpen, groupsPaused, groupsInsufficientFunds, groupsClosed)) - - return nil -} diff --git a/upgrades/software/v1.0.0/escrow.go b/upgrades/software/v1.0.0/escrow.go deleted file mode 100644 index 60bf5563e8..0000000000 --- a/upgrades/software/v1.0.0/escrow.go +++ /dev/null @@ -1,120 +0,0 @@ -// Package v1_0_0 -// nolint revive -package v1_0_0 - -import ( - "fmt" - - "cosmossdk.io/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkmodule "github.com/cosmos/cosmos-sdk/types/module" - etypes "pkg.akt.dev/go/node/escrow/types/v1" - "pkg.akt.dev/go/node/migrate" - - utypes "pkg.akt.dev/node/upgrades/types" - ekeeper "pkg.akt.dev/node/x/escrow/keeper" -) - -type escrowMigrations struct { - utypes.Migrator -} - -func newEscrowMigration(m utypes.Migrator) utypes.Migration { - return escrowMigrations{Migrator: m} -} - -func (m escrowMigrations) GetHandler() sdkmodule.MigrationHandler { - return m.handler -} - -// handler migrates escrow store from version 2 to 3. -func (m escrowMigrations) handler(ctx sdk.Context) error { - store := ctx.KVStore(m.StoreKey()) - - oStore := prefix.NewStore(store, migrate.AccountV1beta3Prefix()) - - iter := oStore.Iterator(nil, nil) - defer func() { - _ = iter.Close() - }() - - cdc := m.Codec() - - var accountsTotal uint64 - var accountsActive uint64 - var accountsClosed uint64 - var accountsOverdrawn uint64 - - for ; iter.Valid(); iter.Next() { - key := append(migrate.AccountV1beta3Prefix(), iter.Key()...) - - nVal := migrate.AccountFromV1beta3(cdc, key, iter.Value()) - bz := cdc.MustMarshal(&nVal.State) - - switch nVal.State.State { - case etypes.StateOpen: - accountsActive++ - case etypes.StateClosed: - accountsClosed++ - case etypes.StateOverdrawn: - accountsOverdrawn++ - } - - accountsTotal++ - - oStore.Delete(key) - - key = ekeeper.BuildAccountsKey(nVal.State.State, &nVal.ID) - store.Set(key, bz) - } - - oStore = prefix.NewStore(store, migrate.PaymentV1beta3Prefix()) - - iter = oStore.Iterator(nil, nil) - defer func() { - _ = iter.Close() - }() - - var paymentsTotal uint64 - var paymentsActive uint64 - var paymentsClosed uint64 - var paymentsOverdrawn uint64 - - for ; iter.Valid(); iter.Next() { - key := append(migrate.PaymentV1beta3Prefix(), iter.Key()...) - - nVal := migrate.PaymentFromV1beta3(cdc, key, iter.Value()) - bz := cdc.MustMarshal(&nVal.State) - - switch nVal.State.State { - case etypes.StateOpen: - paymentsActive++ - case etypes.StateClosed: - paymentsClosed++ - case etypes.StateOverdrawn: - paymentsOverdrawn++ - } - - paymentsTotal++ - - oStore.Delete(key) - - key = ekeeper.BuildPaymentsKey(nVal.State.State, &nVal.ID) - store.Set(key, bz) - } - - ctx.Logger().Info(fmt.Sprintf("[upgrade %s]: updated x/escrow store keys:"+ - "\n\taccounts total: %d"+ - "\n\taccounts open: %d"+ - "\n\taccounts closed: %d"+ - "\n\taccounts overdrawn: %d"+ - "\n\tpayments total: %d"+ - "\n\tpayments open: %d"+ - "\n\tpayments closed: %d"+ - "\n\tpayments overdrawn: %d", - UpgradeName, - accountsTotal, accountsActive, accountsClosed, accountsOverdrawn, - paymentsTotal, paymentsActive, paymentsClosed, paymentsOverdrawn)) - - return nil -} diff --git a/upgrades/software/v1.0.0/init.go b/upgrades/software/v1.0.0/init.go deleted file mode 100644 index 94567250d0..0000000000 --- a/upgrades/software/v1.0.0/init.go +++ /dev/null @@ -1,27 +0,0 @@ -// Package v1_0_0 -// nolint revive -package v1_0_0 - -import ( - av1 "pkg.akt.dev/go/node/audit/v1" - cv1 "pkg.akt.dev/go/node/cert/v1" - dv1 "pkg.akt.dev/go/node/deployment/v1" - emodule "pkg.akt.dev/go/node/escrow/module" - mv1 "pkg.akt.dev/go/node/market/v1" - pv1 "pkg.akt.dev/go/node/provider/v1beta4" - tv1 "pkg.akt.dev/go/node/take/v1" - - utypes "pkg.akt.dev/node/upgrades/types" -) - -func init() { - utypes.RegisterUpgrade(UpgradeName, initUpgrade) - - utypes.RegisterMigration(av1.ModuleName, 2, newAuditMigration) - utypes.RegisterMigration(cv1.ModuleName, 3, newCertsMigration) - utypes.RegisterMigration(dv1.ModuleName, 4, newDeploymentsMigration) - utypes.RegisterMigration(emodule.ModuleName, 2, newEscrowMigration) - utypes.RegisterMigration(mv1.ModuleName, 6, newMarketMigration) - utypes.RegisterMigration(pv1.ModuleName, 2, newProviderMigration) - utypes.RegisterMigration(tv1.ModuleName, 2, newTakeMigration) -} diff --git a/upgrades/software/v1.0.0/market.go b/upgrades/software/v1.0.0/market.go deleted file mode 100644 index 6274f2caf0..0000000000 --- a/upgrades/software/v1.0.0/market.go +++ /dev/null @@ -1,198 +0,0 @@ -// Package v1_0_0 -// nolint revive -package v1_0_0 - -import ( - "fmt" - - storetypes "cosmossdk.io/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkmodule "github.com/cosmos/cosmos-sdk/types/module" - mv1 "pkg.akt.dev/go/node/market/v1" - mv1beta "pkg.akt.dev/go/node/market/v1beta5" - - "pkg.akt.dev/go/node/migrate" - - utypes "pkg.akt.dev/node/upgrades/types" - mkeys "pkg.akt.dev/node/x/market/keeper/keys" -) - -type marketMigrations struct { - utypes.Migrator -} - -func newMarketMigration(m utypes.Migrator) utypes.Migration { - return marketMigrations{Migrator: m} -} - -func (m marketMigrations) GetHandler() sdkmodule.MigrationHandler { - return m.handler -} - -// handler migrates market from version 6 to 7. -func (m marketMigrations) handler(ctx sdk.Context) error { - store := ctx.KVStore(m.StoreKey()) - - cdc := m.Codec() - - // order prefix does not change in this upgrade - oiter := storetypes.KVStorePrefixIterator(store, mkeys.OrderPrefix) - defer func() { - _ = oiter.Close() - }() - - var ordersTotal uint64 - var ordersOpen uint64 - var ordersActive uint64 - var ordersClosed uint64 - - for ; oiter.Valid(); oiter.Next() { - nVal := migrate.OrderFromV1beta4(cdc, oiter.Value()) - - switch nVal.State { - case mv1beta.OrderOpen: - ordersOpen++ - case mv1beta.OrderActive: - ordersActive++ - case mv1beta.OrderClosed: - ordersClosed++ - default: - return fmt.Errorf("unknown order state %d", nVal.State) - } - - ordersTotal++ - - bz := cdc.MustMarshal(&nVal) - - store.Delete(oiter.Key()) - - key := mkeys.MustOrderKey(mkeys.OrderStateToPrefix(nVal.State), nVal.ID) - store.Set(key, bz) - } - - // bid prefixes do not change in this upgrade - store.Delete(mkeys.BidPrefixReverse) - biter := storetypes.KVStorePrefixIterator(store, mkeys.BidPrefix) - defer func() { - _ = biter.Close() - }() - - var bidsTotal uint64 - var bidsOpen uint64 - var bidsActive uint64 - var bidsLost uint64 - var bidsClosed uint64 - - for ; biter.Valid(); biter.Next() { - nVal := migrate.BidFromV1beta4(cdc, biter.Value()) - - switch nVal.State { - case mv1beta.BidOpen: - bidsOpen++ - case mv1beta.BidActive: - bidsActive++ - case mv1beta.BidLost: - bidsLost++ - case mv1beta.BidClosed: - bidsClosed++ - default: - panic(fmt.Sprintf("unknown order state %d", nVal.State)) - } - - bidsTotal++ - - store.Delete(biter.Key()) - - data, err := m.Codec().Marshal(&nVal) - if err != nil { - return err - } - - state := mkeys.BidStateToPrefix(nVal.State) - key, err := mkeys.BidKey(state, nVal.ID) - if err != nil { - return err - } - - revKey, err := mkeys.BidReverseKey(state, nVal.ID) - if err != nil { - return err - } - - store.Set(key, data) - if len(revKey) > 0 { - store.Set(revKey, data) - } - } - - // lease prefixes do not change in this upgrade - store.Delete(mkeys.LeasePrefixReverse) - liter := storetypes.KVStorePrefixIterator(store, mkeys.LeasePrefix) - defer func() { - _ = liter.Close() - }() - - var leasesTotal uint64 - var leasesActive uint64 - var leasesInsufficientFunds uint64 - var leasesClosed uint64 - - for ; liter.Valid(); liter.Next() { - nVal := migrate.LeaseFromV1beta4(cdc, liter.Value()) - - switch nVal.State { - case mv1.LeaseActive: - leasesActive++ - case mv1.LeaseInsufficientFunds: - leasesInsufficientFunds++ - case mv1.LeaseClosed: - leasesClosed++ - default: - panic(fmt.Sprintf("unknown order state %d", nVal.State)) - } - - leasesTotal++ - store.Delete(liter.Key()) - - data, err := m.Codec().Marshal(&nVal) - if err != nil { - return err - } - - state := mkeys.LeaseStateToPrefix(nVal.State) - key, err := mkeys.LeaseKey(state, nVal.ID) - if err != nil { - return err - } - - revKey, err := mkeys.LeaseReverseKey(state, nVal.ID) - if err != nil { - return err - } - - store.Set(key, data) - if len(revKey) > 0 { - store.Set(revKey, data) - } - } - ctx.Logger().Info(fmt.Sprintf("[upgrade %s]: updated x/market store keys:"+ - "\n\torders total: %d"+ - "\n\torders open: %d"+ - "\n\torders active: %d"+ - "\n\torders closed: %d"+ - "\n\tbids total: %d"+ - "\n\tbids open: %d"+ - "\n\tbids active: %d"+ - "\n\tbids lost: %d"+ - "\n\tbids closed: %d"+ - "\n\tleases total: %d"+ - "\n\tleases active: %d"+ - "\n\tleases insufficient funds: %d"+ - "\n\tleases closed: %d", - UpgradeName, - ordersTotal, ordersOpen, ordersActive, ordersClosed, - bidsTotal, bidsOpen, bidsActive, bidsLost, bidsClosed, - leasesTotal, leasesActive, leasesInsufficientFunds, leasesClosed)) - - return nil -} diff --git a/upgrades/software/v1.0.0/provider.go b/upgrades/software/v1.0.0/provider.go deleted file mode 100644 index 50d2c77920..0000000000 --- a/upgrades/software/v1.0.0/provider.go +++ /dev/null @@ -1,65 +0,0 @@ -// Package v1_0_0 -// nolint revive -package v1_0_0 - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/address" - sdkmodule "github.com/cosmos/cosmos-sdk/types/module" - "pkg.akt.dev/go/node/migrate" - "pkg.akt.dev/go/sdkutil" - - utypes "pkg.akt.dev/node/upgrades/types" - pkeeper "pkg.akt.dev/node/x/provider/keeper" -) - -type providerMigrations struct { - utypes.Migrator -} - -func newProviderMigration(m utypes.Migrator) utypes.Migration { - return providerMigrations{Migrator: m} -} - -func (m providerMigrations) GetHandler() sdkmodule.MigrationHandler { - return m.handler -} - -func ProviderKey(id sdk.Address) []byte { - return address.MustLengthPrefix(id.Bytes()) -} - -// handler migrates provider store from version 2 to 3. -func (m providerMigrations) handler(ctx sdk.Context) (err error) { - store := ctx.KVStore(m.StoreKey()) - - iter := store.Iterator(nil, nil) - defer func() { - err = iter.Close() - }() - - cdc := m.Codec() - - var providersTotal uint64 - - for ; iter.Valid(); iter.Next() { - to := migrate.ProviderFromV1beta3(cdc, iter.Value()) - - id := sdkutil.MustAccAddressFromBech32(to.Owner) - bz := cdc.MustMarshal(&to) - - providersTotal++ - - store.Delete(iter.Key()) - store.Set(pkeeper.ProviderKey(id), bz) - } - - ctx.Logger().Info(fmt.Sprintf("[upgrade %s]: updated x/provider store keys:"+ - "\n\tproviders total: %d", - UpgradeName, - providersTotal)) - - return nil -} diff --git a/upgrades/software/v1.0.0/take.go b/upgrades/software/v1.0.0/take.go deleted file mode 100644 index ef06f2e2a4..0000000000 --- a/upgrades/software/v1.0.0/take.go +++ /dev/null @@ -1,27 +0,0 @@ -// Package v1_0_0 -// nolint revive -package v1_0_0 - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkmodule "github.com/cosmos/cosmos-sdk/types/module" - - utypes "pkg.akt.dev/node/upgrades/types" -) - -type takeMigrations struct { - utypes.Migrator -} - -func newTakeMigration(m utypes.Migrator) utypes.Migration { - return takeMigrations{Migrator: m} -} - -func (m takeMigrations) GetHandler() sdkmodule.MigrationHandler { - return m.handler -} - -// handler migrates provider store from version 2 to 3. -func (m takeMigrations) handler(_ sdk.Context) error { - return nil -} diff --git a/upgrades/software/v1.0.0/upgrade.go b/upgrades/software/v1.0.0/upgrade.go deleted file mode 100644 index 06dc36c2a3..0000000000 --- a/upgrades/software/v1.0.0/upgrade.go +++ /dev/null @@ -1,346 +0,0 @@ -// Package v1_0_0 -// nolint revive -package v1_0_0 - -import ( - "context" - "fmt" - "reflect" - "time" - - "cosmossdk.io/log" - sdkmath "cosmossdk.io/math" - storetypes "cosmossdk.io/store/types" - upgradetypes "cosmossdk.io/x/upgrade/types" - "github.com/cosmos/cosmos-sdk/baseapp" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - "github.com/cosmos/cosmos-sdk/x/authz" - consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types" - crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" - paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - - dv1 "pkg.akt.dev/go/node/deployment/v1" - dv1beta3 "pkg.akt.dev/go/node/deployment/v1beta3" - dv1beta "pkg.akt.dev/go/node/deployment/v1beta4" - ev1 "pkg.akt.dev/go/node/escrow/v1" - agovtypes "pkg.akt.dev/go/node/gov/v1beta3" - mv1 "pkg.akt.dev/go/node/market/v1" - mv1beta4 "pkg.akt.dev/go/node/market/v1beta4" - mv1beta "pkg.akt.dev/go/node/market/v1beta5" - astakingtypes "pkg.akt.dev/go/node/staking/v1beta3" - taketypes "pkg.akt.dev/go/node/take/v1" - - apptypes "pkg.akt.dev/node/app/types" - utypes "pkg.akt.dev/node/upgrades/types" -) - -const ( - UpgradeName = "v1.0.0" -) - -type upgrade struct { - *apptypes.App - log log.Logger -} - -var _ utypes.IUpgrade = (*upgrade)(nil) - -func initUpgrade(log log.Logger, app *apptypes.App) (utypes.IUpgrade, error) { - up := &upgrade{ - App: app, - log: log.With("module", fmt.Sprintf("upgrade/%s", UpgradeName)), - } - - return up, nil -} - -func (up *upgrade) StoreLoader() *storetypes.StoreUpgrades { - return &storetypes.StoreUpgrades{ - Added: []string{ - // With the migrations of all modules away from x/params, the crisis module now has a store. - // The store must be created during a chain upgrade to v0.53.x. - consensustypes.ModuleName, - }, - Deleted: []string{ - "agov", - "astaking", - crisistypes.ModuleName, - }, - } -} - -type AccountKeeper interface { - NewAccount(sdk.Context, sdk.AccountI) sdk.AccountI - - GetAccount(ctx sdk.Context, addr sdk.AccAddress) sdk.AccountI - SetAccount(ctx sdk.Context, acc sdk.AccountI) -} - -// AkashUtilsExtraAccountTypes is a map of extra account types that can be overridden. -// This is defined as a global variable, so it can be modified in the chain's app.go and used here without -// having to import the chain. Specifically, this is used for compatibility with Akash' Cosmos SDK fork -var AkashUtilsExtraAccountTypes map[reflect.Type]struct{} - -// CanCreateModuleAccountAtAddr tells us if we can safely make a module account at -// a given address. By collision resistance of the address (given API safe construction), -// the only way for an account to be already be at this address is if its claimed by the same -// pre-image from the correct module, -// or some SDK command breaks assumptions and creates an account at designated address. -// This function checks if there is an account at that address, and runs some safety checks -// to be extra-sure its not a user account (e.g. non-zero sequence, pubkey, of fore-seen account types). -// If there is no account, or if we believe its not a user-spendable account, we allow module account -// creation at the address. -// else, we do not. -// -// TODO: This is generally from an SDK design flaw -// code based off wasmd code: https://github.com/CosmWasm/wasmd/pull/996 -// Its _mandatory_ that the caller do the API safe construction to generate a module account addr, -// namely, address.Module(ModuleName, {key}) -func CanCreateModuleAccountAtAddr(ctx sdk.Context, ak AccountKeeper, addr sdk.AccAddress) error { - existingAcct := ak.GetAccount(ctx, addr) - if existingAcct == nil { - return nil - } - if existingAcct.GetSequence() != 0 || existingAcct.GetPubKey() != nil { - return fmt.Errorf("cannot create module account %s, "+ - "due to an account at that address already existing & having sent txs", addr) - } - overrideAccountTypes := map[reflect.Type]struct{}{ - reflect.TypeOf(&authtypes.BaseAccount{}): {}, - reflect.TypeOf(&vestingtypes.DelayedVestingAccount{}): {}, - reflect.TypeOf(&vestingtypes.ContinuousVestingAccount{}): {}, - reflect.TypeOf(&vestingtypes.BaseVestingAccount{}): {}, - reflect.TypeOf(&vestingtypes.PeriodicVestingAccount{}): {}, - reflect.TypeOf(&vestingtypes.PermanentLockedAccount{}): {}, - } - for extraAccountType := range AkashUtilsExtraAccountTypes { - overrideAccountTypes[extraAccountType] = struct{}{} - } - - if _, isClear := overrideAccountTypes[reflect.TypeOf(existingAcct)]; isClear { - return nil - } - - return fmt.Errorf("cannot create module account %s, "+ - "due to an account at that address already existing & not being an overridable type", existingAcct) -} - -// CreateModuleAccountByName creates a module account at the provided name -func CreateModuleAccountByName(ctx sdk.Context, ak AccountKeeper, name string) error { - addr := authtypes.NewModuleAddress(name) - err := CanCreateModuleAccountAtAddr(ctx, ak, addr) - if err != nil { - return err - } - - acc := ak.NewAccount( - ctx, - authtypes.NewModuleAccount( - authtypes.NewBaseAccountWithAddress(addr), - name, - ), - ) - ak.SetAccount(ctx, acc) - return nil -} - -func (up *upgrade) UpgradeHandler() upgradetypes.UpgradeHandler { - baseAppLegacySS := up.Keepers.Cosmos.Params.Subspace(baseapp.Paramspace).WithKeyTable(paramstypes.ConsensusParamsKeyTable()) - - return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - // Migrate Tendermint consensus parameters from x/params module to a - // dedicated x/consensus module. - sctx := sdk.UnwrapSDKContext(ctx) - - err := baseapp.MigrateParams(sctx, baseAppLegacySS, up.Keepers.Cosmos.ConsensusParams.ParamsStore) - if err != nil { - return nil, err - } - sspace, exists := up.Keepers.Cosmos.Params.GetSubspace(stakingtypes.ModuleName) - if !exists { - return nil, fmt.Errorf("params subspace \"%s\" not found", stakingtypes.ModuleName) - } - - up.log.Info("migrating x/take to self-managed params") - sspace, exists = up.Keepers.Cosmos.Params.GetSubspace(taketypes.ModuleName) - if !exists { - return nil, fmt.Errorf("params subspace \"%s\" not found", taketypes.ModuleName) - } - - tparams := taketypes.Params{} - sspace.Get(sctx, taketypes.KeyDefaultTakeRate, &tparams.DefaultTakeRate) - sspace.Get(sctx, taketypes.KeyDenomTakeRates, &tparams.DenomTakeRates) - - err = up.Keepers.Akash.Take.SetParams(sctx, tparams) - if err != nil { - return nil, err - } - - up.log.Info("migrating x/deployment to self-managed params") - sspace, exists = up.Keepers.Cosmos.Params.GetSubspace(dv1.ModuleName) - if !exists { - return nil, fmt.Errorf("params subspace \"%s\" not found", dv1.ModuleName) - } - - deplParams := &dv1beta3.Params{} - sspace.GetParamSet(sctx, deplParams) - - nDeplParams := dv1beta.Params{ - MinDeposits: make(sdk.Coins, 0, len(deplParams.MinDeposits)), - } - - for _, coin := range deplParams.MinDeposits { - nDeplParams.MinDeposits = append(nDeplParams.MinDeposits, sdk.Coin{ - Denom: coin.Denom, - Amount: sdkmath.NewIntFromBigInt(coin.Amount.BigInt()), - }) - } - err = up.Keepers.Akash.Deployment.SetParams(sctx, nDeplParams) - if err != nil { - return nil, err - } - - up.log.Info("migrating x/market to self-managed params") - sspace, exists = up.Keepers.Cosmos.Params.GetSubspace(mv1.ModuleName) - if !exists { - return nil, fmt.Errorf("params subspace \"%s\" not found", mv1.ModuleName) - } - - mParams := &mv1beta4.Params{} - sspace.GetParamSet(sctx, mParams) - - err = up.Keepers.Akash.Market.SetParams(sctx, mv1beta.Params{ - BidMinDeposit: mParams.BidMinDeposit, - OrderMaxBids: mParams.OrderMaxBids, - }) - if err != nil { - return nil, err - } - - sspace, exists = up.Keepers.Cosmos.Params.GetSubspace("agov") - if !exists { - return nil, fmt.Errorf("params subspace \"%s\" not found", "agov") - } - - dparams := agovtypes.DepositParams{} - sspace.Get(sctx, agovtypes.KeyDepositParams, &dparams) - - sspace, exists = up.Keepers.Cosmos.Params.GetSubspace(astakingtypes.ModuleName) - if !exists { - return nil, fmt.Errorf("params subspace \"%s\" not found", astakingtypes.ModuleName) - } - - sparam := sdkmath.LegacyDec{} - sspace.Get(sctx, astakingtypes.KeyMinCommissionRate, &sparam) - - toVM, err := up.MM.RunMigrations(ctx, up.Configurator, fromVM) - if err != nil { - return nil, err - } - - // patch deposit authorizations after authz store upgrade - err = up.patchDepositAuthorizations(sctx) - if err != nil { - return nil, err - } - - up.log.Info(fmt.Sprintf("migrating param agov.MinInitialDepositRate to gov.MinInitialDepositRatio")) - up.log.Info(fmt.Sprintf("setting gov.ExpeditedMinDeposit to 2000akt")) - up.log.Info(fmt.Sprintf("setting gov.ExpeditedThreshold to 67%%")) - - // Migrate governance min deposit parameter to builtin gov params - gparams, err := up.Keepers.Cosmos.Gov.Params.Get(ctx) - if err != nil { - return nil, err - } - - gparams.MinInitialDepositRatio = dparams.MinInitialDepositRate.String() - - // min deposit for an expedited proposal is set to 2000AKT - gparams.ExpeditedMinDeposit = sdk.NewCoins(sdk.NewCoin("uakt", sdkmath.NewInt(2000000000))) - gparams.ExpeditedThreshold = sdkmath.LegacyNewDecWithPrec(667, 3).String() - - eVotePeriod := time.Hour * 24 - gparams.ExpeditedVotingPeriod = &eVotePeriod - - err = up.Keepers.Cosmos.Gov.Params.Set(ctx, gparams) - if err != nil { - return nil, err - } - - up.log.Info(fmt.Sprintf("migrating param astaking.MinCommissionRate to staking.MinCommissionRate")) - sparams, err := up.Keepers.Cosmos.Staking.GetParams(sctx) - if err != nil { - return nil, err - } - sparams.MinCommissionRate = sparam - - err = up.Keepers.Cosmos.Staking.SetParams(ctx, sparams) - if err != nil { - return nil, err - } - - up.log.Info(fmt.Sprintf("all migrations have been completed")) - - return toVM, err - } -} - -func (up *upgrade) patchDepositAuthorizations(ctx sdk.Context) error { - msgUrlOld := "/akash.deployment.v1beta3.MsgDepositDeployment" - - var err error - up.log.Info(fmt.Sprintf("migrating \"%s\" to \"%s\"", msgUrlOld, (&ev1.DepositAuthorization{}).MsgTypeURL())) - up.Keepers.Cosmos.Authz.IterateGrants(ctx, func(granterAddr sdk.AccAddress, granteeAddr sdk.AccAddress, grant authz.Grant) bool { - var authorization authz.Authorization - authorization, err = grant.GetAuthorization() - if err != nil { - up.log.Error(fmt.Sprintf("unable to get authorization. err=%s", err.Error())) - return false - } - - var nAuthz authz.Authorization - - switch authorization.MsgTypeURL() { - case msgUrlOld: - authzOld, valid := authorization.(*dv1beta3.DepositDeploymentAuthorization) - if !valid { - up.log.Error(fmt.Sprintf("invalid authorization type %s", reflect.TypeOf(authorization).String())) - return false - } - nAuthz = ev1.NewDepositAuthorization(ev1.DepositAuthorizationScopes{ev1.DepositScopeDeployment}, authzOld.SpendLimit) - default: - return false - } - - err = up.Keepers.Cosmos.Authz.DeleteGrant(ctx, granteeAddr, granterAddr, authorization.MsgTypeURL()) - if err != nil { - up.log.Error(fmt.Sprintf("unable to delete autorization. err=%s", err.Error())) - return false - } - - err = up.Keepers.Cosmos.Authz.SaveGrant(ctx, granteeAddr, granterAddr, nAuthz, grant.Expiration) - if err != nil { - up.log.Error(fmt.Sprintf("unable to save autorization. err=%s", err.Error())) - return true - } - - return false - }) - if err != nil { - return err - } - - up.log.Info("cleaning expired grants") - err = up.Keepers.Cosmos.Authz.DequeueAndDeleteExpiredGrants(ctx) - if err != nil { - return err - } - up.log.Info("cleaning expired grants - DONE") - - return nil -} diff --git a/upgrades/software/v1.1.0/upgrade.go b/upgrades/software/v1.1.0/upgrade.go deleted file mode 100644 index 8e244037ad..0000000000 --- a/upgrades/software/v1.1.0/upgrade.go +++ /dev/null @@ -1,466 +0,0 @@ -// Package v1_1_0 -// nolint revive -package v1_1_0 - -import ( - "context" - "fmt" - - "cosmossdk.io/log" - sdkmath "cosmossdk.io/math" - "cosmossdk.io/store/prefix" - storetypes "cosmossdk.io/store/types" - upgradetypes "cosmossdk.io/x/upgrade/types" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - - dv1 "pkg.akt.dev/go/node/deployment/v1" - dtypes "pkg.akt.dev/go/node/deployment/v1beta4" - escrowid "pkg.akt.dev/go/node/escrow/id/v1" - idv1 "pkg.akt.dev/go/node/escrow/id/v1" - emodule "pkg.akt.dev/go/node/escrow/module" - etypes "pkg.akt.dev/go/node/escrow/types/v1" - mv1 "pkg.akt.dev/go/node/market/v1" - mtypes "pkg.akt.dev/go/node/market/v1beta5" - - apptypes "pkg.akt.dev/node/app/types" - utypes "pkg.akt.dev/node/upgrades/types" - ekeeper "pkg.akt.dev/node/x/escrow/keeper" - "pkg.akt.dev/node/x/market" - mhooks "pkg.akt.dev/node/x/market/hooks" - "pkg.akt.dev/node/x/market/keeper/keys" -) - -const ( - UpgradeName = "v1.1.0" -) - -type upgrade struct { - *apptypes.App - log log.Logger -} - -var _ utypes.IUpgrade = (*upgrade)(nil) - -func initUpgrade(log log.Logger, app *apptypes.App) (utypes.IUpgrade, error) { - up := &upgrade{ - App: app, - log: log.With("module", fmt.Sprintf("upgrade/%s", UpgradeName)), - } - - return up, nil -} - -func (up *upgrade) StoreLoader() *storetypes.StoreUpgrades { - return &storetypes.StoreUpgrades{} -} - -func (up *upgrade) UpgradeHandler() upgradetypes.UpgradeHandler { - return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - toVM, err := up.MM.RunMigrations(ctx, up.Configurator, fromVM) - if err != nil { - return nil, err - } - - sctx := sdk.UnwrapSDKContext(ctx) - err = up.closeOverdrawnEscrowAccounts(sctx) - if err != nil { - return nil, err - } - - up.log.Info(fmt.Sprintf("all migrations have been completed")) - - return toVM, err - } -} - -func (up *upgrade) closeOverdrawnEscrowAccounts(ctx sdk.Context) error { - store := ctx.KVStore(up.GetKey(emodule.StoreKey)) - searchPrefix := ekeeper.BuildSearchPrefix(ekeeper.AccountPrefix, etypes.StateOpen.String(), "") - - searchStore := prefix.NewStore(store, searchPrefix) - - iter := searchStore.Iterator(nil, nil) - defer func() { - _ = iter.Close() - }() - - cdc := up.GetCodec() - - totalAccounts := 0 - totalPayments := 0 - - for ; iter.Valid(); iter.Next() { - id, _ := ekeeper.ParseAccountKey(append(searchPrefix, iter.Key()...)) - val := etypes.Account{ - ID: id, - } - - cdc.MustUnmarshal(iter.Value(), &val.State) - - if val.State.Funds[0].Denom != "ibc/170C677610AC31DF0904FFE09CD3B5C657492170E7E52372E48756B71E56F2F1" { - continue - } - - aPrevState := val.State.State - - heightDelta := ctx.BlockHeight() + val.State.SettledAt - - totalAvailableDeposits := sdkmath.LegacyZeroDec() - - for _, deposit := range val.State.Deposits { - totalAvailableDeposits.AddMut(deposit.Balance.Amount) - } - - payments := up.accountPayments(cdc, store, id, []etypes.State{etypes.StateOpen, etypes.StateOverdrawn}) - - totalBlockRate := sdkmath.LegacyZeroDec() - - for _, pmnt := range payments { - totalBlockRate.AddMut(pmnt.State.Rate.Amount) - - if pmnt.State.State == etypes.StateOverdrawn { - val.State.State = etypes.StateOverdrawn - } - } - - owed := sdkmath.LegacyZeroDec() - owed.AddMut(totalBlockRate) - owed.MulInt64Mut(heightDelta) - - overdraft := totalAvailableDeposits.LTE(owed) || val.State.State == etypes.StateOverdrawn - - totalAccounts++ - - val.State.Deposits = nil - val.State.Funds[0].Amount = val.State.Funds[0].Amount.Sub(owed) - - key := ekeeper.BuildAccountsKey(aPrevState, &val.ID) - store.Delete(key) - - if !overdraft { - val.State.State = etypes.StateClosed - } - - // find associated deployment/groups/lease/bid and close it - hooks := mhooks.New(up.Keepers.Akash.Deployment, up.Keepers.Akash.Market) - - err := up.OnEscrowAccountClosed(ctx, val) - if err != nil { - return err - } - - key = ekeeper.BuildAccountsKey(val.State.State, &val.ID) - store.Set(key, cdc.MustMarshal(&val.State)) - - for i := range payments { - totalPayments++ - key = ekeeper.BuildPaymentsKey(payments[i].State.State, &payments[i].ID) - store.Delete(key) - - payments[i].State.State = etypes.StateClosed - if overdraft { - payments[i].State.State = etypes.StateOverdrawn - } - - payments[i].State.Balance.Amount.Set(sdkmath.LegacyZeroDec()) - payments[i].State.Unsettled.Amount.Set(payments[i].State.Rate.Amount.MulInt64Mut(heightDelta)) - - key = ekeeper.BuildPaymentsKey(payments[i].State.State, &payments[i].ID) - err = hooks.OnEscrowPaymentClosed(ctx, payments[i]) - if err != nil { - return err - } - - store.Set(key, cdc.MustMarshal(&payments[i].State)) - } - } - - biter := searchStore.Iterator(nil, nil) - defer func() { - _ = biter.Close() - }() - - for ; biter.Valid(); biter.Next() { - eid, _ := ekeeper.ParseAccountKey(append(searchPrefix, biter.Key()...)) - val := etypes.Account{ - ID: eid, - } - - if eid.Scope != idv1.ScopeDeployment { - continue - } - - cdc.MustUnmarshal(biter.Value(), &val.State) - aPrevState := val.State.State - - did, err := dv1.DeploymentIDFromEscrowID(val.ID) - if err != nil { - return err - } - - deployment, found := up.Keepers.Akash.Deployment.GetDeployment(ctx, did) - if !found { - return nil - } - - if deployment.State == dv1.DeploymentClosed { - totalAccounts++ - - val.State.Deposits = nil - val.State.State = etypes.StateClosed - val.State.Funds[0].Amount.Set(sdkmath.LegacyZeroDec()) - - key := ekeeper.BuildAccountsKey(aPrevState, &val.ID) - store.Delete(key) - - key = ekeeper.BuildAccountsKey(val.State.State, &val.ID) - store.Set(key, cdc.MustMarshal(&val.State)) - - payments := up.accountPayments(cdc, store, eid, []etypes.State{etypes.StateOpen, etypes.StateOverdrawn}) - - for i := range payments { - totalPayments++ - key = ekeeper.BuildPaymentsKey(payments[i].State.State, &payments[i].ID) - store.Delete(key) - - payments[i].State.State = etypes.StateClosed - payments[i].State.Balance.Amount.Set(sdkmath.LegacyZeroDec()) - - key = ekeeper.BuildPaymentsKey(payments[i].State.State, &payments[i].ID) - store.Set(key, cdc.MustMarshal(&payments[i].State)) - } - } - } - - up.log.Info(fmt.Sprintf("cleaned up overdrawn:\n"+ - "\taccounts: %d\n"+ - "\tpayments: %d", totalAccounts, totalPayments)) - - return nil -} - -func (up *upgrade) accountPayments(cdc codec.Codec, store storetypes.KVStore, id escrowid.Account, states []etypes.State) []etypes.Payment { - var payments []etypes.Payment - - iters := make([]storetypes.Iterator, 0, len(states)) - defer func() { - for _, iter := range iters { - _ = iter.Close() - } - }() - - for _, state := range states { - pprefix := ekeeper.BuildPaymentsKey(state, &id) - iter := storetypes.KVStorePrefixIterator(store, pprefix) - iters = append(iters, iter) - - for ; iter.Valid(); iter.Next() { - id, _ := ekeeper.ParsePaymentKey(iter.Key()) - val := etypes.Payment{ - ID: id, - } - cdc.MustUnmarshal(iter.Value(), &val.State) - payments = append(payments, val) - } - } - return payments -} - -func (up *upgrade) OnEscrowAccountClosed(ctx sdk.Context, obj etypes.Account) error { - id, err := dv1.DeploymentIDFromEscrowID(obj.ID) - if err != nil { - return err - } - - deployment, found := up.Keepers.Akash.Deployment.GetDeployment(ctx, id) - if !found { - return nil - } - - if deployment.State != dv1.DeploymentActive { - return nil - } - err = up.Keepers.Akash.Deployment.CloseDeployment(ctx, deployment) - if err != nil { - return err - } - - gstate := dtypes.GroupClosed - if obj.State.State == etypes.StateOverdrawn { - gstate = dtypes.GroupInsufficientFunds - } - - for _, group := range up.Keepers.Akash.Deployment.GetGroups(ctx, deployment.ID) { - if group.ValidateClosable() == nil { - err = up.Keepers.Akash.Deployment.OnCloseGroup(ctx, group, gstate) - if err != nil { - return err - } - err = up.OnGroupClosed(ctx, group.ID) - if err != nil { - return err - } - } - } - - return nil -} - -func (up *upgrade) OnGroupClosed(ctx sdk.Context, id dv1.GroupID) error { - processClose := func(ctx sdk.Context, bid mtypes.Bid) error { - err := up.Keepers.Akash.Market.OnBidClosed(ctx, bid) - if err != nil { - return err - } - - if lease, ok := up.Keepers.Akash.Market.GetLease(ctx, bid.ID.LeaseID()); ok { - // OnGroupClosed is callable by x/deployment only so only reason is owner - err = up.Keepers.Akash.Market.OnLeaseClosed(ctx, lease, mv1.LeaseClosed, mv1.LeaseClosedReasonOwner) - if err != nil { - return err - } - } - - return nil - } - - var err error - up.Keepers.Akash.Market.WithOrdersForGroup(ctx, id, mtypes.OrderActive, func(order mtypes.Order) bool { - err = up.Keepers.Akash.Market.OnOrderClosed(ctx, order) - if err != nil { - return true - } - - up.Keepers.Akash.Market.WithBidsForOrder(ctx, order.ID, mtypes.BidOpen, func(bid mtypes.Bid) bool { - err = processClose(ctx, bid) - return err != nil - }) - - if err != nil { - return true - } - - up.Keepers.Akash.Market.WithBidsForOrder(ctx, order.ID, mtypes.BidActive, func(bid mtypes.Bid) bool { - err = processClose(ctx, bid) - return err != nil - }) - - return err != nil - }) - - if err != nil { - return err - } - - return nil -} - -func (up *upgrade) OnEscrowPaymentClosed(ctx sdk.Context, obj etypes.Payment) error { - id, err := mv1.LeaseIDFromPaymentID(obj.ID) - if err != nil { - return nil - } - - bid, ok := up.Keepers.Akash.Market.GetBid(ctx, id.BidID()) - if !ok { - return nil - } - - if bid.State != mtypes.BidActive { - return nil - } - - order, ok := up.Keepers.Akash.Market.GetOrder(ctx, id.OrderID()) - if !ok { - return mv1.ErrOrderNotFound - } - - lease, ok := up.Keepers.Akash.Market.GetLease(ctx, id) - if !ok { - return mv1.ErrLeaseNotFound - } - - err = up.Keepers.Akash.Market.OnOrderClosed(ctx, order) - if err != nil { - return err - } - err = up.OnBidClosed(ctx, bid) - if err != nil { - return err - } - - if obj.State.State == etypes.StateOverdrawn { - err = up.Keepers.Akash.Market.OnLeaseClosed(ctx, lease, mv1.LeaseInsufficientFunds, mv1.LeaseClosedReasonInsufficientFunds) - if err != nil { - return err - } - } else { - err = up.Keepers.Akash.Market.OnLeaseClosed(ctx, lease, mv1.LeaseClosed, mv1.LeaseClosedReasonUnspecified) - if err != nil { - return err - } - } - - return nil -} - -// OnBidClosed updates bid state to closed -func (up *upgrade) OnBidClosed(ctx sdk.Context, bid mtypes.Bid) error { - switch bid.State { - case mtypes.BidClosed, mtypes.BidLost: - return nil - } - - currState := bid.State - bid.State = mtypes.BidClosed - up.updateBid(ctx, bid, currState) - - err := ctx.EventManager().EmitTypedEvent( - &mv1.EventBidClosed{ - ID: bid.ID, - }, - ) - if err != nil { - return err - } - - return nil -} - -func (up *upgrade) updateBid(ctx sdk.Context, bid mtypes.Bid, currState mtypes.Bid_State) { - store := ctx.KVStore(up.GetKey(market.StoreKey)) - - switch currState { - case mtypes.BidOpen: - case mtypes.BidActive: - default: - panic(fmt.Sprintf("unexpected current state of the bid: %d", currState)) - } - - key := keys.MustBidKey(keys.BidStateToPrefix(currState), bid.ID) - revKey := keys.MustBidStateRevereKey(currState, bid.ID) - store.Delete(key) - if revKey != nil { - store.Delete(revKey) - } - - switch bid.State { - case mtypes.BidActive: - case mtypes.BidLost: - case mtypes.BidClosed: - default: - panic(fmt.Sprintf("unexpected new state of the bid: %d", bid.State)) - } - - data := up.App.Cdc.MustMarshal(&bid) - - key = keys.MustBidKey(keys.BidStateToPrefix(bid.State), bid.ID) - revKey = keys.MustBidStateRevereKey(bid.State, bid.ID) - - store.Set(key, data) - if len(revKey) > 0 { - store.Set(revKey, data) - } -} diff --git a/upgrades/software/v1.1.0/init.go b/upgrades/software/v2.0.0/init.go similarity index 55% rename from upgrades/software/v1.1.0/init.go rename to upgrades/software/v2.0.0/init.go index 4115a2760e..d19b34204d 100644 --- a/upgrades/software/v1.1.0/init.go +++ b/upgrades/software/v2.0.0/init.go @@ -1,9 +1,9 @@ -// Package v1_1_0 +// Package v2_0_0 // nolint revive -package v1_1_0 +package v2_0_0 import ( - utypes "pkg.akt.dev/node/upgrades/types" + utypes "pkg.akt.dev/node/v2/upgrades/types" ) func init() { diff --git a/upgrades/software/v2.0.0/upgrade.go b/upgrades/software/v2.0.0/upgrade.go new file mode 100644 index 0000000000..412e1ea866 --- /dev/null +++ b/upgrades/software/v2.0.0/upgrade.go @@ -0,0 +1,88 @@ +// Package v2_0_0 +// nolint revive +package v2_0_0 + +import ( + "context" + "fmt" + + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + upgradetypes "cosmossdk.io/x/upgrade/types" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/cosmos/cosmos-sdk/types/module" + + apptypes "pkg.akt.dev/node/v2/app/types" + utypes "pkg.akt.dev/node/v2/upgrades/types" + oracle "pkg.akt.dev/node/v2/x/oracle" + awasm "pkg.akt.dev/node/v2/x/wasm" +) + +const ( + UpgradeName = "v2.0.0" +) + +type upgrade struct { + *apptypes.App + log log.Logger +} + +var _ utypes.IUpgrade = (*upgrade)(nil) + +func initUpgrade(log log.Logger, app *apptypes.App) (utypes.IUpgrade, error) { + up := &upgrade{ + App: app, + log: log.With("module", fmt.Sprintf("upgrade/%s", UpgradeName)), + } + + return up, nil +} + +func (up *upgrade) StoreLoader() *storetypes.StoreUpgrades { + return &storetypes.StoreUpgrades{ + Added: []string{ + oracle.StoreKey, + awasm.StoreKey, + wasmtypes.StoreKey, + }, + Deleted: []string{}, + } +} + +func (up *upgrade) UpgradeHandler() upgradetypes.UpgradeHandler { + return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + // Set wasm old version to 1 if we want to call wasm's InitGenesis ourselves + // in this upgrade logic ourselves. + // + // vm[wasm.ModuleName] = wasm.ConsensusVersion + // + // Otherwise we run this, which will run wasm.InitGenesis(wasm.DefaultGenesis()) + // and then override it after. + + // Set the initial wasm module version + //fromVM[wasmtypes.ModuleName] = wasm.AppModule{}.ConsensusVersion() + + toVM, err := up.MM.RunMigrations(ctx, up.Configurator, fromVM) + if err != nil { + return toVM, err + } + + params := up.Keepers.Cosmos.Wasm.GetParams(ctx) + // Configure code upload access - RESTRICTED TO GOVERNANCE ONLY + // Only governance proposals can upload contract code + // This provides maximum security for mainnet deployment + params.CodeUploadAccess = wasmtypes.AccessConfig{ + Permission: wasmtypes.AccessTypeNobody, + } + + // Configure instantiate default permission + params.InstantiateDefaultPermission = wasmtypes.AccessTypeEverybody + + err = up.Keepers.Cosmos.Wasm.SetParams(ctx, params) + if err != nil { + return toVM, err + } + + return toVM, err + } +} diff --git a/upgrades/types/types.go b/upgrades/types/types.go index cbd69bca1d..ca2be6bd4e 100644 --- a/upgrades/types/types.go +++ b/upgrades/types/types.go @@ -10,7 +10,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkmodule "github.com/cosmos/cosmos-sdk/types/module" - apptypes "pkg.akt.dev/node/app/types" + apptypes "pkg.akt.dev/node/v2/app/types" ) var ( diff --git a/upgrades/upgrades.go b/upgrades/upgrades.go index 01852a09d7..b04dad889f 100644 --- a/upgrades/upgrades.go +++ b/upgrades/upgrades.go @@ -2,5 +2,5 @@ package upgrades import ( // nolint: revive - _ "pkg.akt.dev/node/upgrades/software/v1.1.0" + _ "pkg.akt.dev/node/v2/upgrades/software/v2.0.0" ) diff --git a/upgrades/upgrades_test.go b/upgrades/upgrades_test.go index fc379aa757..b0496c7e09 100644 --- a/upgrades/upgrades_test.go +++ b/upgrades/upgrades_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/mod/semver" - utypes "pkg.akt.dev/node/upgrades/types" + utypes "pkg.akt.dev/node/v2/upgrades/types" ) func TestUpgradesName(t *testing.T) { diff --git a/util/partialord/internal/dag/dag_test.go b/util/partialord/internal/dag/dag_test.go index 7a7cbf4551..ffee61b490 100644 --- a/util/partialord/internal/dag/dag_test.go +++ b/util/partialord/internal/dag/dag_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "pkg.akt.dev/node/util/partialord/internal/dag" + "pkg.akt.dev/node/v2/util/partialord/internal/dag" ) type edge struct { diff --git a/util/partialord/partialord.go b/util/partialord/partialord.go index d1d4387e5f..aa81843964 100644 --- a/util/partialord/partialord.go +++ b/util/partialord/partialord.go @@ -3,7 +3,7 @@ package partialord import ( "sort" - "pkg.akt.dev/node/util/partialord/internal/dag" + "pkg.akt.dev/node/v2/util/partialord/internal/dag" ) type PartialOrdering struct { diff --git a/util/partialord/partialord_test.go b/util/partialord/partialord_test.go index 451cf29718..c2cf7d8253 100644 --- a/util/partialord/partialord_test.go +++ b/util/partialord/partialord_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - "pkg.akt.dev/node/util/partialord" + "pkg.akt.dev/node/v2/util/partialord" ) func TestAPI(t *testing.T) { diff --git a/util/query/pagination.go b/util/query/pagination.go index 9138469a60..85b097f8a2 100644 --- a/util/query/pagination.go +++ b/util/query/pagination.go @@ -5,7 +5,7 @@ import ( "fmt" "hash/crc32" - "pkg.akt.dev/node/util/validation" + "pkg.akt.dev/node/v2/util/validation" ) var ( diff --git a/wasmvm.go b/wasmvm.go new file mode 100644 index 0000000000..e745e2390e --- /dev/null +++ b/wasmvm.go @@ -0,0 +1,3 @@ +package node + +// #cgo LDFLAGS: -Wl,-rpath,${SRCDIR}/.cache/lib -L${SRCDIR}/.cache/lib diff --git a/x/audit/alias.go b/x/audit/alias.go index 4500cd1be4..c00657554c 100644 --- a/x/audit/alias.go +++ b/x/audit/alias.go @@ -3,7 +3,7 @@ package audit import ( types "pkg.akt.dev/go/node/audit/v1" - "pkg.akt.dev/node/x/audit/keeper" + "pkg.akt.dev/node/v2/x/audit/keeper" ) const ( diff --git a/x/audit/genesis.go b/x/audit/genesis.go index 0ffcffadf8..918f40a141 100644 --- a/x/audit/genesis.go +++ b/x/audit/genesis.go @@ -10,7 +10,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" types "pkg.akt.dev/go/node/audit/v1" - "pkg.akt.dev/node/x/audit/keeper" + "pkg.akt.dev/node/v2/x/audit/keeper" ) // ValidateGenesis does validation check of the Genesis and returns error in-case of failure diff --git a/x/audit/handler/handler.go b/x/audit/handler/handler.go index 112323a8e8..715ee040b8 100644 --- a/x/audit/handler/handler.go +++ b/x/audit/handler/handler.go @@ -9,7 +9,7 @@ import ( types "pkg.akt.dev/go/node/audit/v1" - "pkg.akt.dev/node/x/audit/keeper" + "pkg.akt.dev/node/v2/x/audit/keeper" ) // NewHandler returns a handler for "provider" type messages. diff --git a/x/audit/handler/handler_test.go b/x/audit/handler/handler_test.go index b1fecf6232..1c85a47028 100644 --- a/x/audit/handler/handler_test.go +++ b/x/audit/handler/handler_test.go @@ -23,8 +23,8 @@ import ( "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/x/audit/handler" - "pkg.akt.dev/node/x/audit/keeper" + "pkg.akt.dev/node/v2/x/audit/handler" + "pkg.akt.dev/node/v2/x/audit/keeper" ) type testSuite struct { diff --git a/x/audit/handler/msg_server.go b/x/audit/handler/msg_server.go index f5aac32c55..5628df5293 100644 --- a/x/audit/handler/msg_server.go +++ b/x/audit/handler/msg_server.go @@ -7,7 +7,7 @@ import ( types "pkg.akt.dev/go/node/audit/v1" - "pkg.akt.dev/node/x/audit/keeper" + "pkg.akt.dev/node/v2/x/audit/keeper" ) type msgServer struct { diff --git a/x/audit/keeper/grpc_query_test.go b/x/audit/keeper/grpc_query_test.go index f267e7ff7c..069b2b796e 100644 --- a/x/audit/keeper/grpc_query_test.go +++ b/x/audit/keeper/grpc_query_test.go @@ -13,8 +13,8 @@ import ( types "pkg.akt.dev/go/node/audit/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/app" - "pkg.akt.dev/node/x/audit/keeper" + "pkg.akt.dev/node/v2/app" + "pkg.akt.dev/node/v2/x/audit/keeper" ) type grpcTestSuite struct { @@ -31,7 +31,7 @@ func setupTest(t *testing.T) *grpcTestSuite { t: t, } - suite.app = app.Setup(app.WithGenesis(app.GenesisStateWithValSet)) + suite.app = app.Setup(app.WithHome(t.TempDir()), app.WithGenesis(app.GenesisStateWithValSet)) suite.ctx, suite.keeper = setupKeeper(t) querier := keeper.Querier{Keeper: suite.keeper} diff --git a/x/audit/keeper/keeper_test.go b/x/audit/keeper/keeper_test.go index 23f1f05215..4b2b17a83c 100644 --- a/x/audit/keeper/keeper_test.go +++ b/x/audit/keeper/keeper_test.go @@ -21,7 +21,7 @@ import ( types "pkg.akt.dev/go/node/audit/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/x/audit/keeper" + "pkg.akt.dev/node/v2/x/audit/keeper" ) func TestProviderCreate(t *testing.T) { diff --git a/x/audit/keeper/key.go b/x/audit/keeper/key.go index 75cf186c2f..e0e03dd5a9 100644 --- a/x/audit/keeper/key.go +++ b/x/audit/keeper/key.go @@ -10,7 +10,7 @@ import ( types "pkg.akt.dev/go/node/audit/v1" - "pkg.akt.dev/node/util/validation" + "pkg.akt.dev/node/v2/util/validation" ) func ProviderKey(id types.ProviderID) []byte { diff --git a/x/audit/module.go b/x/audit/module.go index b4d0078e2e..c70f068c21 100644 --- a/x/audit/module.go +++ b/x/audit/module.go @@ -19,8 +19,8 @@ import ( types "pkg.akt.dev/go/node/audit/v1" - "pkg.akt.dev/node/x/audit/handler" - "pkg.akt.dev/node/x/audit/keeper" + "pkg.akt.dev/node/v2/x/audit/handler" + "pkg.akt.dev/node/v2/x/audit/keeper" ) var ( @@ -35,17 +35,17 @@ var ( _ module.AppModuleSimulation = AppModule{} ) -// AppModuleBasic defines the basic application module used by the provider module. +// AppModuleBasic defines the basic application module used by the audit module. type AppModuleBasic struct { cdc codec.Codec } -// Name returns provider module's name +// Name returns audit module's name func (AppModuleBasic) Name() string { return types.ModuleName } -// RegisterLegacyAminoCodec registers the provider module's types for the given codec. +// RegisterLegacyAminoCodec registers the audit module's types for the given codec. func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { types.RegisterLegacyAminoCodec(cdc) // nolint: staticcheck } @@ -55,8 +55,7 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) types.RegisterInterfaces(registry) } -// DefaultGenesis returns default genesis state as raw bytes for the provider -// module. +// DefaultGenesis returns default genesis state as raw bytes for the audit module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(DefaultGenesisState()) } @@ -84,7 +83,7 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingCo // rest.RegisterRoutes(clientCtx, rtr, StoreKey) // } -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the provider module. +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the audit module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) if err != nil { @@ -166,7 +165,7 @@ func (am AppModule) BeginBlock(_ context.Context) error { return nil } -// EndBlock returns the end blocker for the deployment module. It returns no validator +// EndBlock returns the end blocker for the audit module. It returns no validator // updates. func (am AppModule) EndBlock(_ context.Context) error { return nil diff --git a/x/cert/alias.go b/x/cert/alias.go index 97dc00d932..e146a74674 100644 --- a/x/cert/alias.go +++ b/x/cert/alias.go @@ -3,7 +3,7 @@ package cert import ( types "pkg.akt.dev/go/node/cert/v1" - "pkg.akt.dev/node/x/cert/keeper" + "pkg.akt.dev/node/v2/x/cert/keeper" ) const ( diff --git a/x/cert/genesis.go b/x/cert/genesis.go index 5e902d4f24..0e5cd4c01c 100644 --- a/x/cert/genesis.go +++ b/x/cert/genesis.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "pkg.akt.dev/node/x/cert/keeper" + "pkg.akt.dev/node/v2/x/cert/keeper" types "pkg.akt.dev/go/node/cert/v1" ) diff --git a/x/cert/handler/handler.go b/x/cert/handler/handler.go index e80a034e42..e8761292f3 100644 --- a/x/cert/handler/handler.go +++ b/x/cert/handler/handler.go @@ -7,7 +7,7 @@ import ( types "pkg.akt.dev/go/node/cert/v1" - "pkg.akt.dev/node/x/cert/keeper" + "pkg.akt.dev/node/v2/x/cert/keeper" ) // NewHandler returns a handler for "provider" type messages. diff --git a/x/cert/handler/handler_test.go b/x/cert/handler/handler_test.go index 73345eef06..ee5535d7e8 100644 --- a/x/cert/handler/handler_test.go +++ b/x/cert/handler/handler_test.go @@ -22,8 +22,8 @@ import ( types "pkg.akt.dev/go/node/cert/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/x/cert/handler" - "pkg.akt.dev/node/x/cert/keeper" + "pkg.akt.dev/node/v2/x/cert/handler" + "pkg.akt.dev/node/v2/x/cert/keeper" ) type testSuite struct { diff --git a/x/cert/handler/msg_server.go b/x/cert/handler/msg_server.go index b92685765e..39201cdd51 100644 --- a/x/cert/handler/msg_server.go +++ b/x/cert/handler/msg_server.go @@ -7,7 +7,7 @@ import ( types "pkg.akt.dev/go/node/cert/v1" - "pkg.akt.dev/node/x/cert/keeper" + "pkg.akt.dev/node/v2/x/cert/keeper" ) type msgServer struct { diff --git a/x/cert/keeper/grpc_query.go b/x/cert/keeper/grpc_query.go index 9826cb2ba2..1b61a0e01b 100644 --- a/x/cert/keeper/grpc_query.go +++ b/x/cert/keeper/grpc_query.go @@ -12,7 +12,7 @@ import ( types "pkg.akt.dev/go/node/cert/v1" - "pkg.akt.dev/node/util/query" + "pkg.akt.dev/node/v2/util/query" ) // Querier is used as Keeper will have duplicate methods if used directly, and gRPC names take precedence over keeper diff --git a/x/cert/keeper/grpc_query_test.go b/x/cert/keeper/grpc_query_test.go index 44ee036d71..6eb3bfb95a 100644 --- a/x/cert/keeper/grpc_query_test.go +++ b/x/cert/keeper/grpc_query_test.go @@ -14,8 +14,8 @@ import ( types "pkg.akt.dev/go/node/cert/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/app" - "pkg.akt.dev/node/x/cert/keeper" + "pkg.akt.dev/node/v2/app" + "pkg.akt.dev/node/v2/x/cert/keeper" ) type grpcTestSuite struct { diff --git a/x/cert/keeper/keeper_test.go b/x/cert/keeper/keeper_test.go index 83da5c9142..55a5d2dfa3 100644 --- a/x/cert/keeper/keeper_test.go +++ b/x/cert/keeper/keeper_test.go @@ -19,7 +19,7 @@ import ( types "pkg.akt.dev/go/node/cert/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/x/cert/keeper" + "pkg.akt.dev/node/v2/x/cert/keeper" ) func TestCertKeeperCreate(t *testing.T) { diff --git a/x/cert/keeper/key.go b/x/cert/keeper/key.go index 87f02a7d35..1e1e8e0573 100644 --- a/x/cert/keeper/key.go +++ b/x/cert/keeper/key.go @@ -13,7 +13,7 @@ import ( types "pkg.akt.dev/go/node/cert/v1" - "pkg.akt.dev/node/util/validation" + "pkg.akt.dev/node/v2/util/validation" ) const ( diff --git a/x/cert/module.go b/x/cert/module.go index 29b5e14259..b4edb9898e 100644 --- a/x/cert/module.go +++ b/x/cert/module.go @@ -18,9 +18,9 @@ import ( types "pkg.akt.dev/go/node/cert/v1" - "pkg.akt.dev/node/x/cert/handler" - "pkg.akt.dev/node/x/cert/keeper" - "pkg.akt.dev/node/x/cert/simulation" + "pkg.akt.dev/node/v2/x/cert/handler" + "pkg.akt.dev/node/v2/x/cert/keeper" + "pkg.akt.dev/node/v2/x/cert/simulation" ) var ( @@ -35,23 +35,23 @@ var ( _ module.AppModuleSimulation = AppModule{} ) -// AppModuleBasic defines the basic application module used by the provider module. +// AppModuleBasic defines the basic application module used by the cert module. type AppModuleBasic struct { cdc codec.Codec } -// AppModule implements an application module for the audit module. +// AppModule implements an application module for the cert module. type AppModule struct { AppModuleBasic keeper keeper.Keeper } -// Name returns provider module's name +// Name returns cert module's name func (AppModuleBasic) Name() string { return types.ModuleName } -// RegisterLegacyAminoCodec registers the provider module's types for the given codec. +// RegisterLegacyAminoCodec registers the cert module's types for the given codec. func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { types.RegisterLegacyAminoCodec(cdc) // nolint: staticcheck } @@ -61,8 +61,7 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) types.RegisterInterfaces(registry) } -// DefaultGenesis returns default genesis state as raw bytes for the provider -// module. +// DefaultGenesis returns default genesis state as raw bytes for the cert module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(DefaultGenesisState()) } @@ -83,7 +82,7 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingCo return ValidateGenesis(&data) } -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the provider module. +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the cert module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) if err != nil { @@ -136,7 +135,7 @@ func (am AppModule) BeginBlock(_ context.Context) error { return nil } -// EndBlock returns the end blocker for the deployment module. It returns no validator +// EndBlock returns the end blocker for the cert module. It returns no validator // updates. func (am AppModule) EndBlock(_ context.Context) error { return nil diff --git a/x/cert/utils/key_pair_manager.go b/x/cert/utils/key_pair_manager.go index 5ab6776154..8132b92e2a 100644 --- a/x/cert/utils/key_pair_manager.go +++ b/x/cert/utils/key_pair_manager.go @@ -27,7 +27,7 @@ import ( types "pkg.akt.dev/go/node/cert/v1" - certerrors "pkg.akt.dev/node/x/cert/errors" + certerrors "pkg.akt.dev/node/v2/x/cert/errors" ) var ( diff --git a/x/cert/utils/utils.go b/x/cert/utils/utils.go index 19f854e980..66c9806d2a 100644 --- a/x/cert/utils/utils.go +++ b/x/cert/utils/utils.go @@ -7,7 +7,7 @@ import ( "io" "time" - certerrors "pkg.akt.dev/node/x/cert/errors" + certerrors "pkg.akt.dev/node/v2/x/cert/errors" "github.com/cosmos/cosmos-sdk/client" diff --git a/x/deployment/alias.go b/x/deployment/alias.go index 8ffc73a9b0..b38bec9771 100644 --- a/x/deployment/alias.go +++ b/x/deployment/alias.go @@ -3,7 +3,7 @@ package deployment import ( types "pkg.akt.dev/go/node/deployment/v1" - "pkg.akt.dev/node/x/deployment/keeper" + "pkg.akt.dev/node/v2/x/deployment/keeper" ) const ( diff --git a/x/deployment/genesis.go b/x/deployment/genesis.go index e60754a3bb..32fac6183c 100644 --- a/x/deployment/genesis.go +++ b/x/deployment/genesis.go @@ -10,7 +10,7 @@ import ( "pkg.akt.dev/go/node/deployment/v1" "pkg.akt.dev/go/node/deployment/v1beta4" - "pkg.akt.dev/node/x/deployment/keeper" + "pkg.akt.dev/node/v2/x/deployment/keeper" ) // ValidateGenesis does validation check of the Genesis and return error in case of failure diff --git a/x/deployment/handler/handler.go b/x/deployment/handler/handler.go index 865b819961..e788711a6f 100644 --- a/x/deployment/handler/handler.go +++ b/x/deployment/handler/handler.go @@ -7,7 +7,7 @@ import ( types "pkg.akt.dev/go/node/deployment/v1beta4" - "pkg.akt.dev/node/x/deployment/keeper" + "pkg.akt.dev/node/v2/x/deployment/keeper" ) // NewHandler returns a handler for "deployment" type messages diff --git a/x/deployment/handler/handler_test.go b/x/deployment/handler/handler_test.go index 4752b53eba..4f91eb88f1 100644 --- a/x/deployment/handler/handler_test.go +++ b/x/deployment/handler/handler_test.go @@ -27,12 +27,12 @@ import ( deposit "pkg.akt.dev/go/node/types/deposit/v1" "pkg.akt.dev/go/testutil" - cmocks "pkg.akt.dev/node/testutil/cosmos/mocks" - "pkg.akt.dev/node/testutil/state" - "pkg.akt.dev/node/x/deployment/handler" - "pkg.akt.dev/node/x/deployment/keeper" - ehandler "pkg.akt.dev/node/x/escrow/handler" - mkeeper "pkg.akt.dev/node/x/market/keeper" + cmocks "pkg.akt.dev/node/v2/testutil/cosmos/mocks" + "pkg.akt.dev/node/v2/testutil/state" + "pkg.akt.dev/node/v2/x/deployment/handler" + "pkg.akt.dev/node/v2/x/deployment/keeper" + ehandler "pkg.akt.dev/node/v2/x/escrow/handler" + mkeeper "pkg.akt.dev/node/v2/x/market/keeper" ) type testSuite struct { diff --git a/x/deployment/handler/server.go b/x/deployment/handler/server.go index 54f6b2a6e4..dace203894 100644 --- a/x/deployment/handler/server.go +++ b/x/deployment/handler/server.go @@ -11,7 +11,7 @@ import ( v1 "pkg.akt.dev/go/node/deployment/v1" types "pkg.akt.dev/go/node/deployment/v1beta4" - "pkg.akt.dev/node/x/deployment/keeper" + "pkg.akt.dev/node/v2/x/deployment/keeper" ) var _ types.MsgServer = msgServer{} diff --git a/x/deployment/keeper/grpc_query.go b/x/deployment/keeper/grpc_query.go index 14d75f97bc..a4bf7964e3 100644 --- a/x/deployment/keeper/grpc_query.go +++ b/x/deployment/keeper/grpc_query.go @@ -14,7 +14,7 @@ import ( "pkg.akt.dev/go/node/deployment/v1" types "pkg.akt.dev/go/node/deployment/v1beta4" - "pkg.akt.dev/node/util/query" + "pkg.akt.dev/node/v2/util/query" ) // Querier is used as Keeper will have duplicate methods if used directly, and gRPC names take precedence over keeper diff --git a/x/deployment/keeper/grpc_query_test.go b/x/deployment/keeper/grpc_query_test.go index cdcb093dc7..4e2b262cd5 100644 --- a/x/deployment/keeper/grpc_query_test.go +++ b/x/deployment/keeper/grpc_query_test.go @@ -19,10 +19,10 @@ import ( eid "pkg.akt.dev/go/node/escrow/id/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/app" - "pkg.akt.dev/node/testutil/state" - "pkg.akt.dev/node/x/deployment/keeper" - ekeeper "pkg.akt.dev/node/x/escrow/keeper" + "pkg.akt.dev/node/v2/app" + "pkg.akt.dev/node/v2/testutil/state" + "pkg.akt.dev/node/v2/x/deployment/keeper" + ekeeper "pkg.akt.dev/node/v2/x/escrow/keeper" ) type grpcTestSuite struct { diff --git a/x/deployment/keeper/keeper_test.go b/x/deployment/keeper/keeper_test.go index 834edec661..097207ca33 100644 --- a/x/deployment/keeper/keeper_test.go +++ b/x/deployment/keeper/keeper_test.go @@ -11,8 +11,8 @@ import ( types "pkg.akt.dev/go/node/deployment/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/testutil/state" - "pkg.akt.dev/node/x/deployment/keeper" + "pkg.akt.dev/node/v2/testutil/state" + "pkg.akt.dev/node/v2/x/deployment/keeper" ) func Test_Create(t *testing.T) { diff --git a/x/deployment/module.go b/x/deployment/module.go index a6a8bcc87a..693ecafa32 100644 --- a/x/deployment/module.go +++ b/x/deployment/module.go @@ -22,9 +22,9 @@ import ( types "pkg.akt.dev/go/node/deployment/v1beta4" "pkg.akt.dev/go/node/migrate" - "pkg.akt.dev/node/x/deployment/handler" - "pkg.akt.dev/node/x/deployment/keeper" - "pkg.akt.dev/node/x/deployment/simulation" + "pkg.akt.dev/node/v2/x/deployment/handler" + "pkg.akt.dev/node/v2/x/deployment/keeper" + "pkg.akt.dev/node/v2/x/deployment/simulation" ) // type check to ensure the interface is properly implemented diff --git a/x/deployment/simulation/operations.go b/x/deployment/simulation/operations.go index c3c87c291b..ab8d5790d8 100644 --- a/x/deployment/simulation/operations.go +++ b/x/deployment/simulation/operations.go @@ -21,9 +21,9 @@ import ( sdlv1 "pkg.akt.dev/go/sdl" - appparams "pkg.akt.dev/node/app/params" - testsim "pkg.akt.dev/node/testutil/sim" - "pkg.akt.dev/node/x/deployment/keeper" + appparams "pkg.akt.dev/node/v2/app/params" + testsim "pkg.akt.dev/node/v2/testutil/sim" + "pkg.akt.dev/node/v2/x/deployment/keeper" ) // Simulation operation weights constants diff --git a/x/escrow/genesis.go b/x/escrow/genesis.go index 07eb8152b5..573472a920 100644 --- a/x/escrow/genesis.go +++ b/x/escrow/genesis.go @@ -11,7 +11,7 @@ import ( emodule "pkg.akt.dev/go/node/escrow/module" etypes "pkg.akt.dev/go/node/escrow/types/v1" - "pkg.akt.dev/node/x/escrow/keeper" + "pkg.akt.dev/node/v2/x/escrow/keeper" types "pkg.akt.dev/go/node/escrow/v1" ) diff --git a/x/escrow/handler/handler.go b/x/escrow/handler/handler.go index a4a227418d..9479c61cff 100644 --- a/x/escrow/handler/handler.go +++ b/x/escrow/handler/handler.go @@ -6,7 +6,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" types "pkg.akt.dev/go/node/escrow/v1" - "pkg.akt.dev/node/x/escrow/keeper" + "pkg.akt.dev/node/v2/x/escrow/keeper" ) // NewHandler returns a handler for "deployment" type messages diff --git a/x/escrow/handler/server.go b/x/escrow/handler/server.go index d86e52bdfd..7798286e30 100644 --- a/x/escrow/handler/server.go +++ b/x/escrow/handler/server.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" types "pkg.akt.dev/go/node/escrow/v1" - "pkg.akt.dev/node/x/escrow/keeper" + "pkg.akt.dev/node/v2/x/escrow/keeper" ) var _ types.MsgServer = msgServer{} diff --git a/x/escrow/keeper/grpc_query.go b/x/escrow/keeper/grpc_query.go index 256bd3ba3d..5bc0be690f 100644 --- a/x/escrow/keeper/grpc_query.go +++ b/x/escrow/keeper/grpc_query.go @@ -13,7 +13,7 @@ import ( types "pkg.akt.dev/go/node/escrow/types/v1" "pkg.akt.dev/go/node/escrow/v1" - "pkg.akt.dev/node/util/query" + "pkg.akt.dev/node/v2/util/query" ) // Querier is used as Keeper will have duplicate methods if used directly, and gRPC names take precedence over keeper diff --git a/x/escrow/keeper/grpc_query_test.go b/x/escrow/keeper/grpc_query_test.go index 56fa1dde4e..d6a134695b 100644 --- a/x/escrow/keeper/grpc_query_test.go +++ b/x/escrow/keeper/grpc_query_test.go @@ -20,9 +20,9 @@ import ( deposit "pkg.akt.dev/go/node/types/deposit/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/app" - "pkg.akt.dev/node/testutil/state" - ekeeper "pkg.akt.dev/node/x/escrow/keeper" + "pkg.akt.dev/node/v2/app" + "pkg.akt.dev/node/v2/testutil/state" + ekeeper "pkg.akt.dev/node/v2/x/escrow/keeper" ) type grpcTestSuite struct { diff --git a/x/escrow/keeper/keeper_test.go b/x/escrow/keeper/keeper_test.go index b7c14d1d30..b844bc5cfd 100644 --- a/x/escrow/keeper/keeper_test.go +++ b/x/escrow/keeper/keeper_test.go @@ -14,7 +14,7 @@ import ( etypes "pkg.akt.dev/go/node/escrow/types/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/testutil/state" + "pkg.akt.dev/node/v2/testutil/state" ) type kTestSuite struct { diff --git a/x/escrow/module.go b/x/escrow/module.go index 92ffd660d1..c39faeaa1e 100644 --- a/x/escrow/module.go +++ b/x/escrow/module.go @@ -20,9 +20,9 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" v1 "pkg.akt.dev/go/node/escrow/v1" - "pkg.akt.dev/node/x/escrow/client/rest" - "pkg.akt.dev/node/x/escrow/handler" - "pkg.akt.dev/node/x/escrow/keeper" + "pkg.akt.dev/node/v2/x/escrow/client/rest" + "pkg.akt.dev/node/v2/x/escrow/handler" + "pkg.akt.dev/node/v2/x/escrow/keeper" ) var ( @@ -37,17 +37,17 @@ var ( _ module.AppModuleSimulation = AppModule{} ) -// AppModuleBasic defines the basic application module used by the provider module. +// AppModuleBasic defines the basic application module used by the escrow module. type AppModuleBasic struct { cdc codec.Codec } -// Name returns provider module's name +// Name returns escrow module's name func (AppModuleBasic) Name() string { return emodule.ModuleName } -// RegisterLegacyAminoCodec registers the provider module's types for the given codec. +// RegisterLegacyAminoCodec registers the escrow module's types for the given codec. func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { v1.RegisterLegacyAminoCodec(cdc) } @@ -57,8 +57,7 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) v1.RegisterInterfaces(registry) } -// DefaultGenesis returns default genesis state as raw bytes for the provider -// module. +// DefaultGenesis returns default genesis state as raw bytes for the escrow module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(DefaultGenesisState()) } @@ -84,7 +83,7 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout rest.RegisterRoutes(clientCtx, rtr, emodule.StoreKey) } -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the provider module. +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the escrow module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { err := v1.RegisterQueryHandlerClient(context.Background(), mux, v1.NewQueryClient(clientCtx)) if err != nil { @@ -162,7 +161,7 @@ func (am AppModule) BeginBlock(_ context.Context) error { return nil } -// EndBlock returns the end blocker for the deployment module. It returns no validator +// EndBlock returns the end blocker for the escrow module. It returns no validator // updates. func (am AppModule) EndBlock(_ context.Context) error { return nil diff --git a/x/escrow/query/querier.go b/x/escrow/query/querier.go index 8e8e47f68f..76db96d258 100644 --- a/x/escrow/query/querier.go +++ b/x/escrow/query/querier.go @@ -4,7 +4,7 @@ package query // "github.com/cosmos/cosmos-sdk/codec" // sdk "github.com/cosmos/cosmos-sdk/types" // -// "pkg.akt.dev/node/x/escrow/keeper" +// "pkg.akt.dev/node/v2/x/escrow/keeper" // ) // // func NewQuerier(keeper keeper.Keeper, cdc *codec.LegacyAmino) sdk.Querier { diff --git a/x/market/alias.go b/x/market/alias.go index 330e4913e5..322dd0f07e 100644 --- a/x/market/alias.go +++ b/x/market/alias.go @@ -3,7 +3,7 @@ package market import ( v1 "pkg.akt.dev/go/node/market/v1" - "pkg.akt.dev/node/x/market/keeper" + "pkg.akt.dev/node/v2/x/market/keeper" ) const ( diff --git a/x/market/client/rest/params.go b/x/market/client/rest/params.go index a51bb5fe78..eabee87ad5 100644 --- a/x/market/client/rest/params.go +++ b/x/market/client/rest/params.go @@ -8,7 +8,7 @@ package rest // "pkg.akt.dev/go/node/market/v1" // "pkg.akt.dev/go/node/market/v1beta5" // -// drest "pkg.akt.dev/node/x/deployment/client/rest" +// drest "pkg.akt.dev/node/v2/x/deployment/client/rest" // ) // // // OrderIDFromRequest returns OrderID from parsing request diff --git a/x/market/client/rest/rest.go b/x/market/client/rest/rest.go index 3cadc1c21a..7ab1a06606 100644 --- a/x/market/client/rest/rest.go +++ b/x/market/client/rest/rest.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/gorilla/mux" - // "pkg.akt.dev/node/x/market/query" + // "pkg.akt.dev/node/v2/x/market/query" ) // RegisterRoutes registers all query routes diff --git a/x/market/genesis.go b/x/market/genesis.go index 99485cd201..6bf8f54bc9 100644 --- a/x/market/genesis.go +++ b/x/market/genesis.go @@ -10,8 +10,8 @@ import ( "pkg.akt.dev/go/node/market/v1" "pkg.akt.dev/go/node/market/v1beta5" - "pkg.akt.dev/node/x/market/keeper" - "pkg.akt.dev/node/x/market/keeper/keys" + "pkg.akt.dev/node/v2/x/market/keeper" + "pkg.akt.dev/node/v2/x/market/keeper/keys" ) // ValidateGenesis does validation check of the Genesis diff --git a/x/market/handler/handler_test.go b/x/market/handler/handler_test.go index cc7641ee9d..276fea1bb6 100644 --- a/x/market/handler/handler_test.go +++ b/x/market/handler/handler_test.go @@ -29,10 +29,10 @@ import ( deposit "pkg.akt.dev/go/node/types/deposit/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/testutil/state" - dhandler "pkg.akt.dev/node/x/deployment/handler" - ehandler "pkg.akt.dev/node/x/escrow/handler" - "pkg.akt.dev/node/x/market/handler" + "pkg.akt.dev/node/v2/testutil/state" + dhandler "pkg.akt.dev/node/v2/x/deployment/handler" + ehandler "pkg.akt.dev/node/v2/x/escrow/handler" + "pkg.akt.dev/node/v2/x/market/handler" ) type testSuite struct { diff --git a/x/market/handler/keepers.go b/x/market/handler/keepers.go index c9a3ca3423..c20d4ea05b 100644 --- a/x/market/handler/keepers.go +++ b/x/market/handler/keepers.go @@ -16,7 +16,7 @@ import ( etypes "pkg.akt.dev/go/node/escrow/types/v1" ptypes "pkg.akt.dev/go/node/provider/v1beta4" - "pkg.akt.dev/node/x/market/keeper" + "pkg.akt.dev/node/v2/x/market/keeper" ) type EscrowKeeper interface { diff --git a/x/market/keeper/grpc_query.go b/x/market/keeper/grpc_query.go index 4eb06ac8ff..bd4d431cf9 100644 --- a/x/market/keeper/grpc_query.go +++ b/x/market/keeper/grpc_query.go @@ -13,8 +13,8 @@ import ( "pkg.akt.dev/go/node/market/v1" types "pkg.akt.dev/go/node/market/v1beta5" - "pkg.akt.dev/node/util/query" - "pkg.akt.dev/node/x/market/keeper/keys" + "pkg.akt.dev/node/v2/util/query" + "pkg.akt.dev/node/v2/x/market/keeper/keys" ) // Querier is used as Keeper will have duplicate methods if used directly, and gRPC names take precedence over keeper diff --git a/x/market/keeper/grpc_query_test.go b/x/market/keeper/grpc_query_test.go index fc544c7ef5..c3d925ea37 100644 --- a/x/market/keeper/grpc_query_test.go +++ b/x/market/keeper/grpc_query_test.go @@ -17,8 +17,8 @@ import ( "pkg.akt.dev/go/node/market/v1beta5" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/testutil/state" - "pkg.akt.dev/node/x/market/keeper" + "pkg.akt.dev/node/v2/testutil/state" + "pkg.akt.dev/node/v2/x/market/keeper" ) type grpcTestSuite struct { diff --git a/x/market/keeper/keeper.go b/x/market/keeper/keeper.go index 413f713394..f96ec5e1db 100644 --- a/x/market/keeper/keeper.go +++ b/x/market/keeper/keeper.go @@ -12,7 +12,7 @@ import ( mv1 "pkg.akt.dev/go/node/market/v1" types "pkg.akt.dev/go/node/market/v1beta5" - "pkg.akt.dev/node/x/market/keeper/keys" + "pkg.akt.dev/node/v2/x/market/keeper/keys" ) type IKeeper interface { diff --git a/x/market/keeper/keeper_test.go b/x/market/keeper/keeper_test.go index b7aa87d68e..9286b8f5af 100644 --- a/x/market/keeper/keeper_test.go +++ b/x/market/keeper/keeper_test.go @@ -15,8 +15,8 @@ import ( deposit "pkg.akt.dev/go/node/types/deposit/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/testutil/state" - "pkg.akt.dev/node/x/market/keeper" + "pkg.akt.dev/node/v2/testutil/state" + "pkg.akt.dev/node/v2/x/market/keeper" ) func Test_CreateOrder(t *testing.T) { diff --git a/x/market/module.go b/x/market/module.go index cad5c0f872..ca360a3fa1 100644 --- a/x/market/module.go +++ b/x/market/module.go @@ -21,11 +21,11 @@ import ( bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" types "pkg.akt.dev/go/node/market/v1beta5" - akeeper "pkg.akt.dev/node/x/audit/keeper" - ekeeper "pkg.akt.dev/node/x/escrow/keeper" - "pkg.akt.dev/node/x/market/handler" - "pkg.akt.dev/node/x/market/keeper" - "pkg.akt.dev/node/x/market/simulation" + akeeper "pkg.akt.dev/node/v2/x/audit/keeper" + ekeeper "pkg.akt.dev/node/v2/x/escrow/keeper" + "pkg.akt.dev/node/v2/x/market/handler" + "pkg.akt.dev/node/v2/x/market/keeper" + "pkg.akt.dev/node/v2/x/market/simulation" ) // type check to ensure the interface is properly implemented @@ -156,7 +156,7 @@ func (am AppModule) BeginBlock(_ context.Context) error { return nil } -// EndBlock returns the end blocker for the deployment module. It returns no validator +// EndBlock returns the end blocker for the market module. It returns no validator // updates. func (am AppModule) EndBlock(_ context.Context) error { return nil diff --git a/x/market/query/path.go b/x/market/query/path.go index f686237048..161b648218 100644 --- a/x/market/query/path.go +++ b/x/market/query/path.go @@ -8,7 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" v1 "pkg.akt.dev/go/node/market/v1" - dpath "pkg.akt.dev/node/x/deployment/query" + dpath "pkg.akt.dev/node/v2/x/deployment/query" ) const ( diff --git a/x/market/simulation/operations.go b/x/market/simulation/operations.go index 7ee5552472..46870a75d8 100644 --- a/x/market/simulation/operations.go +++ b/x/market/simulation/operations.go @@ -17,9 +17,9 @@ import ( "pkg.akt.dev/go/node/market/v1" types "pkg.akt.dev/go/node/market/v1beta5" - appparams "pkg.akt.dev/node/app/params" - testsim "pkg.akt.dev/node/testutil/sim" - keepers "pkg.akt.dev/node/x/market/handler" + appparams "pkg.akt.dev/node/v2/app/params" + testsim "pkg.akt.dev/node/v2/testutil/sim" + keepers "pkg.akt.dev/node/v2/x/market/handler" ) // Simulation operation weights constants diff --git a/x/market/simulation/utils.go b/x/market/simulation/utils.go index 2b15153407..bfddde1b7f 100644 --- a/x/market/simulation/utils.go +++ b/x/market/simulation/utils.go @@ -6,7 +6,7 @@ import ( ptypes "pkg.akt.dev/go/node/provider/v1beta4" - keepers "pkg.akt.dev/node/x/market/handler" + keepers "pkg.akt.dev/node/v2/x/market/handler" ) func getOrdersWithState(ctx sdk.Context, ks keepers.Keepers, state v1beta5.Order_State) v1beta5.Orders { diff --git a/x/oracle/alias.go b/x/oracle/alias.go new file mode 100644 index 0000000000..32c4bd2ae2 --- /dev/null +++ b/x/oracle/alias.go @@ -0,0 +1,12 @@ +package wasm + +import ( + types "pkg.akt.dev/go/node/oracle/v1" +) + +const ( + // StoreKey represents storekey of wasm module + StoreKey = types.StoreKey + // ModuleName represents current module name + ModuleName = types.ModuleName +) diff --git a/x/oracle/genesis.go b/x/oracle/genesis.go new file mode 100644 index 0000000000..782b9b1393 --- /dev/null +++ b/x/oracle/genesis.go @@ -0,0 +1,39 @@ +package wasm + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + types "pkg.akt.dev/go/node/oracle/v1" + + "pkg.akt.dev/node/v2/x/oracle/keeper" +) + +// ValidateGenesis does validation check of the Genesis and return error incase of failure +func ValidateGenesis(data *types.GenesisState) error { + return data.Params.Validate() +} + +// DefaultGenesisState returns default genesis state as raw bytes for the deployment +// module. +func DefaultGenesisState() *types.GenesisState { + params := types.DefaultParams() + + return &types.GenesisState{ + Params: params, + } +} + +// InitGenesis initiate genesis state and return updated validator details +func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, data *types.GenesisState) { + err := keeper.SetParams(ctx, data.Params) + if err != nil { + panic(err.Error()) + } +} + +// ExportGenesis returns genesis state for the deployment module +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { + params := k.GetParams(ctx) + return &types.GenesisState{ + Params: params, + } +} diff --git a/x/oracle/handler/server.go b/x/oracle/handler/server.go new file mode 100644 index 0000000000..e4ceae3edb --- /dev/null +++ b/x/oracle/handler/server.go @@ -0,0 +1,39 @@ +package handler + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + types "pkg.akt.dev/go/node/oracle/v1" + + "pkg.akt.dev/node/v2/x/oracle/keeper" +) + +var _ types.MsgServer = msgServer{} + +type msgServer struct { + keeper keeper.Keeper +} + +// NewMsgServerImpl returns an implementation of the akash staking MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(k keeper.Keeper) types.MsgServer { + return &msgServer{ + keeper: k, + } +} + +func (ms msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { + if ms.keeper.GetAuthority() != req.Authority { + return nil, govtypes.ErrInvalidSigner.Wrapf("invalid authority; expected %s, got %s", ms.keeper.GetAuthority(), req.Authority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := ms.keeper.SetParams(ctx, req.Params); err != nil { + return nil, err + } + + return &types.MsgUpdateParamsResponse{}, nil +} diff --git a/x/oracle/keeper/grpc_query.go b/x/oracle/keeper/grpc_query.go new file mode 100644 index 0000000000..5573d402ef --- /dev/null +++ b/x/oracle/keeper/grpc_query.go @@ -0,0 +1,35 @@ +package keeper + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + sdk "github.com/cosmos/cosmos-sdk/types" + + types "pkg.akt.dev/go/node/oracle/v1" +) + +// Querier is used as Keeper will have duplicate methods if used directly, and gRPC names take precedence over keeper +type Querier struct { + Keeper +} + +func (k Querier) PriceFeedConfig(ctx context.Context, request *types.QueryPriceFeedConfigRequest) (*types.QueryPriceFeedConfigResponse, error) { + //TODO implement me + panic("implement me") +} + +var _ types.QueryServer = Querier{} + +func (k Querier) Params(ctx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + if req == nil { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + params := k.GetParams(sdkCtx) + + return &types.QueryParamsResponse{Params: params}, nil +} diff --git a/x/oracle/keeper/keeper.go b/x/oracle/keeper/keeper.go new file mode 100644 index 0000000000..37830b502d --- /dev/null +++ b/x/oracle/keeper/keeper.go @@ -0,0 +1,98 @@ +package keeper + +import ( + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + types "pkg.akt.dev/go/node/oracle/v1" +) + +type SetParamsHook func(sdk.Context, types.Params) + +type Keeper interface { + StoreKey() storetypes.StoreKey + Codec() codec.BinaryCodec + GetParams(ctx sdk.Context) (params types.Params) + SetParams(ctx sdk.Context, params types.Params) error + + NewQuerier() Querier + GetAuthority() string +} + +// Keeper of the deployment store +type keeper struct { + skey storetypes.StoreKey + cdc codec.BinaryCodec + hooks struct { + onSetParams []SetParamsHook + } + + // The address capable of executing an MsgUpdateParams message. + // This should be the x/gov module account. + authority string +} + +// NewKeeper creates and returns an instance of take keeper +func NewKeeper(cdc codec.BinaryCodec, skey storetypes.StoreKey, authority string) Keeper { + return &keeper{ + skey: skey, + cdc: cdc, + authority: authority, + } +} + +// Codec returns keeper codec +func (k *keeper) Codec() codec.BinaryCodec { + return k.cdc +} + +func (k *keeper) StoreKey() storetypes.StoreKey { + return k.skey +} + +func (k *keeper) NewQuerier() Querier { + return Querier{k} +} + +// GetAuthority returns the x/mint module's authority. +func (k *keeper) GetAuthority() string { + return k.authority +} + +// SetParams sets the x/take module parameters. +func (k *keeper) SetParams(ctx sdk.Context, p types.Params) error { + if err := p.Validate(); err != nil { + return err + } + + store := ctx.KVStore(k.skey) + bz := k.cdc.MustMarshal(&p) + store.Set(types.ParamsPrefix(), bz) + + // call hooks + for _, hook := range k.hooks.onSetParams { + hook(ctx, p) + } + + return nil +} + +// GetParams returns the current x/take module parameters. +func (k *keeper) GetParams(ctx sdk.Context) (p types.Params) { + store := ctx.KVStore(k.skey) + bz := store.Get(types.ParamsPrefix()) + if bz == nil { + return p + } + + k.cdc.MustUnmarshal(bz, &p) + + return p +} + +func (k *keeper) AddOnSetParamsHook(hook SetParamsHook) Keeper { + k.hooks.onSetParams = append(k.hooks.onSetParams, hook) + + return k +} diff --git a/x/oracle/module.go b/x/oracle/module.go new file mode 100644 index 0000000000..4419baca14 --- /dev/null +++ b/x/oracle/module.go @@ -0,0 +1,182 @@ +package wasm + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + "cosmossdk.io/core/appmodule" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + types "pkg.akt.dev/go/node/oracle/v1" + + "pkg.akt.dev/node/v2/x/oracle/handler" + "pkg.akt.dev/node/v2/x/oracle/keeper" + "pkg.akt.dev/node/v2/x/oracle/simulation" +) + +var ( + _ module.AppModuleBasic = AppModuleBasic{} + _ module.HasGenesisBasics = AppModuleBasic{} + + _ appmodule.AppModule = AppModule{} + _ module.HasConsensusVersion = AppModule{} + _ module.HasGenesis = AppModule{} + _ module.HasServices = AppModule{} + + _ module.AppModuleSimulation = AppModule{} +) + +// AppModuleBasic defines the basic application module used by the oracle module. +type AppModuleBasic struct { + cdc codec.Codec +} + +// AppModule implements an application module for the oracle module. +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper +} + +// Name returns oracle module's name +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the oracle module's types for the given codec. +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) // nolint staticcheck +} + +// RegisterInterfaces registers the module's interface types +func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// DefaultGenesis returns default genesis state as raw bytes for the oracle module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) +} + +// ValidateGenesis validation check of the Genesis +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + if bz == nil { + return nil + } + + var data types.GenesisState + + err := cdc.UnmarshalJSON(bz, &data) + if err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %v", types.ModuleName, err) + } + + return ValidateGenesis(&data) +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the oracle module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(cctx client.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(cctx)); err != nil { + panic(err) + } +} + +// GetQueryCmd returns the root query command of this module +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + panic("akash modules do not export cli commands via cosmos interface") +} + +// GetTxCmd returns the transaction commands for this module +func (AppModuleBasic) GetTxCmd() *cobra.Command { + panic("akash modules do not export cli commands via cosmos interface") +} + +// NewAppModule creates a new AppModule object +func NewAppModule(cdc codec.Codec, k keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{cdc: cdc}, + keeper: k, + } +} + +// Name returns the provider module name +func (AppModule) Name() string { + return types.ModuleName +} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (am AppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (am AppModule) IsAppModule() {} + +// QuerierRoute returns the oracle module's querier route name. +func (am AppModule) QuerierRoute() string { + return types.ModuleName +} + +// RegisterServices registers the module's services +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), handler.NewMsgServerImpl(am.keeper)) + querier := am.keeper.NewQuerier() + types.RegisterQueryServer(cfg.QueryServer(), querier) +} + +// BeginBlock performs no-op +func (am AppModule) BeginBlock(_ context.Context) error { + return nil +} + +// EndBlock returns the end blocker for the oracle module. It returns no validator +// updates. +func (am AppModule) EndBlock(_ context.Context) error { + return nil +} + +// InitGenesis performs genesis initialization for the oracle module. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) { + var genesisState types.GenesisState + cdc.MustUnmarshalJSON(data, &genesisState) + InitGenesis(ctx, am.keeper, &genesisState) +} + +// ExportGenesis returns the exported genesis state as raw bytes for the oracle +// module. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(gs) +} + +// ConsensusVersion implements module.AppModule#ConsensusVersion +func (am AppModule) ConsensusVersion() uint64 { + return 1 +} + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the staking module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(_ module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() +} + +// RegisterStoreDecoder registers a decoder for take module's types. +func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry) {} + +// WeightedOperations doesn't return any take module operation. +func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { + return nil +} diff --git a/x/oracle/simulation/decoder.go b/x/oracle/simulation/decoder.go new file mode 100644 index 0000000000..c1be5a2b23 --- /dev/null +++ b/x/oracle/simulation/decoder.go @@ -0,0 +1,17 @@ +package simulation + +// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's +// Value to the corresponding mint type. +// func NewDecodeStore(_ codec.Codec) func(kvA, kvB kv.Pair) string { +// return func(kvA, kvB kv.Pair) string { +// switch { +// case bytes.Equal(kvA.Key, types.MinterKey): +// var minterA, minterB types.Minter +// cdc.MustUnmarshal(kvA.Value, &minterA) +// cdc.MustUnmarshal(kvB.Value, &minterB) +// return fmt.Sprintf("%v\n%v", minterA, minterB) +// default: +// panic(fmt.Sprintf("invalid mint key %X", kvA.Key)) +// } +// } +// } diff --git a/x/oracle/simulation/genesis.go b/x/oracle/simulation/genesis.go new file mode 100644 index 0000000000..586df37a13 --- /dev/null +++ b/x/oracle/simulation/genesis.go @@ -0,0 +1,16 @@ +package simulation + +import ( + "github.com/cosmos/cosmos-sdk/types/module" + + types "pkg.akt.dev/go/node/oracle/v1" +) + +// RandomizedGenState generates a random GenesisState for supply +func RandomizedGenState(simState *module.SimulationState) { + takeGenesis := &types.GenesisState{ + Params: types.DefaultParams(), + } + + simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(takeGenesis) +} diff --git a/x/oracle/simulation/proposals.go b/x/oracle/simulation/proposals.go new file mode 100644 index 0000000000..b8a0332d57 --- /dev/null +++ b/x/oracle/simulation/proposals.go @@ -0,0 +1,42 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + + types "pkg.akt.dev/go/node/oracle/v1" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" //nolint:gosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateMsgUpdateParams, + ), + } +} + +func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // use the default gov module account address as authority + var authority sdk.AccAddress = address.Module("gov") + + params := types.DefaultParams() + + return &types.MsgUpdateParams{ + Authority: authority.String(), + Params: params, + } +} diff --git a/x/provider/alias.go b/x/provider/alias.go index 90407bcba8..3e64924663 100644 --- a/x/provider/alias.go +++ b/x/provider/alias.go @@ -3,7 +3,7 @@ package provider import ( types "pkg.akt.dev/go/node/provider/v1beta4" - "pkg.akt.dev/node/x/provider/keeper" + "pkg.akt.dev/node/v2/x/provider/keeper" ) const ( diff --git a/x/provider/genesis.go b/x/provider/genesis.go index 3e1c7ac179..1290febb4e 100644 --- a/x/provider/genesis.go +++ b/x/provider/genesis.go @@ -9,7 +9,7 @@ import ( types "pkg.akt.dev/go/node/provider/v1beta4" - "pkg.akt.dev/node/x/provider/keeper" + "pkg.akt.dev/node/v2/x/provider/keeper" ) // ValidateGenesis does validation check of the Genesis and returns error in case of failure diff --git a/x/provider/handler/handler.go b/x/provider/handler/handler.go index 4d2e742c0f..dc47e76ab5 100644 --- a/x/provider/handler/handler.go +++ b/x/provider/handler/handler.go @@ -7,8 +7,8 @@ import ( types "pkg.akt.dev/go/node/provider/v1beta4" - mkeeper "pkg.akt.dev/node/x/market/keeper" - "pkg.akt.dev/node/x/provider/keeper" + mkeeper "pkg.akt.dev/node/v2/x/market/keeper" + "pkg.akt.dev/node/v2/x/provider/keeper" ) // NewHandler returns a handler for "provider" type messages. diff --git a/x/provider/handler/handler_test.go b/x/provider/handler/handler_test.go index bd13daff5c..4438368f97 100644 --- a/x/provider/handler/handler_test.go +++ b/x/provider/handler/handler_test.go @@ -15,10 +15,10 @@ import ( akashtypes "pkg.akt.dev/go/node/types/attributes/v1" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/testutil/state" - mkeeper "pkg.akt.dev/node/x/market/keeper" - "pkg.akt.dev/node/x/provider/handler" - "pkg.akt.dev/node/x/provider/keeper" + "pkg.akt.dev/node/v2/testutil/state" + mkeeper "pkg.akt.dev/node/v2/x/market/keeper" + "pkg.akt.dev/node/v2/x/provider/handler" + "pkg.akt.dev/node/v2/x/provider/keeper" ) const ( diff --git a/x/provider/handler/server.go b/x/provider/handler/server.go index d353df7fd2..045d01003a 100644 --- a/x/provider/handler/server.go +++ b/x/provider/handler/server.go @@ -8,8 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" types "pkg.akt.dev/go/node/provider/v1beta4" - mkeeper "pkg.akt.dev/node/x/market/keeper" - "pkg.akt.dev/node/x/provider/keeper" + mkeeper "pkg.akt.dev/node/v2/x/market/keeper" + "pkg.akt.dev/node/v2/x/provider/keeper" ) var ( diff --git a/x/provider/keeper/grpc_query_test.go b/x/provider/keeper/grpc_query_test.go index 06891f9c16..0d63ffdd76 100644 --- a/x/provider/keeper/grpc_query_test.go +++ b/x/provider/keeper/grpc_query_test.go @@ -13,9 +13,9 @@ import ( types "pkg.akt.dev/go/node/provider/v1beta4" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/app" - "pkg.akt.dev/node/testutil/state" - "pkg.akt.dev/node/x/provider/keeper" + "pkg.akt.dev/node/v2/app" + "pkg.akt.dev/node/v2/testutil/state" + "pkg.akt.dev/node/v2/x/provider/keeper" ) type grpcTestSuite struct { diff --git a/x/provider/keeper/keeper_test.go b/x/provider/keeper/keeper_test.go index a65852bfaf..cb55306c1e 100644 --- a/x/provider/keeper/keeper_test.go +++ b/x/provider/keeper/keeper_test.go @@ -10,8 +10,8 @@ import ( types "pkg.akt.dev/go/node/provider/v1beta4" "pkg.akt.dev/go/testutil" - "pkg.akt.dev/node/testutil/state" - "pkg.akt.dev/node/x/provider/keeper" + "pkg.akt.dev/node/v2/testutil/state" + "pkg.akt.dev/node/v2/x/provider/keeper" ) func TestProviderCreate(t *testing.T) { diff --git a/x/provider/module.go b/x/provider/module.go index 4123e310c1..5338be45b4 100644 --- a/x/provider/module.go +++ b/x/provider/module.go @@ -20,10 +20,10 @@ import ( types "pkg.akt.dev/go/node/provider/v1beta4" - mkeeper "pkg.akt.dev/node/x/market/keeper" - "pkg.akt.dev/node/x/provider/handler" - "pkg.akt.dev/node/x/provider/keeper" - "pkg.akt.dev/node/x/provider/simulation" + mkeeper "pkg.akt.dev/node/v2/x/market/keeper" + "pkg.akt.dev/node/v2/x/provider/handler" + "pkg.akt.dev/node/v2/x/provider/keeper" + "pkg.akt.dev/node/v2/x/provider/simulation" ) // type check to ensure the interface is properly implemented @@ -69,8 +69,7 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) types.RegisterInterfaces(registry) } -// DefaultGenesis returns default genesis state as raw bytes for the provider -// module. +// DefaultGenesis returns default genesis state as raw bytes for the provider module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(DefaultGenesisState()) } @@ -143,7 +142,7 @@ func (am AppModule) BeginBlock(_ context.Context) error { return nil } -// EndBlock returns the end blocker for the deployment module. It returns no validator +// EndBlock returns the end blocker for the provider module. It returns no validator // updates. func (am AppModule) EndBlock(_ context.Context) error { return nil diff --git a/x/provider/simulation/operations.go b/x/provider/simulation/operations.go index 7eb0286518..eee7469290 100644 --- a/x/provider/simulation/operations.go +++ b/x/provider/simulation/operations.go @@ -19,10 +19,10 @@ import ( types "pkg.akt.dev/go/node/provider/v1beta4" - appparams "pkg.akt.dev/node/app/params" - testsim "pkg.akt.dev/node/testutil/sim" - "pkg.akt.dev/node/x/provider/config" - "pkg.akt.dev/node/x/provider/keeper" + appparams "pkg.akt.dev/node/v2/app/params" + testsim "pkg.akt.dev/node/v2/testutil/sim" + "pkg.akt.dev/node/v2/x/provider/config" + "pkg.akt.dev/node/v2/x/provider/keeper" ) // Simulation operation weights constants diff --git a/x/take/genesis.go b/x/take/genesis.go index 7391ab625b..02a2713cd8 100644 --- a/x/take/genesis.go +++ b/x/take/genesis.go @@ -5,7 +5,7 @@ import ( types "pkg.akt.dev/go/node/take/v1" - "pkg.akt.dev/node/x/take/keeper" + "pkg.akt.dev/node/v2/x/take/keeper" ) // ValidateGenesis does validation check of the Genesis and return error incase of failure diff --git a/x/take/handler/server.go b/x/take/handler/server.go index 1dcdb75acf..01cd806b3e 100644 --- a/x/take/handler/server.go +++ b/x/take/handler/server.go @@ -8,7 +8,7 @@ import ( types "pkg.akt.dev/go/node/take/v1" - "pkg.akt.dev/node/x/take/keeper" + "pkg.akt.dev/node/v2/x/take/keeper" ) var _ types.MsgServer = msgServer{} diff --git a/x/take/module.go b/x/take/module.go index fb16f4ea61..62e9130c80 100644 --- a/x/take/module.go +++ b/x/take/module.go @@ -17,9 +17,9 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" types "pkg.akt.dev/go/node/take/v1" - "pkg.akt.dev/node/x/take/handler" - "pkg.akt.dev/node/x/take/keeper" - "pkg.akt.dev/node/x/take/simulation" + "pkg.akt.dev/node/v2/x/take/handler" + "pkg.akt.dev/node/v2/x/take/keeper" + "pkg.akt.dev/node/v2/x/take/simulation" ) var ( @@ -34,7 +34,7 @@ var ( _ module.AppModuleSimulation = AppModule{} ) -// AppModuleBasic defines the basic application module used by the provider module. +// AppModuleBasic defines the basic application module used by the take module. type AppModuleBasic struct { cdc codec.Codec } @@ -45,12 +45,12 @@ type AppModule struct { keeper keeper.IKeeper } -// Name returns provider module's name +// Name returns take module's name func (AppModuleBasic) Name() string { return types.ModuleName } -// RegisterLegacyAminoCodec registers the provider module's types for the given codec. +// RegisterLegacyAminoCodec registers the take module's types for the given codec. func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { types.RegisterLegacyAminoCodec(cdc) // nolint staticcheck } @@ -60,8 +60,7 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) types.RegisterInterfaces(registry) } -// DefaultGenesis returns default genesis state as raw bytes for the provider -// module. +// DefaultGenesis returns default genesis state as raw bytes for the take module. func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(DefaultGenesisState()) } @@ -82,7 +81,7 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingCo return ValidateGenesis(&data) } -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the provider module. +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the take module. func (AppModuleBasic) RegisterGRPCGatewayRoutes(cctx client.Context, mux *runtime.ServeMux) { if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(cctx)); err != nil { panic(err) @@ -135,7 +134,7 @@ func (am AppModule) BeginBlock(_ context.Context) error { return nil } -// EndBlock returns the end blocker for the deployment module. It returns no validator +// EndBlock returns the end blocker for the take module. It returns no validator // updates. func (am AppModule) EndBlock(_ context.Context) error { return nil diff --git a/x/wasm/alias.go b/x/wasm/alias.go new file mode 100644 index 0000000000..56f36b6779 --- /dev/null +++ b/x/wasm/alias.go @@ -0,0 +1,12 @@ +package wasm + +import ( + types "pkg.akt.dev/go/node/wasm/v1" +) + +const ( + // StoreKey represents storekey of wasm module + StoreKey = types.StoreKey + // ModuleName represents current module name + ModuleName = types.ModuleName +) diff --git a/x/wasm/genesis.go b/x/wasm/genesis.go new file mode 100644 index 0000000000..c08296b14e --- /dev/null +++ b/x/wasm/genesis.go @@ -0,0 +1,50 @@ +package wasm + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + types "pkg.akt.dev/go/node/wasm/v1" + + "pkg.akt.dev/node/v2/x/wasm/keeper" +) + +// ValidateGenesis does validation check of the Genesis and return error incase of failure +func ValidateGenesis(data *types.GenesisState) error { + return data.Params.Validate() +} + +// DefaultGenesisState returns default genesis state as raw bytes for the deployment +// module. +func DefaultGenesisState() *types.GenesisState { + params := types.DefaultParams() + params.BlockedAddresses = []string{ + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + authtypes.NewModuleAddress(distrtypes.ModuleName).String(), + authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), + authtypes.NewModuleAddress(stakingtypes.NotBondedPoolName).String(), + } + + return &types.GenesisState{ + Params: params, + } +} + +// InitGenesis initiate genesis state and return updated validator details +func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, data *types.GenesisState) { + err := keeper.SetParams(ctx, data.Params) + if err != nil { + panic(err.Error()) + } +} + +// ExportGenesis returns genesis state for the deployment module +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { + params := k.GetParams(ctx) + return &types.GenesisState{ + Params: params, + } +} diff --git a/x/wasm/handler/server.go b/x/wasm/handler/server.go new file mode 100644 index 0000000000..d6186a0430 --- /dev/null +++ b/x/wasm/handler/server.go @@ -0,0 +1,39 @@ +package handler + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + types "pkg.akt.dev/go/node/wasm/v1" + + "pkg.akt.dev/node/v2/x/wasm/keeper" +) + +var _ types.MsgServer = msgServer{} + +type msgServer struct { + keeper keeper.Keeper +} + +// NewMsgServerImpl returns an implementation of the akash staking MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(k keeper.Keeper) types.MsgServer { + return &msgServer{ + keeper: k, + } +} + +func (ms msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { + if ms.keeper.GetAuthority() != req.Authority { + return nil, govtypes.ErrInvalidSigner.Wrapf("invalid authority; expected %s, got %s", ms.keeper.GetAuthority(), req.Authority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := ms.keeper.SetParams(ctx, req.Params); err != nil { + return nil, err + } + + return &types.MsgUpdateParamsResponse{}, nil +} diff --git a/x/wasm/keeper/grpc_query.go b/x/wasm/keeper/grpc_query.go new file mode 100644 index 0000000000..643811b736 --- /dev/null +++ b/x/wasm/keeper/grpc_query.go @@ -0,0 +1,30 @@ +package keeper + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + sdk "github.com/cosmos/cosmos-sdk/types" + + types "pkg.akt.dev/go/node/wasm/v1" +) + +// Querier is used as Keeper will have duplicate methods if used directly, and gRPC names take precedence over keeper +type Querier struct { + Keeper +} + +var _ types.QueryServer = Querier{} + +func (k Querier) Params(ctx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + if req == nil { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + params := k.GetParams(sdkCtx) + + return &types.QueryParamsResponse{Params: params}, nil +} diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go new file mode 100644 index 0000000000..4eca06d15f --- /dev/null +++ b/x/wasm/keeper/keeper.go @@ -0,0 +1,102 @@ +package keeper + +import ( + storetypes "cosmossdk.io/store/types" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + types "pkg.akt.dev/go/node/wasm/v1" +) + +type SetParamsHook func(sdk.Context, types.Params) + +type Keeper interface { + StoreKey() storetypes.StoreKey + Codec() codec.BinaryCodec + GetParams(ctx sdk.Context) (params types.Params) + SetParams(ctx sdk.Context, params types.Params) error + NewMsgFilterDecorator() func(wasmkeeper.Messenger) wasmkeeper.Messenger + + AddOnSetParamsHook(SetParamsHook) Keeper + + NewQuerier() Querier + GetAuthority() string +} + +// Keeper of the deployment store +type keeper struct { + skey storetypes.StoreKey + cdc codec.BinaryCodec + hooks struct { + onSetParams []SetParamsHook + } + + // The address capable of executing an MsgUpdateParams message. + // This should be the x/gov module account. + authority string +} + +// NewKeeper creates and returns an instance of take keeper +func NewKeeper(cdc codec.BinaryCodec, skey storetypes.StoreKey, authority string) Keeper { + return &keeper{ + skey: skey, + cdc: cdc, + authority: authority, + } +} + +// Codec returns keeper codec +func (k *keeper) Codec() codec.BinaryCodec { + return k.cdc +} + +func (k *keeper) StoreKey() storetypes.StoreKey { + return k.skey +} + +func (k *keeper) NewQuerier() Querier { + return Querier{k} +} + +// GetAuthority returns the x/mint module's authority. +func (k *keeper) GetAuthority() string { + return k.authority +} + +// SetParams sets the x/take module parameters. +func (k *keeper) SetParams(ctx sdk.Context, p types.Params) error { + if err := p.Validate(); err != nil { + return err + } + + store := ctx.KVStore(k.skey) + bz := k.cdc.MustMarshal(&p) + store.Set(types.ParamsPrefix(), bz) + + // call hooks + for _, hook := range k.hooks.onSetParams { + hook(ctx, p) + } + + return nil +} + +// GetParams returns the current x/take module parameters. +func (k *keeper) GetParams(ctx sdk.Context) (p types.Params) { + store := ctx.KVStore(k.skey) + bz := store.Get(types.ParamsPrefix()) + if bz == nil { + return p + } + + k.cdc.MustUnmarshal(bz, &p) + + return p +} + +func (k *keeper) AddOnSetParamsHook(hook SetParamsHook) Keeper { + k.hooks.onSetParams = append(k.hooks.onSetParams, hook) + + return k +} diff --git a/x/wasm/keeper/msg_filter.go b/x/wasm/keeper/msg_filter.go new file mode 100644 index 0000000000..afd8230fa9 --- /dev/null +++ b/x/wasm/keeper/msg_filter.go @@ -0,0 +1,209 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmvmtypes "github.com/CosmWasm/wasmvm/v3/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + + wv1 "pkg.akt.dev/go/node/wasm/v1" +) + +// FilterMessenger wraps the default messenger with Phase 1 restrictions +type FilterMessenger struct { + k *keeper + next wasmkeeper.Messenger +} + +// NewMsgFilterDecorator returns the message filter decorator +func (k *keeper) NewMsgFilterDecorator() func(wasmkeeper.Messenger) wasmkeeper.Messenger { + return func(next wasmkeeper.Messenger) wasmkeeper.Messenger { + return &FilterMessenger{ + k: k, + next: next, + } + } +} + +// DispatchMsg applies Phase 1 filtering before dispatching +func (m *FilterMessenger) DispatchMsg( + ctx sdk.Context, + contractAddr sdk.AccAddress, + contractIBCPortID string, + msg wasmvmtypes.CosmosMsg, +) (events []sdk.Event, data [][]byte, msgResponses [][]*codectypes.Any, err error) { + // Apply Phase 1 restrictions + if err := m.k.FilterMessage(ctx, contractAddr, msg); err != nil { + // Emit event for monitoring + _ = ctx.EventManager().EmitTypedEvent( + &wv1.EventMsgBlocked{ + ContractAddress: contractAddr.String(), + MsgType: getMessageType(msg), + Reason: err.Error(), + }, + ) + + ctx.Logger().Info("Phase 1: Message blocked", + "contract", contractAddr.String(), + "type", getMessageType(msg), + "reason", err.Error(), + ) + + return nil, nil, nil, err + } + + // Pass to wrapped messenger + return m.next.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) +} + +// FilterMessage applies Phase 1 filtering rules +func (k *keeper) FilterMessage(sctx sdk.Context, contractAddr sdk.AccAddress, msg wasmvmtypes.CosmosMsg, +) error { + // ALLOW Bank messages (with restrictions) + if msg.Bank != nil { + return k.filterBankMessage(sctx, msg.Bank) + } + + // BLOCK Staking messages + if msg.Staking != nil { + return errorsmod.Wrap( + sdkerrors.ErrUnauthorized, + "Staking operations not allowed", + ) + } + + // BLOCK Distribution messages + if msg.Distribution != nil { + return errorsmod.Wrap( + sdkerrors.ErrUnauthorized, + "Distribution operations not allowed", + ) + } + + // BLOCK Governance messages + if msg.Gov != nil { + return errorsmod.Wrap( + sdkerrors.ErrUnauthorized, + "Governance operations not allowed", + ) + } + + // BLOCK IBC messages + if msg.IBC != nil { + return errorsmod.Wrap( + sdkerrors.ErrUnauthorized, + "IBC messages not allowed", + ) + } + + if msg.IBC2 != nil { + return errorsmod.Wrap( + sdkerrors.ErrUnauthorized, + "IBC2 messages not allowed", + ) + } + + // BLOCK Custom messages (no Akash bindings) + if msg.Custom != nil { + return errorsmod.Wrap( + sdkerrors.ErrUnauthorized, + "Custom messages not allowed", + ) + } + + // BLOCK Any messages (no Akash bindings) + if msg.Any != nil { + return errorsmod.Wrap( + sdkerrors.ErrUnauthorized, + "Any messages not allowed", + ) + } + + // ALLOW Wasm messages (contract-to-contract calls) + if msg.Wasm != nil { + // Wasm execute/instantiate allowed + return nil + } + + // BLOCK unknown/unhandled message types + return errorsmod.Wrap( + sdkerrors.ErrUnauthorized, + "Unknown message type not allowed", + ) +} + +// filterBankMessage applies restrictions to bank operations +func (k *keeper) filterBankMessage(sctx sdk.Context, msg *wasmvmtypes.BankMsg) error { + // Allow send with restrictions + if msg.Send != nil { + params := k.GetParams(sctx) + + // Block transfers to critical addresses + for _, addr := range params.BlockedAddresses { + if addr == msg.Send.ToAddress { + return errorsmod.Wrapf( + sdkerrors.ErrUnauthorized, + "Transfers to %s blocked (critical address)", + msg.Send.ToAddress, + ) + } + } + + // Transfers to regular addresses allowed + return nil + } + + // Deny burns + if msg.Burn != nil { + return errorsmod.Wrapf( + sdkerrors.ErrUnauthorized, + "Burn is not allowed", + ) + } + + return nil +} + +// getMessageType returns a human-readable message type +func getMessageType(msg wasmvmtypes.CosmosMsg) string { + if msg.Bank != nil { + if msg.Bank.Send != nil { + return "bank.send" + } + if msg.Bank.Burn != nil { + return "bank.burn" + } + return "bank.unknown" + } + if msg.Staking != nil { + return "staking" + } + if msg.Distribution != nil { + return "distribution" + } + if msg.IBC != nil { + return "ibc" + } + if msg.IBC2 != nil { + return "ibc2" + } + if msg.Wasm != nil { + return "wasm" + } + if msg.Gov != nil { + return "gov" + } + if msg.Custom != nil { + return "custom" + } + + if msg.Any != nil { + return msg.Any.TypeURL + } + + return "unknown" +} diff --git a/x/wasm/module.go b/x/wasm/module.go new file mode 100644 index 0000000000..970fcd4c41 --- /dev/null +++ b/x/wasm/module.go @@ -0,0 +1,182 @@ +package wasm + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + "cosmossdk.io/core/appmodule" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + types "pkg.akt.dev/go/node/wasm/v1" + + "pkg.akt.dev/node/v2/x/wasm/handler" + "pkg.akt.dev/node/v2/x/wasm/keeper" + "pkg.akt.dev/node/v2/x/wasm/simulation" +) + +var ( + _ module.AppModuleBasic = AppModuleBasic{} + _ module.HasGenesisBasics = AppModuleBasic{} + + _ appmodule.AppModule = AppModule{} + _ module.HasConsensusVersion = AppModule{} + _ module.HasGenesis = AppModule{} + _ module.HasServices = AppModule{} + + _ module.AppModuleSimulation = AppModule{} +) + +// AppModuleBasic defines the basic application module used by the wasm module. +type AppModuleBasic struct { + cdc codec.Codec +} + +// AppModule implements an application module for the wasm module. +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper +} + +// Name returns wasm module's name +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the wasm module's types for the given codec. +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) // nolint staticcheck +} + +// RegisterInterfaces registers the module's interface types +func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// DefaultGenesis returns default genesis state as raw bytes for the wasm module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(DefaultGenesisState()) +} + +// ValidateGenesis validation check of the Genesis +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + if bz == nil { + return nil + } + + var data types.GenesisState + + err := cdc.UnmarshalJSON(bz, &data) + if err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %v", types.ModuleName, err) + } + + return ValidateGenesis(&data) +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the wasm module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(cctx client.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(cctx)); err != nil { + panic(err) + } +} + +// GetQueryCmd returns the root query command of this module +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + panic("akash modules do not export cli commands via cosmos interface") +} + +// GetTxCmd returns the transaction commands for this module +func (AppModuleBasic) GetTxCmd() *cobra.Command { + panic("akash modules do not export cli commands via cosmos interface") +} + +// NewAppModule creates a new AppModule object +func NewAppModule(cdc codec.Codec, k keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{cdc: cdc}, + keeper: k, + } +} + +// Name returns the provider module name +func (AppModule) Name() string { + return types.ModuleName +} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (am AppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (am AppModule) IsAppModule() {} + +// QuerierRoute returns the wasm module's querier route name. +func (am AppModule) QuerierRoute() string { + return types.ModuleName +} + +// RegisterServices registers the module's services +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), handler.NewMsgServerImpl(am.keeper)) + querier := am.keeper.NewQuerier() + types.RegisterQueryServer(cfg.QueryServer(), querier) +} + +// BeginBlock performs no-op +func (am AppModule) BeginBlock(_ context.Context) error { + return nil +} + +// EndBlock returns the end blocker for the wasm module. It returns no validator +// updates. +func (am AppModule) EndBlock(_ context.Context) error { + return nil +} + +// InitGenesis performs genesis initialization for the wasm module. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) { + var genesisState types.GenesisState + cdc.MustUnmarshalJSON(data, &genesisState) + InitGenesis(ctx, am.keeper, &genesisState) +} + +// ExportGenesis returns the exported genesis state as raw bytes for the wasm +// module. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(gs) +} + +// ConsensusVersion implements module.AppModule#ConsensusVersion +func (am AppModule) ConsensusVersion() uint64 { + return 1 +} + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the staking module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(_ module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() +} + +// RegisterStoreDecoder registers a decoder for take module's types. +func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry) {} + +// WeightedOperations doesn't return any take module operation. +func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { + return nil +} diff --git a/x/wasm/simulation/decoder.go b/x/wasm/simulation/decoder.go new file mode 100644 index 0000000000..c1be5a2b23 --- /dev/null +++ b/x/wasm/simulation/decoder.go @@ -0,0 +1,17 @@ +package simulation + +// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's +// Value to the corresponding mint type. +// func NewDecodeStore(_ codec.Codec) func(kvA, kvB kv.Pair) string { +// return func(kvA, kvB kv.Pair) string { +// switch { +// case bytes.Equal(kvA.Key, types.MinterKey): +// var minterA, minterB types.Minter +// cdc.MustUnmarshal(kvA.Value, &minterA) +// cdc.MustUnmarshal(kvB.Value, &minterB) +// return fmt.Sprintf("%v\n%v", minterA, minterB) +// default: +// panic(fmt.Sprintf("invalid mint key %X", kvA.Key)) +// } +// } +// } diff --git a/x/wasm/simulation/genesis.go b/x/wasm/simulation/genesis.go new file mode 100644 index 0000000000..aa1e5ee055 --- /dev/null +++ b/x/wasm/simulation/genesis.go @@ -0,0 +1,16 @@ +package simulation + +import ( + "github.com/cosmos/cosmos-sdk/types/module" + + types "pkg.akt.dev/go/node/wasm/v1" +) + +// RandomizedGenState generates a random GenesisState for supply +func RandomizedGenState(simState *module.SimulationState) { + takeGenesis := &types.GenesisState{ + Params: types.DefaultParams(), + } + + simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(takeGenesis) +} diff --git a/x/wasm/simulation/proposals.go b/x/wasm/simulation/proposals.go new file mode 100644 index 0000000000..bd76c12b01 --- /dev/null +++ b/x/wasm/simulation/proposals.go @@ -0,0 +1,42 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + + types "pkg.akt.dev/go/node/wasm/v1" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" //nolint:gosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateMsgUpdateParams, + ), + } +} + +func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // use the default gov module account address as authority + var authority sdk.AccAddress = address.Module("gov") + + params := types.DefaultParams() + + return &types.MsgUpdateParams{ + Authority: authority.String(), + Params: params, + } +}